aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_reminders
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_reminders')
-rw-r--r--apps/files_reminders/appinfo/info.xml39
-rw-r--r--apps/files_reminders/appinfo/routes.php20
-rw-r--r--apps/files_reminders/composer/autoload.php25
-rw-r--r--apps/files_reminders/composer/composer.json13
-rw-r--r--apps/files_reminders/composer/composer.lock18
-rw-r--r--apps/files_reminders/composer/composer/ClassLoader.php579
-rw-r--r--apps/files_reminders/composer/composer/InstalledVersions.php359
-rw-r--r--apps/files_reminders/composer/composer/LICENSE21
-rw-r--r--apps/files_reminders/composer/composer/autoload_classmap.php30
-rw-r--r--apps/files_reminders/composer/composer/autoload_namespaces.php9
-rw-r--r--apps/files_reminders/composer/composer/autoload_psr4.php10
-rw-r--r--apps/files_reminders/composer/composer/autoload_real.php37
-rw-r--r--apps/files_reminders/composer/composer/autoload_static.php56
-rw-r--r--apps/files_reminders/composer/composer/installed.json5
-rw-r--r--apps/files_reminders/composer/composer/installed.php23
-rw-r--r--apps/files_reminders/img/app-dark.svg1
-rw-r--r--apps/files_reminders/img/app.svg1
-rw-r--r--apps/files_reminders/l10n/.gitkeep0
-rw-r--r--apps/files_reminders/l10n/ar.js35
-rw-r--r--apps/files_reminders/l10n/ar.json33
-rw-r--r--apps/files_reminders/l10n/cs.js36
-rw-r--r--apps/files_reminders/l10n/cs.json34
-rw-r--r--apps/files_reminders/l10n/da.js37
-rw-r--r--apps/files_reminders/l10n/da.json35
-rw-r--r--apps/files_reminders/l10n/de.js39
-rw-r--r--apps/files_reminders/l10n/de.json37
-rw-r--r--apps/files_reminders/l10n/de_DE.js39
-rw-r--r--apps/files_reminders/l10n/de_DE.json37
-rw-r--r--apps/files_reminders/l10n/el.js27
-rw-r--r--apps/files_reminders/l10n/el.json25
-rw-r--r--apps/files_reminders/l10n/en_GB.js39
-rw-r--r--apps/files_reminders/l10n/en_GB.json37
-rw-r--r--apps/files_reminders/l10n/es.js39
-rw-r--r--apps/files_reminders/l10n/es.json37
-rw-r--r--apps/files_reminders/l10n/et_EE.js37
-rw-r--r--apps/files_reminders/l10n/et_EE.json35
-rw-r--r--apps/files_reminders/l10n/eu.js22
-rw-r--r--apps/files_reminders/l10n/eu.json20
-rw-r--r--apps/files_reminders/l10n/fi.js30
-rw-r--r--apps/files_reminders/l10n/fi.json28
-rw-r--r--apps/files_reminders/l10n/fr.js37
-rw-r--r--apps/files_reminders/l10n/fr.json35
-rw-r--r--apps/files_reminders/l10n/ga.js37
-rw-r--r--apps/files_reminders/l10n/ga.json35
-rw-r--r--apps/files_reminders/l10n/gl.js32
-rw-r--r--apps/files_reminders/l10n/gl.json30
-rw-r--r--apps/files_reminders/l10n/hu.js31
-rw-r--r--apps/files_reminders/l10n/hu.json29
-rw-r--r--apps/files_reminders/l10n/it.js39
-rw-r--r--apps/files_reminders/l10n/it.json37
-rw-r--r--apps/files_reminders/l10n/ja.js37
-rw-r--r--apps/files_reminders/l10n/ja.json35
-rw-r--r--apps/files_reminders/l10n/ko.js29
-rw-r--r--apps/files_reminders/l10n/ko.json27
-rw-r--r--apps/files_reminders/l10n/lt_LT.js31
-rw-r--r--apps/files_reminders/l10n/lt_LT.json29
-rw-r--r--apps/files_reminders/l10n/mk.js28
-rw-r--r--apps/files_reminders/l10n/mk.json26
-rw-r--r--apps/files_reminders/l10n/nb.js31
-rw-r--r--apps/files_reminders/l10n/nb.json29
-rw-r--r--apps/files_reminders/l10n/pl.js29
-rw-r--r--apps/files_reminders/l10n/pl.json27
-rw-r--r--apps/files_reminders/l10n/pt_BR.js39
-rw-r--r--apps/files_reminders/l10n/pt_BR.json37
-rw-r--r--apps/files_reminders/l10n/ro.js29
-rw-r--r--apps/files_reminders/l10n/ro.json27
-rw-r--r--apps/files_reminders/l10n/ru.js32
-rw-r--r--apps/files_reminders/l10n/ru.json30
-rw-r--r--apps/files_reminders/l10n/sk.js32
-rw-r--r--apps/files_reminders/l10n/sk.json30
-rw-r--r--apps/files_reminders/l10n/sr.js37
-rw-r--r--apps/files_reminders/l10n/sr.json35
-rw-r--r--apps/files_reminders/l10n/sv.js37
-rw-r--r--apps/files_reminders/l10n/sv.json35
-rw-r--r--apps/files_reminders/l10n/sw.js37
-rw-r--r--apps/files_reminders/l10n/sw.json35
-rw-r--r--apps/files_reminders/l10n/tr.js37
-rw-r--r--apps/files_reminders/l10n/tr.json35
-rw-r--r--apps/files_reminders/l10n/ug.js31
-rw-r--r--apps/files_reminders/l10n/ug.json29
-rw-r--r--apps/files_reminders/l10n/uk.js39
-rw-r--r--apps/files_reminders/l10n/uk.json37
-rw-r--r--apps/files_reminders/l10n/zh_CN.js31
-rw-r--r--apps/files_reminders/l10n/zh_CN.json29
-rw-r--r--apps/files_reminders/l10n/zh_HK.js39
-rw-r--r--apps/files_reminders/l10n/zh_HK.json37
-rw-r--r--apps/files_reminders/l10n/zh_TW.js39
-rw-r--r--apps/files_reminders/l10n/zh_TW.json37
-rw-r--r--apps/files_reminders/lib/AppInfo/Application.php49
-rw-r--r--apps/files_reminders/lib/BackgroundJob/CleanUpReminders.php33
-rw-r--r--apps/files_reminders/lib/BackgroundJob/ScheduledNotifications.php44
-rw-r--r--apps/files_reminders/lib/Command/ListCommand.php102
-rw-r--r--apps/files_reminders/lib/Controller/ApiController.php131
-rw-r--r--apps/files_reminders/lib/Dav/PropFindPlugin.php82
-rw-r--r--apps/files_reminders/lib/Db/Reminder.php50
-rw-r--r--apps/files_reminders/lib/Db/ReminderMapper.php151
-rw-r--r--apps/files_reminders/lib/Exception/NodeNotFoundException.php15
-rw-r--r--apps/files_reminders/lib/Exception/ReminderNotFoundException.php15
-rw-r--r--apps/files_reminders/lib/Exception/UserNotFoundException.php15
-rw-r--r--apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php41
-rw-r--r--apps/files_reminders/lib/Listener/NodeDeletedListener.php32
-rw-r--r--apps/files_reminders/lib/Listener/SabrePluginAddListener.php34
-rw-r--r--apps/files_reminders/lib/Listener/UserDeletedListener.php32
-rw-r--r--apps/files_reminders/lib/Migration/Version10000Date20230725162149.php65
-rw-r--r--apps/files_reminders/lib/Model/RichReminder.php57
-rw-r--r--apps/files_reminders/lib/Notification/Notifier.php110
-rw-r--r--apps/files_reminders/lib/Service/ReminderService.php217
-rw-r--r--apps/files_reminders/lib/SetupChecks/NeedNotificationsApp.php39
-rw-r--r--apps/files_reminders/openapi.json508
-rw-r--r--apps/files_reminders/openapi.json.license2
-rw-r--r--apps/files_reminders/src/actions/clearReminderAction.ts54
-rw-r--r--apps/files_reminders/src/actions/reminderStatusAction.ts45
-rw-r--r--apps/files_reminders/src/actions/setReminderCustomAction.ts43
-rw-r--r--apps/files_reminders/src/actions/setReminderMenuAction.ts37
-rw-r--r--apps/files_reminders/src/actions/setReminderSuggestionActions.scss23
-rw-r--r--apps/files_reminders/src/actions/setReminderSuggestionActions.ts143
-rw-r--r--apps/files_reminders/src/components/SetCustomReminderModal.vue195
-rw-r--r--apps/files_reminders/src/init.ts19
-rw-r--r--apps/files_reminders/src/services/customPicker.ts29
-rw-r--r--apps/files_reminders/src/services/reminderService.ts38
-rw-r--r--apps/files_reminders/src/shared/logger.ts11
-rw-r--r--apps/files_reminders/src/shared/types.ts10
-rw-r--r--apps/files_reminders/src/shared/utils.ts162
123 files changed, 6209 insertions, 0 deletions
diff --git a/apps/files_reminders/appinfo/info.xml b/apps/files_reminders/appinfo/info.xml
new file mode 100644
index 00000000000..cd3ed204743
--- /dev/null
+++ b/apps/files_reminders/appinfo/info.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+ - SPDX-FileCopyrightText: 2023 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>files_reminders</id>
+ <name>File reminders</name>
+ <summary>Set file reminders</summary>
+ <description><![CDATA[**📣 File reminders**
+
+Set file reminders.
+
+Note: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly.
+
+ ]]></description>
+ <version>1.5.0</version>
+ <licence>agpl</licence>
+ <author>Christopher Ng</author>
+ <namespace>FilesReminders</namespace>
+
+ <category>files</category>
+
+ <bugs>https://github.com/nextcloud/server/issues</bugs>
+
+ <dependencies>
+ <nextcloud min-version="32" max-version="32"/>
+ </dependencies>
+
+ <background-jobs>
+ <job>OCA\FilesReminders\BackgroundJob\CleanUpReminders</job>
+ <job>OCA\FilesReminders\BackgroundJob\ScheduledNotifications</job>
+ </background-jobs>
+
+ <commands>
+ <command>OCA\FilesReminders\Command\ListCommand</command>
+ </commands>
+ </info>
diff --git a/apps/files_reminders/appinfo/routes.php b/apps/files_reminders/appinfo/routes.php
new file mode 100644
index 00000000000..e6333282b34
--- /dev/null
+++ b/apps/files_reminders/appinfo/routes.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+$requirements = [
+ 'version' => '1',
+];
+
+return [
+ 'ocs' => [
+ ['name' => 'Api#get', 'url' => '/api/v{version}/{fileId}', 'verb' => 'GET', 'requirements' => $requirements],
+ ['name' => 'Api#set', 'url' => '/api/v{version}/{fileId}', 'verb' => 'PUT', 'requirements' => $requirements],
+ ['name' => 'Api#remove', 'url' => '/api/v{version}/{fileId}', 'verb' => 'DELETE', 'requirements' => $requirements],
+ ],
+];
diff --git a/apps/files_reminders/composer/autoload.php b/apps/files_reminders/composer/autoload.php
new file mode 100644
index 00000000000..ec4c8a9b85f
--- /dev/null
+++ b/apps/files_reminders/composer/autoload.php
@@ -0,0 +1,25 @@
+<?php
+
+// autoload.php @generated by Composer
+
+if (PHP_VERSION_ID < 50600) {
+ 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';
+
+return ComposerAutoloaderInitFilesReminders::getLoader();
diff --git a/apps/files_reminders/composer/composer.json b/apps/files_reminders/composer/composer.json
new file mode 100644
index 00000000000..f2d8aa0e73a
--- /dev/null
+++ b/apps/files_reminders/composer/composer.json
@@ -0,0 +1,13 @@
+{
+ "config" : {
+ "vendor-dir": ".",
+ "optimize-autoloader": true,
+ "classmap-authoritative": true,
+ "autoloader-suffix": "FilesReminders"
+ },
+ "autoload" : {
+ "psr-4": {
+ "OCA\\FilesReminders\\": "../lib/"
+ }
+ }
+}
diff --git a/apps/files_reminders/composer/composer.lock b/apps/files_reminders/composer/composer.lock
new file mode 100644
index 00000000000..62a29d36726
--- /dev/null
+++ b/apps/files_reminders/composer/composer.lock
@@ -0,0 +1,18 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "d751713988987e9331980363e24189ce",
+ "packages": [],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.3.0"
+}
diff --git a/apps/files_reminders/composer/composer/ClassLoader.php b/apps/files_reminders/composer/composer/ClassLoader.php
new file mode 100644
index 00000000000..7824d8f7eaf
--- /dev/null
+++ b/apps/files_reminders/composer/composer/ClassLoader.php
@@ -0,0 +1,579 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see https://www.php-fig.org/psr/psr-0/
+ * @see https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ /** @var \Closure(string):void */
+ private static $includeFile;
+
+ /** @var string|null */
+ private $vendorDir;
+
+ // PSR-4
+ /**
+ * @var array<string, array<string, int>>
+ */
+ private $prefixLengthsPsr4 = array();
+ /**
+ * @var array<string, list<string>>
+ */
+ private $prefixDirsPsr4 = array();
+ /**
+ * @var list<string>
+ */
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ /**
+ * 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 list<string>
+ */
+ private $fallbackDirsPsr0 = array();
+
+ /** @var bool */
+ private $useIncludePath = false;
+
+ /**
+ * @var array<string, string>
+ */
+ private $classMap = array();
+
+ /** @var bool */
+ private $classMapAuthoritative = false;
+
+ /**
+ * @var array<string, bool>
+ */
+ private $missingClasses = array();
+
+ /** @var string|null */
+ private $apcuPrefix;
+
+ /**
+ * @var array<string, self>
+ */
+ private static $registeredLoaders = array();
+
+ /**
+ * @param string|null $vendorDir
+ */
+ public function __construct($vendorDir = null)
+ {
+ $this->vendorDir = $vendorDir;
+ self::initializeIncludeClosure();
+ }
+
+ /**
+ * @return array<string, list<string>>
+ */
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+ }
+
+ return array();
+ }
+
+ /**
+ * @return array<string, list<string>>
+ */
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ /**
+ * @return list<string>
+ */
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ /**
+ * @return list<string>
+ */
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ /**
+ * @return array<string, string> Array of classname => path
+ */
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array<string, string> $classMap Class to filename map
+ *
+ * @return void
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * 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 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(
+ $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ $paths
+ );
+ }
+ }
+
+ /**
+ * 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 list<string>|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ $paths = (array) $paths;
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ $paths
+ );
+ }
+ }
+
+ /**
+ * 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 list<string>|string $paths The PSR-0 base directories
+ *
+ * @return void
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * 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 list<string>|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return void
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ 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;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ *
+ * @return void
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ *
+ * @return void
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ *
+ * @return void
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ *
+ * @return void
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+ if (null === $this->vendorDir) {
+ return;
+ }
+
+ if ($prepend) {
+ self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+ } else {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ self::$registeredLoaders[$this->vendorDir] = $this;
+ }
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ *
+ * @return void
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+
+ if (null !== $this->vendorDir) {
+ unset(self::$registeredLoaders[$this->vendorDir]);
+ }
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return true|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ $includeFile = self::$includeFile;
+ $includeFile($file);
+
+ return true;
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ /**
+ * Returns the currently registered loaders keyed by their corresponding vendor directories.
+ *
+ * @return array<string, self>
+ */
+ public static function getRegisteredLoaders()
+ {
+ return self::$registeredLoaders;
+ }
+
+ /**
+ * @param string $class
+ * @param string $ext
+ * @return string|false
+ */
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+
+ /**
+ * @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/files_reminders/composer/composer/InstalledVersions.php b/apps/files_reminders/composer/composer/InstalledVersions.php
new file mode 100644
index 00000000000..51e734a774b
--- /dev/null
+++ b/apps/files_reminders/composer/composer/InstalledVersions.php
@@ -0,0 +1,359 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ * Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+ /**
+ * @var mixed[]|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;
+
+ /**
+ * @var bool|null
+ */
+ private static $canGetVendors;
+
+ /**
+ * @var array[]
+ * @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();
+
+ /**
+ * Returns a list of all package names which are present, either by being installed, replaced or provided
+ *
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackages()
+ {
+ $packages = array();
+ foreach (self::getInstalled() as $installed) {
+ $packages[] = array_keys($installed['versions']);
+ }
+
+ if (1 === \count($packages)) {
+ return $packages[0];
+ }
+
+ return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+ }
+
+ /**
+ * Returns a list of all package names with a specific type e.g. 'library'
+ *
+ * @param string $type
+ * @return string[]
+ * @psalm-return list<string>
+ */
+ public static function getInstalledPackagesByType($type)
+ {
+ $packagesByType = array();
+
+ foreach (self::getInstalled() as $installed) {
+ foreach ($installed['versions'] as $name => $package) {
+ if (isset($package['type']) && $package['type'] === $type) {
+ $packagesByType[] = $name;
+ }
+ }
+ }
+
+ return $packagesByType;
+ }
+
+ /**
+ * Checks whether the given package is installed
+ *
+ * This also returns true if the package name is provided or replaced by another package
+ *
+ * @param string $packageName
+ * @param bool $includeDevRequirements
+ * @return bool
+ */
+ public static function isInstalled($packageName, $includeDevRequirements = true)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (isset($installed['versions'][$packageName])) {
+ return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the given package satisfies a version constraint
+ *
+ * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+ *
+ * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+ *
+ * @param VersionParser $parser Install composer/semver to have access to this class and functionality
+ * @param string $packageName
+ * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+ * @return bool
+ */
+ public static function satisfies(VersionParser $parser, $packageName, $constraint)
+ {
+ $constraint = $parser->parseConstraints((string) $constraint);
+ $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+ return $provided->matches($constraint);
+ }
+
+ /**
+ * Returns a version constraint representing all the range(s) which are installed for a given package
+ *
+ * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+ * whether a given version of a package is installed, and not just whether it exists
+ *
+ * @param string $packageName
+ * @return string Version constraint usable with composer/semver
+ */
+ public static function getVersionRanges($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ $ranges = array();
+ if (isset($installed['versions'][$packageName]['pretty_version'])) {
+ $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+ }
+ if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+ }
+ if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+ }
+ if (array_key_exists('provided', $installed['versions'][$packageName])) {
+ $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+ }
+
+ return implode(' || ', $ranges);
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+ */
+ public static function getPrettyVersion($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['pretty_version'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+ */
+ public static function getReference($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ if (!isset($installed['versions'][$packageName]['reference'])) {
+ return null;
+ }
+
+ return $installed['versions'][$packageName]['reference'];
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @param string $packageName
+ * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+ */
+ public static function getInstallPath($packageName)
+ {
+ foreach (self::getInstalled() as $installed) {
+ if (!isset($installed['versions'][$packageName])) {
+ continue;
+ }
+
+ return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+ }
+
+ throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+ }
+
+ /**
+ * @return array
+ * @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()
+ {
+ $installed = self::getInstalled();
+
+ return $installed[0]['root'];
+ }
+
+ /**
+ * Returns the raw installed.php data for custom implementations
+ *
+ * @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, 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()
+ {
+ @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+ if (null === self::$installed) {
+ // 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 = include __DIR__ . '/installed.php';
+ } else {
+ self::$installed = array();
+ }
+ }
+
+ return self::$installed;
+ }
+
+ /**
+ * 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, 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()
+ {
+ return self::getInstalled();
+ }
+
+ /**
+ * Lets you reload the static array from another file
+ *
+ * This is only useful for complex integrations in which a project needs to use
+ * this class but then also needs to execute another project's autoloader in process,
+ * and wants to ensure both projects have access to their version of installed.php.
+ *
+ * A typical case would be PHPUnit, where it would need to make sure it reads all
+ * the data it needs from this class, then call reload() with
+ * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+ * the project in which it runs can then also use this class safely, without
+ * interference between PHPUnit's dependencies and the project's dependencies.
+ *
+ * @param array[] $data A vendor/composer/installed.php data set
+ * @return void
+ *
+ * @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)
+ {
+ self::$installed = $data;
+ self::$installedByVendor = array();
+ }
+
+ /**
+ * @return array[]
+ * @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()
+ {
+ if (null === self::$canGetVendors) {
+ self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+ }
+
+ $installed = array();
+
+ if (self::$canGetVendors) {
+ foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+ if (isset(self::$installedByVendor[$vendorDir])) {
+ $installed[] = self::$installedByVendor[$vendorDir];
+ } elseif (is_file($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];
+ }
+ }
+ }
+ }
+
+ if (null === self::$installed) {
+ // 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') {
+ /** @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();
+ }
+ }
+
+ if (self::$installed !== array()) {
+ $installed[] = self::$installed;
+ }
+
+ return $installed;
+ }
+}
diff --git a/apps/files_reminders/composer/composer/LICENSE b/apps/files_reminders/composer/composer/LICENSE
new file mode 100644
index 00000000000..f27399a042d
--- /dev/null
+++ b/apps/files_reminders/composer/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/apps/files_reminders/composer/composer/autoload_classmap.php b/apps/files_reminders/composer/composer/autoload_classmap.php
new file mode 100644
index 00000000000..f3a95a64e74
--- /dev/null
+++ b/apps/files_reminders/composer/composer/autoload_classmap.php
@@ -0,0 +1,30 @@
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = $vendorDir;
+
+return array(
+ 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+ 'OCA\\FilesReminders\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
+ 'OCA\\FilesReminders\\BackgroundJob\\CleanUpReminders' => $baseDir . '/../lib/BackgroundJob/CleanUpReminders.php',
+ 'OCA\\FilesReminders\\BackgroundJob\\ScheduledNotifications' => $baseDir . '/../lib/BackgroundJob/ScheduledNotifications.php',
+ 'OCA\\FilesReminders\\Command\\ListCommand' => $baseDir . '/../lib/Command/ListCommand.php',
+ 'OCA\\FilesReminders\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php',
+ 'OCA\\FilesReminders\\Dav\\PropFindPlugin' => $baseDir . '/../lib/Dav/PropFindPlugin.php',
+ 'OCA\\FilesReminders\\Db\\Reminder' => $baseDir . '/../lib/Db/Reminder.php',
+ 'OCA\\FilesReminders\\Db\\ReminderMapper' => $baseDir . '/../lib/Db/ReminderMapper.php',
+ 'OCA\\FilesReminders\\Exception\\NodeNotFoundException' => $baseDir . '/../lib/Exception/NodeNotFoundException.php',
+ 'OCA\\FilesReminders\\Exception\\ReminderNotFoundException' => $baseDir . '/../lib/Exception/ReminderNotFoundException.php',
+ 'OCA\\FilesReminders\\Exception\\UserNotFoundException' => $baseDir . '/../lib/Exception/UserNotFoundException.php',
+ 'OCA\\FilesReminders\\Listener\\LoadAdditionalScriptsListener' => $baseDir . '/../lib/Listener/LoadAdditionalScriptsListener.php',
+ 'OCA\\FilesReminders\\Listener\\NodeDeletedListener' => $baseDir . '/../lib/Listener/NodeDeletedListener.php',
+ 'OCA\\FilesReminders\\Listener\\SabrePluginAddListener' => $baseDir . '/../lib/Listener/SabrePluginAddListener.php',
+ 'OCA\\FilesReminders\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php',
+ 'OCA\\FilesReminders\\Migration\\Version10000Date20230725162149' => $baseDir . '/../lib/Migration/Version10000Date20230725162149.php',
+ 'OCA\\FilesReminders\\Model\\RichReminder' => $baseDir . '/../lib/Model/RichReminder.php',
+ 'OCA\\FilesReminders\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
+ 'OCA\\FilesReminders\\Service\\ReminderService' => $baseDir . '/../lib/Service/ReminderService.php',
+ 'OCA\\FilesReminders\\SetupChecks\\NeedNotificationsApp' => $baseDir . '/../lib/SetupChecks/NeedNotificationsApp.php',
+);
diff --git a/apps/files_reminders/composer/composer/autoload_namespaces.php b/apps/files_reminders/composer/composer/autoload_namespaces.php
new file mode 100644
index 00000000000..3f5c9296251
--- /dev/null
+++ b/apps/files_reminders/composer/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = $vendorDir;
+
+return array(
+);
diff --git a/apps/files_reminders/composer/composer/autoload_psr4.php b/apps/files_reminders/composer/composer/autoload_psr4.php
new file mode 100644
index 00000000000..51a8f01603e
--- /dev/null
+++ b/apps/files_reminders/composer/composer/autoload_psr4.php
@@ -0,0 +1,10 @@
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = $vendorDir;
+
+return array(
+ 'OCA\\FilesReminders\\' => array($baseDir . '/../lib'),
+);
diff --git a/apps/files_reminders/composer/composer/autoload_real.php b/apps/files_reminders/composer/composer/autoload_real.php
new file mode 100644
index 00000000000..f7b0857737e
--- /dev/null
+++ b/apps/files_reminders/composer/composer/autoload_real.php
@@ -0,0 +1,37 @@
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInitFilesReminders
+{
+ private static $loader;
+
+ public static function loadClassLoader($class)
+ {
+ if ('Composer\Autoload\ClassLoader' === $class) {
+ require __DIR__ . '/ClassLoader.php';
+ }
+ }
+
+ /**
+ * @return \Composer\Autoload\ClassLoader
+ */
+ public static function getLoader()
+ {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+
+ spl_autoload_register(array('ComposerAutoloaderInitFilesReminders', 'loadClassLoader'), true, true);
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
+ spl_autoload_unregister(array('ComposerAutoloaderInitFilesReminders', 'loadClassLoader'));
+
+ require __DIR__ . '/autoload_static.php';
+ call_user_func(\Composer\Autoload\ComposerStaticInitFilesReminders::getInitializer($loader));
+
+ $loader->setClassMapAuthoritative(true);
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/apps/files_reminders/composer/composer/autoload_static.php b/apps/files_reminders/composer/composer/autoload_static.php
new file mode 100644
index 00000000000..6a6475e03de
--- /dev/null
+++ b/apps/files_reminders/composer/composer/autoload_static.php
@@ -0,0 +1,56 @@
+<?php
+
+// autoload_static.php @generated by Composer
+
+namespace Composer\Autoload;
+
+class ComposerStaticInitFilesReminders
+{
+ public static $prefixLengthsPsr4 = array (
+ 'O' =>
+ array (
+ 'OCA\\FilesReminders\\' => 19,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'OCA\\FilesReminders\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/../lib',
+ ),
+ );
+
+ public static $classMap = array (
+ 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+ 'OCA\\FilesReminders\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
+ 'OCA\\FilesReminders\\BackgroundJob\\CleanUpReminders' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanUpReminders.php',
+ 'OCA\\FilesReminders\\BackgroundJob\\ScheduledNotifications' => __DIR__ . '/..' . '/../lib/BackgroundJob/ScheduledNotifications.php',
+ 'OCA\\FilesReminders\\Command\\ListCommand' => __DIR__ . '/..' . '/../lib/Command/ListCommand.php',
+ 'OCA\\FilesReminders\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php',
+ 'OCA\\FilesReminders\\Dav\\PropFindPlugin' => __DIR__ . '/..' . '/../lib/Dav/PropFindPlugin.php',
+ 'OCA\\FilesReminders\\Db\\Reminder' => __DIR__ . '/..' . '/../lib/Db/Reminder.php',
+ 'OCA\\FilesReminders\\Db\\ReminderMapper' => __DIR__ . '/..' . '/../lib/Db/ReminderMapper.php',
+ 'OCA\\FilesReminders\\Exception\\NodeNotFoundException' => __DIR__ . '/..' . '/../lib/Exception/NodeNotFoundException.php',
+ 'OCA\\FilesReminders\\Exception\\ReminderNotFoundException' => __DIR__ . '/..' . '/../lib/Exception/ReminderNotFoundException.php',
+ 'OCA\\FilesReminders\\Exception\\UserNotFoundException' => __DIR__ . '/..' . '/../lib/Exception/UserNotFoundException.php',
+ 'OCA\\FilesReminders\\Listener\\LoadAdditionalScriptsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalScriptsListener.php',
+ 'OCA\\FilesReminders\\Listener\\NodeDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/NodeDeletedListener.php',
+ 'OCA\\FilesReminders\\Listener\\SabrePluginAddListener' => __DIR__ . '/..' . '/../lib/Listener/SabrePluginAddListener.php',
+ 'OCA\\FilesReminders\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php',
+ 'OCA\\FilesReminders\\Migration\\Version10000Date20230725162149' => __DIR__ . '/..' . '/../lib/Migration/Version10000Date20230725162149.php',
+ 'OCA\\FilesReminders\\Model\\RichReminder' => __DIR__ . '/..' . '/../lib/Model/RichReminder.php',
+ 'OCA\\FilesReminders\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
+ 'OCA\\FilesReminders\\Service\\ReminderService' => __DIR__ . '/..' . '/../lib/Service/ReminderService.php',
+ 'OCA\\FilesReminders\\SetupChecks\\NeedNotificationsApp' => __DIR__ . '/..' . '/../lib/SetupChecks/NeedNotificationsApp.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInitFilesReminders::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInitFilesReminders::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInitFilesReminders::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/apps/files_reminders/composer/composer/installed.json b/apps/files_reminders/composer/composer/installed.json
new file mode 100644
index 00000000000..f20a6c47c6d
--- /dev/null
+++ b/apps/files_reminders/composer/composer/installed.json
@@ -0,0 +1,5 @@
+{
+ "packages": [],
+ "dev": false,
+ "dev-package-names": []
+}
diff --git a/apps/files_reminders/composer/composer/installed.php b/apps/files_reminders/composer/composer/installed.php
new file mode 100644
index 00000000000..6ec8a491b0b
--- /dev/null
+++ b/apps/files_reminders/composer/composer/installed.php
@@ -0,0 +1,23 @@
+<?php return array(
+ 'root' => array(
+ 'name' => '__root__',
+ 'pretty_version' => 'dev-master',
+ 'version' => 'dev-master',
+ 'reference' => '9685b49f0d8f9e7d34f299e51628748a04d0e175',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../',
+ 'aliases' => array(),
+ 'dev' => false,
+ ),
+ 'versions' => array(
+ '__root__' => array(
+ 'pretty_version' => 'dev-master',
+ 'version' => 'dev-master',
+ 'reference' => '9685b49f0d8f9e7d34f299e51628748a04d0e175',
+ 'type' => 'library',
+ 'install_path' => __DIR__ . '/../',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
+ ),
+);
diff --git a/apps/files_reminders/img/app-dark.svg b/apps/files_reminders/img/app-dark.svg
new file mode 100644
index 00000000000..4f276090198
--- /dev/null
+++ b/apps/files_reminders/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="M480-96q-70 0-131.13-26.6-61.14-26.6-106.4-71.87-45.27-45.26-71.87-106.4Q144-362 144-432t26.6-131.13q26.6-61.14 71.87-106.4 45.26-45.27 106.4-71.87Q410-768 480-768t131.13 26.6q61.14 26.6 106.4 71.87 45.27 45.26 71.87 106.4Q816-502 816-432t-26.6 131.13q-26.6 61.14-71.87 106.4-45.26 45.27-106.4 71.87Q550-96 480-96Zm100-200 51-51-115-115v-162h-72v192l136 136ZM237-845l51 51-170 170-51-51 170-170Zm486 0 170 170-51 51-170-170 51-51Z"/></svg> \ No newline at end of file
diff --git a/apps/files_reminders/img/app.svg b/apps/files_reminders/img/app.svg
new file mode 100644
index 00000000000..8350139e3ed
--- /dev/null
+++ b/apps/files_reminders/img/app.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#fff"><path d="M480-96q-70 0-131.13-26.6-61.14-26.6-106.4-71.87-45.27-45.26-71.87-106.4Q144-362 144-432t26.6-131.13q26.6-61.14 71.87-106.4 45.26-45.27 106.4-71.87Q410-768 480-768t131.13 26.6q61.14 26.6 106.4 71.87 45.27 45.26 71.87 106.4Q816-502 816-432t-26.6 131.13q-26.6 61.14-71.87 106.4-45.26 45.27-106.4 71.87Q550-96 480-96Zm100-200 51-51-115-115v-162h-72v192l136 136ZM237-845l51 51-170 170-51-51 170-170Zm486 0 170 170-51 51-170-170 51-51Z"/></svg> \ No newline at end of file
diff --git a/apps/files_reminders/l10n/.gitkeep b/apps/files_reminders/l10n/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/apps/files_reminders/l10n/.gitkeep
diff --git a/apps/files_reminders/l10n/ar.js b/apps/files_reminders/l10n/ar.js
new file mode 100644
index 00000000000..67cf6016dfe
--- /dev/null
+++ b/apps/files_reminders/l10n/ar.js
@@ -0,0 +1,35 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "التذكير بالملفات",
+ "Reminder for {name}" : "تذكير لـ {name}",
+ "View file" : "أعرُض الملف",
+ "View folder" : "أعرُض المجلد",
+ "Files reminder" : "التذكير بالملفات",
+ "Set file reminders" : "ضبط تذكير بالملفات",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 التذكير بالملفات** \n\nضبط التذكير بالملفات. \n\nملاحظة: لاستخدام تطبيق \"التذكير بالملفات\"، تأكد من تثبيت تطبيق الإشعارات وتمكينه. يوفر تطبيق الإشعارات واجهة برمجة التطبيقات API اللازمة لتطبيق \"التذكير بالملفات\" ليعمل بالشكل الصحيح.",
+ "Set reminder for \"{fileName}\"" : "ضبط تذكير بالملف \"{fileName}\"",
+ "Clear reminder" : "محو التذكير",
+ "Please choose a valid date & time" : "من فضلك، إختَر وقتاً و تاريخاً صحيحين",
+ "Reminder set for \"{fileName}\"" : "تمّ ضبط تذكير بالملف \"{fileName}\"",
+ "Failed to set reminder" : "تعذّر ضبط التذكير",
+ "Reminder cleared for \"{fileName}\"" : "تمّ إلغاء التذكير بالملف \"{fileName}\"",
+ "Failed to clear reminder" : "تعذّرت إزالة التذكير",
+ "We will remind you of this file" : "سوف يتم تذكيرك بهذا الملف",
+ "Cancel" : "إلغاء",
+ "Set reminder" : "ضبط التذكير",
+ "Reminder set" : "تمّ وضع تذكير",
+ "Later today" : "في وقت لاحقٍ اليوم",
+ "Set reminder for later today" : "إضبِط التذكير لوقت لاحقٍ اليوم",
+ "Tomorrow" : "غداً",
+ "Set reminder for tomorrow" : "إضبِط التذكير للغد",
+ "This weekend" : "نهاية هذا الأسبوع",
+ "Set reminder for this weekend" : "إضبِط التذكير لنهاية هذا الأسبوع",
+ "Next week" : "الأسبوع القادم",
+ "Set reminder for next week" : "إضبِط التذكير للأسبوع القادم",
+ "This files_reminder can work properly." : "وظيفة التذكير بالملفات هذه تعمل بالشكل الصحيح.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "تطبيق التذكير بالملفات يحتاج إلى تطبيق الإشعارات ليعمل بالشكل الصحيح. عليك إمّا أن تقوم بتمكين الإشعارات او تعطيل التذكير بالملفات.",
+ "Set reminder at custom date & time" : "حدّد التذكير في وقت و تاريخ مخصص",
+ "Set custom reminder" : "ضبط تذكير مخصص"
+},
+"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/files_reminders/l10n/ar.json b/apps/files_reminders/l10n/ar.json
new file mode 100644
index 00000000000..344c1eea6f9
--- /dev/null
+++ b/apps/files_reminders/l10n/ar.json
@@ -0,0 +1,33 @@
+{ "translations": {
+ "File reminders" : "التذكير بالملفات",
+ "Reminder for {name}" : "تذكير لـ {name}",
+ "View file" : "أعرُض الملف",
+ "View folder" : "أعرُض المجلد",
+ "Files reminder" : "التذكير بالملفات",
+ "Set file reminders" : "ضبط تذكير بالملفات",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 التذكير بالملفات** \n\nضبط التذكير بالملفات. \n\nملاحظة: لاستخدام تطبيق \"التذكير بالملفات\"، تأكد من تثبيت تطبيق الإشعارات وتمكينه. يوفر تطبيق الإشعارات واجهة برمجة التطبيقات API اللازمة لتطبيق \"التذكير بالملفات\" ليعمل بالشكل الصحيح.",
+ "Set reminder for \"{fileName}\"" : "ضبط تذكير بالملف \"{fileName}\"",
+ "Clear reminder" : "محو التذكير",
+ "Please choose a valid date & time" : "من فضلك، إختَر وقتاً و تاريخاً صحيحين",
+ "Reminder set for \"{fileName}\"" : "تمّ ضبط تذكير بالملف \"{fileName}\"",
+ "Failed to set reminder" : "تعذّر ضبط التذكير",
+ "Reminder cleared for \"{fileName}\"" : "تمّ إلغاء التذكير بالملف \"{fileName}\"",
+ "Failed to clear reminder" : "تعذّرت إزالة التذكير",
+ "We will remind you of this file" : "سوف يتم تذكيرك بهذا الملف",
+ "Cancel" : "إلغاء",
+ "Set reminder" : "ضبط التذكير",
+ "Reminder set" : "تمّ وضع تذكير",
+ "Later today" : "في وقت لاحقٍ اليوم",
+ "Set reminder for later today" : "إضبِط التذكير لوقت لاحقٍ اليوم",
+ "Tomorrow" : "غداً",
+ "Set reminder for tomorrow" : "إضبِط التذكير للغد",
+ "This weekend" : "نهاية هذا الأسبوع",
+ "Set reminder for this weekend" : "إضبِط التذكير لنهاية هذا الأسبوع",
+ "Next week" : "الأسبوع القادم",
+ "Set reminder for next week" : "إضبِط التذكير للأسبوع القادم",
+ "This files_reminder can work properly." : "وظيفة التذكير بالملفات هذه تعمل بالشكل الصحيح.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "تطبيق التذكير بالملفات يحتاج إلى تطبيق الإشعارات ليعمل بالشكل الصحيح. عليك إمّا أن تقوم بتمكين الإشعارات او تعطيل التذكير بالملفات.",
+ "Set reminder at custom date & time" : "حدّد التذكير في وقت و تاريخ مخصص",
+ "Set custom reminder" : "ضبط تذكير مخصص"
+},"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/files_reminders/l10n/cs.js b/apps/files_reminders/l10n/cs.js
new file mode 100644
index 00000000000..409a22f5546
--- /dev/null
+++ b/apps/files_reminders/l10n/cs.js
@@ -0,0 +1,36 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Připomínky souborů",
+ "Reminder for {name}" : "Připomínka ohledně {name}",
+ "View file" : "Zobrazit soubor",
+ "View folder" : "Zobrazit složku",
+ "Files reminder" : "Připomínka souboru",
+ "The \"files_reminders\" app can work properly." : "Aplikace „files_reminder“ může fungovat správně.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Aplikace „files_reminder“ potřebuje, aby aplikace notifikace správně fungovala. Buď byste měli zapnout notifikace, nebo vypnout files_reminder.",
+ "Set file reminders" : "Nastavit připomínky souborů",
+ "Set reminder for \"{fileName}\"" : "Nastavit připomínku pro „{fileName}",
+ "Clear reminder" : "Vyčistit připomínku",
+ "Please choose a valid date & time" : "Zvolte platný datum a čas",
+ "Reminder set for \"{fileName}\"" : "Nastavena připomínka ohledně „{fileName}“",
+ "Failed to set reminder" : "Připomínku se nepodařilo nastavit",
+ "Reminder cleared for \"{fileName}\"" : "Připomínka ohledně „{fileName}“ vyčištěna",
+ "Failed to clear reminder" : "Připomínku se nepodařilo vyčistit",
+ "We will remind you of this file" : "Připomeneme vám tento soubor",
+ "Cancel" : "Storno",
+ "Set reminder" : "Nastavit připomínku",
+ "Reminder set" : "Nastavit připomínku",
+ "Later today" : "Později dnes",
+ "Set reminder for later today" : "Nastavit připomínku na později dnes",
+ "Tomorrow" : "Zítra",
+ "Set reminder for tomorrow" : "Nastavit připomínku na zítra",
+ "This weekend" : "Tento víkend",
+ "Set reminder for this weekend" : "Nastavit připomínku na tento víkend",
+ "Next week" : "Příští týden",
+ "Set reminder for next week" : "Nastavit připomínku pro příští týden",
+ "This files_reminder can work properly." : "Tento files_reminder může fungovat správně.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Aplikace files_reminder potřebuje, aby aplikace notifikace správně fungovala. Buď byste měli zapnout notifikace, nebo vypnout files_reminder.",
+ "Set reminder at custom date & time" : "Nastavit připomínku na uživatelsky určené datum a čas",
+ "Set custom reminder" : "Nastavit uživatelsky určenou připomínku"
+},
+"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/files_reminders/l10n/cs.json b/apps/files_reminders/l10n/cs.json
new file mode 100644
index 00000000000..af1f102fb9c
--- /dev/null
+++ b/apps/files_reminders/l10n/cs.json
@@ -0,0 +1,34 @@
+{ "translations": {
+ "File reminders" : "Připomínky souborů",
+ "Reminder for {name}" : "Připomínka ohledně {name}",
+ "View file" : "Zobrazit soubor",
+ "View folder" : "Zobrazit složku",
+ "Files reminder" : "Připomínka souboru",
+ "The \"files_reminders\" app can work properly." : "Aplikace „files_reminder“ může fungovat správně.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Aplikace „files_reminder“ potřebuje, aby aplikace notifikace správně fungovala. Buď byste měli zapnout notifikace, nebo vypnout files_reminder.",
+ "Set file reminders" : "Nastavit připomínky souborů",
+ "Set reminder for \"{fileName}\"" : "Nastavit připomínku pro „{fileName}",
+ "Clear reminder" : "Vyčistit připomínku",
+ "Please choose a valid date & time" : "Zvolte platný datum a čas",
+ "Reminder set for \"{fileName}\"" : "Nastavena připomínka ohledně „{fileName}“",
+ "Failed to set reminder" : "Připomínku se nepodařilo nastavit",
+ "Reminder cleared for \"{fileName}\"" : "Připomínka ohledně „{fileName}“ vyčištěna",
+ "Failed to clear reminder" : "Připomínku se nepodařilo vyčistit",
+ "We will remind you of this file" : "Připomeneme vám tento soubor",
+ "Cancel" : "Storno",
+ "Set reminder" : "Nastavit připomínku",
+ "Reminder set" : "Nastavit připomínku",
+ "Later today" : "Později dnes",
+ "Set reminder for later today" : "Nastavit připomínku na později dnes",
+ "Tomorrow" : "Zítra",
+ "Set reminder for tomorrow" : "Nastavit připomínku na zítra",
+ "This weekend" : "Tento víkend",
+ "Set reminder for this weekend" : "Nastavit připomínku na tento víkend",
+ "Next week" : "Příští týden",
+ "Set reminder for next week" : "Nastavit připomínku pro příští týden",
+ "This files_reminder can work properly." : "Tento files_reminder může fungovat správně.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Aplikace files_reminder potřebuje, aby aplikace notifikace správně fungovala. Buď byste měli zapnout notifikace, nebo vypnout files_reminder.",
+ "Set reminder at custom date & time" : "Nastavit připomínku na uživatelsky určené datum a čas",
+ "Set custom reminder" : "Nastavit uživatelsky určenou připomínku"
+},"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/files_reminders/l10n/da.js b/apps/files_reminders/l10n/da.js
new file mode 100644
index 00000000000..0ace810f929
--- /dev/null
+++ b/apps/files_reminders/l10n/da.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Filpåmindelser",
+ "Reminder for {name}" : "Påmindelse af {name}",
+ "View file" : "Vis fil",
+ "View folder" : "Vis mappe",
+ "Files reminder" : "Filpåmindelse",
+ "The \"files_reminders\" app can work properly." : "Appen \"files_reminders\" kan fungere korrekt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen \"files_reminders\" skal bruge notifikationsappen for at fungere korrekt. Du bør enten aktivere meddelelser eller deaktivere files_reminder.",
+ "Set file reminders" : "Sæt filpåmindelser",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Filpåmindelser**\n\nIndstil filpåmindelser.\n\nBemærk: For at bruge appen \"Filpåmindelser\" skal du sikre dig, at appen \"Meddelelser\" er installeret og aktiveret. Appen 'Notifikationer' giver de nødvendige API'er for at appen 'Filpåmindelser' kan fungere korrekt.",
+ "Set reminder for \"{fileName}\"" : "Indstil påmindelse for \"{fileName}\"",
+ "Clear reminder" : "Ryd påmindelse",
+ "Please choose a valid date & time" : "Vælg en gyldig dato & tid",
+ "Reminder set for \"{fileName}\"" : "Påmindelse indstillet til \"{fileName}\"",
+ "Failed to set reminder" : "Kunne ikke indstille påmindelsen",
+ "Reminder cleared for \"{fileName}\"" : "Påmindelsen blev ryddet for \"{fileName}\"",
+ "Failed to clear reminder" : "Kunne ikke rydde påmindelse",
+ "We will remind you of this file" : "Vi vil minde dig om denne fil",
+ "Cancel" : "Annuller",
+ "Set reminder" : "Sæt påmindelse",
+ "Reminder set" : "Påmindelse sat",
+ "Later today" : "Senere i dag",
+ "Set reminder for later today" : "Sæt påmindelse for senere i dag",
+ "Tomorrow" : "I morgen",
+ "Set reminder for tomorrow" : "Sæt påmindelse for i morgen",
+ "This weekend" : "Denne weekend",
+ "Set reminder for this weekend" : "Sæt påmindelse for denne weekend",
+ "Next week" : "Næste uge",
+ "Set reminder for next week" : "Sæt påmindelse for næste weekend",
+ "This files_reminder can work properly." : "Denne files_reminder kan fungere korrekt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Files_reminder-appen skal bruge notifikationsappen for at fungere korrekt. Du bør enten aktivere meddelelser eller deaktivere files_reminder.",
+ "Set reminder at custom date & time" : "Indstil påmindelse til tilpasset dato og klokkeslæt",
+ "Set custom reminder" : "Sæt brugerdefineret påmindelse"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/da.json b/apps/files_reminders/l10n/da.json
new file mode 100644
index 00000000000..0c9771b1dd2
--- /dev/null
+++ b/apps/files_reminders/l10n/da.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Filpåmindelser",
+ "Reminder for {name}" : "Påmindelse af {name}",
+ "View file" : "Vis fil",
+ "View folder" : "Vis mappe",
+ "Files reminder" : "Filpåmindelse",
+ "The \"files_reminders\" app can work properly." : "Appen \"files_reminders\" kan fungere korrekt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen \"files_reminders\" skal bruge notifikationsappen for at fungere korrekt. Du bør enten aktivere meddelelser eller deaktivere files_reminder.",
+ "Set file reminders" : "Sæt filpåmindelser",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Filpåmindelser**\n\nIndstil filpåmindelser.\n\nBemærk: For at bruge appen \"Filpåmindelser\" skal du sikre dig, at appen \"Meddelelser\" er installeret og aktiveret. Appen 'Notifikationer' giver de nødvendige API'er for at appen 'Filpåmindelser' kan fungere korrekt.",
+ "Set reminder for \"{fileName}\"" : "Indstil påmindelse for \"{fileName}\"",
+ "Clear reminder" : "Ryd påmindelse",
+ "Please choose a valid date & time" : "Vælg en gyldig dato & tid",
+ "Reminder set for \"{fileName}\"" : "Påmindelse indstillet til \"{fileName}\"",
+ "Failed to set reminder" : "Kunne ikke indstille påmindelsen",
+ "Reminder cleared for \"{fileName}\"" : "Påmindelsen blev ryddet for \"{fileName}\"",
+ "Failed to clear reminder" : "Kunne ikke rydde påmindelse",
+ "We will remind you of this file" : "Vi vil minde dig om denne fil",
+ "Cancel" : "Annuller",
+ "Set reminder" : "Sæt påmindelse",
+ "Reminder set" : "Påmindelse sat",
+ "Later today" : "Senere i dag",
+ "Set reminder for later today" : "Sæt påmindelse for senere i dag",
+ "Tomorrow" : "I morgen",
+ "Set reminder for tomorrow" : "Sæt påmindelse for i morgen",
+ "This weekend" : "Denne weekend",
+ "Set reminder for this weekend" : "Sæt påmindelse for denne weekend",
+ "Next week" : "Næste uge",
+ "Set reminder for next week" : "Sæt påmindelse for næste weekend",
+ "This files_reminder can work properly." : "Denne files_reminder kan fungere korrekt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Files_reminder-appen skal bruge notifikationsappen for at fungere korrekt. Du bør enten aktivere meddelelser eller deaktivere files_reminder.",
+ "Set reminder at custom date & time" : "Indstil påmindelse til tilpasset dato og klokkeslæt",
+ "Set custom reminder" : "Sæt brugerdefineret påmindelse"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/de.js b/apps/files_reminders/l10n/de.js
new file mode 100644
index 00000000000..d46b079f3fe
--- /dev/null
+++ b/apps/files_reminders/l10n/de.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Dateierinnerungen",
+ "Reminder for {name}" : "Erinnerung für {name}",
+ "View file" : "Datei anzeigen",
+ "View folder" : "Ordner anzeigen",
+ "Files reminder" : "Dateierinnerung",
+ "The \"files_reminders\" app can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminders“ deaktivieren.",
+ "Set file reminders" : "Dateierinnerungen setzen",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dateierinnerungen**\n\nDateierinnerungen festlegen.\n\nHinweis: Um die App ``Dateierinnerungen` zu verwenden, stelle sicher, dass die App `Benachrichtigungen` installiert und aktiviert ist. Die App `Benachrichtigungen` bietet die erforderlichen APIs, damit die App `Dateierinnerungen`ordnungsgemäß funktioniert.",
+ "Set reminder for \"{fileName}\"" : "Erinnerung für \"{fileName}\" setzen",
+ "Reminder at custom date & time" : "Erinnerung zu benutzerdefiniertem Zeitpunkt und Tag",
+ "Clear reminder" : "Erinnerung löschen",
+ "Please choose a valid date & time" : "Bitte gültiges Datum und Uhrzeit wählen",
+ "Reminder set for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gesetzt",
+ "Failed to set reminder" : "Erinnerung konnte nicht festgelegt werden",
+ "Reminder cleared for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gelöscht",
+ "Failed to clear reminder" : "Erinnerung konnte nicht gelöscht werden",
+ "We will remind you of this file" : "Du wirst an diese Datei erinnert",
+ "Cancel" : "Abbrechen",
+ "Set reminder" : "Erinnerung erstellen",
+ "Reminder set" : "Erinnerung gesetzt",
+ "Custom reminder" : "Benutzerdefinierte Erinnerung",
+ "Later today" : "Später heute",
+ "Set reminder for later today" : "Erinnerung für nachher erstellen",
+ "Tomorrow" : "Morgen",
+ "Set reminder for tomorrow" : "Erinnerung für morgen erstellen",
+ "This weekend" : "Dieses Wochenende",
+ "Set reminder for this weekend" : "Erinnerung für dieses Wochenende erstellen",
+ "Next week" : "Nächste Woche",
+ "Set reminder for next week" : "Erinnerung für nächste Woche erstellen",
+ "This files_reminder can work properly." : "Dieser „files_reminder“ funktioniert ordnungsgemäß.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App „files_reminder“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminder“ deaktivieren.",
+ "Set reminder at custom date & time" : "Erinnerung für benutzerdefinierten Zeitpunkt und Tag erstellen",
+ "Set custom reminder" : "Benutzerdefinierte Erinnerung erstellen"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/de.json b/apps/files_reminders/l10n/de.json
new file mode 100644
index 00000000000..2b82a91d296
--- /dev/null
+++ b/apps/files_reminders/l10n/de.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Dateierinnerungen",
+ "Reminder for {name}" : "Erinnerung für {name}",
+ "View file" : "Datei anzeigen",
+ "View folder" : "Ordner anzeigen",
+ "Files reminder" : "Dateierinnerung",
+ "The \"files_reminders\" app can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminders“ deaktivieren.",
+ "Set file reminders" : "Dateierinnerungen setzen",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dateierinnerungen**\n\nDateierinnerungen festlegen.\n\nHinweis: Um die App ``Dateierinnerungen` zu verwenden, stelle sicher, dass die App `Benachrichtigungen` installiert und aktiviert ist. Die App `Benachrichtigungen` bietet die erforderlichen APIs, damit die App `Dateierinnerungen`ordnungsgemäß funktioniert.",
+ "Set reminder for \"{fileName}\"" : "Erinnerung für \"{fileName}\" setzen",
+ "Reminder at custom date & time" : "Erinnerung zu benutzerdefiniertem Zeitpunkt und Tag",
+ "Clear reminder" : "Erinnerung löschen",
+ "Please choose a valid date & time" : "Bitte gültiges Datum und Uhrzeit wählen",
+ "Reminder set for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gesetzt",
+ "Failed to set reminder" : "Erinnerung konnte nicht festgelegt werden",
+ "Reminder cleared for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gelöscht",
+ "Failed to clear reminder" : "Erinnerung konnte nicht gelöscht werden",
+ "We will remind you of this file" : "Du wirst an diese Datei erinnert",
+ "Cancel" : "Abbrechen",
+ "Set reminder" : "Erinnerung erstellen",
+ "Reminder set" : "Erinnerung gesetzt",
+ "Custom reminder" : "Benutzerdefinierte Erinnerung",
+ "Later today" : "Später heute",
+ "Set reminder for later today" : "Erinnerung für nachher erstellen",
+ "Tomorrow" : "Morgen",
+ "Set reminder for tomorrow" : "Erinnerung für morgen erstellen",
+ "This weekend" : "Dieses Wochenende",
+ "Set reminder for this weekend" : "Erinnerung für dieses Wochenende erstellen",
+ "Next week" : "Nächste Woche",
+ "Set reminder for next week" : "Erinnerung für nächste Woche erstellen",
+ "This files_reminder can work properly." : "Dieser „files_reminder“ funktioniert ordnungsgemäß.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App „files_reminder“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminder“ deaktivieren.",
+ "Set reminder at custom date & time" : "Erinnerung für benutzerdefinierten Zeitpunkt und Tag erstellen",
+ "Set custom reminder" : "Benutzerdefinierte Erinnerung erstellen"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/de_DE.js b/apps/files_reminders/l10n/de_DE.js
new file mode 100644
index 00000000000..2cd6103db1e
--- /dev/null
+++ b/apps/files_reminders/l10n/de_DE.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Dateierinnerungen",
+ "Reminder for {name}" : "Erinnerung für {name}",
+ "View file" : "Datei anzeigen",
+ "View folder" : "Ordner anzeigen",
+ "Files reminder" : "Dateierinnerung",
+ "The \"files_reminders\" app can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders\" benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder \"files_reminders\" deaktivieren.",
+ "Set file reminders" : "Dateierinnerungen setzen",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dateierinnerungen**\n\nDateierinnerungen festlegen.\n\nHinweis: Um die App ``Dateierinnerungen` zu verwenden, stellen Sie sicher, dass die App `Benachrichtigungen` installiert und aktiviert ist. Die App `Benachrichtigungen` bietet die erforderlichen APIs, damit die App `Dateierinnerungen` ordnungsgemäß funktioniert.",
+ "Set reminder for \"{fileName}\"" : "Erinnerung für \"{fileName}\" setzen",
+ "Reminder at custom date & time" : "Erinnerung zu benutzerdefiniertem Zeitpunkt und Tag",
+ "Clear reminder" : "Erinnerung löschen",
+ "Please choose a valid date & time" : "Bitte gültiges Datum und Uhrzeit wählen",
+ "Reminder set for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gesetzt",
+ "Failed to set reminder" : "Erinnerung konnte nicht festgelegt werden",
+ "Reminder cleared for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gelöscht",
+ "Failed to clear reminder" : "Erinnerung konnte nicht gelöscht werden",
+ "We will remind you of this file" : "Sie werden an diese Datei erinnert",
+ "Cancel" : "Abbrechen",
+ "Set reminder" : "Erinnerung erstellen",
+ "Reminder set" : "Erinnerung gesetzt",
+ "Custom reminder" : "Benutzerdefinierte Erinnerung",
+ "Later today" : "Später heute",
+ "Set reminder for later today" : "Erinnerung für später heute erstellen",
+ "Tomorrow" : "Morgen",
+ "Set reminder for tomorrow" : "Erinnerung für morgen erstellen",
+ "This weekend" : "Dieses Wochenende",
+ "Set reminder for this weekend" : "Erinnerung für diese Wochenende erstellen",
+ "Next week" : "Nächste Woche",
+ "Set reminder for next week" : "Erinnerung für nächste Woche erstellen",
+ "This files_reminder can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminders“ deaktivieren.",
+ "Set reminder at custom date & time" : "Erinnerung für benutzerdefinierten Zeitpunkt und Tag erstellen",
+ "Set custom reminder" : "Benutzerdefinierte Erinnerung erstellen"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/de_DE.json b/apps/files_reminders/l10n/de_DE.json
new file mode 100644
index 00000000000..98d256c97bb
--- /dev/null
+++ b/apps/files_reminders/l10n/de_DE.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Dateierinnerungen",
+ "Reminder for {name}" : "Erinnerung für {name}",
+ "View file" : "Datei anzeigen",
+ "View folder" : "Ordner anzeigen",
+ "Files reminder" : "Dateierinnerung",
+ "The \"files_reminders\" app can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders\" benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder \"files_reminders\" deaktivieren.",
+ "Set file reminders" : "Dateierinnerungen setzen",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dateierinnerungen**\n\nDateierinnerungen festlegen.\n\nHinweis: Um die App ``Dateierinnerungen` zu verwenden, stellen Sie sicher, dass die App `Benachrichtigungen` installiert und aktiviert ist. Die App `Benachrichtigungen` bietet die erforderlichen APIs, damit die App `Dateierinnerungen` ordnungsgemäß funktioniert.",
+ "Set reminder for \"{fileName}\"" : "Erinnerung für \"{fileName}\" setzen",
+ "Reminder at custom date & time" : "Erinnerung zu benutzerdefiniertem Zeitpunkt und Tag",
+ "Clear reminder" : "Erinnerung löschen",
+ "Please choose a valid date & time" : "Bitte gültiges Datum und Uhrzeit wählen",
+ "Reminder set for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gesetzt",
+ "Failed to set reminder" : "Erinnerung konnte nicht festgelegt werden",
+ "Reminder cleared for \"{fileName}\"" : "Erinnerung für \"{fileName}\" gelöscht",
+ "Failed to clear reminder" : "Erinnerung konnte nicht gelöscht werden",
+ "We will remind you of this file" : "Sie werden an diese Datei erinnert",
+ "Cancel" : "Abbrechen",
+ "Set reminder" : "Erinnerung erstellen",
+ "Reminder set" : "Erinnerung gesetzt",
+ "Custom reminder" : "Benutzerdefinierte Erinnerung",
+ "Later today" : "Später heute",
+ "Set reminder for later today" : "Erinnerung für später heute erstellen",
+ "Tomorrow" : "Morgen",
+ "Set reminder for tomorrow" : "Erinnerung für morgen erstellen",
+ "This weekend" : "Dieses Wochenende",
+ "Set reminder for this weekend" : "Erinnerung für diese Wochenende erstellen",
+ "Next week" : "Nächste Woche",
+ "Set reminder for next week" : "Erinnerung für nächste Woche erstellen",
+ "This files_reminder can work properly." : "Die App \"files_reminders\" kann ordnungsgemäß funktionieren.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Die App \"files_reminders“ benötigt die Benachrichtigungs-App, um ordnungsgemäß zu funktionieren. Sie sollten entweder Benachrichtigungen aktivieren oder „files_reminders“ deaktivieren.",
+ "Set reminder at custom date & time" : "Erinnerung für benutzerdefinierten Zeitpunkt und Tag erstellen",
+ "Set custom reminder" : "Benutzerdefinierte Erinnerung erstellen"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/el.js b/apps/files_reminders/l10n/el.js
new file mode 100644
index 00000000000..4faa92eaf2a
--- /dev/null
+++ b/apps/files_reminders/l10n/el.js
@@ -0,0 +1,27 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Υπενθυμίσεις αρχείων",
+ "Reminder for {name}" : "Υπενθύμιση για {name}",
+ "View file" : "Προβολή αρχείου",
+ "View folder" : "Προβολή φακέλου",
+ "Set file reminders" : "Ορίστε υπενθυμίσεις αρχείων",
+ "Clear reminder" : "Εκκαθάριση υπενθύμισης",
+ "Please choose a valid date & time" : "Επιλέξτε μια έγκυρη ημερομηνία και ώρα",
+ "Reminder set for \"{fileName}\"" : "Ορίστηκε υπενθύμιση για \"{fileName}\"",
+ "Failed to set reminder" : "Αποτυχία ορισμού υπενθύμισης",
+ "Failed to clear reminder" : "Αποτυχία εκκαθάρισης της υπενθύμισης",
+ "Cancel" : "Ακύρωση",
+ "Set reminder" : "Προσθήκη υπενθύμισης",
+ "Later today" : "Αργότερα σήμερα",
+ "Set reminder for later today" : "Ορισμός υπενθύμισης για αργότερα σήμερα",
+ "Tomorrow" : "Αύριο",
+ "Set reminder for tomorrow" : "Ορισμός υπενθύμισης για αύριο",
+ "This weekend" : "Αυτό το Σαββατοκύριακο",
+ "Set reminder for this weekend" : "Ορίστε υπενθύμιση για αυτό το Σαββατοκύριακο",
+ "Next week" : "Επόμενη εβδομάδα",
+ "Set reminder for next week" : "Ορίστε υπενθύμιση για την επόμενη εβδομάδα",
+ "Set reminder at custom date & time" : "Ορίστε την υπενθύμιση σε προσαρμοσμένη ημερομηνία και ώρα",
+ "Set custom reminder" : "Ορισμός προσαρμοσμένης υπενθύμισης"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/el.json b/apps/files_reminders/l10n/el.json
new file mode 100644
index 00000000000..b4d487abc20
--- /dev/null
+++ b/apps/files_reminders/l10n/el.json
@@ -0,0 +1,25 @@
+{ "translations": {
+ "File reminders" : "Υπενθυμίσεις αρχείων",
+ "Reminder for {name}" : "Υπενθύμιση για {name}",
+ "View file" : "Προβολή αρχείου",
+ "View folder" : "Προβολή φακέλου",
+ "Set file reminders" : "Ορίστε υπενθυμίσεις αρχείων",
+ "Clear reminder" : "Εκκαθάριση υπενθύμισης",
+ "Please choose a valid date & time" : "Επιλέξτε μια έγκυρη ημερομηνία και ώρα",
+ "Reminder set for \"{fileName}\"" : "Ορίστηκε υπενθύμιση για \"{fileName}\"",
+ "Failed to set reminder" : "Αποτυχία ορισμού υπενθύμισης",
+ "Failed to clear reminder" : "Αποτυχία εκκαθάρισης της υπενθύμισης",
+ "Cancel" : "Ακύρωση",
+ "Set reminder" : "Προσθήκη υπενθύμισης",
+ "Later today" : "Αργότερα σήμερα",
+ "Set reminder for later today" : "Ορισμός υπενθύμισης για αργότερα σήμερα",
+ "Tomorrow" : "Αύριο",
+ "Set reminder for tomorrow" : "Ορισμός υπενθύμισης για αύριο",
+ "This weekend" : "Αυτό το Σαββατοκύριακο",
+ "Set reminder for this weekend" : "Ορίστε υπενθύμιση για αυτό το Σαββατοκύριακο",
+ "Next week" : "Επόμενη εβδομάδα",
+ "Set reminder for next week" : "Ορίστε υπενθύμιση για την επόμενη εβδομάδα",
+ "Set reminder at custom date & time" : "Ορίστε την υπενθύμιση σε προσαρμοσμένη ημερομηνία και ώρα",
+ "Set custom reminder" : "Ορισμός προσαρμοσμένης υπενθύμισης"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/en_GB.js b/apps/files_reminders/l10n/en_GB.js
new file mode 100644
index 00000000000..dff76ce098e
--- /dev/null
+++ b/apps/files_reminders/l10n/en_GB.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "File reminders",
+ "Reminder for {name}" : "Reminder for {name}",
+ "View file" : "View file",
+ "View folder" : "View folder",
+ "Files reminder" : "Files reminder",
+ "The \"files_reminders\" app can work properly." : "The \"files_reminders\" app can work properly.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder.",
+ "Set file reminders" : "Set file reminders",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly.",
+ "Set reminder for \"{fileName}\"" : "Set reminder for \"{fileName}\"",
+ "Reminder at custom date & time" : "Reminder at custom date & time",
+ "Clear reminder" : "Clear reminder",
+ "Please choose a valid date & time" : "Please choose a valid date & time",
+ "Reminder set for \"{fileName}\"" : "Reminder set for \"{fileName}\"",
+ "Failed to set reminder" : "Failed to set reminder",
+ "Reminder cleared for \"{fileName}\"" : "Reminder cleared for \"{fileName}\"",
+ "Failed to clear reminder" : "Failed to clear reminder",
+ "We will remind you of this file" : "We will remind you of this file",
+ "Cancel" : "Cancel",
+ "Set reminder" : "Set reminder",
+ "Reminder set" : "Reminder set",
+ "Custom reminder" : "Custom reminder",
+ "Later today" : "Later today",
+ "Set reminder for later today" : "Set reminder for later today",
+ "Tomorrow" : "Tomorrow",
+ "Set reminder for tomorrow" : "Set reminder for tomorrow",
+ "This weekend" : "This weekend",
+ "Set reminder for this weekend" : "Set reminder for this weekend",
+ "Next week" : "Next week",
+ "Set reminder for next week" : "Set reminder for next week",
+ "This files_reminder can work properly." : "This files_reminder can work properly.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder.",
+ "Set reminder at custom date & time" : "Set reminder at custom date & time",
+ "Set custom reminder" : "Set custom reminder"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/en_GB.json b/apps/files_reminders/l10n/en_GB.json
new file mode 100644
index 00000000000..1991fb3799a
--- /dev/null
+++ b/apps/files_reminders/l10n/en_GB.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "File reminders",
+ "Reminder for {name}" : "Reminder for {name}",
+ "View file" : "View file",
+ "View folder" : "View folder",
+ "Files reminder" : "Files reminder",
+ "The \"files_reminders\" app can work properly." : "The \"files_reminders\" app can work properly.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder.",
+ "Set file reminders" : "Set file reminders",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly.",
+ "Set reminder for \"{fileName}\"" : "Set reminder for \"{fileName}\"",
+ "Reminder at custom date & time" : "Reminder at custom date & time",
+ "Clear reminder" : "Clear reminder",
+ "Please choose a valid date & time" : "Please choose a valid date & time",
+ "Reminder set for \"{fileName}\"" : "Reminder set for \"{fileName}\"",
+ "Failed to set reminder" : "Failed to set reminder",
+ "Reminder cleared for \"{fileName}\"" : "Reminder cleared for \"{fileName}\"",
+ "Failed to clear reminder" : "Failed to clear reminder",
+ "We will remind you of this file" : "We will remind you of this file",
+ "Cancel" : "Cancel",
+ "Set reminder" : "Set reminder",
+ "Reminder set" : "Reminder set",
+ "Custom reminder" : "Custom reminder",
+ "Later today" : "Later today",
+ "Set reminder for later today" : "Set reminder for later today",
+ "Tomorrow" : "Tomorrow",
+ "Set reminder for tomorrow" : "Set reminder for tomorrow",
+ "This weekend" : "This weekend",
+ "Set reminder for this weekend" : "Set reminder for this weekend",
+ "Next week" : "Next week",
+ "Set reminder for next week" : "Set reminder for next week",
+ "This files_reminder can work properly." : "This files_reminder can work properly.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder.",
+ "Set reminder at custom date & time" : "Set reminder at custom date & time",
+ "Set custom reminder" : "Set custom reminder"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/es.js b/apps/files_reminders/l10n/es.js
new file mode 100644
index 00000000000..3161133516a
--- /dev/null
+++ b/apps/files_reminders/l10n/es.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Recordatorios de archivo",
+ "Reminder for {name}" : "Recordatorio para {name}",
+ "View file" : "Ver archivo",
+ "View folder" : "Ver carpeta",
+ "Files reminder" : "Recordatorios de archivo",
+ "The \"files_reminders\" app can work properly." : "La app \"files_reminders\" puede trabajar de forma apropiada.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "La app \"files_reminders\" requiere la app de notificaciones para trabajar de forma apropiada. Debería o bien habilitar las notificaciones o deshabilitar files_reminder.",
+ "Set file reminders" : "Establecer recordatorios de archivo",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Recordatorios de archivo**\n\nEstablecer recordatorios de archivo.\n\nNota: para usar la app de `Recordatorios de archivo`, asegúrese de que la app de `Notificaciones` está instalada y habilitada. La app de `Notificaciones` provee las APIs necesarias para que la app de `Recordatorios de archivo` funcione correctamente.",
+ "Set reminder for \"{fileName}\"" : "Establecer recordatorio para \"{fileName}\"",
+ "Reminder at custom date & time" : "Recordatorio en una fecha y hora personalizada",
+ "Clear reminder" : "Borrar recordatorio",
+ "Please choose a valid date & time" : "Por favor, escoja una fecha y hora válidas",
+ "Reminder set for \"{fileName}\"" : "Se estableció recordatorio para \"{fileName}\"",
+ "Failed to set reminder" : "No se pudo establecer el recordatorio",
+ "Reminder cleared for \"{fileName}\"" : "Se limpió el recordatorio para \"{fileName}\"",
+ "Failed to clear reminder" : "Fallo al borrar el recordatorio",
+ "We will remind you of this file" : "Le recordaremos de este archivo",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Establecer recordatorio",
+ "Reminder set" : "Recordatorio establecido",
+ "Custom reminder" : "Recordatorio personalizado",
+ "Later today" : "Más tarde hoy",
+ "Set reminder for later today" : "Establecer recordatorio para hoy, más tarde",
+ "Tomorrow" : "Mañana",
+ "Set reminder for tomorrow" : "Establecer recordatorio para mañana",
+ "This weekend" : "Este fin de semana",
+ "Set reminder for this weekend" : "Establecer recordatorio para este fin de semana",
+ "Next week" : "Próxima semana",
+ "Set reminder for next week" : "Establecer recordatorio para la próxima semana",
+ "This files_reminder can work properly." : "Este files_reminder puede trabajar de forma apropiada.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "La app \"files_reminders\" requiere la app de notificaciones para trabajar de forma apropiada. Debería o bien habilitar las notificaciones o deshabilitar files_reminder.",
+ "Set reminder at custom date & time" : "Establecer recordatorio a una fecha y hora personalizada",
+ "Set custom reminder" : "Establecer recordatorio personalizado"
+},
+"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/files_reminders/l10n/es.json b/apps/files_reminders/l10n/es.json
new file mode 100644
index 00000000000..ca3bc8ce1cd
--- /dev/null
+++ b/apps/files_reminders/l10n/es.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Recordatorios de archivo",
+ "Reminder for {name}" : "Recordatorio para {name}",
+ "View file" : "Ver archivo",
+ "View folder" : "Ver carpeta",
+ "Files reminder" : "Recordatorios de archivo",
+ "The \"files_reminders\" app can work properly." : "La app \"files_reminders\" puede trabajar de forma apropiada.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "La app \"files_reminders\" requiere la app de notificaciones para trabajar de forma apropiada. Debería o bien habilitar las notificaciones o deshabilitar files_reminder.",
+ "Set file reminders" : "Establecer recordatorios de archivo",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Recordatorios de archivo**\n\nEstablecer recordatorios de archivo.\n\nNota: para usar la app de `Recordatorios de archivo`, asegúrese de que la app de `Notificaciones` está instalada y habilitada. La app de `Notificaciones` provee las APIs necesarias para que la app de `Recordatorios de archivo` funcione correctamente.",
+ "Set reminder for \"{fileName}\"" : "Establecer recordatorio para \"{fileName}\"",
+ "Reminder at custom date & time" : "Recordatorio en una fecha y hora personalizada",
+ "Clear reminder" : "Borrar recordatorio",
+ "Please choose a valid date & time" : "Por favor, escoja una fecha y hora válidas",
+ "Reminder set for \"{fileName}\"" : "Se estableció recordatorio para \"{fileName}\"",
+ "Failed to set reminder" : "No se pudo establecer el recordatorio",
+ "Reminder cleared for \"{fileName}\"" : "Se limpió el recordatorio para \"{fileName}\"",
+ "Failed to clear reminder" : "Fallo al borrar el recordatorio",
+ "We will remind you of this file" : "Le recordaremos de este archivo",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Establecer recordatorio",
+ "Reminder set" : "Recordatorio establecido",
+ "Custom reminder" : "Recordatorio personalizado",
+ "Later today" : "Más tarde hoy",
+ "Set reminder for later today" : "Establecer recordatorio para hoy, más tarde",
+ "Tomorrow" : "Mañana",
+ "Set reminder for tomorrow" : "Establecer recordatorio para mañana",
+ "This weekend" : "Este fin de semana",
+ "Set reminder for this weekend" : "Establecer recordatorio para este fin de semana",
+ "Next week" : "Próxima semana",
+ "Set reminder for next week" : "Establecer recordatorio para la próxima semana",
+ "This files_reminder can work properly." : "Este files_reminder puede trabajar de forma apropiada.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "La app \"files_reminders\" requiere la app de notificaciones para trabajar de forma apropiada. Debería o bien habilitar las notificaciones o deshabilitar files_reminder.",
+ "Set reminder at custom date & time" : "Establecer recordatorio a una fecha y hora personalizada",
+ "Set custom reminder" : "Establecer recordatorio personalizado"
+},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/et_EE.js b/apps/files_reminders/l10n/et_EE.js
new file mode 100644
index 00000000000..93e4be54a08
--- /dev/null
+++ b/apps/files_reminders/l10n/et_EE.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Failide ja kaustade meeldetuletused",
+ "Reminder for {name}" : "Meeldetuletus: „{name}“",
+ "View file" : "Vaata faili",
+ "View folder" : "Vaata kausta",
+ "Files reminder" : "Failide ja kaustade meeldetuletused",
+ "The \"files_reminders\" app can work properly." : "See Failide meeldetuletaja võib toimida korrektselt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Failide meeldetuletusrakendus vajab korrektseks toimimiseks teavituste rakenduse olemasolu. Palun lisa vajalik abirakendus või eemalda see rakendus kasutuselt.",
+ "Set file reminders" : "Meeldetuletuste lisamine failidele ja kaustadele",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Failide meeldetuletused**\n\nLisa failidele ja kaustadele meeldetuletusi.\n\nMärkus: Teavituste rakendus peab olema paigaldatud ja kasutusel, et see Failide meeldetuletuste rakendus saaks korrektselt toimida. Teavituste rakendus tagab selle rakenduse toimimiseks vajalik liideste olemasolu.",
+ "Set reminder for \"{fileName}\"" : "Lisa meeldetuletus: „{fileName}“",
+ "Clear reminder" : "Eemalda meeldetuletus",
+ "Please choose a valid date & time" : "Palun vali korrektne kuupäev ja kellaaeg",
+ "Reminder set for \"{fileName}\"" : "Meeldetuletus on lisatud: „{fileName}“",
+ "Failed to set reminder" : "Meeldetuletuse lisamine ei õnnestunud",
+ "Reminder cleared for \"{fileName}\"" : "Meeldetuletus on eemaldatud: „{fileName}“",
+ "Failed to clear reminder" : "Meeldetuletuse eemaldamine ei õnnestunud",
+ "We will remind you of this file" : "Me anname sulle selle faili või kausta osas märku",
+ "Cancel" : "Tühista",
+ "Set reminder" : "Lisa meeldetuletus",
+ "Reminder set" : "Meeldetuletus on lisatud",
+ "Later today" : "Täna hiljem",
+ "Set reminder for later today" : "Lisa meeldetuletus tänaseks hilisemaks ajaks",
+ "Tomorrow" : "Homme",
+ "Set reminder for tomorrow" : "Lisa meeldetuletus homseks",
+ "This weekend" : "See nädalavahetus",
+ "Set reminder for this weekend" : "Lisa meeldetuletus selleks nädalavahetuseks",
+ "Next week" : "Järgmine nädal",
+ "Set reminder for next week" : "Lisa meeldetuletus järgmiseks nädalaks",
+ "This files_reminder can work properly." : "See Failide meeldetuletaja võib toimida korrektselt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Failide meeldetuletusrakendus vajab korrektseks toimimiseks teavituste rakenduse olemasolu. Palun lisa vajalik abirakendus või eemalda see rakendus kasutuselt.",
+ "Set reminder at custom date & time" : "Säti meeldetuletus valitud kuupäevaks ja ajaks",
+ "Set custom reminder" : "Lisa enda valitud meeldetuletus"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/et_EE.json b/apps/files_reminders/l10n/et_EE.json
new file mode 100644
index 00000000000..bf389a3ab35
--- /dev/null
+++ b/apps/files_reminders/l10n/et_EE.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Failide ja kaustade meeldetuletused",
+ "Reminder for {name}" : "Meeldetuletus: „{name}“",
+ "View file" : "Vaata faili",
+ "View folder" : "Vaata kausta",
+ "Files reminder" : "Failide ja kaustade meeldetuletused",
+ "The \"files_reminders\" app can work properly." : "See Failide meeldetuletaja võib toimida korrektselt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Failide meeldetuletusrakendus vajab korrektseks toimimiseks teavituste rakenduse olemasolu. Palun lisa vajalik abirakendus või eemalda see rakendus kasutuselt.",
+ "Set file reminders" : "Meeldetuletuste lisamine failidele ja kaustadele",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Failide meeldetuletused**\n\nLisa failidele ja kaustadele meeldetuletusi.\n\nMärkus: Teavituste rakendus peab olema paigaldatud ja kasutusel, et see Failide meeldetuletuste rakendus saaks korrektselt toimida. Teavituste rakendus tagab selle rakenduse toimimiseks vajalik liideste olemasolu.",
+ "Set reminder for \"{fileName}\"" : "Lisa meeldetuletus: „{fileName}“",
+ "Clear reminder" : "Eemalda meeldetuletus",
+ "Please choose a valid date & time" : "Palun vali korrektne kuupäev ja kellaaeg",
+ "Reminder set for \"{fileName}\"" : "Meeldetuletus on lisatud: „{fileName}“",
+ "Failed to set reminder" : "Meeldetuletuse lisamine ei õnnestunud",
+ "Reminder cleared for \"{fileName}\"" : "Meeldetuletus on eemaldatud: „{fileName}“",
+ "Failed to clear reminder" : "Meeldetuletuse eemaldamine ei õnnestunud",
+ "We will remind you of this file" : "Me anname sulle selle faili või kausta osas märku",
+ "Cancel" : "Tühista",
+ "Set reminder" : "Lisa meeldetuletus",
+ "Reminder set" : "Meeldetuletus on lisatud",
+ "Later today" : "Täna hiljem",
+ "Set reminder for later today" : "Lisa meeldetuletus tänaseks hilisemaks ajaks",
+ "Tomorrow" : "Homme",
+ "Set reminder for tomorrow" : "Lisa meeldetuletus homseks",
+ "This weekend" : "See nädalavahetus",
+ "Set reminder for this weekend" : "Lisa meeldetuletus selleks nädalavahetuseks",
+ "Next week" : "Järgmine nädal",
+ "Set reminder for next week" : "Lisa meeldetuletus järgmiseks nädalaks",
+ "This files_reminder can work properly." : "See Failide meeldetuletaja võib toimida korrektselt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Failide meeldetuletusrakendus vajab korrektseks toimimiseks teavituste rakenduse olemasolu. Palun lisa vajalik abirakendus või eemalda see rakendus kasutuselt.",
+ "Set reminder at custom date & time" : "Säti meeldetuletus valitud kuupäevaks ja ajaks",
+ "Set custom reminder" : "Lisa enda valitud meeldetuletus"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/eu.js b/apps/files_reminders/l10n/eu.js
new file mode 100644
index 00000000000..f138b1e56db
--- /dev/null
+++ b/apps/files_reminders/l10n/eu.js
@@ -0,0 +1,22 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Fitxategiaren gogorarazpenak",
+ "View file" : "Ikusi fitxategia",
+ "View folder" : "Ikusi karpeta",
+ "Clear reminder" : "Garbitu gogorarazpena",
+ "Failed to clear reminder" : "Gogorarazpena garbitzeak huts egin du",
+ "Cancel" : "Utzi",
+ "Set reminder" : "Ezarri gogorarazpena",
+ "Reminder set" : "Gogorarazpena ezarrita",
+ "Later today" : "Beranduago gaur",
+ "Set reminder for later today" : "Ezarri gogorarazpena gaur beranduagorako",
+ "Tomorrow" : "Bihar",
+ "Set reminder for tomorrow" : "Ezarri gogorarazpena biharko",
+ "This weekend" : "Asteburu hau",
+ "Set reminder for this weekend" : "Ezarri gogorarazpena asteburu honetarako",
+ "Next week" : "Hurrengo astea",
+ "Set reminder for next week" : "Ezarri gogorarazpena hurrengo asterako",
+ "Set custom reminder" : "Ezarri gogorarazpen pertsonalizatua"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/eu.json b/apps/files_reminders/l10n/eu.json
new file mode 100644
index 00000000000..56c4c9d02db
--- /dev/null
+++ b/apps/files_reminders/l10n/eu.json
@@ -0,0 +1,20 @@
+{ "translations": {
+ "File reminders" : "Fitxategiaren gogorarazpenak",
+ "View file" : "Ikusi fitxategia",
+ "View folder" : "Ikusi karpeta",
+ "Clear reminder" : "Garbitu gogorarazpena",
+ "Failed to clear reminder" : "Gogorarazpena garbitzeak huts egin du",
+ "Cancel" : "Utzi",
+ "Set reminder" : "Ezarri gogorarazpena",
+ "Reminder set" : "Gogorarazpena ezarrita",
+ "Later today" : "Beranduago gaur",
+ "Set reminder for later today" : "Ezarri gogorarazpena gaur beranduagorako",
+ "Tomorrow" : "Bihar",
+ "Set reminder for tomorrow" : "Ezarri gogorarazpena biharko",
+ "This weekend" : "Asteburu hau",
+ "Set reminder for this weekend" : "Ezarri gogorarazpena asteburu honetarako",
+ "Next week" : "Hurrengo astea",
+ "Set reminder for next week" : "Ezarri gogorarazpena hurrengo asterako",
+ "Set custom reminder" : "Ezarri gogorarazpen pertsonalizatua"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/fi.js b/apps/files_reminders/l10n/fi.js
new file mode 100644
index 00000000000..0ecb1cead95
--- /dev/null
+++ b/apps/files_reminders/l10n/fi.js
@@ -0,0 +1,30 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Tiedostomuistutukset",
+ "Reminder for {name}" : "Muistutus kohteesta {name}",
+ "View file" : "Näytä tiedosto",
+ "View folder" : "Näytä kansio",
+ "Set file reminders" : "Aseta tiedostomuistutuksia",
+ "Set reminder for \"{fileName}\"" : "Muistutus asetettu tiedostolle \"{fileName}\"",
+ "Clear reminder" : "Tyhjennä muistutus",
+ "Please choose a valid date & time" : "Valitse kelvollinen päivä ja aika",
+ "Reminder set for \"{fileName}\"" : "Muistutus asetettu tiedostolle \"{fileName}\"",
+ "Failed to set reminder" : "Muistutuksen asettaminen epäonnistui",
+ "Failed to clear reminder" : "Muistutuksen tyhjentäminen epäonnistui",
+ "We will remind you of this file" : "Muistutamme sinua tästä tiedostosta",
+ "Cancel" : "Peruuta",
+ "Set reminder" : "Aseta muistutus",
+ "Reminder set" : "Muistutus asetettu",
+ "Later today" : "Myöhemmin tänään",
+ "Set reminder for later today" : "Aseta muistutus myöhemmälle ajankohdalle tälle päivälle",
+ "Tomorrow" : "Huomenna",
+ "Set reminder for tomorrow" : "Aseta muistutus huomiselle",
+ "This weekend" : "Tämä viikonloppu",
+ "Set reminder for this weekend" : "Aseta muistutus tälle viikonlopulle",
+ "Next week" : "Seuraava viikko",
+ "Set reminder for next week" : "Aseta muistutus seuraavalle viikolle",
+ "Set reminder at custom date & time" : "Aseta muistutus mukautetulle päivälle ja ajankohdalle",
+ "Set custom reminder" : "Aseta mukautettu muistutus"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/fi.json b/apps/files_reminders/l10n/fi.json
new file mode 100644
index 00000000000..0a75fa7481d
--- /dev/null
+++ b/apps/files_reminders/l10n/fi.json
@@ -0,0 +1,28 @@
+{ "translations": {
+ "File reminders" : "Tiedostomuistutukset",
+ "Reminder for {name}" : "Muistutus kohteesta {name}",
+ "View file" : "Näytä tiedosto",
+ "View folder" : "Näytä kansio",
+ "Set file reminders" : "Aseta tiedostomuistutuksia",
+ "Set reminder for \"{fileName}\"" : "Muistutus asetettu tiedostolle \"{fileName}\"",
+ "Clear reminder" : "Tyhjennä muistutus",
+ "Please choose a valid date & time" : "Valitse kelvollinen päivä ja aika",
+ "Reminder set for \"{fileName}\"" : "Muistutus asetettu tiedostolle \"{fileName}\"",
+ "Failed to set reminder" : "Muistutuksen asettaminen epäonnistui",
+ "Failed to clear reminder" : "Muistutuksen tyhjentäminen epäonnistui",
+ "We will remind you of this file" : "Muistutamme sinua tästä tiedostosta",
+ "Cancel" : "Peruuta",
+ "Set reminder" : "Aseta muistutus",
+ "Reminder set" : "Muistutus asetettu",
+ "Later today" : "Myöhemmin tänään",
+ "Set reminder for later today" : "Aseta muistutus myöhemmälle ajankohdalle tälle päivälle",
+ "Tomorrow" : "Huomenna",
+ "Set reminder for tomorrow" : "Aseta muistutus huomiselle",
+ "This weekend" : "Tämä viikonloppu",
+ "Set reminder for this weekend" : "Aseta muistutus tälle viikonlopulle",
+ "Next week" : "Seuraava viikko",
+ "Set reminder for next week" : "Aseta muistutus seuraavalle viikolle",
+ "Set reminder at custom date & time" : "Aseta muistutus mukautetulle päivälle ja ajankohdalle",
+ "Set custom reminder" : "Aseta mukautettu muistutus"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/fr.js b/apps/files_reminders/l10n/fr.js
new file mode 100644
index 00000000000..f72db23f822
--- /dev/null
+++ b/apps/files_reminders/l10n/fr.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Rappels de fichiers",
+ "Reminder for {name}" : "Rappel pour {name}",
+ "View file" : "Voir le fichier",
+ "View folder" : "Voir le dossier",
+ "Files reminder" : "Rappel des fichiers",
+ "The \"files_reminders\" app can work properly." : "L'application « files_reminders » peut fonctionner correctement.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'application « files_reminders » a besoin de l'application de notifications pour fonctionner correctement. Vous devez activer les notifications ou désactiver « files_reminder ».",
+ "Set file reminders" : "Définir des rappels pour des fichiers",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Rappels de fichiers**\n\nDéfinit des rappels de fichiers.\n\nNote: pour utiliser l'application `Rappels de fichiers`, assurez-vous que l'application `Notifications` est installée et activée. L'application `Notifications` fournit les APIs nécessaires pour que l'application `Rappels de fichiers` fonctionne correctement.",
+ "Set reminder for \"{fileName}\"" : "Définir un rappel pour « {fileName} »",
+ "Clear reminder" : "Effacer le rappel",
+ "Please choose a valid date & time" : "Veuillez choisir une date et une heure valables",
+ "Reminder set for \"{fileName}\"" : "Définition d’un rappel pour « {fileName} »",
+ "Failed to set reminder" : "Échec de la définition du rappel",
+ "Reminder cleared for \"{fileName}\"" : "Rappel effacé pour « {fileName} »",
+ "Failed to clear reminder" : "Échec de l'effacement du rappel",
+ "We will remind you of this file" : "Nous vous rappellerons de ce fichier",
+ "Cancel" : "Annuler",
+ "Set reminder" : "Définir un rappel",
+ "Reminder set" : "Rappel défini",
+ "Later today" : "Plus tard aujourd'hui",
+ "Set reminder for later today" : "Définir un rappel pour plus tard aujourd'hui",
+ "Tomorrow" : "Demain",
+ "Set reminder for tomorrow" : "Définir un rappel pour demain",
+ "This weekend" : "Ce week-end",
+ "Set reminder for this weekend" : "Définir un rappel pour ce week-end",
+ "Next week" : "Semaine suivante",
+ "Set reminder for next week" : "Définir un rappel pour la semaine prochaine",
+ "This files_reminder can work properly." : "Ce files_reminder peut fonctionner correctement.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'application files_reminder a besoin de l'application de notifications pour fonctionner correctement. Vous devez activer les notifications ou désactiver files_reminder.",
+ "Set reminder at custom date & time" : "Définition d'un rappel à une date et une heure personnalisées",
+ "Set custom reminder" : "Définir un rappel personnalisé"
+},
+"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/files_reminders/l10n/fr.json b/apps/files_reminders/l10n/fr.json
new file mode 100644
index 00000000000..d18f411842b
--- /dev/null
+++ b/apps/files_reminders/l10n/fr.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Rappels de fichiers",
+ "Reminder for {name}" : "Rappel pour {name}",
+ "View file" : "Voir le fichier",
+ "View folder" : "Voir le dossier",
+ "Files reminder" : "Rappel des fichiers",
+ "The \"files_reminders\" app can work properly." : "L'application « files_reminders » peut fonctionner correctement.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'application « files_reminders » a besoin de l'application de notifications pour fonctionner correctement. Vous devez activer les notifications ou désactiver « files_reminder ».",
+ "Set file reminders" : "Définir des rappels pour des fichiers",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Rappels de fichiers**\n\nDéfinit des rappels de fichiers.\n\nNote: pour utiliser l'application `Rappels de fichiers`, assurez-vous que l'application `Notifications` est installée et activée. L'application `Notifications` fournit les APIs nécessaires pour que l'application `Rappels de fichiers` fonctionne correctement.",
+ "Set reminder for \"{fileName}\"" : "Définir un rappel pour « {fileName} »",
+ "Clear reminder" : "Effacer le rappel",
+ "Please choose a valid date & time" : "Veuillez choisir une date et une heure valables",
+ "Reminder set for \"{fileName}\"" : "Définition d’un rappel pour « {fileName} »",
+ "Failed to set reminder" : "Échec de la définition du rappel",
+ "Reminder cleared for \"{fileName}\"" : "Rappel effacé pour « {fileName} »",
+ "Failed to clear reminder" : "Échec de l'effacement du rappel",
+ "We will remind you of this file" : "Nous vous rappellerons de ce fichier",
+ "Cancel" : "Annuler",
+ "Set reminder" : "Définir un rappel",
+ "Reminder set" : "Rappel défini",
+ "Later today" : "Plus tard aujourd'hui",
+ "Set reminder for later today" : "Définir un rappel pour plus tard aujourd'hui",
+ "Tomorrow" : "Demain",
+ "Set reminder for tomorrow" : "Définir un rappel pour demain",
+ "This weekend" : "Ce week-end",
+ "Set reminder for this weekend" : "Définir un rappel pour ce week-end",
+ "Next week" : "Semaine suivante",
+ "Set reminder for next week" : "Définir un rappel pour la semaine prochaine",
+ "This files_reminder can work properly." : "Ce files_reminder peut fonctionner correctement.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'application files_reminder a besoin de l'application de notifications pour fonctionner correctement. Vous devez activer les notifications ou désactiver files_reminder.",
+ "Set reminder at custom date & time" : "Définition d'un rappel à une date et une heure personnalisées",
+ "Set custom reminder" : "Définir un rappel personnalisé"
+},"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/files_reminders/l10n/ga.js b/apps/files_reminders/l10n/ga.js
new file mode 100644
index 00000000000..2167cd7b864
--- /dev/null
+++ b/apps/files_reminders/l10n/ga.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Meabhrúcháin comhaid",
+ "Reminder for {name}" : "Meabhrúchán do {name}",
+ "View file" : "Féach ar chomhad",
+ "View folder" : "Féach ar fhillteán",
+ "Files reminder" : "Meabhrúchán comhaid",
+ "The \"files_reminders\" app can work properly." : "Is féidir leis an \"files_reminders\" app oibriú i gceart.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Ní mór don app \"files_reminders\" an app fógra a bheith ag obair i gceart. Ba cheart duit fógraí a chumasú nó comhaid_reminder a dhíchumasú.",
+ "Set file reminders" : "Socraigh meabhrúcháin comhaid",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Meabhrúcháin comhaid**\n\nSocraigh meabhrúcháin comhaid.\n\nTabhair faoi deara: chun an aip `Meabhrúcháin Comhad` a úsáid, cinntigh go bhfuil an aip `Fógraí` suiteáilte agus cumasaithe. Soláthraíonn an aip `Fógraí` na APInna riachtanacha chun go n-oibreoidh an aip `Meabhrúcháin Comhad` i gceart.",
+ "Set reminder for \"{fileName}\"" : "Socraigh meabhrúchán do \"{fileName}\"",
+ "Clear reminder" : "Meabhrúchán soiléir",
+ "Please choose a valid date & time" : "Roghnaigh dáta agus am bailí le do thoil",
+ "Reminder set for \"{fileName}\"" : "Meabhrúchán socraithe do \"{fileName}\"",
+ "Failed to set reminder" : "Theip ar an meabhrúchán a shocrú",
+ "Reminder cleared for \"{fileName}\"" : "Glanadh an meabhrúchán le haghaidh \"{fileName}\"",
+ "Failed to clear reminder" : "Theip ar an meabhrúchán a ghlanadh",
+ "We will remind you of this file" : "Cuirfimid an comhad seo i gcuimhne duit",
+ "Cancel" : "Cealaigh",
+ "Set reminder" : "Socraigh meabhrúchán",
+ "Reminder set" : "Meabhrúchán socraithe",
+ "Later today" : "Níos déanaí inniu",
+ "Set reminder for later today" : "Socraigh meabhrúchán le haghaidh níos déanaí inniu",
+ "Tomorrow" : "Amárach",
+ "Set reminder for tomorrow" : "Socraigh meabhrúchán don lá amárach",
+ "This weekend" : "An deireadh seachtaine seo",
+ "Set reminder for this weekend" : "Socraigh meabhrúchán don deireadh seachtaine seo",
+ "Next week" : "An tseachtain seo chugainn",
+ "Set reminder for next week" : "Socraigh meabhrúchán don tseachtain seo chugainn",
+ "This files_reminder can work properly." : "Is féidir leis an gcomhad_reminder seo oibriú i gceart.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Teastaíonn an aip fógraí ón aip files_reminder chun oibriú i gceart. Ba cheart duit fógraí a chumasú nó comhaid_reminder a dhíchumasú.",
+ "Set reminder at custom date & time" : "Socraigh meabhrúchán ar dháta agus am saincheaptha",
+ "Set custom reminder" : "Socraigh meabhrúchán saincheaptha"
+},
+"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);");
diff --git a/apps/files_reminders/l10n/ga.json b/apps/files_reminders/l10n/ga.json
new file mode 100644
index 00000000000..a4fe40de857
--- /dev/null
+++ b/apps/files_reminders/l10n/ga.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Meabhrúcháin comhaid",
+ "Reminder for {name}" : "Meabhrúchán do {name}",
+ "View file" : "Féach ar chomhad",
+ "View folder" : "Féach ar fhillteán",
+ "Files reminder" : "Meabhrúchán comhaid",
+ "The \"files_reminders\" app can work properly." : "Is féidir leis an \"files_reminders\" app oibriú i gceart.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Ní mór don app \"files_reminders\" an app fógra a bheith ag obair i gceart. Ba cheart duit fógraí a chumasú nó comhaid_reminder a dhíchumasú.",
+ "Set file reminders" : "Socraigh meabhrúcháin comhaid",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Meabhrúcháin comhaid**\n\nSocraigh meabhrúcháin comhaid.\n\nTabhair faoi deara: chun an aip `Meabhrúcháin Comhad` a úsáid, cinntigh go bhfuil an aip `Fógraí` suiteáilte agus cumasaithe. Soláthraíonn an aip `Fógraí` na APInna riachtanacha chun go n-oibreoidh an aip `Meabhrúcháin Comhad` i gceart.",
+ "Set reminder for \"{fileName}\"" : "Socraigh meabhrúchán do \"{fileName}\"",
+ "Clear reminder" : "Meabhrúchán soiléir",
+ "Please choose a valid date & time" : "Roghnaigh dáta agus am bailí le do thoil",
+ "Reminder set for \"{fileName}\"" : "Meabhrúchán socraithe do \"{fileName}\"",
+ "Failed to set reminder" : "Theip ar an meabhrúchán a shocrú",
+ "Reminder cleared for \"{fileName}\"" : "Glanadh an meabhrúchán le haghaidh \"{fileName}\"",
+ "Failed to clear reminder" : "Theip ar an meabhrúchán a ghlanadh",
+ "We will remind you of this file" : "Cuirfimid an comhad seo i gcuimhne duit",
+ "Cancel" : "Cealaigh",
+ "Set reminder" : "Socraigh meabhrúchán",
+ "Reminder set" : "Meabhrúchán socraithe",
+ "Later today" : "Níos déanaí inniu",
+ "Set reminder for later today" : "Socraigh meabhrúchán le haghaidh níos déanaí inniu",
+ "Tomorrow" : "Amárach",
+ "Set reminder for tomorrow" : "Socraigh meabhrúchán don lá amárach",
+ "This weekend" : "An deireadh seachtaine seo",
+ "Set reminder for this weekend" : "Socraigh meabhrúchán don deireadh seachtaine seo",
+ "Next week" : "An tseachtain seo chugainn",
+ "Set reminder for next week" : "Socraigh meabhrúchán don tseachtain seo chugainn",
+ "This files_reminder can work properly." : "Is féidir leis an gcomhad_reminder seo oibriú i gceart.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Teastaíonn an aip fógraí ón aip files_reminder chun oibriú i gceart. Ba cheart duit fógraí a chumasú nó comhaid_reminder a dhíchumasú.",
+ "Set reminder at custom date & time" : "Socraigh meabhrúchán ar dháta agus am saincheaptha",
+ "Set custom reminder" : "Socraigh meabhrúchán saincheaptha"
+},"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/files_reminders/l10n/gl.js b/apps/files_reminders/l10n/gl.js
new file mode 100644
index 00000000000..6275d8182a5
--- /dev/null
+++ b/apps/files_reminders/l10n/gl.js
@@ -0,0 +1,32 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Lembretes de ficheiros",
+ "Reminder for {name}" : "Lembrete para {name}",
+ "View file" : "Ver ficheiro",
+ "View folder" : "Ver cartafol",
+ "Set file reminders" : "Definir lembretes de ficheiros",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Lembretes de ficheiros**\n\nDefinir lembretes de ficheiros.\n\nNota: para usar a aplicación «Lembretes de ficheiros», asegúrese de que a aplicación «Notificacións» estea instalada e activada. A aplicación «Notificacións» ofrece as API necesarias para que a aplicación «Lembretes de ficheiros» funcione correctamente.",
+ "Set reminder for \"{fileName}\"" : "Definir un lembrete para «{fileName}»",
+ "Clear reminder" : "Limpar o lembrete",
+ "Please choose a valid date & time" : "Escolla unha data e hora válidas",
+ "Reminder set for \"{fileName}\"" : "Lembrete definido para «{fileName}»",
+ "Failed to set reminder" : "Produciuse un fallo ao definir o lembrete",
+ "Reminder cleared for \"{fileName}\"" : "Limpouse o lembrete para «{fileName}»",
+ "Failed to clear reminder" : "Produciuse un fallo ao limpar o lembrete",
+ "We will remind you of this file" : "Lembrarémoslle este ficheiro",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Definir un lembrete",
+ "Reminder set" : "Definir lembrete",
+ "Later today" : "Hoxe máis tarde",
+ "Set reminder for later today" : "Definir un lembrete para hoxe máis tarde",
+ "Tomorrow" : "Mañá",
+ "Set reminder for tomorrow" : "Definir un lembrete para mañá",
+ "This weekend" : "Este fin de semana",
+ "Set reminder for this weekend" : "Definir un lembrete para este fin de semana",
+ "Next week" : "Semana seguinte",
+ "Set reminder for next week" : "Definir un lembrete para a semana seguinte",
+ "Set reminder at custom date & time" : "Definir lembrete na data e hora personalizadas",
+ "Set custom reminder" : "Definir un lembrete personalizado"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/gl.json b/apps/files_reminders/l10n/gl.json
new file mode 100644
index 00000000000..678ba6bcca8
--- /dev/null
+++ b/apps/files_reminders/l10n/gl.json
@@ -0,0 +1,30 @@
+{ "translations": {
+ "File reminders" : "Lembretes de ficheiros",
+ "Reminder for {name}" : "Lembrete para {name}",
+ "View file" : "Ver ficheiro",
+ "View folder" : "Ver cartafol",
+ "Set file reminders" : "Definir lembretes de ficheiros",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Lembretes de ficheiros**\n\nDefinir lembretes de ficheiros.\n\nNota: para usar a aplicación «Lembretes de ficheiros», asegúrese de que a aplicación «Notificacións» estea instalada e activada. A aplicación «Notificacións» ofrece as API necesarias para que a aplicación «Lembretes de ficheiros» funcione correctamente.",
+ "Set reminder for \"{fileName}\"" : "Definir un lembrete para «{fileName}»",
+ "Clear reminder" : "Limpar o lembrete",
+ "Please choose a valid date & time" : "Escolla unha data e hora válidas",
+ "Reminder set for \"{fileName}\"" : "Lembrete definido para «{fileName}»",
+ "Failed to set reminder" : "Produciuse un fallo ao definir o lembrete",
+ "Reminder cleared for \"{fileName}\"" : "Limpouse o lembrete para «{fileName}»",
+ "Failed to clear reminder" : "Produciuse un fallo ao limpar o lembrete",
+ "We will remind you of this file" : "Lembrarémoslle este ficheiro",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Definir un lembrete",
+ "Reminder set" : "Definir lembrete",
+ "Later today" : "Hoxe máis tarde",
+ "Set reminder for later today" : "Definir un lembrete para hoxe máis tarde",
+ "Tomorrow" : "Mañá",
+ "Set reminder for tomorrow" : "Definir un lembrete para mañá",
+ "This weekend" : "Este fin de semana",
+ "Set reminder for this weekend" : "Definir un lembrete para este fin de semana",
+ "Next week" : "Semana seguinte",
+ "Set reminder for next week" : "Definir un lembrete para a semana seguinte",
+ "Set reminder at custom date & time" : "Definir lembrete na data e hora personalizadas",
+ "Set custom reminder" : "Definir un lembrete personalizado"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/hu.js b/apps/files_reminders/l10n/hu.js
new file mode 100644
index 00000000000..ff9c901ffae
--- /dev/null
+++ b/apps/files_reminders/l10n/hu.js
@@ -0,0 +1,31 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Fájl emlékeztetők",
+ "Reminder for {name}" : "Emlékeztető a következőhöz: {name}",
+ "View file" : "Fájl megtekintése",
+ "View folder" : "Mappa megtekintése",
+ "Set file reminders" : "Fájl emlékeztetők beállítása",
+ "Set reminder for \"{fileName}\"" : "Emlékeztető beállítása a következőhöz: „{fileName}”",
+ "Clear reminder" : "Emlékeztető törlése",
+ "Please choose a valid date & time" : "Adjon meg egy érvényes dátumot és időt",
+ "Reminder set for \"{fileName}\"" : "Emlékeztető beállítva a következőhöz: {fileName}",
+ "Failed to set reminder" : "Nem sikerült beállítani az emlékeztetőt",
+ "Reminder cleared for \"{fileName}\"" : "Emlékeztető törlése a következőhöz: „{fileName}”",
+ "Failed to clear reminder" : "Nem sikerült törölni az emlékeztetőt",
+ "We will remind you of this file" : "Emlékeztetni fogjuk Önt erre a fájlra",
+ "Cancel" : "Mégse",
+ "Set reminder" : "Emlékeztető beállítása",
+ "Reminder set" : "Emlékeztető beállítása",
+ "Later today" : "Mai nap később",
+ "Set reminder for later today" : "Emlékeztető beállítása a mai napon későbbre",
+ "Tomorrow" : "Holnap",
+ "Set reminder for tomorrow" : "Emlékeztető beállítása holnapra",
+ "This weekend" : "Ezen a héten",
+ "Set reminder for this weekend" : "Emlékeztető beállítása erre a hétvégére",
+ "Next week" : "Következő hét",
+ "Set reminder for next week" : "Emlékeztető beállítása a következő hétre",
+ "Set reminder at custom date & time" : "Emlékeztető beállítása tetszőleges időpontra",
+ "Set custom reminder" : "Egyéni emlékeztető beállítása"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/hu.json b/apps/files_reminders/l10n/hu.json
new file mode 100644
index 00000000000..36c4ace533f
--- /dev/null
+++ b/apps/files_reminders/l10n/hu.json
@@ -0,0 +1,29 @@
+{ "translations": {
+ "File reminders" : "Fájl emlékeztetők",
+ "Reminder for {name}" : "Emlékeztető a következőhöz: {name}",
+ "View file" : "Fájl megtekintése",
+ "View folder" : "Mappa megtekintése",
+ "Set file reminders" : "Fájl emlékeztetők beállítása",
+ "Set reminder for \"{fileName}\"" : "Emlékeztető beállítása a következőhöz: „{fileName}”",
+ "Clear reminder" : "Emlékeztető törlése",
+ "Please choose a valid date & time" : "Adjon meg egy érvényes dátumot és időt",
+ "Reminder set for \"{fileName}\"" : "Emlékeztető beállítva a következőhöz: {fileName}",
+ "Failed to set reminder" : "Nem sikerült beállítani az emlékeztetőt",
+ "Reminder cleared for \"{fileName}\"" : "Emlékeztető törlése a következőhöz: „{fileName}”",
+ "Failed to clear reminder" : "Nem sikerült törölni az emlékeztetőt",
+ "We will remind you of this file" : "Emlékeztetni fogjuk Önt erre a fájlra",
+ "Cancel" : "Mégse",
+ "Set reminder" : "Emlékeztető beállítása",
+ "Reminder set" : "Emlékeztető beállítása",
+ "Later today" : "Mai nap később",
+ "Set reminder for later today" : "Emlékeztető beállítása a mai napon későbbre",
+ "Tomorrow" : "Holnap",
+ "Set reminder for tomorrow" : "Emlékeztető beállítása holnapra",
+ "This weekend" : "Ezen a héten",
+ "Set reminder for this weekend" : "Emlékeztető beállítása erre a hétvégére",
+ "Next week" : "Következő hét",
+ "Set reminder for next week" : "Emlékeztető beállítása a következő hétre",
+ "Set reminder at custom date & time" : "Emlékeztető beállítása tetszőleges időpontra",
+ "Set custom reminder" : "Egyéni emlékeztető beállítása"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/it.js b/apps/files_reminders/l10n/it.js
new file mode 100644
index 00000000000..c9c3a08142d
--- /dev/null
+++ b/apps/files_reminders/l10n/it.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Promemoria file",
+ "Reminder for {name}" : "Promemoria per {name}",
+ "View file" : "Visualizza file",
+ "View folder" : "Visualizza cartella",
+ "Files reminder" : "Files reminder",
+ "The \"files_reminders\" app can work properly." : "L'app \"files_reminders\" può funzionare correttamente.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'app \"files_reminders\" necessita dell'app di notifica per funzionare correttamente. È necessario abilitare le notifiche o disabilitare files_reminder.",
+ "Set file reminders" : "Imposta promemoria per i file",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**I\n\nImposta promemoria file.\n\nNota: per usare l'app `Promemoria file`, assicurati che l'app `Notifiche` sia installata e abilitata. L'app `Notifiche` fornisce le API necessarie per il corretto funzionamento dell'app `File reminders`.",
+ "Set reminder for \"{fileName}\"" : "Imposta promemoria per \"{fileName}\"",
+ "Reminder at custom date & time" : "Promemoria a data e ora personalizzate",
+ "Clear reminder" : "Elimina promemoria",
+ "Please choose a valid date & time" : "Si prega di scegliere una data valida & ora",
+ "Reminder set for \"{fileName}\"" : "Promemoria impostato per \"{fileName}\"",
+ "Failed to set reminder" : "Impossibile impostare il promemoria",
+ "Reminder cleared for \"{fileName}\"" : "Promemoria cancellato per \"{fileName}\"",
+ "Failed to clear reminder" : "Impossibile cancellare il promemoria",
+ "We will remind you of this file" : "Ti ricorderemo questo file",
+ "Cancel" : "Annulla",
+ "Set reminder" : "Imposta promemoria",
+ "Reminder set" : "Promemoria impostato",
+ "Custom reminder" : "Promemoria personalizzato",
+ "Later today" : "Più tardi oggi",
+ "Set reminder for later today" : "Imposta promemoria per più tardi oggi",
+ "Tomorrow" : "Domani",
+ "Set reminder for tomorrow" : "Imposta promemoria per domani",
+ "This weekend" : "Questo fine settimana",
+ "Set reminder for this weekend" : "Imposta promemoria per questo fine settimana",
+ "Next week" : "Settimana successiva",
+ "Set reminder for next week" : "Imposta promemoria per la prossima settimana",
+ "This files_reminder can work properly." : "Questo file_promemoria può funzionare correttamente.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'app files_reminder necessita dell'app notifiche per funzionare correttamente. È necessario abilitare le notifiche o disabilitare files_reminder.",
+ "Set reminder at custom date & time" : "Imposta promemoria per data personalizzata & ora",
+ "Set custom reminder" : "Imposta promemoria personalizzato"
+},
+"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/files_reminders/l10n/it.json b/apps/files_reminders/l10n/it.json
new file mode 100644
index 00000000000..193ff9393db
--- /dev/null
+++ b/apps/files_reminders/l10n/it.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Promemoria file",
+ "Reminder for {name}" : "Promemoria per {name}",
+ "View file" : "Visualizza file",
+ "View folder" : "Visualizza cartella",
+ "Files reminder" : "Files reminder",
+ "The \"files_reminders\" app can work properly." : "L'app \"files_reminders\" può funzionare correttamente.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'app \"files_reminders\" necessita dell'app di notifica per funzionare correttamente. È necessario abilitare le notifiche o disabilitare files_reminder.",
+ "Set file reminders" : "Imposta promemoria per i file",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**I\n\nImposta promemoria file.\n\nNota: per usare l'app `Promemoria file`, assicurati che l'app `Notifiche` sia installata e abilitata. L'app `Notifiche` fornisce le API necessarie per il corretto funzionamento dell'app `File reminders`.",
+ "Set reminder for \"{fileName}\"" : "Imposta promemoria per \"{fileName}\"",
+ "Reminder at custom date & time" : "Promemoria a data e ora personalizzate",
+ "Clear reminder" : "Elimina promemoria",
+ "Please choose a valid date & time" : "Si prega di scegliere una data valida & ora",
+ "Reminder set for \"{fileName}\"" : "Promemoria impostato per \"{fileName}\"",
+ "Failed to set reminder" : "Impossibile impostare il promemoria",
+ "Reminder cleared for \"{fileName}\"" : "Promemoria cancellato per \"{fileName}\"",
+ "Failed to clear reminder" : "Impossibile cancellare il promemoria",
+ "We will remind you of this file" : "Ti ricorderemo questo file",
+ "Cancel" : "Annulla",
+ "Set reminder" : "Imposta promemoria",
+ "Reminder set" : "Promemoria impostato",
+ "Custom reminder" : "Promemoria personalizzato",
+ "Later today" : "Più tardi oggi",
+ "Set reminder for later today" : "Imposta promemoria per più tardi oggi",
+ "Tomorrow" : "Domani",
+ "Set reminder for tomorrow" : "Imposta promemoria per domani",
+ "This weekend" : "Questo fine settimana",
+ "Set reminder for this weekend" : "Imposta promemoria per questo fine settimana",
+ "Next week" : "Settimana successiva",
+ "Set reminder for next week" : "Imposta promemoria per la prossima settimana",
+ "This files_reminder can work properly." : "Questo file_promemoria può funzionare correttamente.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "L'app files_reminder necessita dell'app notifiche per funzionare correttamente. È necessario abilitare le notifiche o disabilitare files_reminder.",
+ "Set reminder at custom date & time" : "Imposta promemoria per data personalizzata & ora",
+ "Set custom reminder" : "Imposta promemoria personalizzato"
+},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/ja.js b/apps/files_reminders/l10n/ja.js
new file mode 100644
index 00000000000..8fb3cf19d7c
--- /dev/null
+++ b/apps/files_reminders/l10n/ja.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "ファイル リマインダー",
+ "Reminder for {name}" : "{name}のリマインダー",
+ "View file" : "ファイルを表示",
+ "View folder" : "フォルダーを表示",
+ "Files reminder" : "ファイル リマインダー",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\"アプリは正しく機能します。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "\"files_reminder\"アプリが正しく動作するには、通知アプリが必要です。通知を有効にするか、files_reminderを無効にしてください。",
+ "Set file reminders" : "ファイルのリマインダーを設定する",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**\n\nファイルのリマインダーを設定します。\n\n注意:`File reminders`アプリを使用するには、`Notifications`アプリがインストールされ、有効になっていることを確認してください。Notifications` アプリは `File reminders` アプリが正しく動作するために必要な API を提供します。",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\"のリマインダーを設定",
+ "Clear reminder" : "リマインダーをクリア",
+ "Please choose a valid date & time" : "有効な日付と時間を選択してください。",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\"のリマインダーを設定しました",
+ "Failed to set reminder" : "リマインダーの設定に失敗しました",
+ "Reminder cleared for \"{fileName}\"" : "\"{fileName}\"のリマインダーをクリアしました",
+ "Failed to clear reminder" : "リマインダーのクリアに失敗しました",
+ "We will remind you of this file" : "このファイルをリマインドします",
+ "Cancel" : "キャンセル",
+ "Set reminder" : "リマインダーを設定",
+ "Reminder set" : "リマインダーセット",
+ "Later today" : "今日この後",
+ "Set reminder for later today" : "今日中にリマインダーを設定する",
+ "Tomorrow" : "明日",
+ "Set reminder for tomorrow" : "明日のリマインダーを設定する",
+ "This weekend" : "この週末",
+ "Set reminder for this weekend" : "今週末のリマインダーを設定する",
+ "Next week" : "来週",
+ "Set reminder for next week" : "来週のリマインダーを設定する",
+ "This files_reminder can work properly." : "このfiles_reminderは正しく機能します。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminderアプリが正しく動作するには、通知アプリが必要です。通知を有効にするか、files_reminderを無効にしてください。",
+ "Set reminder at custom date & time" : "カスタムした日付と時刻にリマインダーを設定",
+ "Set custom reminder" : "カスタムリマインダーを設定する"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/files_reminders/l10n/ja.json b/apps/files_reminders/l10n/ja.json
new file mode 100644
index 00000000000..9bde1978bd2
--- /dev/null
+++ b/apps/files_reminders/l10n/ja.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "ファイル リマインダー",
+ "Reminder for {name}" : "{name}のリマインダー",
+ "View file" : "ファイルを表示",
+ "View folder" : "フォルダーを表示",
+ "Files reminder" : "ファイル リマインダー",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\"アプリは正しく機能します。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "\"files_reminder\"アプリが正しく動作するには、通知アプリが必要です。通知を有効にするか、files_reminderを無効にしてください。",
+ "Set file reminders" : "ファイルのリマインダーを設定する",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 File reminders**\n\nファイルのリマインダーを設定します。\n\n注意:`File reminders`アプリを使用するには、`Notifications`アプリがインストールされ、有効になっていることを確認してください。Notifications` アプリは `File reminders` アプリが正しく動作するために必要な API を提供します。",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\"のリマインダーを設定",
+ "Clear reminder" : "リマインダーをクリア",
+ "Please choose a valid date & time" : "有効な日付と時間を選択してください。",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\"のリマインダーを設定しました",
+ "Failed to set reminder" : "リマインダーの設定に失敗しました",
+ "Reminder cleared for \"{fileName}\"" : "\"{fileName}\"のリマインダーをクリアしました",
+ "Failed to clear reminder" : "リマインダーのクリアに失敗しました",
+ "We will remind you of this file" : "このファイルをリマインドします",
+ "Cancel" : "キャンセル",
+ "Set reminder" : "リマインダーを設定",
+ "Reminder set" : "リマインダーセット",
+ "Later today" : "今日この後",
+ "Set reminder for later today" : "今日中にリマインダーを設定する",
+ "Tomorrow" : "明日",
+ "Set reminder for tomorrow" : "明日のリマインダーを設定する",
+ "This weekend" : "この週末",
+ "Set reminder for this weekend" : "今週末のリマインダーを設定する",
+ "Next week" : "来週",
+ "Set reminder for next week" : "来週のリマインダーを設定する",
+ "This files_reminder can work properly." : "このfiles_reminderは正しく機能します。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminderアプリが正しく動作するには、通知アプリが必要です。通知を有効にするか、files_reminderを無効にしてください。",
+ "Set reminder at custom date & time" : "カスタムした日付と時刻にリマインダーを設定",
+ "Set custom reminder" : "カスタムリマインダーを設定する"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/ko.js b/apps/files_reminders/l10n/ko.js
new file mode 100644
index 00000000000..a7efcbaee36
--- /dev/null
+++ b/apps/files_reminders/l10n/ko.js
@@ -0,0 +1,29 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "파일 알림",
+ "Reminder for {name}" : "{name}에 대한 알림",
+ "View file" : "파일 보기",
+ "View folder" : "폴더 보기",
+ "Set file reminders" : "파일 알림 설정",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\"에 대한 알림 지정",
+ "Clear reminder" : "알림 초기화",
+ "Please choose a valid date & time" : "유효한 날짜와 시간을 지정하십시오",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\"에 대한 알림 목록",
+ "Failed to set reminder" : "알림을 설정할 수 없음",
+ "Failed to clear reminder" : "알림을 초기화할 수 없음",
+ "We will remind you of this file" : "이 파일에 대해 알림을 드립니다",
+ "Cancel" : "취소",
+ "Set reminder" : "알림 설정",
+ "Later today" : "오늘 늦게",
+ "Set reminder for later today" : "알림을 오늘 나중에 설정",
+ "Tomorrow" : "내일",
+ "Set reminder for tomorrow" : "알림을 내일로 설정",
+ "This weekend" : "이번 주말",
+ "Set reminder for this weekend" : "알림을 주말로 설정",
+ "Next week" : "다음주",
+ "Set reminder for next week" : "알림을 다음주로 설정",
+ "Set reminder at custom date & time" : "알림 날짜와 시간을 직접 지정",
+ "Set custom reminder" : "사용자 지정 알림 설정"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/files_reminders/l10n/ko.json b/apps/files_reminders/l10n/ko.json
new file mode 100644
index 00000000000..f7baea1e655
--- /dev/null
+++ b/apps/files_reminders/l10n/ko.json
@@ -0,0 +1,27 @@
+{ "translations": {
+ "File reminders" : "파일 알림",
+ "Reminder for {name}" : "{name}에 대한 알림",
+ "View file" : "파일 보기",
+ "View folder" : "폴더 보기",
+ "Set file reminders" : "파일 알림 설정",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\"에 대한 알림 지정",
+ "Clear reminder" : "알림 초기화",
+ "Please choose a valid date & time" : "유효한 날짜와 시간을 지정하십시오",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\"에 대한 알림 목록",
+ "Failed to set reminder" : "알림을 설정할 수 없음",
+ "Failed to clear reminder" : "알림을 초기화할 수 없음",
+ "We will remind you of this file" : "이 파일에 대해 알림을 드립니다",
+ "Cancel" : "취소",
+ "Set reminder" : "알림 설정",
+ "Later today" : "오늘 늦게",
+ "Set reminder for later today" : "알림을 오늘 나중에 설정",
+ "Tomorrow" : "내일",
+ "Set reminder for tomorrow" : "알림을 내일로 설정",
+ "This weekend" : "이번 주말",
+ "Set reminder for this weekend" : "알림을 주말로 설정",
+ "Next week" : "다음주",
+ "Set reminder for next week" : "알림을 다음주로 설정",
+ "Set reminder at custom date & time" : "알림 날짜와 시간을 직접 지정",
+ "Set custom reminder" : "사용자 지정 알림 설정"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/lt_LT.js b/apps/files_reminders/l10n/lt_LT.js
new file mode 100644
index 00000000000..69d97b6c96f
--- /dev/null
+++ b/apps/files_reminders/l10n/lt_LT.js
@@ -0,0 +1,31 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Priminimai apie failus",
+ "Reminder for {name}" : "Priminimas apie {name}",
+ "View file" : "Rodyti failą",
+ "View folder" : "Rodyti aplanką",
+ "Set file reminders" : "Nustatyti priminimus apie failus",
+ "Set reminder for \"{fileName}\"" : "Nustatyti priminimą apie „{fileName}“",
+ "Clear reminder" : "Panaikinti priminimą",
+ "Please choose a valid date & time" : "Pasirinkite tinkamą datą ir laiką",
+ "Reminder set for \"{fileName}\"" : "Nustatytas priminimas apie „{fileName}“",
+ "Failed to set reminder" : "Nepavyko nustatyti priminimo",
+ "Reminder cleared for \"{fileName}\"" : "Priminimas apie „{fileName}“ išvalytas",
+ "Failed to clear reminder" : "Nepavyko panaikinti priminimo",
+ "We will remind you of this file" : "Jums bus priminta apie šį failą",
+ "Cancel" : "Atsisakyti",
+ "Set reminder" : "Nustatyti priminimą",
+ "Reminder set" : "Priminimas nustatytas",
+ "Later today" : "Šiandien vėliau",
+ "Set reminder for later today" : "Nustatyti priminimą šiandien vėliau",
+ "Tomorrow" : "Rytoj",
+ "Set reminder for tomorrow" : "Nustatyti priminimą rytoj",
+ "This weekend" : "Šį savaitgalį",
+ "Set reminder for this weekend" : "Nustatyti priminimą šį savaitgalį",
+ "Next week" : "Kitą savaitę",
+ "Set reminder for next week" : "Nustatyti priminimą kitą savaitę",
+ "Set reminder at custom date & time" : "Nustatyti priminimą tinkintą datą ir laiką",
+ "Set custom reminder" : "Nustatyti tinkintą priminimą"
+},
+"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/files_reminders/l10n/lt_LT.json b/apps/files_reminders/l10n/lt_LT.json
new file mode 100644
index 00000000000..912fa2d31b2
--- /dev/null
+++ b/apps/files_reminders/l10n/lt_LT.json
@@ -0,0 +1,29 @@
+{ "translations": {
+ "File reminders" : "Priminimai apie failus",
+ "Reminder for {name}" : "Priminimas apie {name}",
+ "View file" : "Rodyti failą",
+ "View folder" : "Rodyti aplanką",
+ "Set file reminders" : "Nustatyti priminimus apie failus",
+ "Set reminder for \"{fileName}\"" : "Nustatyti priminimą apie „{fileName}“",
+ "Clear reminder" : "Panaikinti priminimą",
+ "Please choose a valid date & time" : "Pasirinkite tinkamą datą ir laiką",
+ "Reminder set for \"{fileName}\"" : "Nustatytas priminimas apie „{fileName}“",
+ "Failed to set reminder" : "Nepavyko nustatyti priminimo",
+ "Reminder cleared for \"{fileName}\"" : "Priminimas apie „{fileName}“ išvalytas",
+ "Failed to clear reminder" : "Nepavyko panaikinti priminimo",
+ "We will remind you of this file" : "Jums bus priminta apie šį failą",
+ "Cancel" : "Atsisakyti",
+ "Set reminder" : "Nustatyti priminimą",
+ "Reminder set" : "Priminimas nustatytas",
+ "Later today" : "Šiandien vėliau",
+ "Set reminder for later today" : "Nustatyti priminimą šiandien vėliau",
+ "Tomorrow" : "Rytoj",
+ "Set reminder for tomorrow" : "Nustatyti priminimą rytoj",
+ "This weekend" : "Šį savaitgalį",
+ "Set reminder for this weekend" : "Nustatyti priminimą šį savaitgalį",
+ "Next week" : "Kitą savaitę",
+ "Set reminder for next week" : "Nustatyti priminimą kitą savaitę",
+ "Set reminder at custom date & time" : "Nustatyti priminimą tinkintą datą ir laiką",
+ "Set custom reminder" : "Nustatyti tinkintą priminimą"
+},"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/files_reminders/l10n/mk.js b/apps/files_reminders/l10n/mk.js
new file mode 100644
index 00000000000..d608e3c2781
--- /dev/null
+++ b/apps/files_reminders/l10n/mk.js
@@ -0,0 +1,28 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Потсетник на датотеки",
+ "Reminder for {name}" : "Потсетник за {name}",
+ "View file" : "Види датотека",
+ "View folder" : "Види папка",
+ "Set file reminders" : "Постави потсетник на датотека",
+ "Set reminder for \"{fileName}\"" : "Постави потсетник за \"{fileName}\"",
+ "Clear reminder" : "Острани потсетник",
+ "Please choose a valid date & time" : "Внесете валиден датум & време",
+ "Reminder set for \"{fileName}\"" : "Поставен потсетник за \"{fileName}\"",
+ "Failed to set reminder" : "Неуспешно поставување на потсетник",
+ "Failed to clear reminder" : "Неуспешно остранување на потсетник",
+ "Cancel" : "Откажи",
+ "Set reminder" : "Постави потсетник",
+ "Later today" : "Денес покасно",
+ "Set reminder for later today" : "Постави потсетник за денес покасно",
+ "Tomorrow" : "Утре",
+ "Set reminder for tomorrow" : "Постави потсетник за утре",
+ "This weekend" : "Овој викенд",
+ "Set reminder for this weekend" : "Постави потсетник за овој викенд",
+ "Next week" : "Следна недела",
+ "Set reminder for next week" : "Постави потсетник за наредната недела",
+ "Set reminder at custom date & time" : "Постави потсетник на прилагоден датум & време",
+ "Set custom reminder" : "Постави прилагоден потсетник"
+},
+"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;");
diff --git a/apps/files_reminders/l10n/mk.json b/apps/files_reminders/l10n/mk.json
new file mode 100644
index 00000000000..a1403cefe97
--- /dev/null
+++ b/apps/files_reminders/l10n/mk.json
@@ -0,0 +1,26 @@
+{ "translations": {
+ "File reminders" : "Потсетник на датотеки",
+ "Reminder for {name}" : "Потсетник за {name}",
+ "View file" : "Види датотека",
+ "View folder" : "Види папка",
+ "Set file reminders" : "Постави потсетник на датотека",
+ "Set reminder for \"{fileName}\"" : "Постави потсетник за \"{fileName}\"",
+ "Clear reminder" : "Острани потсетник",
+ "Please choose a valid date & time" : "Внесете валиден датум & време",
+ "Reminder set for \"{fileName}\"" : "Поставен потсетник за \"{fileName}\"",
+ "Failed to set reminder" : "Неуспешно поставување на потсетник",
+ "Failed to clear reminder" : "Неуспешно остранување на потсетник",
+ "Cancel" : "Откажи",
+ "Set reminder" : "Постави потсетник",
+ "Later today" : "Денес покасно",
+ "Set reminder for later today" : "Постави потсетник за денес покасно",
+ "Tomorrow" : "Утре",
+ "Set reminder for tomorrow" : "Постави потсетник за утре",
+ "This weekend" : "Овој викенд",
+ "Set reminder for this weekend" : "Постави потсетник за овој викенд",
+ "Next week" : "Следна недела",
+ "Set reminder for next week" : "Постави потсетник за наредната недела",
+ "Set reminder at custom date & time" : "Постави потсетник на прилагоден датум & време",
+ "Set custom reminder" : "Постави прилагоден потсетник"
+},"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/nb.js b/apps/files_reminders/l10n/nb.js
new file mode 100644
index 00000000000..13c42a535d1
--- /dev/null
+++ b/apps/files_reminders/l10n/nb.js
@@ -0,0 +1,31 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Filpåminnelser",
+ "Reminder for {name}" : "Påminnelse for {name}",
+ "View file" : "Vis fil",
+ "View folder" : "Vis mappe",
+ "Set file reminders" : "Angi filpåminnelser",
+ "Set reminder for \"{fileName}\"" : "Angi påminnelse for \"{fileName}\"",
+ "Clear reminder" : "Tydelig påminnelse",
+ "Please choose a valid date & time" : "Vennligst velg en gyldig dato og tid",
+ "Reminder set for \"{fileName}\"" : "Påminnelse satt for «{fileName}»",
+ "Failed to set reminder" : "Kunne ikke angi påminnelse",
+ "Reminder cleared for \"{fileName}\"" : "Påminnelse slettet for \"{fileName}\"",
+ "Failed to clear reminder" : "Kunne ikke fjerne påminnelsen",
+ "We will remind you of this file" : "Vi minner deg på denne filen",
+ "Cancel" : "Avbryt",
+ "Set reminder" : "Angi påminnelse",
+ "Reminder set" : "Påminnelse angitt",
+ "Later today" : "Senere i dag",
+ "Set reminder for later today" : "Sett påminnelse til senere i dag",
+ "Tomorrow" : "I morgen",
+ "Set reminder for tomorrow" : "Sett påminnelse for i morgen",
+ "This weekend" : "Denne helgen",
+ "Set reminder for this weekend" : "Sett påminnelse for denne helgen",
+ "Next week" : "Neste uke",
+ "Set reminder for next week" : "Sett påminnelse for neste uke",
+ "Set reminder at custom date & time" : "Still inn påminnelse til egendefinert dato og klokkeslett",
+ "Set custom reminder" : "Angi egendefinert påminnelse"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/nb.json b/apps/files_reminders/l10n/nb.json
new file mode 100644
index 00000000000..b6e7dbae2c8
--- /dev/null
+++ b/apps/files_reminders/l10n/nb.json
@@ -0,0 +1,29 @@
+{ "translations": {
+ "File reminders" : "Filpåminnelser",
+ "Reminder for {name}" : "Påminnelse for {name}",
+ "View file" : "Vis fil",
+ "View folder" : "Vis mappe",
+ "Set file reminders" : "Angi filpåminnelser",
+ "Set reminder for \"{fileName}\"" : "Angi påminnelse for \"{fileName}\"",
+ "Clear reminder" : "Tydelig påminnelse",
+ "Please choose a valid date & time" : "Vennligst velg en gyldig dato og tid",
+ "Reminder set for \"{fileName}\"" : "Påminnelse satt for «{fileName}»",
+ "Failed to set reminder" : "Kunne ikke angi påminnelse",
+ "Reminder cleared for \"{fileName}\"" : "Påminnelse slettet for \"{fileName}\"",
+ "Failed to clear reminder" : "Kunne ikke fjerne påminnelsen",
+ "We will remind you of this file" : "Vi minner deg på denne filen",
+ "Cancel" : "Avbryt",
+ "Set reminder" : "Angi påminnelse",
+ "Reminder set" : "Påminnelse angitt",
+ "Later today" : "Senere i dag",
+ "Set reminder for later today" : "Sett påminnelse til senere i dag",
+ "Tomorrow" : "I morgen",
+ "Set reminder for tomorrow" : "Sett påminnelse for i morgen",
+ "This weekend" : "Denne helgen",
+ "Set reminder for this weekend" : "Sett påminnelse for denne helgen",
+ "Next week" : "Neste uke",
+ "Set reminder for next week" : "Sett påminnelse for neste uke",
+ "Set reminder at custom date & time" : "Still inn påminnelse til egendefinert dato og klokkeslett",
+ "Set custom reminder" : "Angi egendefinert påminnelse"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/pl.js b/apps/files_reminders/l10n/pl.js
new file mode 100644
index 00000000000..133c9095016
--- /dev/null
+++ b/apps/files_reminders/l10n/pl.js
@@ -0,0 +1,29 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Przypomnienia o plikach",
+ "Reminder for {name}" : "Przypomnienie dla {name}",
+ "View file" : "Zobacz plik",
+ "View folder" : "Wyświetl katalog",
+ "Set file reminders" : "Ustaw przypomnienia o plikach",
+ "Set reminder for \"{fileName}\"" : "Ustaw przypomnienie dla \"{fileName}\"",
+ "Clear reminder" : "Wyczyść przypomnienie",
+ "Please choose a valid date & time" : "Wybierz prawidłową datę i godzinę",
+ "Reminder set for \"{fileName}\"" : "Przypomnienie ustawione dla \"{fileName}\"",
+ "Failed to set reminder" : "Nie udało się ustawić przypomnienia",
+ "Failed to clear reminder" : "Nie udało się wyczyścić przypomnienia",
+ "We will remind you of this file" : "Przypomnimy Tobie o tym pliku",
+ "Cancel" : "Anuluj",
+ "Set reminder" : "Ustaw przypomnienie",
+ "Later today" : "Później dzisiaj",
+ "Set reminder for later today" : "Ustaw przypomnienie na dzisiaj na późniejszy czas",
+ "Tomorrow" : "Jutro",
+ "Set reminder for tomorrow" : "Ustaw przypomnienie na jutro",
+ "This weekend" : "W ten weekend",
+ "Set reminder for this weekend" : "Ustaw przypomnienie na ten weekend",
+ "Next week" : "Następny tydzień",
+ "Set reminder for next week" : "Ustaw przypomnienie na przyszły tydzień",
+ "Set reminder at custom date & time" : "Ustaw przypomnienie o własnej dacie i godzinie",
+ "Set custom reminder" : "Ustaw niestandardowe przypomnienie"
+},
+"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/files_reminders/l10n/pl.json b/apps/files_reminders/l10n/pl.json
new file mode 100644
index 00000000000..1cc94af73b8
--- /dev/null
+++ b/apps/files_reminders/l10n/pl.json
@@ -0,0 +1,27 @@
+{ "translations": {
+ "File reminders" : "Przypomnienia o plikach",
+ "Reminder for {name}" : "Przypomnienie dla {name}",
+ "View file" : "Zobacz plik",
+ "View folder" : "Wyświetl katalog",
+ "Set file reminders" : "Ustaw przypomnienia o plikach",
+ "Set reminder for \"{fileName}\"" : "Ustaw przypomnienie dla \"{fileName}\"",
+ "Clear reminder" : "Wyczyść przypomnienie",
+ "Please choose a valid date & time" : "Wybierz prawidłową datę i godzinę",
+ "Reminder set for \"{fileName}\"" : "Przypomnienie ustawione dla \"{fileName}\"",
+ "Failed to set reminder" : "Nie udało się ustawić przypomnienia",
+ "Failed to clear reminder" : "Nie udało się wyczyścić przypomnienia",
+ "We will remind you of this file" : "Przypomnimy Tobie o tym pliku",
+ "Cancel" : "Anuluj",
+ "Set reminder" : "Ustaw przypomnienie",
+ "Later today" : "Później dzisiaj",
+ "Set reminder for later today" : "Ustaw przypomnienie na dzisiaj na późniejszy czas",
+ "Tomorrow" : "Jutro",
+ "Set reminder for tomorrow" : "Ustaw przypomnienie na jutro",
+ "This weekend" : "W ten weekend",
+ "Set reminder for this weekend" : "Ustaw przypomnienie na ten weekend",
+ "Next week" : "Następny tydzień",
+ "Set reminder for next week" : "Ustaw przypomnienie na przyszły tydzień",
+ "Set reminder at custom date & time" : "Ustaw przypomnienie o własnej dacie i godzinie",
+ "Set custom reminder" : "Ustaw niestandardowe przypomnienie"
+},"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/files_reminders/l10n/pt_BR.js b/apps/files_reminders/l10n/pt_BR.js
new file mode 100644
index 00000000000..3ed3e3e2949
--- /dev/null
+++ b/apps/files_reminders/l10n/pt_BR.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Lembretes de arquivos",
+ "Reminder for {name}" : "Lembrete para {name}",
+ "View file" : "Ver arquivo",
+ "View folder" : "Ver pasta",
+ "Files reminder" : "Lembrete de arquivos",
+ "The \"files_reminders\" app can work properly." : "O aplicativo \"files_reminders\" pode funcionar corretamente.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "O aplicativo \"files_reminders\" precisa do aplicativo de notificações para funcionar corretamente. Você deve ativar notificações ou desativar o files_reminder.",
+ "Set file reminders" : "Defina lembretes de arquivo",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Lembretes de arquivos** \n\nDefina lembretes de arquivos. \n\nObservação: para usar o aplicativo `Lembretes de arquivos`, certifique-se de que o aplicativo `Notificações` esteja instalado e habilitado. O aplicativo `Notificações` fornece as APIs necessárias para que o aplicativo `Lembretes de arquivos` funcione corretamente.",
+ "Set reminder for \"{fileName}\"" : "Definir lembrete para \"{fileName}\"",
+ "Reminder at custom date & time" : "Lembrete em data e hora personalizadas",
+ "Clear reminder" : "Limpar lembrete",
+ "Please choose a valid date & time" : "Por favor escolha uma data & hora válida.",
+ "Reminder set for \"{fileName}\"" : "Lembrete definido para \"{fileName}\"",
+ "Failed to set reminder" : "Falha ao definir lembrete",
+ "Reminder cleared for \"{fileName}\"" : "Lembrete removido para \"{fileName}\"",
+ "Failed to clear reminder" : "Falha ao remover lembrete",
+ "We will remind you of this file" : "Lembraremos você desse arquivo",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Definir lembrete",
+ "Reminder set" : "Lembrete definido",
+ "Custom reminder" : "Lembrete personalizado",
+ "Later today" : "Hoje mais tarde",
+ "Set reminder for later today" : "Definir lembrete para hoje mais tarde",
+ "Tomorrow" : "Amanhã",
+ "Set reminder for tomorrow" : "Definir lembrete para amanhã",
+ "This weekend" : "Este fim de semana",
+ "Set reminder for this weekend" : "Definir lembrete para este fim de semana",
+ "Next week" : "Próxima semana",
+ "Set reminder for next week" : "Definir lembrete para a próxima semana",
+ "This files_reminder can work properly." : "Este files_reminder pode funcionar corretamente.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "O aplicativo files_reminder precisa do aplicativo de notificações para funcionar corretamente. Você deve ativar notificações ou desativar o files_reminder.",
+ "Set reminder at custom date & time" : "Definir lembrete em data & hora customizada",
+ "Set custom reminder" : "Definir lembrete personalizado"
+},
+"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;");
diff --git a/apps/files_reminders/l10n/pt_BR.json b/apps/files_reminders/l10n/pt_BR.json
new file mode 100644
index 00000000000..e5be7701fae
--- /dev/null
+++ b/apps/files_reminders/l10n/pt_BR.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Lembretes de arquivos",
+ "Reminder for {name}" : "Lembrete para {name}",
+ "View file" : "Ver arquivo",
+ "View folder" : "Ver pasta",
+ "Files reminder" : "Lembrete de arquivos",
+ "The \"files_reminders\" app can work properly." : "O aplicativo \"files_reminders\" pode funcionar corretamente.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "O aplicativo \"files_reminders\" precisa do aplicativo de notificações para funcionar corretamente. Você deve ativar notificações ou desativar o files_reminder.",
+ "Set file reminders" : "Defina lembretes de arquivo",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Lembretes de arquivos** \n\nDefina lembretes de arquivos. \n\nObservação: para usar o aplicativo `Lembretes de arquivos`, certifique-se de que o aplicativo `Notificações` esteja instalado e habilitado. O aplicativo `Notificações` fornece as APIs necessárias para que o aplicativo `Lembretes de arquivos` funcione corretamente.",
+ "Set reminder for \"{fileName}\"" : "Definir lembrete para \"{fileName}\"",
+ "Reminder at custom date & time" : "Lembrete em data e hora personalizadas",
+ "Clear reminder" : "Limpar lembrete",
+ "Please choose a valid date & time" : "Por favor escolha uma data & hora válida.",
+ "Reminder set for \"{fileName}\"" : "Lembrete definido para \"{fileName}\"",
+ "Failed to set reminder" : "Falha ao definir lembrete",
+ "Reminder cleared for \"{fileName}\"" : "Lembrete removido para \"{fileName}\"",
+ "Failed to clear reminder" : "Falha ao remover lembrete",
+ "We will remind you of this file" : "Lembraremos você desse arquivo",
+ "Cancel" : "Cancelar",
+ "Set reminder" : "Definir lembrete",
+ "Reminder set" : "Lembrete definido",
+ "Custom reminder" : "Lembrete personalizado",
+ "Later today" : "Hoje mais tarde",
+ "Set reminder for later today" : "Definir lembrete para hoje mais tarde",
+ "Tomorrow" : "Amanhã",
+ "Set reminder for tomorrow" : "Definir lembrete para amanhã",
+ "This weekend" : "Este fim de semana",
+ "Set reminder for this weekend" : "Definir lembrete para este fim de semana",
+ "Next week" : "Próxima semana",
+ "Set reminder for next week" : "Definir lembrete para a próxima semana",
+ "This files_reminder can work properly." : "Este files_reminder pode funcionar corretamente.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "O aplicativo files_reminder precisa do aplicativo de notificações para funcionar corretamente. Você deve ativar notificações ou desativar o files_reminder.",
+ "Set reminder at custom date & time" : "Definir lembrete em data & hora customizada",
+ "Set custom reminder" : "Definir lembrete personalizado"
+},"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/files_reminders/l10n/ro.js b/apps/files_reminders/l10n/ro.js
new file mode 100644
index 00000000000..016c87ca66f
--- /dev/null
+++ b/apps/files_reminders/l10n/ro.js
@@ -0,0 +1,29 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Memo fișier",
+ "Reminder for {name}" : "Memo pentru {name}",
+ "View file" : "Vezi fișierul",
+ "View folder" : "Vezi dosarul",
+ "Set file reminders" : "Setează memo pentru fișier",
+ "Set reminder for \"{fileName}\"" : "Setează memento pentru \"{fileName}\"",
+ "Clear reminder" : "Șterge memento",
+ "Please choose a valid date & time" : "Selectați o dată și o oră valide",
+ "Reminder set for \"{fileName}\"" : "Memento setat pentru \"{fileName}\"",
+ "Failed to set reminder" : "Eroare la setarea mementoului",
+ "Failed to clear reminder" : "Eroare la ștergerea mementoului",
+ "We will remind you of this file" : "Vă vom reaminti despre acest fișier",
+ "Cancel" : "Anulare",
+ "Set reminder" : "Setează memo",
+ "Later today" : "Mai târziu în cursul zilei",
+ "Set reminder for later today" : "Setează memo pentru azi, mai târziu",
+ "Tomorrow" : "Mâine",
+ "Set reminder for tomorrow" : "Setează memo pentru mâine",
+ "This weekend" : "În acest weekend",
+ "Set reminder for this weekend" : "Setează memo pentru acest weekend",
+ "Next week" : "Saptămâna următoare",
+ "Set reminder for next week" : "Setează memo pentru săptămâna viitoare",
+ "Set reminder at custom date & time" : "Setează memento la o dată și oră particulare",
+ "Set custom reminder" : "Setează memento particular"
+},
+"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));");
diff --git a/apps/files_reminders/l10n/ro.json b/apps/files_reminders/l10n/ro.json
new file mode 100644
index 00000000000..9d0b51fbaa6
--- /dev/null
+++ b/apps/files_reminders/l10n/ro.json
@@ -0,0 +1,27 @@
+{ "translations": {
+ "File reminders" : "Memo fișier",
+ "Reminder for {name}" : "Memo pentru {name}",
+ "View file" : "Vezi fișierul",
+ "View folder" : "Vezi dosarul",
+ "Set file reminders" : "Setează memo pentru fișier",
+ "Set reminder for \"{fileName}\"" : "Setează memento pentru \"{fileName}\"",
+ "Clear reminder" : "Șterge memento",
+ "Please choose a valid date & time" : "Selectați o dată și o oră valide",
+ "Reminder set for \"{fileName}\"" : "Memento setat pentru \"{fileName}\"",
+ "Failed to set reminder" : "Eroare la setarea mementoului",
+ "Failed to clear reminder" : "Eroare la ștergerea mementoului",
+ "We will remind you of this file" : "Vă vom reaminti despre acest fișier",
+ "Cancel" : "Anulare",
+ "Set reminder" : "Setează memo",
+ "Later today" : "Mai târziu în cursul zilei",
+ "Set reminder for later today" : "Setează memo pentru azi, mai târziu",
+ "Tomorrow" : "Mâine",
+ "Set reminder for tomorrow" : "Setează memo pentru mâine",
+ "This weekend" : "În acest weekend",
+ "Set reminder for this weekend" : "Setează memo pentru acest weekend",
+ "Next week" : "Saptămâna următoare",
+ "Set reminder for next week" : "Setează memo pentru săptămâna viitoare",
+ "Set reminder at custom date & time" : "Setează memento la o dată și oră particulare",
+ "Set custom reminder" : "Setează memento particular"
+},"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/files_reminders/l10n/ru.js b/apps/files_reminders/l10n/ru.js
new file mode 100644
index 00000000000..c2c17dce06c
--- /dev/null
+++ b/apps/files_reminders/l10n/ru.js
@@ -0,0 +1,32 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Напоминания о файлах",
+ "Reminder for {name}" : "Напоминание для {name}",
+ "View file" : "Просмотреть файл",
+ "View folder" : "Просмотреть папку",
+ "Set file reminders" : "Установить напоминания о файлах",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣Напоминания о файлах**\n\nУстановите напоминания о файлах.\n\nПримечание: чтобы использовать приложение \"Напоминания о файлах\", убедитесь, что приложение \"Уведомления\" установлено и включено. Приложение \"Уведомления\" предоставляет необходимые API-интерфейсы для правильной работы приложения \"Напоминания о файлах\".",
+ "Set reminder for \"{fileName}\"" : "Установить напоминание для \"{fileName}\"",
+ "Clear reminder" : "Очистить напоминание",
+ "Please choose a valid date & time" : "Пожалуйста, выберите правильную дату и время",
+ "Reminder set for \"{fileName}\"" : "Напоминание для \"{fileName}\"",
+ "Failed to set reminder" : "Не удалось установить напоминание",
+ "Reminder cleared for \"{fileName}\"" : "Напоминание очищено для \"{fileName}\"",
+ "Failed to clear reminder" : "Не удалось удалить напоминание",
+ "We will remind you of this file" : "Мы напомним вам об этом файле",
+ "Cancel" : "Отмена",
+ "Set reminder" : "Установить напоминание",
+ "Reminder set" : "Установить напоминание",
+ "Later today" : "Позже сегодня",
+ "Set reminder for later today" : "Установить напоминание позднее сегодня",
+ "Tomorrow" : "Завтра",
+ "Set reminder for tomorrow" : "Установить напоминание на завтра",
+ "This weekend" : "Эта неделя",
+ "Set reminder for this weekend" : "Установить напоминание на эти выходные",
+ "Next week" : "Следующая неделя",
+ "Set reminder for next week" : "Установить напоминание на следующую неделю",
+ "Set reminder at custom date & time" : "Установить напоминание на индивидуальную дату и время",
+ "Set custom reminder" : "Установить особое напоминание"
+},
+"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/files_reminders/l10n/ru.json b/apps/files_reminders/l10n/ru.json
new file mode 100644
index 00000000000..9dab1fd734e
--- /dev/null
+++ b/apps/files_reminders/l10n/ru.json
@@ -0,0 +1,30 @@
+{ "translations": {
+ "File reminders" : "Напоминания о файлах",
+ "Reminder for {name}" : "Напоминание для {name}",
+ "View file" : "Просмотреть файл",
+ "View folder" : "Просмотреть папку",
+ "Set file reminders" : "Установить напоминания о файлах",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣Напоминания о файлах**\n\nУстановите напоминания о файлах.\n\nПримечание: чтобы использовать приложение \"Напоминания о файлах\", убедитесь, что приложение \"Уведомления\" установлено и включено. Приложение \"Уведомления\" предоставляет необходимые API-интерфейсы для правильной работы приложения \"Напоминания о файлах\".",
+ "Set reminder for \"{fileName}\"" : "Установить напоминание для \"{fileName}\"",
+ "Clear reminder" : "Очистить напоминание",
+ "Please choose a valid date & time" : "Пожалуйста, выберите правильную дату и время",
+ "Reminder set for \"{fileName}\"" : "Напоминание для \"{fileName}\"",
+ "Failed to set reminder" : "Не удалось установить напоминание",
+ "Reminder cleared for \"{fileName}\"" : "Напоминание очищено для \"{fileName}\"",
+ "Failed to clear reminder" : "Не удалось удалить напоминание",
+ "We will remind you of this file" : "Мы напомним вам об этом файле",
+ "Cancel" : "Отмена",
+ "Set reminder" : "Установить напоминание",
+ "Reminder set" : "Установить напоминание",
+ "Later today" : "Позже сегодня",
+ "Set reminder for later today" : "Установить напоминание позднее сегодня",
+ "Tomorrow" : "Завтра",
+ "Set reminder for tomorrow" : "Установить напоминание на завтра",
+ "This weekend" : "Эта неделя",
+ "Set reminder for this weekend" : "Установить напоминание на эти выходные",
+ "Next week" : "Следующая неделя",
+ "Set reminder for next week" : "Установить напоминание на следующую неделю",
+ "Set reminder at custom date & time" : "Установить напоминание на индивидуальную дату и время",
+ "Set custom reminder" : "Установить особое напоминание"
+},"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/files_reminders/l10n/sk.js b/apps/files_reminders/l10n/sk.js
new file mode 100644
index 00000000000..5adaedefa15
--- /dev/null
+++ b/apps/files_reminders/l10n/sk.js
@@ -0,0 +1,32 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Pripomienky súborov",
+ "Reminder for {name}" : "Pripomienka pre {name}",
+ "View file" : "Zobraziť súbor",
+ "View folder" : "Zobraziť adresár",
+ "Set file reminders" : "Nastaviť pripomienky súborov",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Pripomienky súborov**\n\nNastavte pripomienky súborov.\n\nPoznámka: Ak chcete použiť aplikáciu „Pripomienky súborov“, uistite sa, že je nainštalovaná a povolená aplikácia „Upozornenia“. Aplikácia „Upozornenia“ poskytuje potrebné rozhrania API, aby aplikácia „Pripomienky súborov“ fungovala správne.",
+ "Set reminder for \"{fileName}\"" : "Nastaviť pripomienku pre \"{fileName}\"",
+ "Clear reminder" : "Vymazať pripomienku",
+ "Please choose a valid date & time" : "Prosím, vyberte platný dátum a čas",
+ "Reminder set for \"{fileName}\"" : "Pripomienka nastavená pre \"{fileName}\"",
+ "Failed to set reminder" : "Nepodarilo sa nastavit pripomienku",
+ "Reminder cleared for \"{fileName}\"" : "Pripomienka pre \"{fileName}\" bola odstránená",
+ "Failed to clear reminder" : "Nepodarilo sa odstrániť pripomienku",
+ "We will remind you of this file" : "Pripomenieme vám tento súbor",
+ "Cancel" : "Zrušiť",
+ "Set reminder" : "Nastaviť pripomienku",
+ "Reminder set" : "Pripomienka bola nastavená",
+ "Later today" : "Neskôr dnes",
+ "Set reminder for later today" : "Nastaviť pripomienku na dnes-neskôr.",
+ "Tomorrow" : "Zajtra",
+ "Set reminder for tomorrow" : "Nastaviť pripomienku na zajtra",
+ "This weekend" : "Tento víkend",
+ "Set reminder for this weekend" : "Nastaviť pripomienku na tento víkend",
+ "Next week" : "Nasledujúci týždeň",
+ "Set reminder for next week" : "Nastaviť pripomienku na budúci týždeň",
+ "Set reminder at custom date & time" : "Nastaviť pripomienku na vlastn dátum a čas",
+ "Set custom reminder" : "Nastaviť vlastnú pripomienku"
+},
+"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/files_reminders/l10n/sk.json b/apps/files_reminders/l10n/sk.json
new file mode 100644
index 00000000000..c048fbfc050
--- /dev/null
+++ b/apps/files_reminders/l10n/sk.json
@@ -0,0 +1,30 @@
+{ "translations": {
+ "File reminders" : "Pripomienky súborov",
+ "Reminder for {name}" : "Pripomienka pre {name}",
+ "View file" : "Zobraziť súbor",
+ "View folder" : "Zobraziť adresár",
+ "Set file reminders" : "Nastaviť pripomienky súborov",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Pripomienky súborov**\n\nNastavte pripomienky súborov.\n\nPoznámka: Ak chcete použiť aplikáciu „Pripomienky súborov“, uistite sa, že je nainštalovaná a povolená aplikácia „Upozornenia“. Aplikácia „Upozornenia“ poskytuje potrebné rozhrania API, aby aplikácia „Pripomienky súborov“ fungovala správne.",
+ "Set reminder for \"{fileName}\"" : "Nastaviť pripomienku pre \"{fileName}\"",
+ "Clear reminder" : "Vymazať pripomienku",
+ "Please choose a valid date & time" : "Prosím, vyberte platný dátum a čas",
+ "Reminder set for \"{fileName}\"" : "Pripomienka nastavená pre \"{fileName}\"",
+ "Failed to set reminder" : "Nepodarilo sa nastavit pripomienku",
+ "Reminder cleared for \"{fileName}\"" : "Pripomienka pre \"{fileName}\" bola odstránená",
+ "Failed to clear reminder" : "Nepodarilo sa odstrániť pripomienku",
+ "We will remind you of this file" : "Pripomenieme vám tento súbor",
+ "Cancel" : "Zrušiť",
+ "Set reminder" : "Nastaviť pripomienku",
+ "Reminder set" : "Pripomienka bola nastavená",
+ "Later today" : "Neskôr dnes",
+ "Set reminder for later today" : "Nastaviť pripomienku na dnes-neskôr.",
+ "Tomorrow" : "Zajtra",
+ "Set reminder for tomorrow" : "Nastaviť pripomienku na zajtra",
+ "This weekend" : "Tento víkend",
+ "Set reminder for this weekend" : "Nastaviť pripomienku na tento víkend",
+ "Next week" : "Nasledujúci týždeň",
+ "Set reminder for next week" : "Nastaviť pripomienku na budúci týždeň",
+ "Set reminder at custom date & time" : "Nastaviť pripomienku na vlastn dátum a čas",
+ "Set custom reminder" : "Nastaviť vlastnú pripomienku"
+},"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/files_reminders/l10n/sr.js b/apps/files_reminders/l10n/sr.js
new file mode 100644
index 00000000000..bbf5bbb77d0
--- /dev/null
+++ b/apps/files_reminders/l10n/sr.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Подсетници о фајлу",
+ "Reminder for {name}" : "Подсетник за {name}",
+ "View file" : "Погледај фајл",
+ "View folder" : "Погледај фолдер",
+ "Files reminder" : "Подсетник фајлова",
+ "The \"files_reminders\" app can work properly." : "Апликација „files_reminder може да ради како треба.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Да би „files_reminder” апликација радила како треба, потребна је апликација обавештења. Требало би или да укључите обавештења, или да искључите files_reminder.",
+ "Set file reminders" : "Постави подсетнике о фајлу",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Фајл подсетници**\n\nПоставите фајл подсетнике.\n\nНапомена: ако желите да користите апликацију `Фајл подсетници`, обезбедите да је инсталирана и укључена апликација `Обавештења`. Апликација `Обавештења` обезбеђује неопходне API-је уз чију помоћ апликација `Фајл подестници` функционише како треба.",
+ "Set reminder for \"{fileName}\"" : "Постави подсетник за „{fileName}”",
+ "Clear reminder" : "Обриши подсетник",
+ "Please choose a valid date & time" : "Молимо вас да изаберете исправни датум и време",
+ "Reminder set for \"{fileName}\"" : "Подсетник је постављен за „{fileName}”",
+ "Failed to set reminder" : "Није успело постављање подсетника",
+ "Reminder cleared for \"{fileName}\"" : "Уклоњен је подсетник за „{fileName}”",
+ "Failed to clear reminder" : "Није успело брисање подсетника",
+ "We will remind you of this file" : "Подсетићемо вас на овај фајл",
+ "Cancel" : "Откажи",
+ "Set reminder" : "Постави подсетник",
+ "Reminder set" : "Подсетник је постављен",
+ "Later today" : "Касније данас",
+ "Set reminder for later today" : "Поставља подсетник за касније данас",
+ "Tomorrow" : "Сутра",
+ "Set reminder for tomorrow" : "Поставља подсетник за сутра",
+ "This weekend" : "Овог викенда",
+ "Set reminder for this weekend" : "Поставља подсетник за овај викенд",
+ "Next week" : "Наредне недеље",
+ "Set reminder for next week" : "Поставља подсетник за наредну недељу",
+ "This files_reminder can work properly." : "Овај files_reminder може да ради како треба.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Да би files_reminder апликација радила како треба, потребна је апликација обавештења. Требало би или да укључите обавештења, или да искључите files_reminder.",
+ "Set reminder at custom date & time" : "Постави подсетник на произвољни датум и време",
+ "Set custom reminder" : "Постави произвољни подсетник"
+},
+"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/files_reminders/l10n/sr.json b/apps/files_reminders/l10n/sr.json
new file mode 100644
index 00000000000..edc15226645
--- /dev/null
+++ b/apps/files_reminders/l10n/sr.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Подсетници о фајлу",
+ "Reminder for {name}" : "Подсетник за {name}",
+ "View file" : "Погледај фајл",
+ "View folder" : "Погледај фолдер",
+ "Files reminder" : "Подсетник фајлова",
+ "The \"files_reminders\" app can work properly." : "Апликација „files_reminder може да ради како треба.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Да би „files_reminder” апликација радила како треба, потребна је апликација обавештења. Требало би или да укључите обавештења, или да искључите files_reminder.",
+ "Set file reminders" : "Постави подсетнике о фајлу",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Фајл подсетници**\n\nПоставите фајл подсетнике.\n\nНапомена: ако желите да користите апликацију `Фајл подсетници`, обезбедите да је инсталирана и укључена апликација `Обавештења`. Апликација `Обавештења` обезбеђује неопходне API-је уз чију помоћ апликација `Фајл подестници` функционише како треба.",
+ "Set reminder for \"{fileName}\"" : "Постави подсетник за „{fileName}”",
+ "Clear reminder" : "Обриши подсетник",
+ "Please choose a valid date & time" : "Молимо вас да изаберете исправни датум и време",
+ "Reminder set for \"{fileName}\"" : "Подсетник је постављен за „{fileName}”",
+ "Failed to set reminder" : "Није успело постављање подсетника",
+ "Reminder cleared for \"{fileName}\"" : "Уклоњен је подсетник за „{fileName}”",
+ "Failed to clear reminder" : "Није успело брисање подсетника",
+ "We will remind you of this file" : "Подсетићемо вас на овај фајл",
+ "Cancel" : "Откажи",
+ "Set reminder" : "Постави подсетник",
+ "Reminder set" : "Подсетник је постављен",
+ "Later today" : "Касније данас",
+ "Set reminder for later today" : "Поставља подсетник за касније данас",
+ "Tomorrow" : "Сутра",
+ "Set reminder for tomorrow" : "Поставља подсетник за сутра",
+ "This weekend" : "Овог викенда",
+ "Set reminder for this weekend" : "Поставља подсетник за овај викенд",
+ "Next week" : "Наредне недеље",
+ "Set reminder for next week" : "Поставља подсетник за наредну недељу",
+ "This files_reminder can work properly." : "Овај files_reminder може да ради како треба.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Да би files_reminder апликација радила како треба, потребна је апликација обавештења. Требало би или да укључите обавештења, или да искључите files_reminder.",
+ "Set reminder at custom date & time" : "Постави подсетник на произвољни датум и време",
+ "Set custom reminder" : "Постави произвољни подсетник"
+},"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/files_reminders/l10n/sv.js b/apps/files_reminders/l10n/sv.js
new file mode 100644
index 00000000000..c23bf99a29e
--- /dev/null
+++ b/apps/files_reminders/l10n/sv.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Filpåminnelser",
+ "Reminder for {name}" : "Påminnelse för {name}",
+ "View file" : "Visa fil",
+ "View folder" : "Visa mapp",
+ "Files reminder" : "Filpåminnelse",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\" appen kan fungera korrekt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen \"files_reminders\" behöver notification appen för att fungera korrekt. Du bör antingen aktivera aviseringar eller inaktivera files_reminder.",
+ "Set file reminders" : "Ställ in filpåminnelser",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Filpåminnelser**\n\nStäll in påminnelser för filer.\n\nObs: För att använda appen `Filpåminnelser` måste du se till att appen `Aviseringar` är installerad och aktiverad. Appen `Aviseringar` tillhandahåller de nödvändiga API:erna för att appen `File reminders` ska fungera korrekt.",
+ "Set reminder for \"{fileName}\"" : "Ställ in påminnelse för \"{fileName}\"",
+ "Clear reminder" : "Rensa påminnelse",
+ "Please choose a valid date & time" : "Välj ett giltigt datum och tid",
+ "Reminder set for \"{fileName}\"" : "Påminnelse inställd för \"{fileName}\"",
+ "Failed to set reminder" : "Kunde inte ställa in påminnelsen",
+ "Reminder cleared for \"{fileName}\"" : "Påminnelse borttagen för \"{fileName}\"",
+ "Failed to clear reminder" : "Kunde inte rensa påminnelsen",
+ "We will remind you of this file" : "Vi kommer att påminna dig om denna fil",
+ "Cancel" : "Avbryt",
+ "Set reminder" : "Ställ in påminnelse",
+ "Reminder set" : "Påminnelse inställd",
+ "Later today" : "Senare idag",
+ "Set reminder for later today" : "Ställ in påminnelse för senare idag",
+ "Tomorrow" : "I morgon",
+ "Set reminder for tomorrow" : "Ställ in påminnelse för imorgon",
+ "This weekend" : "Denna helgen",
+ "Set reminder for this weekend" : "Ställ in påminnelse för denna helg",
+ "Next week" : "Nästa vecka",
+ "Set reminder for next week" : "Ställ in påminnelse för nästa vecka",
+ "This files_reminder can work properly." : "Den här filpåminnelsen kan fungera korrekt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen files_reminder behöver notification appen för att fungera korrekt. Du bör antingen aktivera aviseringar eller inaktivera files_reminder.",
+ "Set reminder at custom date & time" : "Ställ in påminnelse vid anpassat datum och tid",
+ "Set custom reminder" : "Ställ in anpassad påminnelse"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/sv.json b/apps/files_reminders/l10n/sv.json
new file mode 100644
index 00000000000..e4d4859d283
--- /dev/null
+++ b/apps/files_reminders/l10n/sv.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Filpåminnelser",
+ "Reminder for {name}" : "Påminnelse för {name}",
+ "View file" : "Visa fil",
+ "View folder" : "Visa mapp",
+ "Files reminder" : "Filpåminnelse",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\" appen kan fungera korrekt.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen \"files_reminders\" behöver notification appen för att fungera korrekt. Du bör antingen aktivera aviseringar eller inaktivera files_reminder.",
+ "Set file reminders" : "Ställ in filpåminnelser",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Filpåminnelser**\n\nStäll in påminnelser för filer.\n\nObs: För att använda appen `Filpåminnelser` måste du se till att appen `Aviseringar` är installerad och aktiverad. Appen `Aviseringar` tillhandahåller de nödvändiga API:erna för att appen `File reminders` ska fungera korrekt.",
+ "Set reminder for \"{fileName}\"" : "Ställ in påminnelse för \"{fileName}\"",
+ "Clear reminder" : "Rensa påminnelse",
+ "Please choose a valid date & time" : "Välj ett giltigt datum och tid",
+ "Reminder set for \"{fileName}\"" : "Påminnelse inställd för \"{fileName}\"",
+ "Failed to set reminder" : "Kunde inte ställa in påminnelsen",
+ "Reminder cleared for \"{fileName}\"" : "Påminnelse borttagen för \"{fileName}\"",
+ "Failed to clear reminder" : "Kunde inte rensa påminnelsen",
+ "We will remind you of this file" : "Vi kommer att påminna dig om denna fil",
+ "Cancel" : "Avbryt",
+ "Set reminder" : "Ställ in påminnelse",
+ "Reminder set" : "Påminnelse inställd",
+ "Later today" : "Senare idag",
+ "Set reminder for later today" : "Ställ in påminnelse för senare idag",
+ "Tomorrow" : "I morgon",
+ "Set reminder for tomorrow" : "Ställ in påminnelse för imorgon",
+ "This weekend" : "Denna helgen",
+ "Set reminder for this weekend" : "Ställ in påminnelse för denna helg",
+ "Next week" : "Nästa vecka",
+ "Set reminder for next week" : "Ställ in påminnelse för nästa vecka",
+ "This files_reminder can work properly." : "Den här filpåminnelsen kan fungera korrekt.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Appen files_reminder behöver notification appen för att fungera korrekt. Du bör antingen aktivera aviseringar eller inaktivera files_reminder.",
+ "Set reminder at custom date & time" : "Ställ in påminnelse vid anpassat datum och tid",
+ "Set custom reminder" : "Ställ in anpassad påminnelse"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/sw.js b/apps/files_reminders/l10n/sw.js
new file mode 100644
index 00000000000..8601ada818d
--- /dev/null
+++ b/apps/files_reminders/l10n/sw.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Vikumbusho vya faili",
+ "Reminder for {name}" : " Kikumbusho kwa {name}",
+ "View file" : "Tazama faili",
+ "View folder" : "Tazama folda",
+ "Files reminder" : "Kikumbusho cha faili",
+ "The \"files_reminders\" app can work properly." : "Programu ya \"files_reminders\" inaweza kufanya kazi ipasavyo.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Programu ya \"files_reminders\" inahitaji programu ya arifa kufanya kazi ipasavyo. Unapaswa kuwezesha arifa au kuzima kikumbusho cha faili.",
+ "Set file reminders" : "Weka vikumbusho vya faili",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Vikumbusho vya faili**\n\nWeka vikumbusho vya faili.\n\nKumbuka: ili kutumia programu ya `Vikumbusho vya faili`, hakikisha kuwa programu ya `Arifa` imesakinishwa na kuwashwa. Programu ya `Arifa` hutoa API zinazohitajika ili programu ya `Vikumbusho vya Faili` ifanye kazi ipasavyo.",
+ "Set reminder for \"{fileName}\"" : "Weka kikumbusho kwa \"{fileName}\"",
+ "Clear reminder" : "Futa kikumbusho ",
+ "Please choose a valid date & time" : " Tafadhali chagua tarehe na saa halali",
+ "Reminder set for \"{fileName}\"" : " Kikumbusho kimewekwa \"{fileName}\"",
+ "Failed to set reminder" : "Imeshindwa kuweka kikumbusho",
+ "Reminder cleared for \"{fileName}\"" : "Kikumbusho kimefutwa kwa \"{fileName}\"",
+ "Failed to clear reminder" : "Imeshindwa kufuta kikumbusho",
+ "We will remind you of this file" : "Tutakukumbusha kuhusu faili hii",
+ "Cancel" : "Ghairi",
+ "Set reminder" : "Weka ukumbusho",
+ "Reminder set" : " Kikumbusho kimewekwa",
+ "Later today" : "Baadaye leo",
+ "Set reminder for later today" : "Weka kikumbusho cha baadaye leo",
+ "Tomorrow" : "Kesho",
+ "Set reminder for tomorrow" : "Weka kikumbusho cha kesho",
+ "This weekend" : "Wikendi hii",
+ "Set reminder for this weekend" : "Weka kikumbusho cha wikendi hii",
+ "Next week" : "Wiki ijayo",
+ "Set reminder for next week" : " Weka kikumbusho cha wiki ijayo",
+ "This files_reminder can work properly." : " Kikumbusho hiki cha faili kinaweza kufanya kazi vizuri.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Programu ya kikumbusho cha faili inahitaji programu ya arifa kufanya kazi vizuri. Unapaswa kuwezesha arifa au kuzima kikumbusho cha faili",
+ "Set reminder at custom date & time" : "Weka kikumbusho kwa tarehe na saa maalum",
+ "Set custom reminder" : " Weka kikumbusho maalum"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/sw.json b/apps/files_reminders/l10n/sw.json
new file mode 100644
index 00000000000..5312ae5063a
--- /dev/null
+++ b/apps/files_reminders/l10n/sw.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Vikumbusho vya faili",
+ "Reminder for {name}" : " Kikumbusho kwa {name}",
+ "View file" : "Tazama faili",
+ "View folder" : "Tazama folda",
+ "Files reminder" : "Kikumbusho cha faili",
+ "The \"files_reminders\" app can work properly." : "Programu ya \"files_reminders\" inaweza kufanya kazi ipasavyo.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Programu ya \"files_reminders\" inahitaji programu ya arifa kufanya kazi ipasavyo. Unapaswa kuwezesha arifa au kuzima kikumbusho cha faili.",
+ "Set file reminders" : "Weka vikumbusho vya faili",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Vikumbusho vya faili**\n\nWeka vikumbusho vya faili.\n\nKumbuka: ili kutumia programu ya `Vikumbusho vya faili`, hakikisha kuwa programu ya `Arifa` imesakinishwa na kuwashwa. Programu ya `Arifa` hutoa API zinazohitajika ili programu ya `Vikumbusho vya Faili` ifanye kazi ipasavyo.",
+ "Set reminder for \"{fileName}\"" : "Weka kikumbusho kwa \"{fileName}\"",
+ "Clear reminder" : "Futa kikumbusho ",
+ "Please choose a valid date & time" : " Tafadhali chagua tarehe na saa halali",
+ "Reminder set for \"{fileName}\"" : " Kikumbusho kimewekwa \"{fileName}\"",
+ "Failed to set reminder" : "Imeshindwa kuweka kikumbusho",
+ "Reminder cleared for \"{fileName}\"" : "Kikumbusho kimefutwa kwa \"{fileName}\"",
+ "Failed to clear reminder" : "Imeshindwa kufuta kikumbusho",
+ "We will remind you of this file" : "Tutakukumbusha kuhusu faili hii",
+ "Cancel" : "Ghairi",
+ "Set reminder" : "Weka ukumbusho",
+ "Reminder set" : " Kikumbusho kimewekwa",
+ "Later today" : "Baadaye leo",
+ "Set reminder for later today" : "Weka kikumbusho cha baadaye leo",
+ "Tomorrow" : "Kesho",
+ "Set reminder for tomorrow" : "Weka kikumbusho cha kesho",
+ "This weekend" : "Wikendi hii",
+ "Set reminder for this weekend" : "Weka kikumbusho cha wikendi hii",
+ "Next week" : "Wiki ijayo",
+ "Set reminder for next week" : " Weka kikumbusho cha wiki ijayo",
+ "This files_reminder can work properly." : " Kikumbusho hiki cha faili kinaweza kufanya kazi vizuri.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Programu ya kikumbusho cha faili inahitaji programu ya arifa kufanya kazi vizuri. Unapaswa kuwezesha arifa au kuzima kikumbusho cha faili",
+ "Set reminder at custom date & time" : "Weka kikumbusho kwa tarehe na saa maalum",
+ "Set custom reminder" : " Weka kikumbusho maalum"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/tr.js b/apps/files_reminders/l10n/tr.js
new file mode 100644
index 00000000000..f505359fcc6
--- /dev/null
+++ b/apps/files_reminders/l10n/tr.js
@@ -0,0 +1,37 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Dosya anımsatıcıları",
+ "Reminder for {name}" : "{name} anımsatıcısı",
+ "View file" : "Dosyayı görüntüle",
+ "View folder" : "Klasörü görüntüle",
+ "Files reminder" : "Dosyalar anımsatıcısı",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\" uygulaması düzgün çalışabilir.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "\"files_reminders\" uygulamasının düzgün çalışması için Bildirimler uygulaması gereklidir. Bildirimler uygulamasını kullanıma alın ya da files_reminder uygulamasını kullanımdan kaldırın.",
+ "Set file reminders" : "Dosya anımsatıcıları ayarla",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dosya anımsatıcıları**\n\nDosya anımsatıcıları ayarlayın.\n\nNot: `Dosya anımsatıcıları` uygulamasını kullanmak için `Bildirimler` uygulamasının kurulmuş ve etkinleştirilmiş olduğundan emin olun. `Bildirimler` uygulaması `Dosya anımsatıcıları` uygulamasının doğru çalışması için gerekli API uygulamalarını sağlar.",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\" için anımsatıcı ayarla",
+ "Clear reminder" : "Anımsatıcıyı temizle",
+ "Please choose a valid date & time" : "Lütfen geçerli bir tarih ve saat seçin",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\" için anımsatıcı ayarlandı",
+ "Failed to set reminder" : "Anımsatıcı ayarlanamadı",
+ "Reminder cleared for \"{fileName}\"" : "\"{fileName}\" anımsatıcısı kaldırıldı",
+ "Failed to clear reminder" : "Anımsatıcı temizlenemedi",
+ "We will remind you of this file" : "Size bu dosyayı anımsatacağız",
+ "Cancel" : "İptal",
+ "Set reminder" : "Anımsatıcı ayarla",
+ "Reminder set" : "Anımsatıcı ayarlandı",
+ "Later today" : "Bugün daha sonra",
+ "Set reminder for later today" : "Bugün daha sonrası için anımsatıcı ayarla",
+ "Tomorrow" : "Yarın",
+ "Set reminder for tomorrow" : "Yarın için anımsatıcı ayarla",
+ "This weekend" : "Bu hafta sonu",
+ "Set reminder for this weekend" : "Bu hafta sonu için anımsatıcı ayarla",
+ "Next week" : "Sonraki hafta",
+ "Set reminder for next week" : "Gelecek hafta için anımsatıcı ayarla",
+ "This files_reminder can work properly." : "Bu files_reminder düzgün çalışabilir.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminders uygulamasının düzgün çalışması için Bildirimler uygulaması gereklidir. Bildirimler uygulamasını kullanıma alın ya da files_reminder uygulamasını kullanımdan kaldırın.",
+ "Set reminder at custom date & time" : "Özel bir tarih ve saat için anımsatıcı ayarla",
+ "Set custom reminder" : "Özel anımsatıcı ayarla"
+},
+"nplurals=2; plural=(n > 1);");
diff --git a/apps/files_reminders/l10n/tr.json b/apps/files_reminders/l10n/tr.json
new file mode 100644
index 00000000000..86fa6b31e0c
--- /dev/null
+++ b/apps/files_reminders/l10n/tr.json
@@ -0,0 +1,35 @@
+{ "translations": {
+ "File reminders" : "Dosya anımsatıcıları",
+ "Reminder for {name}" : "{name} anımsatıcısı",
+ "View file" : "Dosyayı görüntüle",
+ "View folder" : "Klasörü görüntüle",
+ "Files reminder" : "Dosyalar anımsatıcısı",
+ "The \"files_reminders\" app can work properly." : "\"files_reminders\" uygulaması düzgün çalışabilir.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "\"files_reminders\" uygulamasının düzgün çalışması için Bildirimler uygulaması gereklidir. Bildirimler uygulamasını kullanıma alın ya da files_reminder uygulamasını kullanımdan kaldırın.",
+ "Set file reminders" : "Dosya anımsatıcıları ayarla",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Dosya anımsatıcıları**\n\nDosya anımsatıcıları ayarlayın.\n\nNot: `Dosya anımsatıcıları` uygulamasını kullanmak için `Bildirimler` uygulamasının kurulmuş ve etkinleştirilmiş olduğundan emin olun. `Bildirimler` uygulaması `Dosya anımsatıcıları` uygulamasının doğru çalışması için gerekli API uygulamalarını sağlar.",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\" için anımsatıcı ayarla",
+ "Clear reminder" : "Anımsatıcıyı temizle",
+ "Please choose a valid date & time" : "Lütfen geçerli bir tarih ve saat seçin",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\" için anımsatıcı ayarlandı",
+ "Failed to set reminder" : "Anımsatıcı ayarlanamadı",
+ "Reminder cleared for \"{fileName}\"" : "\"{fileName}\" anımsatıcısı kaldırıldı",
+ "Failed to clear reminder" : "Anımsatıcı temizlenemedi",
+ "We will remind you of this file" : "Size bu dosyayı anımsatacağız",
+ "Cancel" : "İptal",
+ "Set reminder" : "Anımsatıcı ayarla",
+ "Reminder set" : "Anımsatıcı ayarlandı",
+ "Later today" : "Bugün daha sonra",
+ "Set reminder for later today" : "Bugün daha sonrası için anımsatıcı ayarla",
+ "Tomorrow" : "Yarın",
+ "Set reminder for tomorrow" : "Yarın için anımsatıcı ayarla",
+ "This weekend" : "Bu hafta sonu",
+ "Set reminder for this weekend" : "Bu hafta sonu için anımsatıcı ayarla",
+ "Next week" : "Sonraki hafta",
+ "Set reminder for next week" : "Gelecek hafta için anımsatıcı ayarla",
+ "This files_reminder can work properly." : "Bu files_reminder düzgün çalışabilir.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminders uygulamasının düzgün çalışması için Bildirimler uygulaması gereklidir. Bildirimler uygulamasını kullanıma alın ya da files_reminder uygulamasını kullanımdan kaldırın.",
+ "Set reminder at custom date & time" : "Özel bir tarih ve saat için anımsatıcı ayarla",
+ "Set custom reminder" : "Özel anımsatıcı ayarla"
+},"pluralForm" :"nplurals=2; plural=(n > 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/ug.js b/apps/files_reminders/l10n/ug.js
new file mode 100644
index 00000000000..f8a92883605
--- /dev/null
+++ b/apps/files_reminders/l10n/ug.js
@@ -0,0 +1,31 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "ھۆججەت ئەسكەرتىشلىرى",
+ "Reminder for {name}" : "{name} for ئەسكەرتىش",
+ "View file" : "ھۆججەتنى كۆرۈش",
+ "View folder" : "ھۆججەت قىسقۇچنى كۆرۈش",
+ "Set file reminders" : "ھۆججەت ئەسكەرتىشلىرىنى بەلگىلەڭ",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\" ئۈچۈن ئەسكەرتىش بەلگىلەڭ",
+ "Clear reminder" : "ئەسكەرتىش",
+ "Please choose a valid date & time" : "ئىناۋەتلىك چېسلا ۋە ۋاقىتنى تاللاڭ",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\" ئۈچۈن ئەسكەرتىش",
+ "Failed to set reminder" : "ئەسكەرتىش بەلگىلەش مەغلۇب بولدى",
+ "Reminder cleared for \"{fileName}\"" : "ئەسكەرتىش \"{fileName}\" ئۈچۈن تازىلاندى",
+ "Failed to clear reminder" : "ئەسكەرتىشنى تازىلاش مەغلۇب بولدى",
+ "We will remind you of this file" : "بۇ ھۆججەتنى ئەسكەرتىمىز",
+ "Cancel" : "بىكار قىلىش",
+ "Set reminder" : "ئەسكەرتىش بەلگىلەڭ",
+ "Reminder set" : "ئەسكەرتىش",
+ "Later today" : "بۈگۈن بۈگۈن",
+ "Set reminder for later today" : "بۈگۈنگە ئەسكەرتىش بەلگىلەڭ",
+ "Tomorrow" : "ئەتە",
+ "Set reminder for tomorrow" : "ئەتە ئۈچۈن ئەسكەرتىش بەلگىلەڭ",
+ "This weekend" : "بۇ ھەپتە ئاخىرى",
+ "Set reminder for this weekend" : "بۇ ھەپتە ئاخىرىدا ئەسكەرتىش بەلگىلەڭ",
+ "Next week" : "كېلەر ھەپتە",
+ "Set reminder for next week" : "كېلەر ھەپتە ئەسكەرتىش بەلگىلەڭ",
+ "Set reminder at custom date & time" : "ئىختىيارى چېسلا ۋە ۋاقىتتا ئەسكەرتىش بەلگىلەڭ",
+ "Set custom reminder" : "ئىختىيارى ئەسكەرتىش بەلگىلەڭ"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/files_reminders/l10n/ug.json b/apps/files_reminders/l10n/ug.json
new file mode 100644
index 00000000000..a5c8e9f7553
--- /dev/null
+++ b/apps/files_reminders/l10n/ug.json
@@ -0,0 +1,29 @@
+{ "translations": {
+ "File reminders" : "ھۆججەت ئەسكەرتىشلىرى",
+ "Reminder for {name}" : "{name} for ئەسكەرتىش",
+ "View file" : "ھۆججەتنى كۆرۈش",
+ "View folder" : "ھۆججەت قىسقۇچنى كۆرۈش",
+ "Set file reminders" : "ھۆججەت ئەسكەرتىشلىرىنى بەلگىلەڭ",
+ "Set reminder for \"{fileName}\"" : "\"{fileName}\" ئۈچۈن ئەسكەرتىش بەلگىلەڭ",
+ "Clear reminder" : "ئەسكەرتىش",
+ "Please choose a valid date & time" : "ئىناۋەتلىك چېسلا ۋە ۋاقىتنى تاللاڭ",
+ "Reminder set for \"{fileName}\"" : "\"{fileName}\" ئۈچۈن ئەسكەرتىش",
+ "Failed to set reminder" : "ئەسكەرتىش بەلگىلەش مەغلۇب بولدى",
+ "Reminder cleared for \"{fileName}\"" : "ئەسكەرتىش \"{fileName}\" ئۈچۈن تازىلاندى",
+ "Failed to clear reminder" : "ئەسكەرتىشنى تازىلاش مەغلۇب بولدى",
+ "We will remind you of this file" : "بۇ ھۆججەتنى ئەسكەرتىمىز",
+ "Cancel" : "بىكار قىلىش",
+ "Set reminder" : "ئەسكەرتىش بەلگىلەڭ",
+ "Reminder set" : "ئەسكەرتىش",
+ "Later today" : "بۈگۈن بۈگۈن",
+ "Set reminder for later today" : "بۈگۈنگە ئەسكەرتىش بەلگىلەڭ",
+ "Tomorrow" : "ئەتە",
+ "Set reminder for tomorrow" : "ئەتە ئۈچۈن ئەسكەرتىش بەلگىلەڭ",
+ "This weekend" : "بۇ ھەپتە ئاخىرى",
+ "Set reminder for this weekend" : "بۇ ھەپتە ئاخىرىدا ئەسكەرتىش بەلگىلەڭ",
+ "Next week" : "كېلەر ھەپتە",
+ "Set reminder for next week" : "كېلەر ھەپتە ئەسكەرتىش بەلگىلەڭ",
+ "Set reminder at custom date & time" : "ئىختىيارى چېسلا ۋە ۋاقىتتا ئەسكەرتىش بەلگىلەڭ",
+ "Set custom reminder" : "ئىختىيارى ئەسكەرتىش بەلگىلەڭ"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/uk.js b/apps/files_reminders/l10n/uk.js
new file mode 100644
index 00000000000..c66399959d3
--- /dev/null
+++ b/apps/files_reminders/l10n/uk.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "Нагадування для файлів",
+ "Reminder for {name}" : "Нагадування для {name}",
+ "View file" : "Переглянути файл",
+ "View folder" : "Переглянути каталог",
+ "Files reminder" : "Нагадування для файлів",
+ "The \"files_reminders\" app can work properly." : "Додаток «files_reminders» може працювати належним чином.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Для нормальної роботи програми «files_reminders» необхідна програма сповіщень. Вам слід або увімкнути сповіщення, або вимкнути files_reminder.",
+ "Set file reminders" : "Встановити нагадування для файлу",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Нагадування про файли**\n\nВстановіть нагадування про файли.\n\nПримітка: щоб використовувати додаток «Нагадування про файли», переконайтеся, що додаток «Повідомлення» встановлено та увімкнено. Додаток «Повідомлення» надає необхідні API для коректної роботи додатка «Нагадування про файли».",
+ "Set reminder for \"{fileName}\"" : "Встановити нагадування для \"{fileName}\"",
+ "Reminder at custom date & time" : "Нагадування в задану дату та час",
+ "Clear reminder" : "Зняти нагадування",
+ "Please choose a valid date & time" : "Виберіть дійсні дату та час",
+ "Reminder set for \"{fileName}\"" : "Встановлено нагадування для \"{fileName}\"",
+ "Failed to set reminder" : "Не вдалося встановити нагадування",
+ "Reminder cleared for \"{fileName}\"" : "Нагадування очищено для \"{fileName}\"",
+ "Failed to clear reminder" : "Не вдалося зняти нагадування",
+ "We will remind you of this file" : "Ми нагадаємо вам про цей файл.",
+ "Cancel" : "Скасувати",
+ "Set reminder" : "Встановити нагадування",
+ "Reminder set" : "Нагадування встановлено",
+ "Custom reminder" : "Індивідуальне нагадування",
+ "Later today" : "Пізніше сьогодні",
+ "Set reminder for later today" : "Встановити нагадування на сьогодні пізніше",
+ "Tomorrow" : "Завтра",
+ "Set reminder for tomorrow" : "Встановити нагадування на завтра",
+ "This weekend" : "Цими вихідними",
+ "Set reminder for this weekend" : "Встановити нагадування на ці вихідні",
+ "Next week" : "Наступний тиждень",
+ "Set reminder for next week" : "Встановити нагадування на наступний тиждень",
+ "This files_reminder can work properly." : "Цей files_reminder може працювати належним чином.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Для нормальної роботи програми files_reminder необхідна програма сповіщень. Вам слід або увімкнути сповіщення, або вимкнути files_reminder.",
+ "Set reminder at custom date & time" : "Встановити нагадування на власну дату та час",
+ "Set custom reminder" : "Встановити власне нагадування"
+},
+"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/files_reminders/l10n/uk.json b/apps/files_reminders/l10n/uk.json
new file mode 100644
index 00000000000..d29c14318da
--- /dev/null
+++ b/apps/files_reminders/l10n/uk.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "Нагадування для файлів",
+ "Reminder for {name}" : "Нагадування для {name}",
+ "View file" : "Переглянути файл",
+ "View folder" : "Переглянути каталог",
+ "Files reminder" : "Нагадування для файлів",
+ "The \"files_reminders\" app can work properly." : "Додаток «files_reminders» може працювати належним чином.",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Для нормальної роботи програми «files_reminders» необхідна програма сповіщень. Вам слід або увімкнути сповіщення, або вимкнути files_reminder.",
+ "Set file reminders" : "Встановити нагадування для файлу",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 Нагадування про файли**\n\nВстановіть нагадування про файли.\n\nПримітка: щоб використовувати додаток «Нагадування про файли», переконайтеся, що додаток «Повідомлення» встановлено та увімкнено. Додаток «Повідомлення» надає необхідні API для коректної роботи додатка «Нагадування про файли».",
+ "Set reminder for \"{fileName}\"" : "Встановити нагадування для \"{fileName}\"",
+ "Reminder at custom date & time" : "Нагадування в задану дату та час",
+ "Clear reminder" : "Зняти нагадування",
+ "Please choose a valid date & time" : "Виберіть дійсні дату та час",
+ "Reminder set for \"{fileName}\"" : "Встановлено нагадування для \"{fileName}\"",
+ "Failed to set reminder" : "Не вдалося встановити нагадування",
+ "Reminder cleared for \"{fileName}\"" : "Нагадування очищено для \"{fileName}\"",
+ "Failed to clear reminder" : "Не вдалося зняти нагадування",
+ "We will remind you of this file" : "Ми нагадаємо вам про цей файл.",
+ "Cancel" : "Скасувати",
+ "Set reminder" : "Встановити нагадування",
+ "Reminder set" : "Нагадування встановлено",
+ "Custom reminder" : "Індивідуальне нагадування",
+ "Later today" : "Пізніше сьогодні",
+ "Set reminder for later today" : "Встановити нагадування на сьогодні пізніше",
+ "Tomorrow" : "Завтра",
+ "Set reminder for tomorrow" : "Встановити нагадування на завтра",
+ "This weekend" : "Цими вихідними",
+ "Set reminder for this weekend" : "Встановити нагадування на ці вихідні",
+ "Next week" : "Наступний тиждень",
+ "Set reminder for next week" : "Встановити нагадування на наступний тиждень",
+ "This files_reminder can work properly." : "Цей files_reminder може працювати належним чином.",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "Для нормальної роботи програми files_reminder необхідна програма сповіщень. Вам слід або увімкнути сповіщення, або вимкнути files_reminder.",
+ "Set reminder at custom date & time" : "Встановити нагадування на власну дату та час",
+ "Set custom reminder" : "Встановити власне нагадування"
+},"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/files_reminders/l10n/zh_CN.js b/apps/files_reminders/l10n/zh_CN.js
new file mode 100644
index 00000000000..23c85d62838
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_CN.js
@@ -0,0 +1,31 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "文件提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "查看文件",
+ "View folder" : "查看文件夹",
+ "Set file reminders" : "设置文件提醒",
+ "Set reminder for \"{fileName}\"" : "设置文件 “{fileName}” 的提醒",
+ "Clear reminder" : "移除提醒",
+ "Please choose a valid date & time" : "请选择一个有效的日期&时间",
+ "Reminder set for \"{fileName}\"" : "文件 “{fileName}” 的提醒设置",
+ "Failed to set reminder" : "无法设置提醒",
+ "Reminder cleared for \"{fileName}\"" : "清除文件 “{fileName}” 的提醒",
+ "Failed to clear reminder" : "无法清除文件提醒",
+ "We will remind you of this file" : "我们将会提醒你该文件",
+ "Cancel" : "取消",
+ "Set reminder" : "设置提醒",
+ "Reminder set" : "提醒设置",
+ "Later today" : "今日稍晚",
+ "Set reminder for later today" : "今日稍晚提醒",
+ "Tomorrow" : "明天",
+ "Set reminder for tomorrow" : "明天提醒",
+ "This weekend" : "本周末",
+ "Set reminder for this weekend" : "本周末提醒",
+ "Next week" : "下周",
+ "Set reminder for next week" : "下周提醒",
+ "Set reminder at custom date & time" : "设置自定义日期&时间提醒",
+ "Set custom reminder" : "设置自定义提醒"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/files_reminders/l10n/zh_CN.json b/apps/files_reminders/l10n/zh_CN.json
new file mode 100644
index 00000000000..f3937525140
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_CN.json
@@ -0,0 +1,29 @@
+{ "translations": {
+ "File reminders" : "文件提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "查看文件",
+ "View folder" : "查看文件夹",
+ "Set file reminders" : "设置文件提醒",
+ "Set reminder for \"{fileName}\"" : "设置文件 “{fileName}” 的提醒",
+ "Clear reminder" : "移除提醒",
+ "Please choose a valid date & time" : "请选择一个有效的日期&时间",
+ "Reminder set for \"{fileName}\"" : "文件 “{fileName}” 的提醒设置",
+ "Failed to set reminder" : "无法设置提醒",
+ "Reminder cleared for \"{fileName}\"" : "清除文件 “{fileName}” 的提醒",
+ "Failed to clear reminder" : "无法清除文件提醒",
+ "We will remind you of this file" : "我们将会提醒你该文件",
+ "Cancel" : "取消",
+ "Set reminder" : "设置提醒",
+ "Reminder set" : "提醒设置",
+ "Later today" : "今日稍晚",
+ "Set reminder for later today" : "今日稍晚提醒",
+ "Tomorrow" : "明天",
+ "Set reminder for tomorrow" : "明天提醒",
+ "This weekend" : "本周末",
+ "Set reminder for this weekend" : "本周末提醒",
+ "Next week" : "下周",
+ "Set reminder for next week" : "下周提醒",
+ "Set reminder at custom date & time" : "设置自定义日期&时间提醒",
+ "Set custom reminder" : "设置自定义提醒"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/zh_HK.js b/apps/files_reminders/l10n/zh_HK.js
new file mode 100644
index 00000000000..c72fb6cde89
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_HK.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "檔案提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "檢視檔案",
+ "View folder" : "檢視資料夾",
+ "Files reminder" : "檔案提醒",
+ "The \"files_reminders\" app can work properly." : "「files_reminders」應用程式可以正常運作。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "「files_reminder」應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set file reminders" : "設定檔案提醒",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 檔案提醒**\n\n設定檔案提醒。\n\n注意:要使用「檔案提醒」應用程式,請確定已安裝並啟用「通知」應用程式。「通知」應用程式提供必要的 API,讓「檔案提醒」應用程式能正常運作。",
+ "Set reminder for \"{fileName}\"" : "設定「{fileName}」的提醒",
+ "Reminder at custom date & time" : "自訂日期與時間的提醒",
+ "Clear reminder" : "清除提醒",
+ "Please choose a valid date & time" : "請選擇有效的日期與時間",
+ "Reminder set for \"{fileName}\"" : "「{fileName}」的提醒設定",
+ "Failed to set reminder" : "設定提醒失敗",
+ "Reminder cleared for \"{fileName}\"" : "已清除「{fileName}」的提醒",
+ "Failed to clear reminder" : "清除提醒失敗",
+ "We will remind you of this file" : "我們會提醒您該檔案",
+ "Cancel" : "取消",
+ "Set reminder" : "設定提醒",
+ "Reminder set" : "提醒設定",
+ "Custom reminder" : "自訂提醒",
+ "Later today" : "今日稍後",
+ "Set reminder for later today" : "設定今天稍後的提醒",
+ "Tomorrow" : "明日",
+ "Set reminder for tomorrow" : "設定明天的提醒",
+ "This weekend" : "本週末",
+ "Set reminder for this weekend" : "設定本週末的提醒",
+ "Next week" : "下星期",
+ "Set reminder for next week" : "設定下星期的提醒",
+ "This files_reminder can work properly." : "此 files_reminder 可以正常運作。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminder 應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set reminder at custom date & time" : "設定自訂日期與時間的提醒",
+ "Set custom reminder" : "設定自訂提醒"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/files_reminders/l10n/zh_HK.json b/apps/files_reminders/l10n/zh_HK.json
new file mode 100644
index 00000000000..339e0cd8cf7
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_HK.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "檔案提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "檢視檔案",
+ "View folder" : "檢視資料夾",
+ "Files reminder" : "檔案提醒",
+ "The \"files_reminders\" app can work properly." : "「files_reminders」應用程式可以正常運作。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "「files_reminder」應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set file reminders" : "設定檔案提醒",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 檔案提醒**\n\n設定檔案提醒。\n\n注意:要使用「檔案提醒」應用程式,請確定已安裝並啟用「通知」應用程式。「通知」應用程式提供必要的 API,讓「檔案提醒」應用程式能正常運作。",
+ "Set reminder for \"{fileName}\"" : "設定「{fileName}」的提醒",
+ "Reminder at custom date & time" : "自訂日期與時間的提醒",
+ "Clear reminder" : "清除提醒",
+ "Please choose a valid date & time" : "請選擇有效的日期與時間",
+ "Reminder set for \"{fileName}\"" : "「{fileName}」的提醒設定",
+ "Failed to set reminder" : "設定提醒失敗",
+ "Reminder cleared for \"{fileName}\"" : "已清除「{fileName}」的提醒",
+ "Failed to clear reminder" : "清除提醒失敗",
+ "We will remind you of this file" : "我們會提醒您該檔案",
+ "Cancel" : "取消",
+ "Set reminder" : "設定提醒",
+ "Reminder set" : "提醒設定",
+ "Custom reminder" : "自訂提醒",
+ "Later today" : "今日稍後",
+ "Set reminder for later today" : "設定今天稍後的提醒",
+ "Tomorrow" : "明日",
+ "Set reminder for tomorrow" : "設定明天的提醒",
+ "This weekend" : "本週末",
+ "Set reminder for this weekend" : "設定本週末的提醒",
+ "Next week" : "下星期",
+ "Set reminder for next week" : "設定下星期的提醒",
+ "This files_reminder can work properly." : "此 files_reminder 可以正常運作。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminder 應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set reminder at custom date & time" : "設定自訂日期與時間的提醒",
+ "Set custom reminder" : "設定自訂提醒"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/l10n/zh_TW.js b/apps/files_reminders/l10n/zh_TW.js
new file mode 100644
index 00000000000..c19c4a803a2
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_TW.js
@@ -0,0 +1,39 @@
+OC.L10N.register(
+ "files_reminders",
+ {
+ "File reminders" : "檔案提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "檢視檔案",
+ "View folder" : "檢視資料夾",
+ "Files reminder" : "檔案提醒",
+ "The \"files_reminders\" app can work properly." : "「files_reminders」應用程式可以正常運作。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "「files_reminder」應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set file reminders" : "設定檔案提醒",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 檔案提醒**\n\n設定檔案提醒。\n\n注意:要使用「檔案提醒」應用程式,請確定已安裝並啟用「通知」應用程式。「通知」應用程式提供必要的 API,讓「檔案提醒」應用程式能正常運作。",
+ "Set reminder for \"{fileName}\"" : "設定「{fileName}」的提醒",
+ "Reminder at custom date & time" : "自訂日期與時間的提醒",
+ "Clear reminder" : "清除提醒",
+ "Please choose a valid date & time" : "請選擇有效的日期與時間",
+ "Reminder set for \"{fileName}\"" : "「{fileName}」的提醒設定",
+ "Failed to set reminder" : "設定提醒失敗",
+ "Reminder cleared for \"{fileName}\"" : "已清除「{fileName}」的提醒",
+ "Failed to clear reminder" : "清除提醒失敗",
+ "We will remind you of this file" : "我們會提醒您該檔案",
+ "Cancel" : "取消",
+ "Set reminder" : "設定提醒",
+ "Reminder set" : "提醒設定",
+ "Custom reminder" : "自訂提醒",
+ "Later today" : "今天稍後",
+ "Set reminder for later today" : "設定今天稍後的提醒",
+ "Tomorrow" : "明天",
+ "Set reminder for tomorrow" : "設定明天的提醒",
+ "This weekend" : "本週末",
+ "Set reminder for this weekend" : "設定本週末的提醒",
+ "Next week" : "下週",
+ "Set reminder for next week" : "設定下週的提醒",
+ "This files_reminder can work properly." : "此 files_reminder 可以正常運作。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminder 應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set reminder at custom date & time" : "設定自訂日期與時間的提醒",
+ "Set custom reminder" : "設定自訂提醒"
+},
+"nplurals=1; plural=0;");
diff --git a/apps/files_reminders/l10n/zh_TW.json b/apps/files_reminders/l10n/zh_TW.json
new file mode 100644
index 00000000000..5035fc1d66b
--- /dev/null
+++ b/apps/files_reminders/l10n/zh_TW.json
@@ -0,0 +1,37 @@
+{ "translations": {
+ "File reminders" : "檔案提醒",
+ "Reminder for {name}" : "{name} 的提醒",
+ "View file" : "檢視檔案",
+ "View folder" : "檢視資料夾",
+ "Files reminder" : "檔案提醒",
+ "The \"files_reminders\" app can work properly." : "「files_reminders」應用程式可以正常運作。",
+ "The \"files_reminders\" app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "「files_reminder」應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set file reminders" : "設定檔案提醒",
+ "**📣 File reminders**\n\nSet file reminders.\n\nNote: to use the `File reminders` app, ensure that the `Notifications` app is installed and enabled. The `Notifications` app provides the necessary APIs for the `File reminders` app to work correctly." : "**📣 檔案提醒**\n\n設定檔案提醒。\n\n注意:要使用「檔案提醒」應用程式,請確定已安裝並啟用「通知」應用程式。「通知」應用程式提供必要的 API,讓「檔案提醒」應用程式能正常運作。",
+ "Set reminder for \"{fileName}\"" : "設定「{fileName}」的提醒",
+ "Reminder at custom date & time" : "自訂日期與時間的提醒",
+ "Clear reminder" : "清除提醒",
+ "Please choose a valid date & time" : "請選擇有效的日期與時間",
+ "Reminder set for \"{fileName}\"" : "「{fileName}」的提醒設定",
+ "Failed to set reminder" : "設定提醒失敗",
+ "Reminder cleared for \"{fileName}\"" : "已清除「{fileName}」的提醒",
+ "Failed to clear reminder" : "清除提醒失敗",
+ "We will remind you of this file" : "我們會提醒您該檔案",
+ "Cancel" : "取消",
+ "Set reminder" : "設定提醒",
+ "Reminder set" : "提醒設定",
+ "Custom reminder" : "自訂提醒",
+ "Later today" : "今天稍後",
+ "Set reminder for later today" : "設定今天稍後的提醒",
+ "Tomorrow" : "明天",
+ "Set reminder for tomorrow" : "設定明天的提醒",
+ "This weekend" : "本週末",
+ "Set reminder for this weekend" : "設定本週末的提醒",
+ "Next week" : "下週",
+ "Set reminder for next week" : "設定下週的提醒",
+ "This files_reminder can work properly." : "此 files_reminder 可以正常運作。",
+ "The files_reminder app needs the notification app to work properly. You should either enable notifications or disable files_reminder." : "files_reminder 應用程式需要通知應用程式才能正常運作。您應該啟用通知或停用 files_reminder。",
+ "Set reminder at custom date & time" : "設定自訂日期與時間的提醒",
+ "Set custom reminder" : "設定自訂提醒"
+},"pluralForm" :"nplurals=1; plural=0;"
+} \ No newline at end of file
diff --git a/apps/files_reminders/lib/AppInfo/Application.php b/apps/files_reminders/lib/AppInfo/Application.php
new file mode 100644
index 00000000000..2776e9db0b1
--- /dev/null
+++ b/apps/files_reminders/lib/AppInfo/Application.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\AppInfo;
+
+use OCA\DAV\Events\SabrePluginAddEvent;
+use OCA\Files\Event\LoadAdditionalScriptsEvent;
+use OCA\FilesReminders\Listener\LoadAdditionalScriptsListener;
+use OCA\FilesReminders\Listener\NodeDeletedListener;
+use OCA\FilesReminders\Listener\SabrePluginAddListener;
+use OCA\FilesReminders\Listener\UserDeletedListener;
+use OCA\FilesReminders\Notification\Notifier;
+use OCA\FilesReminders\SetupChecks\NeedNotificationsApp;
+use OCP\AppFramework\App;
+use OCP\AppFramework\Bootstrap\IBootContext;
+use OCP\AppFramework\Bootstrap\IBootstrap;
+use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\Files\Events\Node\NodeDeletedEvent;
+use OCP\User\Events\UserDeletedEvent;
+
+class Application extends App implements IBootstrap {
+ public const APP_ID = 'files_reminders';
+
+ public function __construct() {
+ parent::__construct(static::APP_ID);
+ }
+
+ public function boot(IBootContext $context): void {
+ }
+
+ public function register(IRegistrationContext $context): void {
+ $context->registerNotifierService(Notifier::class);
+
+ $context->registerEventListener(SabrePluginAddEvent::class, SabrePluginAddListener::class);
+
+ $context->registerEventListener(NodeDeletedEvent::class, NodeDeletedListener::class);
+ $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
+
+ $context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalScriptsListener::class);
+
+ $context->registerSetupCheck(NeedNotificationsApp::class);
+ }
+}
diff --git a/apps/files_reminders/lib/BackgroundJob/CleanUpReminders.php b/apps/files_reminders/lib/BackgroundJob/CleanUpReminders.php
new file mode 100644
index 00000000000..35b72b190e8
--- /dev/null
+++ b/apps/files_reminders/lib/BackgroundJob/CleanUpReminders.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\BackgroundJob;
+
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+
+class CleanUpReminders extends TimedJob {
+ public function __construct(
+ ITimeFactory $time,
+ private ReminderService $reminderService,
+ ) {
+ parent::__construct($time);
+
+ $this->setInterval(24 * 60 * 60); // 1 day
+ $this->setTimeSensitivity(self::TIME_INSENSITIVE);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ protected function run($argument) {
+ $this->reminderService->cleanUp(500);
+ }
+}
diff --git a/apps/files_reminders/lib/BackgroundJob/ScheduledNotifications.php b/apps/files_reminders/lib/BackgroundJob/ScheduledNotifications.php
new file mode 100644
index 00000000000..ab8c762d674
--- /dev/null
+++ b/apps/files_reminders/lib/BackgroundJob/ScheduledNotifications.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\FilesReminders\BackgroundJob;
+
+use OCA\FilesReminders\Db\ReminderMapper;
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+use Psr\Log\LoggerInterface;
+
+class ScheduledNotifications extends TimedJob {
+ public function __construct(
+ ITimeFactory $time,
+ protected ReminderMapper $reminderMapper,
+ protected ReminderService $reminderService,
+ protected LoggerInterface $logger,
+ ) {
+ parent::__construct($time);
+
+ $this->setInterval(60);
+ }
+
+ /**
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function run($argument) {
+ $reminders = $this->reminderMapper->findOverdue();
+ foreach ($reminders as $reminder) {
+ try {
+ $this->reminderService->send($reminder);
+ } catch (DoesNotExistException $e) {
+ $this->logger->debug('Could not send notification for reminder with id ' . $reminder->getId());
+ }
+ }
+ }
+}
diff --git a/apps/files_reminders/lib/Command/ListCommand.php b/apps/files_reminders/lib/Command/ListCommand.php
new file mode 100644
index 00000000000..118d00c45d3
--- /dev/null
+++ b/apps/files_reminders/lib/Command/ListCommand.php
@@ -0,0 +1,102 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Command;
+
+use DateTimeInterface;
+use OC\Core\Command\Base;
+use OCA\FilesReminders\Model\RichReminder;
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class ListCommand extends Base {
+ public function __construct(
+ private ReminderService $reminderService,
+ private IUserManager $userManager,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('files:reminders')
+ ->setDescription('List file reminders')
+ ->addArgument(
+ 'user',
+ InputArgument::OPTIONAL,
+ 'list reminders for user',
+ )
+ ->addOption(
+ 'output',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'Output format (plain, json or json_pretty, default is plain)',
+ $this->defaultOutputFormat,
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $io = new SymfonyStyle($input, $output);
+
+ $uid = $input->getArgument('user');
+ if ($uid !== null) {
+ /** @var string $uid */
+ $user = $this->userManager->get($uid);
+ if ($user === null) {
+ $io->error("Unknown user <$uid>");
+ return 1;
+ }
+ }
+
+ $reminders = $this->reminderService->getAll($user ?? null);
+
+ $outputOption = $input->getOption('output');
+ switch ($outputOption) {
+ case static::OUTPUT_FORMAT_JSON:
+ case static::OUTPUT_FORMAT_JSON_PRETTY:
+ $this->writeArrayInOutputFormat(
+ $input,
+ $io,
+ array_map(
+ fn (RichReminder $reminder) => $reminder->jsonSerialize(),
+ $reminders,
+ ),
+ '',
+ );
+ return 0;
+ default:
+ if (empty($reminders)) {
+ $io->text('No reminders');
+ return 0;
+ }
+
+ $io->table(
+ ['User Id', 'File Id', 'Path', 'Due Date', 'Updated At', 'Created At', 'Notified'],
+ array_map(
+ fn (RichReminder $reminder) => [
+ $reminder->getUserId(),
+ $reminder->getFileId(),
+ $reminder->getNode()->getPath(),
+ $reminder->getDueDate()->format(DateTimeInterface::ATOM), // ISO 8601
+ $reminder->getUpdatedAt()->format(DateTimeInterface::ATOM), // ISO 8601
+ $reminder->getCreatedAt()->format(DateTimeInterface::ATOM), // ISO 8601
+ $reminder->getNotified() ? 'true' : 'false',
+ ],
+ $reminders,
+ ),
+ );
+ return 0;
+ }
+ }
+}
diff --git a/apps/files_reminders/lib/Controller/ApiController.php b/apps/files_reminders/lib/Controller/ApiController.php
new file mode 100644
index 00000000000..c95a74a04f4
--- /dev/null
+++ b/apps/files_reminders/lib/Controller/ApiController.php
@@ -0,0 +1,131 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Controller;
+
+use DateTime;
+use DateTimeInterface;
+use DateTimeZone;
+use Exception;
+use OCA\FilesReminders\Exception\NodeNotFoundException;
+use OCA\FilesReminders\Exception\ReminderNotFoundException;
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\OCSController;
+use OCP\IRequest;
+use OCP\IUserSession;
+use Psr\Log\LoggerInterface;
+
+class ApiController extends OCSController {
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ protected ReminderService $reminderService,
+ protected IUserSession $userSession,
+ protected LoggerInterface $logger,
+ ) {
+ parent::__construct($appName, $request);
+ }
+
+ /**
+ * Get a reminder
+ *
+ * @param int $fileId ID of the file
+ * @return DataResponse<Http::STATUS_OK, array{dueDate: ?string}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, list<empty>, array{}>
+ *
+ * 200: Reminder returned
+ * 401: Account not found
+ */
+ #[NoAdminRequired]
+ public function get(int $fileId): DataResponse {
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ return new DataResponse([], Http::STATUS_UNAUTHORIZED);
+ }
+
+ try {
+ $reminder = $this->reminderService->getDueForUser($user, $fileId);
+ if ($reminder === null) {
+ return new DataResponse(['dueDate' => null], Http::STATUS_OK);
+ }
+ return new DataResponse([
+ 'dueDate' => $reminder->getDueDate()->format(DateTimeInterface::ATOM), // ISO 8601
+ ], Http::STATUS_OK);
+ } catch (NodeNotFoundException $e) {
+ return new DataResponse(['dueDate' => null], Http::STATUS_OK);
+ }
+ }
+
+ /**
+ * Set a reminder
+ *
+ * @param int $fileId ID of the file
+ * @param string $dueDate ISO 8601 formatted date time string
+ *
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_CREATED|Http::STATUS_BAD_REQUEST|Http::STATUS_UNAUTHORIZED|Http::STATUS_NOT_FOUND, list<empty>, array{}>
+ *
+ * 200: Reminder updated
+ * 201: Reminder created successfully
+ * 400: Creating reminder is not possible
+ * 401: Account not found
+ * 404: File not found
+ */
+ #[NoAdminRequired]
+ public function set(int $fileId, string $dueDate): DataResponse {
+ try {
+ $dueDate = (new DateTime($dueDate))->setTimezone(new DateTimeZone('UTC'));
+ } catch (Exception $e) {
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ return new DataResponse([], Http::STATUS_UNAUTHORIZED);
+ }
+
+ try {
+ $created = $this->reminderService->createOrUpdate($user, $fileId, $dueDate);
+ if ($created) {
+ return new DataResponse([], Http::STATUS_CREATED);
+ }
+ return new DataResponse([], Http::STATUS_OK);
+ } catch (NodeNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+
+ /**
+ * Remove a reminder
+ *
+ * @param int $fileId ID of the file
+ *
+ * @return DataResponse<Http::STATUS_OK|Http::STATUS_UNAUTHORIZED|Http::STATUS_NOT_FOUND, list<empty>, array{}>
+ *
+ * 200: Reminder deleted successfully
+ * 401: Account not found
+ * 404: Reminder not found
+ */
+ #[NoAdminRequired]
+ public function remove(int $fileId): DataResponse {
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ return new DataResponse([], Http::STATUS_UNAUTHORIZED);
+ }
+
+ try {
+ $this->reminderService->remove($user, $fileId);
+ return new DataResponse([], Http::STATUS_OK);
+ } catch (NodeNotFoundException|ReminderNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+}
diff --git a/apps/files_reminders/lib/Dav/PropFindPlugin.php b/apps/files_reminders/lib/Dav/PropFindPlugin.php
new file mode 100644
index 00000000000..014e636eb2d
--- /dev/null
+++ b/apps/files_reminders/lib/Dav/PropFindPlugin.php
@@ -0,0 +1,82 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Dav;
+
+use DateTimeInterface;
+use OCA\DAV\Connector\Sabre\Directory;
+use OCA\DAV\Connector\Sabre\Node;
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\Files\Folder;
+use OCP\IUser;
+use OCP\IUserSession;
+use Sabre\DAV\INode;
+use Sabre\DAV\PropFind;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+
+class PropFindPlugin extends ServerPlugin {
+
+ public const REMINDER_DUE_DATE_PROPERTY = '{http://nextcloud.org/ns}reminder-due-date';
+
+ public function __construct(
+ private ReminderService $reminderService,
+ private IUserSession $userSession,
+ ) {
+ }
+
+ public function initialize(Server $server): void {
+ $server->on('propFind', [$this, 'propFind']);
+ }
+
+ public function propFind(PropFind $propFind, INode $node) {
+ if (!in_array(static::REMINDER_DUE_DATE_PROPERTY, $propFind->getRequestedProperties())) {
+ return;
+ }
+
+ if (!($node instanceof Node)) {
+ return;
+ }
+
+ if (
+ $node instanceof Directory
+ && $propFind->getDepth() > 0
+ && $propFind->getStatus(static::REMINDER_DUE_DATE_PROPERTY) !== null
+ ) {
+ $folder = $node->getNode();
+ $this->cacheFolder($folder);
+ }
+
+ $propFind->handle(
+ static::REMINDER_DUE_DATE_PROPERTY,
+ function () use ($node) {
+ $user = $this->userSession->getUser();
+ if (!($user instanceof IUser)) {
+ return '';
+ }
+
+ $fileId = $node->getId();
+ $reminder = $this->reminderService->getDueForUser($user, $fileId, false);
+ if ($reminder === null) {
+ return '';
+ }
+
+ return $reminder->getDueDate()->format(DateTimeInterface::ATOM); // ISO 8601
+ },
+ );
+ }
+
+ private function cacheFolder(Folder $folder): void {
+ $user = $this->userSession->getUser();
+ if (!($user instanceof IUser)) {
+ return;
+ }
+ $this->reminderService->cacheFolder($user, $folder);
+ }
+}
diff --git a/apps/files_reminders/lib/Db/Reminder.php b/apps/files_reminders/lib/Db/Reminder.php
new file mode 100644
index 00000000000..1a8ba15063e
--- /dev/null
+++ b/apps/files_reminders/lib/Db/Reminder.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Db;
+
+use DateTime;
+use OCP\AppFramework\Db\Entity;
+
+/**
+ * @method void setUserId(string $userId)
+ * @method string getUserId()
+ *
+ * @method void setFileId(int $fileId)
+ * @method int getFileId()
+ *
+ * @method void setDueDate(DateTime $dueDate)
+ * @method DateTime getDueDate()
+ *
+ * @method void setUpdatedAt(DateTime $updatedAt)
+ * @method DateTime getUpdatedAt()
+ *
+ * @method void setCreatedAt(DateTime $createdAt)
+ * @method DateTime getCreatedAt()
+ *
+ * @method void setNotified(bool $notified)
+ * @method bool getNotified()
+ */
+class Reminder extends Entity {
+ protected $userId;
+ protected $fileId;
+ protected $dueDate;
+ protected $updatedAt;
+ protected $createdAt;
+ protected $notified = false;
+
+ public function __construct() {
+ $this->addType('userId', 'string');
+ $this->addType('fileId', 'integer');
+ $this->addType('dueDate', 'datetime');
+ $this->addType('updatedAt', 'datetime');
+ $this->addType('createdAt', 'datetime');
+ $this->addType('notified', 'boolean');
+ }
+}
diff --git a/apps/files_reminders/lib/Db/ReminderMapper.php b/apps/files_reminders/lib/Db/ReminderMapper.php
new file mode 100644
index 00000000000..63cba437d07
--- /dev/null
+++ b/apps/files_reminders/lib/Db/ReminderMapper.php
@@ -0,0 +1,151 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Db;
+
+use DateTime;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Files\Folder;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+use OCP\IDBConnection;
+use OCP\IUser;
+
+/**
+ * @template-extends QBMapper<Reminder>
+ */
+class ReminderMapper extends QBMapper {
+ public const TABLE_NAME = 'files_reminders';
+
+ public function __construct(IDBConnection $db) {
+ parent::__construct(
+ $db,
+ static::TABLE_NAME,
+ Reminder::class,
+ );
+ }
+
+ public function markNotified(Reminder $reminder): Reminder {
+ $reminderUpdate = new Reminder();
+ $reminderUpdate->setId($reminder->getId());
+ $reminderUpdate->setNotified(true);
+ return $this->update($reminderUpdate);
+ }
+
+ /**
+ * @throws DoesNotExistException
+ */
+ public function findDueForUser(IUser $user, int $fileId): Reminder {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)))
+ ->andWhere($qb->expr()->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)));
+
+ return $this->findEntity($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAll() {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->orderBy('due_date', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAllForUser(IUser $user) {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)))
+ ->orderBy('due_date', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAllForNode(Node $node) {
+ try {
+ $nodeId = $node->getId();
+ } catch (NotFoundException $e) {
+ return [];
+ }
+
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('file_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)))
+ ->orderBy('due_date', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findOverdue() {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->lt('due_date', $qb->createFunction('NOW()')))
+ ->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
+ ->orderBy('due_date', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findNotified(DateTime $buffer, ?int $limit = null) {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('notified', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)))
+ ->andWhere($qb->expr()->lt('due_date', $qb->createNamedParameter($buffer, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
+ ->orderBy('due_date', 'ASC')
+ ->setMaxResults($limit);
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @return Reminder[]
+ */
+ public function findAllInFolder(IUser $user, Folder $folder) {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('r.id', 'r.user_id', 'r.file_id', 'r.due_date', 'r.updated_at', 'r.created_at', 'r.notified')
+ ->from($this->getTableName(), 'r')
+ ->innerJoin('r', 'filecache', 'f', $qb->expr()->eq('r.file_id', 'f.fileid'))
+ ->where($qb->expr()->eq('r.user_id', $qb->createNamedParameter($user->getUID(), IQueryBuilder::PARAM_STR)))
+ ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT)))
+ ->orderBy('r.due_date', 'ASC');
+
+ return $this->findEntities($qb);
+ }
+}
diff --git a/apps/files_reminders/lib/Exception/NodeNotFoundException.php b/apps/files_reminders/lib/Exception/NodeNotFoundException.php
new file mode 100644
index 00000000000..65e1b28fe1e
--- /dev/null
+++ b/apps/files_reminders/lib/Exception/NodeNotFoundException.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Exception;
+
+use Exception;
+
+class NodeNotFoundException extends Exception {
+}
diff --git a/apps/files_reminders/lib/Exception/ReminderNotFoundException.php b/apps/files_reminders/lib/Exception/ReminderNotFoundException.php
new file mode 100644
index 00000000000..fd7031a834f
--- /dev/null
+++ b/apps/files_reminders/lib/Exception/ReminderNotFoundException.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Exception;
+
+use Exception;
+
+class ReminderNotFoundException extends Exception {
+}
diff --git a/apps/files_reminders/lib/Exception/UserNotFoundException.php b/apps/files_reminders/lib/Exception/UserNotFoundException.php
new file mode 100644
index 00000000000..d1ddf9148cb
--- /dev/null
+++ b/apps/files_reminders/lib/Exception/UserNotFoundException.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Exception;
+
+use Exception;
+
+class UserNotFoundException extends Exception {
+}
diff --git a/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php b/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php
new file mode 100644
index 00000000000..765bf1e3ce2
--- /dev/null
+++ b/apps/files_reminders/lib/Listener/LoadAdditionalScriptsListener.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Listener;
+
+use OCA\Files\Event\LoadAdditionalScriptsEvent;
+use OCA\FilesReminders\AppInfo\Application;
+use OCP\App\IAppManager;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Util;
+use Psr\Log\LoggerInterface;
+
+/** @template-implements IEventListener<LoadAdditionalScriptsEvent> */
+class LoadAdditionalScriptsListener implements IEventListener {
+ public function __construct(
+ private IAppManager $appManager,
+ private LoggerInterface $logger,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof LoadAdditionalScriptsEvent)) {
+ return;
+ }
+
+ if (!$this->appManager->isEnabledForUser(Application::APP_ID)
+ || !$this->appManager->isEnabledForUser('notifications')
+ ) {
+ return;
+ }
+
+ Util::addInitScript(Application::APP_ID, 'init');
+ }
+}
diff --git a/apps/files_reminders/lib/Listener/NodeDeletedListener.php b/apps/files_reminders/lib/Listener/NodeDeletedListener.php
new file mode 100644
index 00000000000..06a4733e6cd
--- /dev/null
+++ b/apps/files_reminders/lib/Listener/NodeDeletedListener.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Listener;
+
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Files\Events\Node\NodeDeletedEvent;
+
+/** @template-implements IEventListener<NodeDeletedEvent> */
+class NodeDeletedListener implements IEventListener {
+ public function __construct(
+ private ReminderService $reminderService,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof NodeDeletedEvent)) {
+ return;
+ }
+
+ $node = $event->getNode();
+ $this->reminderService->removeAllForNode($node);
+ }
+}
diff --git a/apps/files_reminders/lib/Listener/SabrePluginAddListener.php b/apps/files_reminders/lib/Listener/SabrePluginAddListener.php
new file mode 100644
index 00000000000..b2c4501f9af
--- /dev/null
+++ b/apps/files_reminders/lib/Listener/SabrePluginAddListener.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Listener;
+
+use OCA\DAV\Events\SabrePluginAddEvent;
+use OCA\FilesReminders\Dav\PropFindPlugin;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use Psr\Container\ContainerInterface;
+
+/** @template-implements IEventListener<SabrePluginAddEvent> */
+class SabrePluginAddListener implements IEventListener {
+ public function __construct(
+ private ContainerInterface $container,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof SabrePluginAddEvent)) {
+ return;
+ }
+
+ $server = $event->getServer();
+ $plugin = $this->container->get(PropFindPlugin::class);
+ $server->addPlugin($plugin);
+ }
+}
diff --git a/apps/files_reminders/lib/Listener/UserDeletedListener.php b/apps/files_reminders/lib/Listener/UserDeletedListener.php
new file mode 100644
index 00000000000..366a5e60420
--- /dev/null
+++ b/apps/files_reminders/lib/Listener/UserDeletedListener.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Listener;
+
+use OCA\FilesReminders\Service\ReminderService;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\UserDeletedEvent;
+
+/** @template-implements IEventListener<UserDeletedEvent> */
+class UserDeletedListener implements IEventListener {
+ public function __construct(
+ private ReminderService $reminderService,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof UserDeletedEvent)) {
+ return;
+ }
+
+ $user = $event->getUser();
+ $this->reminderService->removeAllForUser($user);
+ }
+}
diff --git a/apps/files_reminders/lib/Migration/Version10000Date20230725162149.php b/apps/files_reminders/lib/Migration/Version10000Date20230725162149.php
new file mode 100644
index 00000000000..74614c6515e
--- /dev/null
+++ b/apps/files_reminders/lib/Migration/Version10000Date20230725162149.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Migration;
+
+use Closure;
+use OCA\FilesReminders\Db\ReminderMapper;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version10000Date20230725162149 extends SimpleMigrationStep {
+ /**
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ if ($schema->hasTable(ReminderMapper::TABLE_NAME)) {
+ return null;
+ }
+
+ $table = $schema->createTable(ReminderMapper::TABLE_NAME);
+ $table->addColumn('id', Types::BIGINT, [
+ 'autoincrement' => true,
+ 'notnull' => true,
+ 'length' => 20,
+ 'unsigned' => true,
+ ]);
+ $table->addColumn('user_id', Types::STRING, [
+ 'notnull' => true,
+ 'length' => 64,
+ ]);
+ $table->addColumn('file_id', Types::BIGINT, [
+ 'notnull' => true,
+ 'length' => 20,
+ 'unsigned' => true,
+ ]);
+ $table->addColumn('due_date', Types::DATETIME, [
+ 'notnull' => true,
+ ]);
+ $table->addColumn('updated_at', Types::DATETIME, [
+ 'notnull' => true,
+ ]);
+ $table->addColumn('created_at', Types::DATETIME, [
+ 'notnull' => true,
+ ]);
+ $table->addColumn('notified', Types::BOOLEAN, [
+ 'notnull' => false,
+ 'default' => false,
+ ]);
+ $table->setPrimaryKey(['id']);
+ $table->addUniqueIndex(['user_id', 'file_id', 'due_date'], 'reminders_uniq_idx');
+
+ return $schema;
+ }
+}
diff --git a/apps/files_reminders/lib/Model/RichReminder.php b/apps/files_reminders/lib/Model/RichReminder.php
new file mode 100644
index 00000000000..4f221252717
--- /dev/null
+++ b/apps/files_reminders/lib/Model/RichReminder.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\FilesReminders\Model;
+
+use DateTimeInterface;
+use JsonSerializable;
+use OCA\FilesReminders\Db\Reminder;
+use OCA\FilesReminders\Exception\NodeNotFoundException;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+
+class RichReminder extends Reminder implements JsonSerializable {
+ public function __construct(
+ private Reminder $reminder,
+ private IRootFolder $root,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @throws NodeNotFoundException
+ */
+ public function getNode(): Node {
+ $node = $this->root->getUserFolder($this->getUserId())->getFirstNodeById($this->getFileId());
+ if (!$node) {
+ throw new NodeNotFoundException();
+ }
+ return $node;
+ }
+
+ protected function getter(string $name): mixed {
+ return $this->reminder->getter($name);
+ }
+
+ public function __call(string $methodName, array $args) {
+ return $this->reminder->__call($methodName, $args);
+ }
+
+ public function jsonSerialize(): array {
+ return [
+ 'userId' => $this->getUserId(),
+ 'fileId' => $this->getFileId(),
+ 'path' => $this->getNode()->getPath(),
+ 'dueDate' => $this->getDueDate()->format(DateTimeInterface::ATOM), // ISO 8601
+ 'updatedAt' => $this->getUpdatedAt()->format(DateTimeInterface::ATOM), // ISO 8601
+ 'createdAt' => $this->getCreatedAt()->format(DateTimeInterface::ATOM), // ISO 8601
+ 'notified' => $this->getNotified(),
+ ];
+ }
+}
diff --git a/apps/files_reminders/lib/Notification/Notifier.php b/apps/files_reminders/lib/Notification/Notifier.php
new file mode 100644
index 00000000000..337ef04c814
--- /dev/null
+++ b/apps/files_reminders/lib/Notification/Notifier.php
@@ -0,0 +1,110 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Notification;
+
+use OCA\FilesReminders\AppInfo\Application;
+use OCP\Files\FileInfo;
+use OCP\Files\IRootFolder;
+use OCP\IURLGenerator;
+use OCP\L10N\IFactory;
+use OCP\Notification\AlreadyProcessedException;
+use OCP\Notification\IAction;
+use OCP\Notification\INotification;
+use OCP\Notification\INotifier;
+use OCP\Notification\UnknownNotificationException;
+
+class Notifier implements INotifier {
+ public function __construct(
+ protected IFactory $l10nFactory,
+ protected IURLGenerator $urlGenerator,
+ protected IRootFolder $root,
+ ) {
+ }
+
+ public function getID(): string {
+ return Application::APP_ID;
+ }
+
+ public function getName(): string {
+ return $this->l10nFactory->get(Application::APP_ID)->t('File reminders');
+ }
+
+ /**
+ * @throws UnknownNotificationException
+ */
+ public function prepare(INotification $notification, string $languageCode): INotification {
+ $l = $this->l10nFactory->get(Application::APP_ID, $languageCode);
+
+ if ($notification->getApp() !== Application::APP_ID) {
+ throw new UnknownNotificationException();
+ }
+
+ switch ($notification->getSubject()) {
+ case 'reminder-due':
+ $params = $notification->getSubjectParameters();
+ $fileId = $params['fileId'];
+
+ $node = $this->root->getUserFolder($notification->getUser())->getFirstNodeById($fileId);
+ if ($node === null) {
+ throw new AlreadyProcessedException();
+ }
+
+ $path = rtrim($node->getPath(), '/');
+ if (strpos($path, '/' . $notification->getUser() . '/files/') === 0) {
+ // Remove /user/files/...
+ $fullPath = $path;
+ [,,, $path] = explode('/', $fullPath, 4);
+ }
+
+ $link = $this->urlGenerator->linkToRouteAbsolute(
+ 'files.viewcontroller.showFile',
+ ['fileid' => $node->getId()],
+ );
+
+ // TRANSLATORS The name placeholder is for a file or folder name
+ $subject = $l->t('Reminder for {name}');
+ $notification
+ ->setRichSubject(
+ $subject,
+ [
+ 'name' => [
+ 'type' => 'highlight',
+ 'id' => (string)$node->getId(),
+ 'name' => $node->getName(),
+ ],
+ ],
+ )
+ ->setLink($link);
+
+ $label = match ($node->getType()) {
+ FileInfo::TYPE_FILE => $l->t('View file'),
+ FileInfo::TYPE_FOLDER => $l->t('View folder'),
+ };
+
+ $this->addActionButton($notification, $label);
+ break;
+ default:
+ throw new UnknownNotificationException();
+ }
+
+ return $notification;
+ }
+
+ protected function addActionButton(INotification $notification, string $label): void {
+ $action = $notification->createAction();
+
+ $action->setLabel($label)
+ ->setParsedLabel($label)
+ ->setLink($notification->getLink(), IAction::TYPE_WEB)
+ ->setPrimary(true);
+
+ $notification->addParsedAction($action);
+ }
+}
diff --git a/apps/files_reminders/lib/Service/ReminderService.php b/apps/files_reminders/lib/Service/ReminderService.php
new file mode 100644
index 00000000000..6ee39562076
--- /dev/null
+++ b/apps/files_reminders/lib/Service/ReminderService.php
@@ -0,0 +1,217 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\Service;
+
+use DateTime;
+use DateTimeZone;
+use OCA\FilesReminders\AppInfo\Application;
+use OCA\FilesReminders\Db\Reminder;
+use OCA\FilesReminders\Db\ReminderMapper;
+use OCA\FilesReminders\Exception\NodeNotFoundException;
+use OCA\FilesReminders\Exception\ReminderNotFoundException;
+use OCA\FilesReminders\Exception\UserNotFoundException;
+use OCA\FilesReminders\Model\RichReminder;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Notification\IManager as INotificationManager;
+use Psr\Log\LoggerInterface;
+use Throwable;
+
+class ReminderService {
+
+ private ICache $cache;
+
+ public function __construct(
+ protected IUserManager $userManager,
+ protected IURLGenerator $urlGenerator,
+ protected INotificationManager $notificationManager,
+ protected ReminderMapper $reminderMapper,
+ protected IRootFolder $root,
+ protected LoggerInterface $logger,
+ protected ICacheFactory $cacheFactory,
+ ) {
+ $this->cache = $this->cacheFactory->createInMemory();
+ }
+
+ public function cacheFolder(IUser $user, Folder $folder): void {
+ $reminders = $this->reminderMapper->findAllInFolder($user, $folder);
+ $reminderMap = [];
+ foreach ($reminders as $reminder) {
+ $reminderMap[$reminder->getFileId()] = $reminder;
+ }
+
+ $nodes = $folder->getDirectoryListing();
+ foreach ($nodes as $node) {
+ $reminder = $reminderMap[$node->getId()] ?? false;
+ $this->cache->set("{$user->getUID()}-{$node->getId()}", $reminder);
+ }
+ }
+
+ /**
+ * @throws NodeNotFoundException
+ */
+ public function getDueForUser(IUser $user, int $fileId, bool $checkNode = true): ?RichReminder {
+ if ($checkNode) {
+ $this->checkNode($user, $fileId);
+ }
+ /** @var null|false|Reminder $cachedReminder */
+ $cachedReminder = $this->cache->get("{$user->getUID()}-$fileId");
+ if ($cachedReminder === false) {
+ return null;
+ }
+ if ($cachedReminder instanceof Reminder) {
+ return new RichReminder($cachedReminder, $this->root);
+ }
+
+ try {
+ $reminder = $this->reminderMapper->findDueForUser($user, $fileId);
+ $this->cache->set("{$user->getUID()}-$fileId", $reminder);
+ return new RichReminder($reminder, $this->root);
+ } catch (DoesNotExistException $e) {
+ $this->cache->set("{$user->getUID()}-$fileId", false);
+ return null;
+ }
+ }
+
+ /**
+ * @return RichReminder[]
+ */
+ public function getAll(?IUser $user = null) {
+ $reminders = ($user !== null)
+ ? $this->reminderMapper->findAllForUser($user)
+ : $this->reminderMapper->findAll();
+ return array_map(
+ fn (Reminder $reminder) => new RichReminder($reminder, $this->root),
+ $reminders,
+ );
+ }
+
+ /**
+ * @return bool true if created, false if updated
+ *
+ * @throws NodeNotFoundException
+ */
+ public function createOrUpdate(IUser $user, int $fileId, DateTime $dueDate): bool {
+ $now = new DateTime('now', new DateTimeZone('UTC'));
+ $this->checkNode($user, $fileId);
+ $reminder = $this->getDueForUser($user, $fileId);
+ if ($reminder === null) {
+ $reminder = new Reminder();
+ $reminder->setUserId($user->getUID());
+ $reminder->setFileId($fileId);
+ $reminder->setDueDate($dueDate);
+ $reminder->setUpdatedAt($now);
+ $reminder->setCreatedAt($now);
+ $this->reminderMapper->insert($reminder);
+ $this->cache->set("{$user->getUID()}-$fileId", $reminder);
+ return true;
+ }
+ $reminder->setDueDate($dueDate);
+ $reminder->setUpdatedAt($now);
+ $this->reminderMapper->update($reminder);
+ $this->cache->set("{$user->getUID()}-$fileId", $reminder);
+ return false;
+ }
+
+ /**
+ * @throws NodeNotFoundException
+ * @throws ReminderNotFoundException
+ */
+ public function remove(IUser $user, int $fileId): void {
+ $this->checkNode($user, $fileId);
+ $reminder = $this->getDueForUser($user, $fileId);
+ if ($reminder === null) {
+ throw new ReminderNotFoundException();
+ }
+ $this->deleteReminder($reminder);
+ }
+
+ public function removeAllForNode(Node $node): void {
+ $reminders = $this->reminderMapper->findAllForNode($node);
+ foreach ($reminders as $reminder) {
+ $this->deleteReminder($reminder);
+ }
+ }
+
+ public function removeAllForUser(IUser $user): void {
+ $reminders = $this->reminderMapper->findAllForUser($user);
+ foreach ($reminders as $reminder) {
+ $this->deleteReminder($reminder);
+ }
+ }
+
+ /**
+ * @throws DoesNotExistException
+ * @throws UserNotFoundException
+ */
+ public function send(Reminder $reminder): void {
+ if ($reminder->getNotified()) {
+ return;
+ }
+
+ $user = $this->userManager->get($reminder->getUserId());
+ if ($user === null) {
+ throw new UserNotFoundException();
+ }
+
+ $notification = $this->notificationManager->createNotification();
+ $notification
+ ->setApp(Application::APP_ID)
+ ->setIcon($this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('files', 'folder.svg')))
+ ->setUser($user->getUID())
+ ->setObject('reminder', (string)$reminder->getId())
+ ->setSubject('reminder-due', [
+ 'fileId' => $reminder->getFileId(),
+ ])
+ ->setDateTime($reminder->getDueDate());
+
+ try {
+ $this->notificationManager->notify($notification);
+ $this->reminderMapper->markNotified($reminder);
+ $this->cache->set("{$user->getUID()}-{$reminder->getFileId()}", $reminder);
+ } catch (Throwable $th) {
+ $this->logger->error($th->getMessage(), $th->getTrace());
+ }
+ }
+
+ public function cleanUp(?int $limit = null): void {
+ $buffer = (new DateTime())
+ ->setTimezone(new DateTimeZone('UTC'))
+ ->modify('-1 day');
+ $reminders = $this->reminderMapper->findNotified($buffer, $limit);
+ foreach ($reminders as $reminder) {
+ $this->deleteReminder($reminder);
+ }
+ }
+
+ private function deleteReminder(Reminder $reminder): void {
+ $this->reminderMapper->delete($reminder);
+ $this->cache->set("{$reminder->getUserId()}-{$reminder->getFileId()}", false);
+ }
+
+
+ /**
+ * @throws NodeNotFoundException
+ */
+ private function checkNode(IUser $user, int $fileId): void {
+ $userFolder = $this->root->getUserFolder($user->getUID());
+ $node = $userFolder->getFirstNodeById($fileId);
+ if ($node === null) {
+ throw new NodeNotFoundException();
+ }
+ }
+}
diff --git a/apps/files_reminders/lib/SetupChecks/NeedNotificationsApp.php b/apps/files_reminders/lib/SetupChecks/NeedNotificationsApp.php
new file mode 100644
index 00000000000..e5890567181
--- /dev/null
+++ b/apps/files_reminders/lib/SetupChecks/NeedNotificationsApp.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\FilesReminders\SetupChecks;
+
+use OCP\App\IAppManager;
+use OCP\IL10N;
+use OCP\SetupCheck\ISetupCheck;
+use OCP\SetupCheck\SetupResult;
+
+class NeedNotificationsApp implements ISetupCheck {
+ public function __construct(
+ private IAppManager $appManager,
+ private IL10N $l10n,
+ ) {
+ }
+
+ public function getName(): string {
+ return $this->l10n->t('Files reminder');
+ }
+
+ public function getCategory(): string {
+ return 'system';
+ }
+
+ public function run(): SetupResult {
+ if ($this->appManager->isEnabledForAnyone('notifications')) {
+ return SetupResult::success($this->l10n->t('The "files_reminders" app can work properly.'));
+ } else {
+ return SetupResult::warning($this->l10n->t('The "files_reminders" app needs the notification app to work properly. You should either enable notifications or disable files_reminder.'));
+ }
+ }
+}
diff --git a/apps/files_reminders/openapi.json b/apps/files_reminders/openapi.json
new file mode 100644
index 00000000000..3564b90b1c2
--- /dev/null
+++ b/apps/files_reminders/openapi.json
@@ -0,0 +1,508 @@
+{
+ "openapi": "3.0.3",
+ "info": {
+ "title": "files_reminders",
+ "version": "0.0.1",
+ "description": "Set file reminders",
+ "license": {
+ "name": "agpl"
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "basic_auth": {
+ "type": "http",
+ "scheme": "basic"
+ },
+ "bearer_auth": {
+ "type": "http",
+ "scheme": "bearer"
+ }
+ },
+ "schemas": {
+ "OCSMeta": {
+ "type": "object",
+ "required": [
+ "status",
+ "statuscode"
+ ],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "statuscode": {
+ "type": "integer"
+ },
+ "message": {
+ "type": "string"
+ },
+ "totalitems": {
+ "type": "string"
+ },
+ "itemsperpage": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "paths": {
+ "/ocs/v2.php/apps/files_reminders/api/v{version}/{fileId}": {
+ "get": {
+ "operationId": "api-get",
+ "summary": "Get a reminder",
+ "tags": [
+ "api"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^1$"
+ }
+ },
+ {
+ "name": "fileId",
+ "in": "path",
+ "description": "ID of the file",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "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": "Reminder returned",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "type": "object",
+ "required": [
+ "dueDate"
+ ],
+ "properties": {
+ "dueDate": {
+ "type": "string",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Account not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "operationId": "api-set",
+ "summary": "Set a reminder",
+ "tags": [
+ "api"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "dueDate"
+ ],
+ "properties": {
+ "dueDate": {
+ "type": "string",
+ "description": "ISO 8601 formatted date time string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^1$"
+ }
+ },
+ {
+ "name": "fileId",
+ "in": "path",
+ "description": "ID of the file",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "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": "Reminder updated",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "201": {
+ "description": "Reminder created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Creating reminder is not possible",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Account not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "File not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "api-remove",
+ "summary": "Remove a reminder",
+ "tags": [
+ "api"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "version",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^1$"
+ }
+ },
+ {
+ "name": "fileId",
+ "in": "path",
+ "description": "ID of the file",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "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": "Reminder deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Account not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Reminder not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/apps/files_reminders/openapi.json.license b/apps/files_reminders/openapi.json.license
new file mode 100644
index 00000000000..83559daa9dc
--- /dev/null
+++ b/apps/files_reminders/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/files_reminders/src/actions/clearReminderAction.ts b/apps/files_reminders/src/actions/clearReminderAction.ts
new file mode 100644
index 00000000000..148861999f4
--- /dev/null
+++ b/apps/files_reminders/src/actions/clearReminderAction.ts
@@ -0,0 +1,54 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import Vue from 'vue'
+import { FileAction, type Node } from '@nextcloud/files'
+import { emit } from '@nextcloud/event-bus'
+import { translate as t } from '@nextcloud/l10n'
+
+import AlarmOffSvg from '@mdi/svg/svg/alarm-off.svg?raw'
+
+import { clearReminder } from '../services/reminderService.ts'
+import { getVerboseDateString } from '../shared/utils.ts'
+
+export const action = new FileAction({
+ id: 'clear-reminder',
+
+ displayName: () => t('files_reminders', 'Clear reminder'),
+
+ title: (nodes: Node[]) => {
+ const node = nodes.at(0)!
+ const dueDate = new Date(node.attributes['reminder-due-date'])
+ return `${t('files_reminders', 'Clear reminder')} – ${getVerboseDateString(dueDate)}`
+ },
+
+ iconSvgInline: () => AlarmOffSvg,
+
+ enabled: (nodes: Node[]) => {
+ // Only allow on a single node
+ if (nodes.length !== 1) {
+ return false
+ }
+ const node = nodes.at(0)!
+ const dueDate = node.attributes['reminder-due-date']
+ return Boolean(dueDate)
+ },
+
+ async exec(node: Node) {
+ if (node.fileid) {
+ try {
+ await clearReminder(node.fileid)
+ Vue.set(node.attributes, 'reminder-due-date', '')
+ emit('files:node:updated', node)
+ return true
+ } catch (error) {
+ return false
+ }
+ }
+ return null
+ },
+
+ order: 19,
+})
diff --git a/apps/files_reminders/src/actions/reminderStatusAction.ts b/apps/files_reminders/src/actions/reminderStatusAction.ts
new file mode 100644
index 00000000000..6a2c9943d3b
--- /dev/null
+++ b/apps/files_reminders/src/actions/reminderStatusAction.ts
@@ -0,0 +1,45 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { FileAction, type Node } from '@nextcloud/files'
+import { translate as t } from '@nextcloud/l10n'
+
+import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
+
+import { pickCustomDate } from '../services/customPicker.ts'
+import { getVerboseDateString } from '../shared/utils.ts'
+
+export const action = new FileAction({
+ id: 'reminder-status',
+
+ inline: () => true,
+
+ displayName: () => '',
+
+ title: (nodes: Node[]) => {
+ const node = nodes.at(0)!
+ const dueDate = new Date(node.attributes['reminder-due-date'])
+ return `${t('files_reminders', 'Reminder set')} – ${getVerboseDateString(dueDate)}`
+ },
+
+ iconSvgInline: () => AlarmSvg,
+
+ enabled: (nodes: Node[]) => {
+ // Only allow on a single node
+ if (nodes.length !== 1) {
+ return false
+ }
+ const node = nodes.at(0)!
+ const dueDate = node.attributes['reminder-due-date']
+ return Boolean(dueDate)
+ },
+
+ async exec(node: Node) {
+ pickCustomDate(node)
+ return null
+ },
+
+ order: -15,
+})
diff --git a/apps/files_reminders/src/actions/setReminderCustomAction.ts b/apps/files_reminders/src/actions/setReminderCustomAction.ts
new file mode 100644
index 00000000000..ea21293ee52
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderCustomAction.ts
@@ -0,0 +1,43 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import type { Node, View } from '@nextcloud/files'
+
+import { FileAction } from '@nextcloud/files'
+import { translate as t } from '@nextcloud/l10n'
+import CalendarClockSvg from '@mdi/svg/svg/calendar-clock.svg?raw'
+
+import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
+import { pickCustomDate } from '../services/customPicker'
+
+export const action = new FileAction({
+ id: 'set-reminder-custom',
+ displayName: () => t('files_reminders', 'Custom reminder'),
+ title: () => t('files_reminders', 'Reminder at custom date & time'),
+ iconSvgInline: () => CalendarClockSvg,
+
+ enabled: (nodes: Node[], view: View) => {
+ if (view.id === 'trashbin') {
+ return false
+ }
+ // Only allow on a single node
+ if (nodes.length !== 1) {
+ return false
+ }
+ const node = nodes.at(0)!
+ const dueDate = node.attributes['reminder-due-date']
+ return dueDate !== undefined
+ },
+
+ parent: SET_REMINDER_MENU_ID,
+
+ async exec(file: Node) {
+ pickCustomDate(file)
+ return null
+ },
+
+ // After presets
+ order: 22,
+})
diff --git a/apps/files_reminders/src/actions/setReminderMenuAction.ts b/apps/files_reminders/src/actions/setReminderMenuAction.ts
new file mode 100644
index 00000000000..d6ddcd90677
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderMenuAction.ts
@@ -0,0 +1,37 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import type { Node, View } from '@nextcloud/files'
+
+import { FileAction } from '@nextcloud/files'
+import { translate as t } from '@nextcloud/l10n'
+import AlarmSvg from '@mdi/svg/svg/alarm.svg?raw'
+
+export const SET_REMINDER_MENU_ID = 'set-reminder-menu'
+
+export const action = new FileAction({
+ id: SET_REMINDER_MENU_ID,
+ displayName: () => t('files_reminders', 'Set reminder'),
+ iconSvgInline: () => AlarmSvg,
+
+ enabled: (nodes: Node[], view: View) => {
+ if (view.id === 'trashbin') {
+ return false
+ }
+ // Only allow on a single node
+ if (nodes.length !== 1) {
+ return false
+ }
+ const node = nodes.at(0)!
+ const dueDate = node.attributes['reminder-due-date']
+ return dueDate !== undefined
+ },
+
+ async exec() {
+ return null
+ },
+
+ order: 20,
+})
diff --git a/apps/files_reminders/src/actions/setReminderSuggestionActions.scss b/apps/files_reminders/src/actions/setReminderSuggestionActions.scss
new file mode 100644
index 00000000000..1327500c964
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderSuggestionActions.scss
@@ -0,0 +1,23 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+ // TODO: remove when/if the actions API supports a separator
+ // This the last preset action, so we need to add a separator
+.files-list__row-action-set-reminder-custom {
+ margin-top: 13px;
+ position: relative;
+
+ &::before {
+ content: "";
+ margin-block: 3px;
+ margin-inline: 15px 10px;
+ border-bottom: 1px solid var(--color-border-dark);
+ cursor: default;
+ display: flex;
+ height: 0;
+ position: absolute;
+ inset-inline: 0;
+ top: -10px;
+ }
+}
diff --git a/apps/files_reminders/src/actions/setReminderSuggestionActions.ts b/apps/files_reminders/src/actions/setReminderSuggestionActions.ts
new file mode 100644
index 00000000000..f92b2f89108
--- /dev/null
+++ b/apps/files_reminders/src/actions/setReminderSuggestionActions.ts
@@ -0,0 +1,143 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import Vue from 'vue'
+import type { Node, View } from '@nextcloud/files'
+
+import { FileAction } from '@nextcloud/files'
+import { emit } from '@nextcloud/event-bus'
+import { showError, showSuccess } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+
+import { DateTimePreset, getDateString, getDateTime, getVerboseDateString } from '../shared/utils'
+import { logger } from '../shared/logger'
+import { SET_REMINDER_MENU_ID } from './setReminderMenuAction'
+import { setReminder } from '../services/reminderService'
+import './setReminderSuggestionActions.scss'
+
+interface ReminderOption {
+ dateTimePreset: DateTimePreset
+ label: string
+ ariaLabel: string
+ dateString?: string
+ verboseDateString?: string
+ action?: () => Promise<void>
+}
+
+const laterToday: ReminderOption = {
+ dateTimePreset: DateTimePreset.LaterToday,
+ label: t('files_reminders', 'Later today'),
+ ariaLabel: t('files_reminders', 'Set reminder for later today'),
+ dateString: '',
+ verboseDateString: '',
+}
+
+const tomorrow: ReminderOption = {
+ dateTimePreset: DateTimePreset.Tomorrow,
+ label: t('files_reminders', 'Tomorrow'),
+ ariaLabel: t('files_reminders', 'Set reminder for tomorrow'),
+ dateString: '',
+ verboseDateString: '',
+}
+
+const thisWeekend: ReminderOption = {
+ dateTimePreset: DateTimePreset.ThisWeekend,
+ label: t('files_reminders', 'This weekend'),
+ ariaLabel: t('files_reminders', 'Set reminder for this weekend'),
+ dateString: '',
+ verboseDateString: '',
+}
+
+const nextWeek: ReminderOption = {
+ dateTimePreset: DateTimePreset.NextWeek,
+ label: t('files_reminders', 'Next week'),
+ ariaLabel: t('files_reminders', 'Set reminder for next week'),
+ dateString: '',
+ verboseDateString: '',
+}
+
+/**
+ * Generate a file action for the given option
+ *
+ * @param option The option to generate the action for
+ * @return The file action or null if the option should not be shown
+ */
+const generateFileAction = (option: ReminderOption): FileAction|null => {
+
+ return new FileAction({
+ id: `set-reminder-${option.dateTimePreset}`,
+ displayName: () => `${option.label} – ${option.dateString}`,
+ title: () => `${option.ariaLabel} – ${option.verboseDateString}`,
+
+ // Empty svg to hide the icon
+ iconSvgInline: () => '<svg></svg>',
+
+ enabled: (nodes: Node[], view: View) => {
+ if (view.id === 'trashbin') {
+ return false
+ }
+ // Only allow on a single node
+ if (nodes.length !== 1) {
+ return false
+ }
+ const node = nodes.at(0)!
+ const dueDate = node.attributes['reminder-due-date']
+ return dueDate !== undefined && Boolean(getDateTime(option.dateTimePreset))
+ },
+
+ parent: SET_REMINDER_MENU_ID,
+
+ async exec(node: Node) {
+ // Can't really happen, but just in case™
+ if (!node.fileid) {
+ logger.error('Failed to set reminder, missing file id')
+ showError(t('files_reminders', 'Failed to set reminder'))
+ return null
+ }
+
+ // Set the reminder
+ try {
+ const dateTime = getDateTime(option.dateTimePreset)!
+ await setReminder(node.fileid, dateTime)
+ Vue.set(node.attributes, 'reminder-due-date', dateTime.toISOString())
+ emit('files:node:updated', node)
+ showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: node.basename }))
+ } catch (error) {
+ logger.error('Failed to set reminder', { error })
+ showError(t('files_reminders', 'Failed to set reminder'))
+ }
+ // Silent success as we display our own notification
+ return null
+ },
+
+ order: 21,
+ })
+}
+
+[laterToday, tomorrow, thisWeekend, nextWeek].forEach((option) => {
+ // Generate the initial date string
+ const dateTime = getDateTime(option.dateTimePreset)
+ if (!dateTime) {
+ return
+ }
+ option.dateString = getDateString(dateTime)
+ option.verboseDateString = getVerboseDateString(dateTime)
+
+ // Update the date string every 30 minutes
+ setInterval(() => {
+ const dateTime = getDateTime(option.dateTimePreset)
+ if (!dateTime) {
+ return
+ }
+
+ // update the submenu remind options strings
+ option.dateString = getDateString(dateTime)
+ option.verboseDateString = getVerboseDateString(dateTime)
+ }, 1000 * 30 * 60)
+})
+
+// Generate the default preset actions
+export const actions = [laterToday, tomorrow, thisWeekend, nextWeek]
+ .map(generateFileAction) as FileAction[]
diff --git a/apps/files_reminders/src/components/SetCustomReminderModal.vue b/apps/files_reminders/src/components/SetCustomReminderModal.vue
new file mode 100644
index 00000000000..59c0886a009
--- /dev/null
+++ b/apps/files_reminders/src/components/SetCustomReminderModal.vue
@@ -0,0 +1,195 @@
+<!--
+ - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <NcDialog v-if="opened"
+ :name="name"
+ :out-transition="true"
+ size="small"
+ close-on-click-outside
+ @closing="onClose">
+ <form id="set-custom-reminder-form"
+ class="custom-reminder-modal"
+ @submit.prevent="setCustom">
+ <NcDateTimePickerNative id="set-custom-reminder"
+ v-model="customDueDate"
+ :label="label"
+ :min="nowDate"
+ :required="true"
+ type="datetime-local"
+ @input="onInput" />
+
+ <NcNoteCard v-if="isValid" type="info">
+ {{ t('files_reminders', 'We will remind you of this file') }}
+ <NcDateTime :timestamp="customDueDate" />
+ </NcNoteCard>
+
+ <NcNoteCard v-else type="error">
+ {{ t('files_reminders', 'Please choose a valid date & time') }}
+ </NcNoteCard>
+ </form>
+ <template #actions>
+ <!-- Cancel pick -->
+ <NcButton type="tertiary" @click="onClose">
+ {{ t('files_reminders', 'Cancel') }}
+ </NcButton>
+
+ <!-- Clear reminder -->
+ <NcButton v-if="hasDueDate" @click="clear">
+ {{ t('files_reminders', 'Clear reminder') }}
+ </NcButton>
+
+ <!-- Set reminder -->
+ <NcButton :disabled="!isValid"
+ type="primary"
+ form="set-custom-reminder-form"
+ native-type="submit">
+ {{ t('files_reminders', 'Set reminder') }}
+ </NcButton>
+ </template>
+ </NcDialog>
+</template>
+
+<script lang="ts">
+import Vue from 'vue'
+import type { Node } from '@nextcloud/files'
+import { emit } from '@nextcloud/event-bus'
+import { showError, showSuccess } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+
+import NcButton from '@nextcloud/vue/components/NcButton'
+import NcDateTime from '@nextcloud/vue/components/NcDateTime'
+import NcDateTimePickerNative from '@nextcloud/vue/components/NcDateTimePickerNative'
+import NcDialog from '@nextcloud/vue/components/NcDialog'
+import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
+
+import { getDateString, getInitialCustomDueDate } from '../shared/utils.ts'
+import { logger } from '../shared/logger.ts'
+import { clearReminder, setReminder } from '../services/reminderService.ts'
+
+export default Vue.extend({
+ name: 'SetCustomReminderModal',
+
+ components: {
+ NcButton,
+ NcDateTime,
+ NcDateTimePickerNative,
+ NcDialog,
+ NcNoteCard,
+ },
+
+ data() {
+ return {
+ node: undefined as Node | undefined,
+ hasDueDate: false,
+ opened: false,
+ isValid: true,
+
+ customDueDate: null as null | Date,
+ nowDate: new Date(),
+ }
+ },
+
+ computed: {
+ fileId(): number|undefined {
+ return this.node?.fileid
+ },
+
+ fileName(): string|undefined {
+ return this.node?.basename
+ },
+
+ name() {
+ return this.fileName ? t('files_reminders', 'Set reminder for "{fileName}"', { fileName: this.fileName }) : ''
+ },
+
+ label(): string {
+ return t('files_reminders', 'Reminder at custom date & time')
+ },
+
+ clearAriaLabel(): string {
+ return t('files_reminders', 'Clear reminder')
+ },
+ },
+
+ methods: {
+ t,
+ getDateString,
+
+ /**
+ * Open the modal to set a custom reminder
+ * and reset the state.
+ * @param node The node to set a reminder for
+ */
+ open(node: Node): void {
+ const dueDate = node.attributes['reminder-due-date'] ? new Date(node.attributes['reminder-due-date']) : null
+
+ this.node = node
+ this.hasDueDate = Boolean(dueDate)
+ this.isValid = true
+ this.opened = true
+ this.customDueDate = dueDate ?? getInitialCustomDueDate()
+ this.nowDate = new Date()
+
+ // Focus the input and show the picker after the animation
+ setTimeout(() => {
+ const input = document.getElementById('set-custom-reminder') as HTMLInputElement
+ input.focus()
+ if (!this.hasDueDate) {
+ input.showPicker()
+ }
+ }, 300)
+ },
+
+ async setCustom(): Promise<void> {
+ // Handle input cleared or invalid date
+ if (!(this.customDueDate instanceof Date) || isNaN(this.customDueDate)) {
+ showError(t('files_reminders', 'Please choose a valid date & time'))
+ return
+ }
+
+ try {
+ await setReminder(this.fileId, this.customDueDate)
+ Vue.set(this.node.attributes, 'reminder-due-date', this.customDueDate.toISOString())
+ emit('files:node:updated', this.node)
+ showSuccess(t('files_reminders', 'Reminder set for "{fileName}"', { fileName: this.fileName }))
+ this.onClose()
+ } catch (error) {
+ logger.error('Failed to set reminder', { error })
+ showError(t('files_reminders', 'Failed to set reminder'))
+ }
+ },
+
+ async clear(): Promise<void> {
+ try {
+ await clearReminder(this.fileId)
+ Vue.set(this.node.attributes, 'reminder-due-date', '')
+ emit('files:node:updated', this.node)
+ showSuccess(t('files_reminders', 'Reminder cleared for "{fileName}"', { fileName: this.fileName }))
+ this.onClose()
+ } catch (error) {
+ logger.error('Failed to clear reminder', { error })
+ showError(t('files_reminders', 'Failed to clear reminder'))
+ }
+ },
+
+ onClose(): void {
+ this.opened = false
+ this.$emit('close')
+ },
+
+ onInput(): void {
+ const input = document.getElementById('set-custom-reminder') as HTMLInputElement
+ this.isValid = input.checkValidity()
+ },
+ },
+})
+</script>
+
+<style lang="scss" scoped>
+.custom-reminder-modal {
+ margin: 0 12px;
+}
+</style>
diff --git a/apps/files_reminders/src/init.ts b/apps/files_reminders/src/init.ts
new file mode 100644
index 00000000000..17da254d0f2
--- /dev/null
+++ b/apps/files_reminders/src/init.ts
@@ -0,0 +1,19 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { registerDavProperty, registerFileAction } from '@nextcloud/files'
+import { action as statusAction } from './actions/reminderStatusAction'
+import { action as clearAction } from './actions/clearReminderAction'
+import { action as menuAction } from './actions/setReminderMenuAction'
+import { actions as suggestionActions } from './actions/setReminderSuggestionActions'
+import { action as customAction } from './actions/setReminderCustomAction'
+
+registerDavProperty('nc:reminder-due-date', { nc: 'http://nextcloud.org/ns' })
+
+registerFileAction(statusAction)
+registerFileAction(clearAction)
+registerFileAction(menuAction)
+registerFileAction(customAction)
+suggestionActions.forEach((action) => registerFileAction(action))
diff --git a/apps/files_reminders/src/services/customPicker.ts b/apps/files_reminders/src/services/customPicker.ts
new file mode 100644
index 00000000000..5cefffe39a5
--- /dev/null
+++ b/apps/files_reminders/src/services/customPicker.ts
@@ -0,0 +1,29 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import type { Node } from '@nextcloud/files'
+import Vue from 'vue'
+
+import SetCustomReminderModal from '../components/SetCustomReminderModal.vue'
+
+const View = Vue.extend(SetCustomReminderModal)
+const mount = document.createElement('div')
+mount.id = 'set-custom-reminder-modal'
+document.body.appendChild(mount)
+
+// Create a new Vue instance and mount it to our modal container
+const CustomReminderModal = new View({
+ name: 'SetCustomReminderModal',
+ el: mount,
+})
+
+export const pickCustomDate = (node: Node): Promise<void> => {
+ CustomReminderModal.open(node)
+
+ // Wait for the modal to close
+ return new Promise((resolve) => {
+ CustomReminderModal.$once('close', resolve)
+ })
+}
diff --git a/apps/files_reminders/src/services/reminderService.ts b/apps/files_reminders/src/services/reminderService.ts
new file mode 100644
index 00000000000..9f58d1bdae3
--- /dev/null
+++ b/apps/files_reminders/src/services/reminderService.ts
@@ -0,0 +1,38 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import axios from '@nextcloud/axios'
+import { generateOcsUrl } from '@nextcloud/router'
+
+interface Reminder {
+ dueDate: null | Date
+}
+
+export const getReminder = async (fileId: number): Promise<Reminder> => {
+ const url = generateOcsUrl('/apps/files_reminders/api/v1/{fileId}', { fileId })
+ const response = await axios.get(url)
+ const dueDate = response.data.ocs.data.dueDate ? new Date(response.data.ocs.data.dueDate) : null
+
+ return {
+ dueDate,
+ }
+}
+
+export const setReminder = async (fileId: number, dueDate: Date): Promise<[]> => {
+ const url = generateOcsUrl('/apps/files_reminders/api/v1/{fileId}', { fileId })
+
+ const response = await axios.put(url, {
+ dueDate: dueDate.toISOString(), // timezone of string is always UTC
+ })
+
+ return response.data.ocs.data
+}
+
+export const clearReminder = async (fileId: number): Promise<[]> => {
+ const url = generateOcsUrl('/apps/files_reminders/api/v1/{fileId}', { fileId })
+ const response = await axios.delete(url)
+
+ return response.data.ocs.data
+}
diff --git a/apps/files_reminders/src/shared/logger.ts b/apps/files_reminders/src/shared/logger.ts
new file mode 100644
index 00000000000..79d663cca16
--- /dev/null
+++ b/apps/files_reminders/src/shared/logger.ts
@@ -0,0 +1,11 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { getLoggerBuilder } from '@nextcloud/logger'
+
+export const logger = getLoggerBuilder()
+ .setApp('files_reminders')
+ .detectUser()
+ .build()
diff --git a/apps/files_reminders/src/shared/types.ts b/apps/files_reminders/src/shared/types.ts
new file mode 100644
index 00000000000..f8da6f6aed0
--- /dev/null
+++ b/apps/files_reminders/src/shared/types.ts
@@ -0,0 +1,10 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+export interface FileAttributes {
+ [key: string]: unknown
+ id: number
+ name: string
+}
diff --git a/apps/files_reminders/src/shared/utils.ts b/apps/files_reminders/src/shared/utils.ts
new file mode 100644
index 00000000000..5d583ad3ddd
--- /dev/null
+++ b/apps/files_reminders/src/shared/utils.ts
@@ -0,0 +1,162 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { getCanonicalLocale } from '@nextcloud/l10n'
+
+export enum DateTimePreset {
+ LaterToday = 'later-today',
+ Tomorrow = 'tomorrow',
+ ThisWeekend = 'this-weekend',
+ NextWeek = 'next-week',
+}
+
+const getFirstWorkdayOfWeek = () => {
+ const now = new Date()
+ now.setHours(0, 0, 0, 0)
+ now.setDate(now.getDate() - now.getDay() + 1)
+ return new Date(now)
+}
+
+const getWeek = (date: Date) => {
+ const dateClone = new Date(date)
+ dateClone.setHours(0, 0, 0, 0)
+ const firstDayOfYear = new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0)
+ const daysFromFirstDay = (date.getTime() - firstDayOfYear.getTime()) / 86400000
+ return Math.ceil((daysFromFirstDay + firstDayOfYear.getDay() + 1) / 7)
+}
+
+const isSameWeek = (a: Date, b: Date) => {
+ return getWeek(a) === getWeek(b)
+ && a.getFullYear() === b.getFullYear()
+}
+
+const isSameDate = (a: Date, b: Date) => {
+ return a.getDate() === b.getDate()
+ && a.getMonth() === b.getMonth()
+ && a.getFullYear() === b.getFullYear()
+}
+
+export const getDateTime = (dateTime: DateTimePreset): null | Date => {
+ const matchPreset: Record<DateTimePreset, () => null | Date> = {
+ [DateTimePreset.LaterToday]: () => {
+ const now = new Date()
+ const evening = new Date()
+ evening.setHours(18, 0, 0, 0)
+ const cutoff = new Date()
+ cutoff.setHours(17, 0, 0, 0)
+ if (now >= cutoff) {
+ return null
+ }
+ return evening
+ },
+
+ [DateTimePreset.Tomorrow]: () => {
+ const now = new Date()
+ const day = new Date()
+ day.setDate(now.getDate() + 1)
+ day.setHours(8, 0, 0, 0)
+ return day
+ },
+
+ [DateTimePreset.ThisWeekend]: () => {
+ const today = new Date()
+ if (
+ [
+ 5, // Friday
+ 6, // Saturday
+ 0, // Sunday
+ ].includes(today.getDay())
+ ) {
+ return null
+ }
+ const saturday = new Date()
+ const firstWorkdayOfWeek = getFirstWorkdayOfWeek()
+ saturday.setDate(firstWorkdayOfWeek.getDate() + 5)
+ saturday.setHours(8, 0, 0, 0)
+ return saturday
+ },
+
+ [DateTimePreset.NextWeek]: () => {
+ const today = new Date()
+ if (today.getDay() === 0) { // Sunday
+ return null
+ }
+ const workday = new Date()
+ const firstWorkdayOfWeek = getFirstWorkdayOfWeek()
+ workday.setDate(firstWorkdayOfWeek.getDate() + 7)
+ workday.setHours(8, 0, 0, 0)
+ return workday
+ },
+ }
+
+ return matchPreset[dateTime]()
+}
+
+export const getInitialCustomDueDate = (): Date => {
+ const now = new Date()
+ const dueDate = new Date()
+ dueDate.setHours(now.getHours() + 2, 0, 0, 0)
+ return dueDate
+}
+
+export const getDateString = (dueDate: Date): string => {
+ let formatOptions: Intl.DateTimeFormatOptions = {
+ hour: 'numeric',
+ minute: '2-digit',
+ }
+
+ const today = new Date()
+
+ if (!isSameDate(dueDate, today)) {
+ formatOptions = {
+ ...formatOptions,
+ weekday: 'short',
+ }
+ }
+
+ if (!isSameWeek(dueDate, today)) {
+ formatOptions = {
+ ...formatOptions,
+ month: 'short',
+ day: 'numeric',
+ }
+ }
+
+ if (dueDate.getFullYear() !== today.getFullYear()) {
+ formatOptions = {
+ ...formatOptions,
+ year: 'numeric',
+ }
+ }
+
+ return dueDate.toLocaleString(
+ getCanonicalLocale(),
+ formatOptions,
+ )
+}
+
+export const getVerboseDateString = (dueDate: Date): string => {
+ let formatOptions: Intl.DateTimeFormatOptions = {
+ month: 'long',
+ day: 'numeric',
+ weekday: 'long',
+ hour: 'numeric',
+ minute: '2-digit',
+ }
+
+ const today = new Date()
+
+ if (dueDate.getFullYear() !== today.getFullYear()) {
+ formatOptions = {
+ ...formatOptions,
+ year: 'numeric',
+ }
+ }
+
+ return dueDate.toLocaleString(
+ getCanonicalLocale(),
+ formatOptions,
+ )
+}