From dae7adec2a1c027d186484498e15c1c4e4e97c44 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Wed, 30 Sep 2026 07:34:18 +0200 Subject: [PATCH 01/60] feat(people): custom profile fields, expertise tags and a directory-wide people search that respects profile visibility Administrators define up to ten fields (text or tags, filled by the person or read from LDAP); people fill their own on their personal settings; GET /api/people?q= matches name, email, role, headline, biography and searchable fields across the directory; a private standard field neither shows nor matches for others, and a group-only field only for colleagues who share a group. REQ-PEX-001..004 (widgets-people-expertise-and-fields) --- appinfo/info.xml | 5 +- appinfo/routes.php | 7 + lib/AppInfo/Application.php | 19 + lib/BackgroundJob/ProfileFieldsSyncJob.php | 86 +++ lib/Controller/PeopleWidgetController.php | 4 + lib/Controller/ProfileFieldsController.php | 205 ++++++ lib/Db/ProfileValue.php | 127 ++++ lib/Db/ProfileValueMapper.php | 192 +++++ lib/Listener/ProfileFieldsListener.php | 88 +++ .../Version002012Date20260930080000.php | 101 +++ lib/Service/PeopleWidgetService.php | 131 +++- lib/Service/ProfileFieldService.php | 674 ++++++++++++++++++ lib/Settings/LaunchPadPersonal.php | 90 +++ lib/actions.seed.json | 4 + templates/settings/personal.php | 8 + .../ProfileFieldsControllerTest.php | 119 ++++ .../Database/ProfileValuesDatabaseTest.php | 55 ++ tests/Unit/Service/ActionAuthBaselineTest.php | 5 + .../Unit/Service/PeopleWidgetServiceTest.php | 136 +++- .../Unit/Service/ProfileFieldServiceTest.php | 318 +++++++++ tests/Unit/Support/InMemoryProfileValues.php | 137 ++++ 21 files changed, 2500 insertions(+), 11 deletions(-) create mode 100644 lib/BackgroundJob/ProfileFieldsSyncJob.php create mode 100644 lib/Controller/ProfileFieldsController.php create mode 100644 lib/Db/ProfileValue.php create mode 100644 lib/Db/ProfileValueMapper.php create mode 100644 lib/Listener/ProfileFieldsListener.php create mode 100644 lib/Migration/Version002012Date20260930080000.php create mode 100644 lib/Service/ProfileFieldService.php create mode 100644 lib/Settings/LaunchPadPersonal.php create mode 100644 templates/settings/personal.php create mode 100644 tests/Unit/Controller/ProfileFieldsControllerTest.php create mode 100644 tests/Unit/Database/ProfileValuesDatabaseTest.php create mode 100644 tests/Unit/Service/ProfileFieldServiceTest.php create mode 100644 tests/Unit/Support/InMemoryProfileValues.php diff --git a/appinfo/info.xml b/appinfo/info.xml index 7c699720c..c268a4903 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -52,7 +52,7 @@ Ideaal voor organisaties die consistente, samengestelde dashboards willen voor h Vrij en open source onder de EUPL-1.2-licentie. ]]> - 1.1.6-unstable.20260930050000 + 1.1.6-unstable.20260930080000 EUPL-1.2 Conduction LaunchPad @@ -95,6 +95,8 @@ Vrij en open source onder de EUPL-1.2-licentie. OCA\LaunchPad\BackgroundJob\OrphanedDataCleanupJob OCA\LaunchPad\BackgroundJob\HealthPingRefreshJob + + OCA\LaunchPad\BackgroundJob\ProfileFieldsSyncJob @@ -169,6 +171,7 @@ Vrij en open source onder de EUPL-1.2-licentie. OCA\LaunchPad\Settings\LaunchPadAdmin OCA\LaunchPad\Settings\LaunchPadAdminSection + OCA\LaunchPad\Settings\LaunchPadPersonal diff --git a/appinfo/routes.php b/appinfo/routes.php index d747b1403..8b77a0048 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -455,6 +455,13 @@ // returns `{users, total, hasMore}` with offset-based pagination. ['name' => 'peopleWidget#getUsers', 'url' => '/api/people', 'verb' => 'GET'], + // Custom profile fields (REQ-PEX-001, REQ-PEX-002): own values for + // every signed-in person, definitions for administrators. + ['name' => 'profileFields#getOwn', 'url' => '/api/profile-fields/me', 'verb' => 'GET'], + ['name' => 'profileFields#saveOwn', 'url' => '/api/profile-fields/me', 'verb' => 'PUT'], + ['name' => 'profileFields#getDefinitions', 'url' => '/api/profile-fields/definitions', 'verb' => 'GET'], + ['name' => 'profileFields#saveDefinitions', 'url' => '/api/profile-fields/definitions', 'verb' => 'PUT'], + // Setup wizard endpoints (REQ-WIZ-008, REQ-WIZ-009, REQ-WIZ-003). // Admin-only via runtime `IGroupManager::isAdmin` check inside the // controller. The state endpoint also drives the "Run setup wizard" diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index e90b899d6..0b7860e23 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -27,6 +27,7 @@ use OCA\LaunchPad\Listener\GroupDeletedListener; use OCA\LaunchPad\Listener\LocksListener; use OCA\LaunchPad\Listener\MetadataValuesListener; +use OCA\LaunchPad\Listener\ProfileFieldsListener; use OCA\LaunchPad\Listener\PublicSharesListener; use OCA\LaunchPad\Listener\ReactionsListener; use OCA\LaunchPad\Listener\TranslationsListener; @@ -41,6 +42,7 @@ use OCA\LaunchPad\Service\ImportService; use OCA\LaunchPad\Service\PublicShareContext; use OCA\LaunchPad\Service\StoreService; +use OCP\Accounts\UserUpdatedEvent; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -48,6 +50,7 @@ use OCP\Group\Events\GroupDeletedEvent; use OCP\Security\CSP\AddContentSecurityPolicyEvent; use OCP\User\Events\UserDeletedEvent; +use OCP\User\Events\UserLoggedInEvent; /** * Application bootstrap. @@ -125,6 +128,22 @@ private function registerUserLifecycle(IRegistrationContext $context): void { event: UserDeletedEvent::class, listener: UserDeletedListener::class ); + + // Custom profile fields (REQ-PEX-001, REQ-PEX-004): LDAP sync and the + // standard-field mirror on sign-in and profile edits; values go with + // the user. + $context->registerEventListener( + event: UserLoggedInEvent::class, + listener: ProfileFieldsListener::class + ); + $context->registerEventListener( + event: UserUpdatedEvent::class, + listener: ProfileFieldsListener::class + ); + $context->registerEventListener( + event: UserDeletedEvent::class, + listener: ProfileFieldsListener::class + ); }//end registerUserLifecycle() /** diff --git a/lib/BackgroundJob/ProfileFieldsSyncJob.php b/lib/BackgroundJob/ProfileFieldsSyncJob.php new file mode 100644 index 000000000..6757f4e97 --- /dev/null +++ b/lib/BackgroundJob/ProfileFieldsSyncJob.php @@ -0,0 +1,86 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\BackgroundJob; + +use OCA\LaunchPad\Service\ProfileFieldService; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\TimedJob; +use OCP\IUser; +use OCP\IUserManager; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Daily profile field sync. + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileFieldsSyncJob extends TimedJob { + /** + * Constructor. + * + * @param ITimeFactory $time Time factory. + * @param IUserManager $userManager Users. + * @param ProfileFieldService $profileFields Profile field service. + * @param LoggerInterface $logger Logger. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct( + ITimeFactory $time, + private readonly IUserManager $userManager, + private readonly ProfileFieldService $profileFields, + private readonly LoggerInterface $logger, + ) { + parent::__construct(time: $time); + $this->setInterval(seconds: 86400); + }//end __construct() + + /** + * Refresh every user that has signed in; one failure does not stop the rest. + * + * @param mixed $argument Unused. + * + * @return void + * + * @spec openspec/specs/people-widget/spec.md + */ + protected function run($argument): void { + $failed = 0; + $this->userManager->callForSeenUsers( + function (IUser $user) use (&$failed): void { + try { + $this->profileFields->syncLdapFields(user: $user); + $this->profileFields->mirrorStandardFields(user: $user); + } catch (Throwable) { + $failed++; + } + } + ); + + if ($failed > 0) { + $this->logger->warning(message: 'ProfileFieldsSyncJob: ' . $failed . ' user(s) could not be refreshed.'); + } + }//end run() +}//end class diff --git a/lib/Controller/PeopleWidgetController.php b/lib/Controller/PeopleWidgetController.php index 49157559f..2adcd7ad4 100644 --- a/lib/Controller/PeopleWidgetController.php +++ b/lib/Controller/PeopleWidgetController.php @@ -88,6 +88,7 @@ public function __construct( * @param string|null $sortBy Sort key. * @param int|null $limit Page size. * @param int|null $offset Page offset. + * @param string|null $q Search text; 2 or more characters search the whole directory by name, email and profile fields (REQ-PEX-003). * * @return JSONResponse * @@ -102,6 +103,7 @@ public function getUsers( ?string $sortBy = 'displayName', ?int $limit = PeopleWidgetService::DEFAULT_LIMIT, ?int $offset = 0, + ?string $q = null, ): JSONResponse { if ($this->userId === null) { return new JSONResponse(['error' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); @@ -137,6 +139,8 @@ public function getUsers( sortBy: ($sortBy ?? 'displayName'), limit: ($limit ?? PeopleWidgetService::DEFAULT_LIMIT), offset: ($offset ?? 0), + query: $q, + viewerId: $user->getUID(), ); } catch (InvalidArgumentException $e) { return ResponseHelper::error( diff --git a/lib/Controller/ProfileFieldsController.php b/lib/Controller/ProfileFieldsController.php new file mode 100644 index 000000000..219206ac9 --- /dev/null +++ b/lib/Controller/ProfileFieldsController.php @@ -0,0 +1,205 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Controller; + +use InvalidArgumentException; +use OCA\LaunchPad\AppInfo\Application; +use OCA\LaunchPad\Service\ActionAuthService; +use OCA\LaunchPad\Service\ProfileFieldService; +use OCA\LaunchPad\Settings\LaunchPadAdmin; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\OCS\OCSForbiddenException; +use OCP\IGroupManager; +use OCP\IRequest; +use OCP\IUser; +use OCP\IUserSession; + +/** + * Custom profile field endpoints. + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileFieldsController extends Controller { + /** + * Constructor. + * + * @param IRequest $request HTTP request. + * @param ProfileFieldService $profileFields Profile field service. + * @param ActionAuthService $actionAuth ADR-023 action authorization. + * @param IUserSession $userSession Current user. + * @param IGroupManager $groupManager Admin check. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct( + IRequest $request, + private readonly ProfileFieldService $profileFields, + private readonly ActionAuthService $actionAuth, + private readonly IUserSession $userSession, + private readonly IGroupManager $groupManager, + ) { + parent::__construct( + appName: Application::APP_ID, + request: $request + ); + }//end __construct() + + /** + * The caller's own fields and values. Each person reads only their own. + * + * @return JSONResponse `{fields: [...]}`, 401 or 403. + * + * @spec openspec/specs/people-widget/spec.md + */ + #[NoAdminRequired] + public function getOwn(): JSONResponse { + $user = $this->userSession->getUser(); + $guard = $this->guard(user: $user, action: 'profile-fields.get-own'); + if ($guard !== null || $user === null) { + return $guard ?? self::unauthenticated(); + } + + return new JSONResponse(data: ['fields' => $this->profileFields->getOwnFields(userId: $user->getUID())]); + }//end getOwn() + + /** + * Save the caller's own values. Each person writes only their own; LDAP + * fields stay read-only. + * + * @param array|null $values Map of field key to a string or a list of tags. + * + * @return JSONResponse `{fields: [...]}`, 400, 401 or 403. + * + * @spec openspec/specs/people-widget/spec.md + */ + #[NoAdminRequired] + public function saveOwn(?array $values = null): JSONResponse { + $user = $this->userSession->getUser(); + $guard = $this->guard(user: $user, action: 'profile-fields.save-own'); + if ($guard !== null || $user === null) { + return $guard ?? self::unauthenticated(); + } + + try { + $fields = $this->profileFields->saveOwnValues(userId: $user->getUID(), values: ($values ?? [])); + } catch (InvalidArgumentException $e) { + return new JSONResponse(data: ['error' => $e->getMessage()], statusCode: Http::STATUS_BAD_REQUEST); + } + + return new JSONResponse(data: ['fields' => $fields]); + }//end saveOwn() + + /** + * The field definitions (administrators). + * + * @return JSONResponse `{fields: [...]}`, 401 or 403. + * + * @spec openspec/specs/people-widget/spec.md + */ + #[AuthorizedAdminSetting(LaunchPadAdmin::class)] + public function getDefinitions(): JSONResponse { + $guard = $this->adminGuard(action: 'profile-fields.get-definitions'); + if ($guard !== null) { + return $guard; + } + + return new JSONResponse(data: ['fields' => $this->profileFields->getDefinitions()]); + }//end getDefinitions() + + /** + * Replace the field definitions (administrators). + * + * @param array|null $fields The definitions. + * + * @return JSONResponse `{fields: [...]}`, 400, 401 or 403. + * + * @spec openspec/specs/people-widget/spec.md + */ + #[AuthorizedAdminSetting(LaunchPadAdmin::class)] + public function saveDefinitions(?array $fields = null): JSONResponse { + $guard = $this->adminGuard(action: 'profile-fields.save-definitions'); + if ($guard !== null) { + return $guard; + } + + try { + $saved = $this->profileFields->saveDefinitions(raw: ($fields ?? [])); + } catch (InvalidArgumentException $e) { + return new JSONResponse(data: ['error' => $e->getMessage()], statusCode: Http::STATUS_BAD_REQUEST); + } + + return new JSONResponse(data: ['fields' => $saved]); + }//end saveDefinitions() + + /** + * Signed-in and allowed to call the action. + * + * @param IUser|null $user The caller. + * @param string $action ADR-023 action id. + * + * @return JSONResponse|null An error response, or null when allowed. + */ + private function guard(?IUser $user, string $action): ?JSONResponse { + if ($user === null) { + return self::unauthenticated(); + } + + try { + $this->actionAuth->requireAction($user, $action); + } catch (OCSForbiddenException) { + return new JSONResponse(data: ['error' => 'Forbidden'], statusCode: Http::STATUS_FORBIDDEN); + } + + return null; + }//end guard() + + /** + * Signed-in administrator allowed to call the action. + * + * @param string $action ADR-023 action id. + * + * @return JSONResponse|null An error response, or null when allowed. + */ + private function adminGuard(string $action): ?JSONResponse { + $user = $this->userSession->getUser(); + if ($user !== null && $this->groupManager->isAdmin(userId: $user->getUID()) === false) { + return new JSONResponse(data: ['error' => 'Admin required'], statusCode: Http::STATUS_FORBIDDEN); + } + + return $this->guard(user: $user, action: $action); + }//end adminGuard() + + /** + * The 401 response. + * + * @return JSONResponse + */ + private static function unauthenticated(): JSONResponse { + return new JSONResponse(data: ['error' => 'Not authenticated'], statusCode: Http::STATUS_UNAUTHORIZED); + }//end unauthenticated() +}//end class diff --git a/lib/Db/ProfileValue.php b/lib/Db/ProfileValue.php new file mode 100644 index 000000000..c3a9a01d9 --- /dev/null +++ b/lib/Db/ProfileValue.php @@ -0,0 +1,127 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Db; + +use JsonSerializable; +use OCP\AppFramework\Db\Entity; + +/** + * Profile value entity. + * + * @method string getUserId() + * @method void setUserId(string $userId) + * @method string getFieldKey() + * @method void setFieldKey(string $fieldKey) + * @method string getValue() + * @method void setValue(string $value) + * @method string getValueSearch() + * @method void setValueSearch(string $valueSearch) + * @method string getSource() + * @method void setSource(string $source) + * @method string|null getScope() + * @method void setScope(?string $scope) + * @method string|null getUpdatedAt() + * @method void setUpdatedAt(?string $updatedAt) + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileValue extends Entity implements JsonSerializable { + + /** + * Owner user id. + * + * @var string + */ + protected string $userId = ''; + + /** + * Field key: a custom field key, or nc:role, nc:headline, nc:biography. + * + * @var string + */ + protected string $fieldKey = ''; + + /** + * The value as entered or read. + * + * @var string + */ + protected string $value = ''; + + /** + * Lower-cased value for the search. + * + * @var string + */ + protected string $valueSearch = ''; + + /** + * Where the value came from: self, ldap or nextcloud. + * + * @var string + */ + protected string $source = ''; + + /** + * Nextcloud visibility scope of a mirrored standard field. + * + * @var string|null + */ + protected ?string $scope = null; + + /** + * Last write. + * + * @var string|null + */ + protected ?string $updatedAt = null; + + /** + * Register the column types. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct() { + $this->addType(fieldName: 'id', type: 'integer'); + }//end __construct() + + /** + * Serialise for the API. + * + * @return array + * + * @spec openspec/specs/people-widget/spec.md + */ + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'userId' => $this->userId, + 'fieldKey' => $this->fieldKey, + 'value' => $this->value, + 'source' => $this->source, + 'scope' => $this->scope, + ]; + }//end jsonSerialize() +}//end class diff --git a/lib/Db/ProfileValueMapper.php b/lib/Db/ProfileValueMapper.php new file mode 100644 index 000000000..aeef45b13 --- /dev/null +++ b/lib/Db/ProfileValueMapper.php @@ -0,0 +1,192 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Db; + +use DateTime; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +/** + * Mapper for profile values. + * + * @extends QBMapper + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileValueMapper extends QBMapper { + /** + * Most rows one search returns before the caller filters them. + * + * @var int + */ + public const SEARCH_ROW_CAP = 1000; + + /** + * Constructor. + * + * @param IDBConnection $db Database connection. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct(IDBConnection $db) { + parent::__construct( + db: $db, + tableName: 'launchpad_profile_values', + entityClass: ProfileValue::class + ); + }//end __construct() + + /** + * Every value of the given people. + * + * @param string[] $userIds User ids. + * + * @return ProfileValue[] + * + * @spec openspec/specs/people-widget/spec.md + */ + public function findByUsers(array $userIds): array { + if ($userIds === []) { + return []; + } + + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(from: $this->getTableName()) + ->where( + $qb->expr()->in( + x: 'user_id', + y: $qb->createNamedParameter( + value: array_values(array: $userIds), + type: IQueryBuilder::PARAM_STR_ARRAY + ) + ) + ) + ->orderBy(sort: 'id'); + + return $this->findEntities(query: $qb); + }//end findByUsers() + + /** + * Values whose lower-cased text contains the needle. + * + * @param string $needle Lower-cased search text. + * + * @return ProfileValue[] At most SEARCH_ROW_CAP rows. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function search(string $needle): array { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(from: $this->getTableName()) + ->where( + $qb->expr()->like( + x: 'value_search', + y: $qb->createNamedParameter( + value: '%' . $this->db->escapeLikeParameter(param: $needle) . '%' + ) + ) + ) + ->setMaxResults(maxResults: self::SEARCH_ROW_CAP); + + return $this->findEntities(query: $qb); + }//end search() + + /** + * Replace one person's values of one field with a new list. + * + * @param string $userId Owner. + * @param string $fieldKey Field key. + * @param string[] $values New values (already cleaned). + * @param string $source self, ldap or nextcloud. + * @param string|null $scope Visibility scope of a mirrored standard field. + * + * @return void + * + * @spec openspec/specs/people-widget/spec.md + */ + public function replaceValues( + string $userId, + string $fieldKey, + array $values, + string $source, + ?string $scope = null, + ): void { + $this->deleteField(userId: $userId, fieldKey: $fieldKey); + + $now = (new DateTime())->format(format: 'Y-m-d H:i:s'); + foreach ($values as $value) { + $row = new ProfileValue(); + // Entity setters take their argument positionally. + // phpcs:disable CustomSniffs.Functions.NamedParameters.RequireNamedParameters + $row->setUserId($userId); + $row->setFieldKey($fieldKey); + $row->setValue($value); + $row->setValueSearch(mb_strtolower(string: $value)); + $row->setSource($source); + $row->setScope($scope); + $row->setUpdatedAt($now); + // phpcs:enable CustomSniffs.Functions.NamedParameters.RequireNamedParameters + $this->insert(entity: $row); + } + }//end replaceValues() + + /** + * Delete one person's values of one field. + * + * @param string $userId Owner. + * @param string $fieldKey Field key. + * + * @return int Rows deleted. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function deleteField(string $userId, string $fieldKey): int { + $qb = $this->db->getQueryBuilder(); + $qb->delete(delete: $this->getTableName()) + ->where( + $qb->expr()->eq(x: 'user_id', y: $qb->createNamedParameter(value: $userId)), + $qb->expr()->eq(x: 'field_key', y: $qb->createNamedParameter(value: $fieldKey)) + ); + + return $qb->executeStatement(); + }//end deleteField() + + /** + * Delete every value of a person (user deletion). + * + * @param string $userId Owner. + * + * @return int Rows deleted. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function deleteByUser(string $userId): int { + $qb = $this->db->getQueryBuilder(); + $qb->delete(delete: $this->getTableName()) + ->where($qb->expr()->eq(x: 'user_id', y: $qb->createNamedParameter(value: $userId))); + + return $qb->executeStatement(); + }//end deleteByUser() +}//end class diff --git a/lib/Listener/ProfileFieldsListener.php b/lib/Listener/ProfileFieldsListener.php new file mode 100644 index 000000000..8f820298d --- /dev/null +++ b/lib/Listener/ProfileFieldsListener.php @@ -0,0 +1,88 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Listener; + +use OCA\LaunchPad\Service\ProfileFieldService; +use OCP\Accounts\UserUpdatedEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\User\Events\UserDeletedEvent; +use OCP\User\Events\UserLoggedInEvent; +use Psr\Log\LoggerInterface; +use Throwable; + +/** + * Profile field sync on sign-in, profile edit and user deletion. + * + * @template-implements IEventListener + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileFieldsListener implements IEventListener { + /** + * Constructor. + * + * @param ProfileFieldService $profileFields Profile field service. + * @param LoggerInterface $logger Logger. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct( + private readonly ProfileFieldService $profileFields, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * Handle the event. A failure is logged and never breaks the sign-in or + * the profile edit that raised it. + * + * @param Event $event The event. + * + * @return void + * + * @spec openspec/specs/people-widget/spec.md + */ + public function handle(Event $event): void { + try { + if ($event instanceof UserLoggedInEvent) { + $this->profileFields->syncLdapFields(user: $event->getUser()); + $this->profileFields->mirrorStandardFields(user: $event->getUser()); + return; + } + + if ($event instanceof UserUpdatedEvent) { + $this->profileFields->mirrorStandardFields(user: $event->getUser()); + return; + } + + if ($event instanceof UserDeletedEvent) { + $this->profileFields->deleteUser(userId: $event->getUser()->getUID()); + } + } catch (Throwable $e) { + $this->logger->warning(message: 'Profile field sync failed: ' . $e->getMessage()); + } + }//end handle() +}//end class diff --git a/lib/Migration/Version002012Date20260930080000.php b/lib/Migration/Version002012Date20260930080000.php new file mode 100644 index 000000000..9216d0efc --- /dev/null +++ b/lib/Migration/Version002012Date20260930080000.php @@ -0,0 +1,101 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * @link https://conduction.nl + * + * @spec openspec/specs/people-widget/spec.md + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Create the profile values table. + * + * @spec openspec/specs/people-widget/spec.md + */ +class Version002012Date20260930080000 extends SimpleMigrationStep { + /** + * Create the table when it is not already there. + * + * @param IOutput $output Migration output. + * @param Closure $schemaClosure Schema closure (provides ISchemaWrapper). + * @param array $options Migration options (unused). + * + * @return ISchemaWrapper|null The modified schema, or null when unchanged. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function changeSchema( + IOutput $output, + Closure $schemaClosure, + array $options, + ): ?ISchemaWrapper { + // @var ISchemaWrapper $schema. + $schema = $schemaClosure(); + + if ($schema->hasTable('launchpad_profile_values') === true) { + return null; + } + + $table = $schema->createTable('launchpad_profile_values'); + $table->addColumn('id', Types::BIGINT, ['autoincrement' => true, 'notnull' => true, 'unsigned' => true]); + $table->addColumn('user_id', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('field_key', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('value', Types::TEXT, ['notnull' => true]); + $table->addColumn( + 'value_search', + Types::TEXT, + [ + 'notnull' => true, + 'comment' => 'Lower-cased value, matched with LIKE by the people search.', + ] + ); + $table->addColumn( + 'source', + Types::STRING, + [ + 'notnull' => true, + 'length' => 16, + 'comment' => 'self, ldap or nextcloud (a mirrored standard field).', + ] + ); + $table->addColumn( + 'scope', + Types::STRING, + [ + 'notnull' => false, + 'length' => 32, + 'comment' => 'Nextcloud visibility scope of a mirrored standard field; NULL for custom fields.', + ] + ); + $table->addColumn('updated_at', Types::DATETIME, ['notnull' => false]); + + $table->setPrimaryKey(['id']); + $table->addIndex(['user_id'], 'launchpad_pv_user'); + $table->addIndex(['field_key'], 'launchpad_pv_field'); + + return $schema; + }//end changeSchema() +}//end class diff --git a/lib/Service/PeopleWidgetService.php b/lib/Service/PeopleWidgetService.php index 9ed9beea0..0a85d8846 100644 --- a/lib/Service/PeopleWidgetService.php +++ b/lib/Service/PeopleWidgetService.php @@ -10,10 +10,10 @@ * the single contact point between the {@see PeopleWidgetController} HTTP * layer and Nextcloud's user / group / account managers. * - * Visibility model (REQ-PPL-004): v1 returns every non-empty profile field - * unconditionally — scope-based (`$prop->getScope()`) filtering is a - * documented follow-up. Empty / null values are still omitted from the - * response, never returned as `null` keys. + * Visibility model (REQ-PPL-004, REQ-PEX-004): a standard profile field + * whose Nextcloud scope is private shows to its owner only; custom fields + * follow their definition's audience. Empty / null values are omitted from + * the response, never returned as `null` keys. * * @category Service * @package OCA\LaunchPad\Service @@ -88,6 +88,28 @@ class PeopleWidgetService { * * @var string[] */ + /** + * Most name and email matches one search reads (REQ-PEX-003). + * + * @var int + */ + public const SEARCH_CANDIDATE_CAP = 500; + + /** + * Shortest query that asks the server (REQ-PEX-003). + * + * @var int + */ + public const MIN_QUERY_LENGTH = 2; + + /** + * The user the current listing is for; decides which fields they may + * see and match (REQ-PEX-004). Set at the start of every listUsers() call. + * + * @var string|null + */ + private ?string $viewerId = null; + private const STANDARD_PROPERTIES = [ IAccountManager::PROPERTY_PHONE, IAccountManager::PROPERTY_ADDRESS, @@ -112,6 +134,7 @@ class PeopleWidgetService { * @param AdminTemplateService $adminTemplateService Single-source-of-truth wrapper around * `IGroupManager::getUserGroupIds` * (REQ-TMPL-013 grep guard). + * @param ProfileFieldService $profileFields Custom profile fields and their visibility. */ public function __construct( private readonly IUserManager $userManager, @@ -119,6 +142,7 @@ public function __construct( private readonly IAccountManager $accountManager, private readonly IURLGenerator $urlGenerator, private readonly AdminTemplateService $adminTemplateService, + private readonly ProfileFieldService $profileFields, ) { }//end __construct() @@ -142,12 +166,18 @@ public function __construct( * `group`, or `recent-activity`. * @param int $limit Page size (1..MAX_LIMIT). * @param int $offset Page offset (>=0). + * @param string|null $query Search text; 2 or more characters search the + * whole directory by name, email and profile + * fields (REQ-PEX-003). + * @param string|null $viewerId The signed-in user the list is for; decides + * which fields show and match (REQ-PEX-004). * * @return array Pagination envelope with keys `users`, `total`, `hasMore`. * * @throws InvalidArgumentException When `limit` exceeds MAX_LIMIT, is * non-positive, or `offset` is negative; - * or when `sortBy` is `recent-activity`. + * when `sortBy` is `recent-activity`; or + * when the query is shorter than 2 characters. * * @spec openspec/specs/people-widget/spec.md */ @@ -158,7 +188,11 @@ public function listUsers( string $sortBy = 'displayName', int $limit = self::DEFAULT_LIMIT, int $offset = 0, + ?string $query = null, + ?string $viewerId = null, ): array { + $this->viewerId = $viewerId; + if ($limit < 1 || $limit > self::MAX_LIMIT) { throw new InvalidArgumentException( message: 'limit must be between 1 and ' . self::MAX_LIMIT @@ -177,6 +211,22 @@ public function listUsers( $groupFilter = $this->extractGroupFilter(filters: $filters); + $query = trim(string: (string)$query); + if ($query !== '') { + if (mb_strlen(string: $query) < self::MIN_QUERY_LENGTH) { + throw new InvalidArgumentException(message: 'q must be at least ' . self::MIN_QUERY_LENGTH . ' characters'); + } + + return $this->paginateCandidates( + candidates: $this->searchCandidates(query: $query, groupFilter: $groupFilter), + excludeDisabled: $excludeDisabled, + showBirthdays: $showBirthdays, + sortBy: 'displayName', + limit: $limit, + offset: $offset + ); + } + // No `group` filter AND the default `displayName` sort: page // directly from the backend in display-name order so we never // materialize more IUser objects than the requested window @@ -253,7 +303,7 @@ private function listDirectoryPageByDisplayName( } return [ - 'users' => $users, + 'users' => $this->attachCustomFields(users: $users), 'total' => $total, 'hasMore' => ($offset + count(value: $page)) < $total, ]; @@ -397,12 +447,73 @@ private function paginateCandidates( } return [ - 'users' => $users, + 'users' => $this->attachCustomFields(users: $users), 'total' => $total, 'hasMore' => ($offset + count(value: $page)) < $total, ]; }//end paginateCandidates() + /** + * Name, email and profile-field matches for a search (REQ-PEX-003), + * bounded to the configured groups when the widget has a group filter. + * + * @param string $query The search text. + * @param array|null $groupFilter The widget's group filter, or null. + * + * @return IUser[] Matching users, unsorted. + * + * @spec openspec/specs/people-widget/spec.md + */ + private function searchCandidates(string $query, ?array $groupFilter): array { + $byUid = []; + foreach ($this->userManager->search(pattern: $query, limit: self::SEARCH_CANDIDATE_CAP) as $user) { + $byUid[$user->getUID()] = $user; + } + + $fieldMatches = $this->profileFields->findMatchingUserIds(viewerId: $this->viewerId, query: $query); + foreach ($fieldMatches as $uid) { + if (isset($byUid[$uid]) === true) { + continue; + } + + $user = $this->userManager->get(uid: $uid); + if ($user !== null) { + $byUid[$uid] = $user; + } + } + + if ($groupFilter === null) { + return array_values(array: $byUid); + } + + $members = []; + foreach ($this->collectGroupMembers(groupIds: (array)($groupFilter['values'] ?? [])) as $member) { + $members[$member->getUID()] = true; + } + + return array_values(array: array_intersect_key($byUid, $members)); + }//end searchCandidates() + + /** + * Add the custom fields the viewer may see to every profile on the page (REQ-PEX-004). + * + * @param array $users Projected profiles. + * + * @return array The profiles with `customFields`. + * + * @spec openspec/specs/people-widget/spec.md + */ + private function attachCustomFields(array $users): array { + $uids = array_map(callback: static fn (array $user): string => $user['uid'], array: $users); + $fields = $this->profileFields->visibleFieldsFor(viewerId: $this->viewerId, userIds: $uids); + + foreach ($users as $index => $user) { + $users[$index]['customFields'] = $fields[$user['uid']] ?? []; + } + + return $users; + }//end attachCustomFields() + /** * Compute the number of days between today (UTC) and the user's next * birthday. Returns `null` for invalid / missing input. @@ -673,10 +784,16 @@ private function buildAccountFields(IUser $user, bool $showBirthdays): array { try { $prop = $account->getProperty(property: $property); $value = $prop->getValue(); + $scope = $prop->getScope(); } catch (Exception $e) { continue; } + // REQ-PEX-004: a private field shows to its owner only. + if (ProfileFieldService::scopeAllows(scope: $scope, viewerId: $this->viewerId, ownerId: $user->getUID()) === false) { + continue; + } + if ($value === '') { continue; } diff --git a/lib/Service/ProfileFieldService.php b/lib/Service/ProfileFieldService.php new file mode 100644 index 000000000..8aa8f9c16 --- /dev/null +++ b/lib/Service/ProfileFieldService.php @@ -0,0 +1,674 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Service; + +use Exception; +use InvalidArgumentException; +use OCA\LaunchPad\Db\AdminSettingMapper; +use OCA\LaunchPad\Db\ProfileValue; +use OCA\LaunchPad\Db\ProfileValueMapper; +use OCP\Accounts\IAccountManager; +use OCP\IUser; +use OCP\LDAP\ILDAPProviderFactory; +use Psr\Log\LoggerInterface; + +/** + * Definitions, values and visibility of custom profile fields. + * + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) Definition validation, + * self edits, the LDAP sync, the standard-field mirror and the visibility + * rule share one data model; splitting them would scatter that rule. + * + * @spec openspec/specs/people-widget/spec.md + */ +class ProfileFieldService { + /** + * Admin setting key holding the field definitions. + * + * @var string + */ + public const SETTING_KEY = 'profile_fields'; + + /** + * Most custom fields an administrator may define. + * + * @var int + */ + public const MAX_FIELDS = 10; + + /** + * Most tags one person may list in one field. + * + * @var int + */ + public const MAX_TAGS = 25; + + /** + * Longest value, in characters. + * + * @var int + */ + public const MAX_VALUE_LENGTH = 255; + + /** + * Standard fields mirrored for the search, keyed by their row key. + * + * @var array + */ + public const MIRRORED_STANDARD_FIELDS = [ + 'nc:role' => IAccountManager::PROPERTY_ROLE, + 'nc:headline' => IAccountManager::PROPERTY_HEADLINE, + 'nc:biography' => IAccountManager::PROPERTY_BIOGRAPHY, + ]; + + private const TYPES = ['text', 'tags']; + private const SOURCES = ['self', 'ldap']; + private const VISIBILITIES = ['everyone', 'groups']; + + /** + * Group ids per user, memoised for one request. + * + * @var array + */ + private array $groupCache = []; + + /** + * Constructor. + * + * @param AdminSettingMapper $settingMapper Admin settings store. + * @param ProfileValueMapper $valueMapper Profile values store. + * @param IAccountManager $accountManager Standard profile fields. + * @param AdminTemplateService $adminTemplateService Group ids of a user. + * @param ILDAPProviderFactory $ldapProviderFactory LDAP attribute access. + * @param LoggerInterface $logger Logger. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct( + private readonly AdminSettingMapper $settingMapper, + private readonly ProfileValueMapper $valueMapper, + private readonly IAccountManager $accountManager, + private readonly AdminTemplateService $adminTemplateService, + private readonly ILDAPProviderFactory $ldapProviderFactory, + private readonly LoggerInterface $logger, + ) { + }//end __construct() + + /** + * The stored field definitions, cleaned. + * + * @return array> + * + * @spec openspec/specs/people-widget/spec.md + */ + public function getDefinitions(): array { + $raw = $this->settingMapper->getValue(key: self::SETTING_KEY, default: []); + if (is_array(value: $raw) === false) { + return []; + } + + try { + return $this->validateDefinitions(raw: $raw); + } catch (InvalidArgumentException) { + return []; + } + }//end getDefinitions() + + /** + * Validate and store the field definitions (REQ-PEX-001). + * + * @param array $raw Definitions as sent by the admin screen. + * + * @return array> The stored definitions. + * + * @throws InvalidArgumentException When a definition is invalid. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function saveDefinitions(array $raw): array { + $definitions = $this->validateDefinitions(raw: $raw); + $this->settingMapper->setSetting(key: self::SETTING_KEY, value: $definitions); + + return $definitions; + }//end saveDefinitions() + + /** + * Check and normalise a list of definitions. + * + * @param array $raw Raw definitions. + * + * @return array> + * + * @throws InvalidArgumentException When a definition is invalid. + */ + private function validateDefinitions(array $raw): array { + if (count(value: $raw) > self::MAX_FIELDS) { + throw new InvalidArgumentException(message: 'At most ' . self::MAX_FIELDS . ' profile fields'); + } + + $result = []; + $seen = []; + foreach (array_values(array: $raw) as $entry) { + $definition = $this->validateDefinition(entry: $entry); + if (isset($seen[$definition['key']]) === true) { + throw new InvalidArgumentException(message: 'Duplicate field key: ' . $definition['key']); + } + + $seen[$definition['key']] = true; + $result[] = $definition; + } + + return $result; + }//end validateDefinitions() + + /** + * Check and normalise one definition. + * + * @param mixed $entry Raw definition. + * + * @return array + * + * @throws InvalidArgumentException When the definition is invalid. + */ + private function validateDefinition(mixed $entry): array { + if (is_array(value: $entry) === false) { + throw new InvalidArgumentException(message: 'A profile field must be an object'); + } + + $key = (string)($entry['key'] ?? ''); + if (preg_match(pattern: '/^[a-z][a-z0-9_]{0,31}$/', subject: $key) !== 1) { + throw new InvalidArgumentException(message: 'Field key must be lower case letters, digits or _: ' . $key); + } + + $label = trim(string: (string)($entry['label'] ?? '')); + if ($label === '' || mb_strlen(string: $label) > 64) { + throw new InvalidArgumentException(message: 'Field label must be 1 to 64 characters: ' . $key); + } + + $type = $this->oneOf(value: $entry['type'] ?? 'text', allowed: self::TYPES, name: 'type'); + $source = $this->oneOf(value: $entry['source'] ?? 'self', allowed: self::SOURCES, name: 'source'); + $visibility = $this->oneOf(value: $entry['visibility'] ?? 'everyone', allowed: self::VISIBILITIES, name: 'visibility'); + + $ldapAttribute = trim(string: (string)($entry['ldapAttribute'] ?? '')); + if ($source === 'ldap' && preg_match(pattern: '/^[A-Za-z][A-Za-z0-9-]{0,63}$/', subject: $ldapAttribute) !== 1) { + throw new InvalidArgumentException(message: 'An LDAP field needs an LDAP attribute name: ' . $key); + } + + if ($source !== 'ldap') { + $ldapAttribute = ''; + } + + return [ + 'key' => $key, + 'label' => $label, + 'type' => $type, + 'source' => $source, + 'ldapAttribute' => $ldapAttribute, + 'searchable' => ($entry['searchable'] ?? false) === true, + 'shownInWidget' => ($entry['shownInWidget'] ?? true) === true, + 'visibility' => $visibility, + ]; + }//end validateDefinition() + + /** + * Check that a value is one of the allowed strings. + * + * @param mixed $value The value. + * @param string[] $allowed Allowed values. + * @param string $name Property name for the message. + * + * @return string The value. + * + * @throws InvalidArgumentException When it is not allowed. + */ + private function oneOf(mixed $value, array $allowed, string $name): string { + if (is_string(value: $value) === false || in_array(needle: $value, haystack: $allowed, strict: true) === false) { + throw new InvalidArgumentException(message: 'Field ' . $name . ' must be one of ' . implode(separator: ', ', array: $allowed)); + } + + return $value; + }//end oneOf() + + /** + * A person's own fields with their values, for the personal settings (REQ-PEX-002). + * + * @param string $userId The person. + * + * @return array> Definitions with `values` and `readOnly`. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function getOwnFields(string $userId): array { + $byKey = $this->groupValues(rows: $this->valueMapper->findByUsers(userIds: [$userId]))[$userId] ?? []; + + $result = []; + foreach ($this->getDefinitions() as $definition) { + $result[] = array_merge( + $definition, + [ + 'values' => $byKey[$definition['key']] ?? [], + 'readOnly' => $definition['source'] !== 'self', + ] + ); + } + + return $result; + }//end getOwnFields() + + /** + * Save a person's own values (REQ-PEX-002). LDAP fields are read-only + * and ignored; unknown keys are rejected. + * + * @param string $userId The person. + * @param array $values Map of field key to a string (text) or a list of strings (tags). + * + * @return array> The fields after saving. + * + * @throws InvalidArgumentException When a key or value is invalid. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function saveOwnValues(string $userId, array $values): array { + $definitions = []; + foreach ($this->getDefinitions() as $definition) { + $definitions[$definition['key']] = $definition; + } + + $clean = []; + foreach ($values as $key => $value) { + $definition = $definitions[$key] ?? null; + if ($definition === null) { + throw new InvalidArgumentException(message: 'Unknown profile field: ' . $key); + } + + if ($definition['source'] !== 'self') { + continue; + } + + $clean[$key] = $this->cleanValues(definition: $definition, value: $value); + } + + foreach ($clean as $key => $list) { + $this->valueMapper->replaceValues(userId: $userId, fieldKey: (string)$key, values: $list, source: 'self'); + } + + return $this->getOwnFields(userId: $userId); + }//end saveOwnValues() + + /** + * Turn a submitted value into a clean list of strings. + * + * @param array $definition The field definition. + * @param mixed $value A string, or a list of strings for tags. + * + * @return string[] + * + * @throws InvalidArgumentException When the value does not fit the type. + */ + private function cleanValues(array $definition, mixed $value): array { + $items = [$value]; + if ($definition['type'] === 'tags') { + if (is_array(value: $value) === false) { + throw new InvalidArgumentException(message: 'Tags must be a list: ' . $definition['key']); + } + + $items = $value; + } + + $result = []; + foreach ($items as $item) { + if ($item === null) { + continue; + } + + if (is_string(value: $item) === false) { + throw new InvalidArgumentException(message: 'A value must be text: ' . $definition['key']); + } + + $item = trim(string: $item); + if ($item === '') { + continue; + } + + if (mb_strlen(string: $item) > self::MAX_VALUE_LENGTH) { + throw new InvalidArgumentException(message: 'A value is longer than ' . self::MAX_VALUE_LENGTH . ' characters: ' . $definition['key']); + } + + // The first spelling of a tag wins. + $result[mb_strtolower(string: $item)] ??= $item; + } + + if (count(value: $result) > self::MAX_TAGS) { + throw new InvalidArgumentException(message: 'At most ' . self::MAX_TAGS . ' tags: ' . $definition['key']); + } + + return array_values(array: $result); + }//end cleanValues() + + /** + * Custom fields shown in the widget that the viewer may see (REQ-PEX-004). + * + * @param string|null $viewerId The viewer, or null for nobody. + * @param string[] $userIds The people on the page. + * + * @return array>> Per user id: `{key, label, type, values}`. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function visibleFieldsFor(?string $viewerId, array $userIds): array { + $definitions = array_filter( + array: $this->getDefinitions(), + callback: static fn (array $definition): bool => $definition['shownInWidget'] === true + ); + if ($definitions === [] || $userIds === []) { + return []; + } + + $grouped = $this->groupValues(rows: $this->valueMapper->findByUsers(userIds: $userIds)); + + $result = []; + foreach ($grouped as $userId => $byKey) { + foreach ($definitions as $definition) { + $values = $byKey[$definition['key']] ?? []; + if ($values === [] || $this->canSee(viewerId: $viewerId, ownerId: (string)$userId, definition: $definition) === false) { + continue; + } + + $result[$userId][] = [ + 'key' => $definition['key'], + 'label' => $definition['label'], + 'type' => $definition['type'], + 'values' => $values, + ]; + } + } + + return $result; + }//end visibleFieldsFor() + + /** + * People whose searchable fields contain the query and the viewer may + * see that field (REQ-PEX-003, REQ-PEX-004). + * + * @param string|null $viewerId The viewer. + * @param string $query The search text. + * + * @return string[] Matching user ids. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function findMatchingUserIds(?string $viewerId, string $query): array { + $needle = mb_strtolower(string: trim(string: $query)); + if ($needle === '') { + return []; + } + + $definitions = []; + foreach ($this->getDefinitions() as $definition) { + if ($definition['searchable'] === true) { + $definitions[$definition['key']] = $definition; + } + } + + $matches = []; + foreach ($this->valueMapper->search(needle: $needle) as $row) { + $owner = $row->getUserId(); + if ($this->rowMatchesFor(viewerId: $viewerId, row: $row, definitions: $definitions) === true) { + $matches[$owner] = true; + } + } + + return array_keys(array: $matches); + }//end findMatchingUserIds() + + /** + * Whether a matching row may count for this viewer. + * + * @param string|null $viewerId The viewer. + * @param ProfileValue $row The matching row. + * @param array> $definitions Searchable definitions by key. + * + * @return bool + */ + private function rowMatchesFor(?string $viewerId, ProfileValue $row, array $definitions): bool { + $key = $row->getFieldKey(); + $owner = $row->getUserId(); + + if (isset(self::MIRRORED_STANDARD_FIELDS[$key]) === true) { + return self::scopeAllows(scope: $row->getScope(), viewerId: $viewerId, ownerId: $owner); + } + + $definition = $definitions[$key] ?? null; + if ($definition === null) { + return false; + } + + return $this->canSee(viewerId: $viewerId, ownerId: $owner, definition: $definition); + }//end rowMatchesFor() + + /** + * Whether a standard field with this Nextcloud scope is visible to the viewer. + * A private field is visible to its owner only; the other scopes reach + * every signed-in user of this instance. + * + * @param string|null $scope The property scope. + * @param string|null $viewerId The viewer. + * @param string $ownerId The owner. + * + * @return bool + * + * @spec openspec/specs/people-widget/spec.md + */ + public static function scopeAllows(?string $scope, ?string $viewerId, string $ownerId): bool { + if ($viewerId !== null && $viewerId === $ownerId) { + return true; + } + + if ($viewerId === null) { + return false; + } + + return $scope !== IAccountManager::SCOPE_PRIVATE; + }//end scopeAllows() + + /** + * Whether the viewer may see a custom field of the owner. + * + * @param string|null $viewerId The viewer. + * @param string $ownerId The owner. + * @param array $definition The field definition. + * + * @return bool + * + * @spec openspec/specs/people-widget/spec.md + */ + public function canSee(?string $viewerId, string $ownerId, array $definition): bool { + if ($viewerId === null) { + return false; + } + + if ($viewerId === $ownerId || $definition['visibility'] === 'everyone') { + return true; + } + + $shared = array_intersect( + $this->groupsOf(userId: $viewerId), + $this->groupsOf(userId: $ownerId) + ); + + return $shared !== []; + }//end canSee() + + /** + * Group ids of a user, memoised. + * + * @param string $userId The user. + * + * @return string[] + */ + private function groupsOf(string $userId): array { + if (isset($this->groupCache[$userId]) === false) { + $this->groupCache[$userId] = $this->adminTemplateService->getUserGroupIdsFor(userId: $userId); + } + + return $this->groupCache[$userId]; + }//end groupsOf() + + /** + * Group rows by user and field key. + * + * @param ProfileValue[] $rows Rows. + * + * @return array> + */ + private function groupValues(array $rows): array { + $result = []; + foreach ($rows as $row) { + $result[$row->getUserId()][$row->getFieldKey()][] = $row->getValue(); + } + + return $result; + }//end groupValues() + + /** + * Mirror a person's searchable standard fields with their scope (REQ-PEX-004). + * + * @param IUser $user The person. + * + * @return void + * + * @spec openspec/specs/people-widget/spec.md + */ + public function mirrorStandardFields(IUser $user): void { + try { + $account = $this->accountManager->getAccount(user: $user); + } catch (Exception $e) { + $this->logger->debug(message: 'Profile mirror: no account for ' . $user->getUID() . ': ' . $e->getMessage()); + return; + } + + foreach (self::MIRRORED_STANDARD_FIELDS as $key => $property) { + $value = ''; + $scope = null; + try { + $prop = $account->getProperty(property: $property); + $value = trim(string: $prop->getValue()); + $scope = $prop->getScope(); + } catch (Exception) { + $value = ''; + } + + $values = []; + if ($value !== '') { + $values = [$value]; + } + + $this->valueMapper->replaceValues( + userId: $user->getUID(), + fieldKey: $key, + values: $values, + source: 'nextcloud', + scope: $scope + ); + }//end foreach + }//end mirrorStandardFields() + + /** + * Read a person's LDAP-sourced fields (REQ-PEX-001). Does nothing when + * `user_ldap` is not available or the account does not come from LDAP. + * + * @param IUser $user The person. + * + * @return int Number of fields synced. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function syncLdapFields(IUser $user): int { + $definitions = array_filter( + array: $this->getDefinitions(), + callback: static fn (array $definition): bool => $definition['source'] === 'ldap' + ); + if ($definitions === [] || $user->getBackendClassName() !== 'LDAP') { + return 0; + } + + if ($this->ldapProviderFactory->isAvailable() === false) { + return 0; + } + + $synced = 0; + try { + $provider = $this->ldapProviderFactory->getLDAPProvider(); + foreach ($definitions as $definition) { + $raw = $provider->getMultiValueUserAttribute(uid: $user->getUID(), attribute: $definition['ldapAttribute']); + $values = $this->cleanLdapValues(definition: $definition, raw: $raw); + $this->valueMapper->replaceValues(userId: $user->getUID(), fieldKey: $definition['key'], values: $values, source: 'ldap'); + $synced++; + } + } catch (Exception $e) { + $this->logger->warning(message: 'Profile LDAP sync failed for ' . $user->getUID() . ': ' . $e->getMessage()); + } + + return $synced; + }//end syncLdapFields() + + /** + * Clean the values read from LDAP: a text field keeps its first value. + * + * @param array $definition The field definition. + * @param array $raw Values from LDAP. + * + * @return string[] + */ + private function cleanLdapValues(array $definition, array $raw): array { + $values = []; + foreach ($raw as $item) { + $item = mb_substr(string: trim(string: (string)$item), start: 0, length: self::MAX_VALUE_LENGTH); + if ($item !== '') { + $values[mb_strtolower(string: $item)] ??= $item; + } + } + + $values = array_values(array: $values); + if ($definition['type'] === 'text') { + return array_slice(array: $values, offset: 0, length: 1); + } + + return array_slice(array: $values, offset: 0, length: self::MAX_TAGS); + }//end cleanLdapValues() + + /** + * Remove every value of a deleted person. + * + * @param string $userId The person. + * + * @return void + * + * @spec openspec/specs/people-widget/spec.md + */ + public function deleteUser(string $userId): void { + $this->valueMapper->deleteByUser(userId: $userId); + }//end deleteUser() +}//end class diff --git a/lib/Settings/LaunchPadPersonal.php b/lib/Settings/LaunchPadPersonal.php new file mode 100644 index 000000000..f702bafcb --- /dev/null +++ b/lib/Settings/LaunchPadPersonal.php @@ -0,0 +1,90 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @version GIT:auto + * @link https://conduction.nl + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace OCA\LaunchPad\Settings; + +use OCA\LaunchPad\AppInfo\Application; +use OCA\LaunchPad\Service\ProfileFieldService; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\Settings\ISettings; +use OCP\Util; + +/** + * Personal settings form for custom profile fields. + * + * @spec openspec/specs/people-widget/spec.md + */ +class LaunchPadPersonal implements ISettings { + /** + * Constructor. + * + * @param ProfileFieldService $profileFields Profile field service. + * + * @spec openspec/specs/people-widget/spec.md + */ + public function __construct( + private readonly ProfileFieldService $profileFields, + ) { + }//end __construct() + + /** + * The form: an empty mount point for the personal settings bundle. + * + * @return TemplateResponse + * + * @spec openspec/specs/people-widget/spec.md + */ + public function getForm(): TemplateResponse { + Util::addScript(application: Application::APP_ID, file: 'launchpad-personal'); + + return new TemplateResponse(appName: Application::APP_ID, templateName: 'settings/personal'); + }//end getForm() + + /** + * The section: the personal information page, next to the standard profile. + * Null hides the form while no field is defined. + * + * @return string|null + * + * @spec openspec/specs/people-widget/spec.md + */ + public function getSection(): ?string { + if ($this->profileFields->getDefinitions() === []) { + return null; + } + + return 'personal-info'; + }//end getSection() + + /** + * Position within the section. + * + * @return int + * + * @spec openspec/specs/people-widget/spec.md + */ + public function getPriority(): int { + return 90; + }//end getPriority() +}//end class diff --git a/lib/actions.seed.json b/lib/actions.seed.json index 470ae2f32..f3c39cf91 100644 --- a/lib/actions.seed.json +++ b/lib/actions.seed.json @@ -60,6 +60,10 @@ "metadata-admin.update-field": ["admin"], "metadata-admin.delete-field": ["admin"], "people-widget.get-users": ["admin"], + "profile-fields.get-own": ["admin", "@all"], + "profile-fields.save-own": ["admin", "@all"], + "profile-fields.get-definitions": ["admin"], + "profile-fields.save-definitions": ["admin"], "resource-serve.get-resource": ["admin", "@all"], "resource-serve.list-resources": ["admin", "@all"], "rule.get-rules": ["admin"], diff --git a/templates/settings/personal.php b/templates/settings/personal.php new file mode 100644 index 000000000..19965281a --- /dev/null +++ b/templates/settings/personal.php @@ -0,0 +1,8 @@ + + * SPDX-License-Identifier: EUPL-1.2 + */ +?> + +
diff --git a/tests/Unit/Controller/ProfileFieldsControllerTest.php b/tests/Unit/Controller/ProfileFieldsControllerTest.php new file mode 100644 index 000000000..58134c901 --- /dev/null +++ b/tests/Unit/Controller/ProfileFieldsControllerTest.php @@ -0,0 +1,119 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace Unit\Controller; + +use OCA\LaunchPad\Controller\ProfileFieldsController; +use OCA\LaunchPad\Db\AdminSetting; +use OCA\LaunchPad\Db\AdminSettingMapper; +use OCA\LaunchPad\Service\ActionAuthService; +use OCA\LaunchPad\Service\AdminTemplateService; +use OCA\LaunchPad\Service\ProfileFieldService; +use OCP\Accounts\IAccountManager; +use OCP\AppFramework\Http; +use OCP\IGroupManager; +use OCP\IRequest; +use OCP\IUser; +use OCP\IUserSession; +use OCP\LDAP\ILDAPProviderFactory; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Unit\Support\InMemoryProfileValues; + +class ProfileFieldsControllerTest extends TestCase { + /** + * Stored admin settings. + * + * @var array + */ + private array $settings = []; + + private InMemoryProfileValues $values; + + private function controller(string $uid, bool $admin): ProfileFieldsController { + $settingMapper = $this->createMock(AdminSettingMapper::class); + $settingMapper->method('getValue')->willReturnCallback( + fn (string $key, mixed $default = null): mixed => $this->settings[$key] ?? $default + ); + $settingMapper->method('setSetting')->willReturnCallback( + function (string $key, mixed $value): AdminSetting { + $this->settings[$key] = $value; + return new AdminSetting(); + } + ); + $this->values ??= new InMemoryProfileValues(); + + $service = new ProfileFieldService( + settingMapper: $settingMapper, + valueMapper: $this->values, + accountManager: $this->createMock(IAccountManager::class), + adminTemplateService: $this->createMock(AdminTemplateService::class), + ldapProviderFactory: $this->createMock(ILDAPProviderFactory::class), + logger: $this->createMock(LoggerInterface::class), + ); + + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn($uid); + $session = $this->createMock(IUserSession::class); + $session->method('getUser')->willReturn($user); + $groups = $this->createMock(IGroupManager::class); + $groups->method('isAdmin')->willReturn($admin); + + return new ProfileFieldsController( + request: $this->createMock(IRequest::class), + profileFields: $service, + actionAuth: $this->createMock(ActionAuthService::class), + userSession: $session, + groupManager: $groups, + ); + }//end controller() + + public function testANonAdminCannotReadOrWriteDefinitions(): void { + $controller = $this->controller(uid: 'sanne', admin: false); + + $this->assertSame(Http::STATUS_FORBIDDEN, $controller->getDefinitions()->getStatus()); + $this->assertSame(Http::STATUS_FORBIDDEN, $controller->saveDefinitions(fields: [['key' => 'x', 'label' => 'X']])->getStatus()); + $this->assertSame([], $this->settings, 'a refused write must not store anything'); + }//end testANonAdminCannotReadOrWriteDefinitions() + + public function testAnAdminDefinesAndAPersonSavesOnlyTheirOwnValues(): void { + $saved = $this->controller(uid: 'noor', admin: true)->saveDefinitions( + fields: [['key' => 'expertise', 'label' => 'Expertise', 'type' => 'tags', 'searchable' => true]] + ); + $this->assertSame(Http::STATUS_OK, $saved->getStatus()); + + $pieter = $this->controller(uid: 'pieter', admin: false); + $response = $pieter->saveOwn(values: ['expertise' => ['subsidies']]); + $this->assertSame(Http::STATUS_OK, $response->getStatus()); + $this->assertSame(['subsidies'], $response->getData()['fields'][0]['values']); + $this->assertSame('pieter', $this->values->rows[0]->getUserId(), 'the value must land on the caller'); + + $sanne = $this->controller(uid: 'sanne', admin: false); + $this->assertSame([], $sanne->getOwn()->getData()['fields'][0]['values'], 'Sanne must not read Pieter\'s values as her own'); + }//end testAnAdminDefinesAndAPersonSavesOnlyTheirOwnValues() + + public function testAnInvalidValueIsABadRequest(): void { + $this->controller(uid: 'noor', admin: true)->saveDefinitions(fields: [['key' => 'expertise', 'label' => 'Expertise', 'type' => 'tags']]); + + $response = $this->controller(uid: 'pieter', admin: false)->saveOwn(values: ['expertise' => 'not a list']); + $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus()); + }//end testAnInvalidValueIsABadRequest() +}//end class diff --git a/tests/Unit/Database/ProfileValuesDatabaseTest.php b/tests/Unit/Database/ProfileValuesDatabaseTest.php new file mode 100644 index 000000000..b46cbf45a --- /dev/null +++ b/tests/Unit/Database/ProfileValuesDatabaseTest.php @@ -0,0 +1,55 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace Unit\Database; + +use OCA\LaunchPad\Db\ProfileValueMapper; +use OCP\Server; + +/** + * @SuppressWarnings(PHPMD.StaticAccess) Server::get() is the only way in from a test. + */ +class ProfileValuesDatabaseTest extends RealDatabaseTestCase { + /** + * A tag is stored per row and found on part of the word, case-insensitively. + * + * @return void + */ + public function testATagIsStoredAndFoundOnPartOfTheWord(): void { + $owner = $this->makeUser(prefix: 'db-profile'); + $this->cleanup(function () use ($owner): void { + $this->deleteRows('launchpad_profile_values', 'user_id', $owner); + }); + + $mapper = Server::get(ProfileValueMapper::class); + $mapper->replaceValues(userId: $owner, fieldKey: 'expertise', values: ['Subsidies', 'Omgevingswet'], source: 'self'); + + $rows = $this->storedRows('launchpad_profile_values', 'user_id', $owner); + $this->assertCount(2, $rows); + $this->assertColumnsFilled($rows[0], ['user_id', 'field_key', 'value', 'value_search', 'source', 'updated_at']); + + $found = array_map(static fn ($row): string => $row->getUserId(), $mapper->search(needle: 'subsidie')); + $this->assertContains($owner, $found); + + $mapper->replaceValues(userId: $owner, fieldKey: 'expertise', values: ['Omgevingswet'], source: 'self'); + $this->assertCount(1, $this->storedRows('launchpad_profile_values', 'user_id', $owner), 'a save replaces the old tags'); + }//end testATagIsStoredAndFoundOnPartOfTheWord() +}//end class diff --git a/tests/Unit/Service/ActionAuthBaselineTest.php b/tests/Unit/Service/ActionAuthBaselineTest.php index 052d0e218..6dc033c92 100644 --- a/tests/Unit/Service/ActionAuthBaselineTest.php +++ b/tests/Unit/Service/ActionAuthBaselineTest.php @@ -84,6 +84,8 @@ class ActionAuthBaselineTest extends TestCase { 'metadata-admin.update-field', 'metadata-admin.delete-field', 'people-widget.get-users', + 'profile-fields.get-definitions', + 'profile-fields.save-definitions', 'rule.get-rules', 'rule.add-rule', 'rule.update-rule', @@ -121,6 +123,9 @@ class ActionAuthBaselineTest extends TestCase { // The `admin.` prefix is the controller's, not a privilege level: // getMyRole() only ever answers for the caller. 'admin.get-my-role', + // REQ-PEX-002: every person fills their own profile fields. + 'profile-fields.get-own', + 'profile-fields.save-own', ]; /** @var IAppConfig&MockObject */ diff --git a/tests/Unit/Service/PeopleWidgetServiceTest.php b/tests/Unit/Service/PeopleWidgetServiceTest.php index 18b559b8c..387e2adac 100644 --- a/tests/Unit/Service/PeopleWidgetServiceTest.php +++ b/tests/Unit/Service/PeopleWidgetServiceTest.php @@ -26,7 +26,10 @@ namespace Unit\Service; use InvalidArgumentException; +use OCA\LaunchPad\Db\AdminSetting; +use OCA\LaunchPad\Db\AdminSettingMapper; use OCA\LaunchPad\Service\AdminTemplateService; +use OCA\LaunchPad\Service\ProfileFieldService; use OCA\LaunchPad\Service\PeopleWidgetService; use OCP\Accounts\IAccount; use OCP\Accounts\IAccountManager; @@ -36,8 +39,11 @@ use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; +use OCP\LDAP\ILDAPProviderFactory; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Unit\Support\InMemoryProfileValues; /** * Tests for the People widget backend service. @@ -73,6 +79,17 @@ class PeopleWidgetServiceTest extends TestCase { private PeopleWidgetService $service; + private ProfileFieldService $profileFields; + + private InMemoryProfileValues $profileValues; + + /** + * Stored admin settings. + * + * @var array + */ + private array $settings = []; + /** * @return void */ @@ -93,12 +110,34 @@ protected function setUp(): void { // Default: any user has no groups. Tests can override per-call. $this->adminTemplateService->method('getUserGroupIdsFor')->willReturn([]); + // The real profile field service, over in-memory values and settings. + $settingMapper = $this->createMock(originalClassName: AdminSettingMapper::class); + $settingMapper->method('getValue')->willReturnCallback( + callback: fn (string $key, mixed $default = null): mixed => $this->settings[$key] ?? $default + ); + $settingMapper->method('setSetting')->willReturnCallback( + callback: function (string $key, mixed $value): AdminSetting { + $this->settings[$key] = $value; + return new AdminSetting(); + } + ); + $this->profileValues = new InMemoryProfileValues(); + $this->profileFields = new ProfileFieldService( + settingMapper: $settingMapper, + valueMapper: $this->profileValues, + accountManager: $this->accountManager, + adminTemplateService: $this->adminTemplateService, + ldapProviderFactory: $this->createMock(originalClassName: ILDAPProviderFactory::class), + logger: $this->createMock(originalClassName: LoggerInterface::class), + ); + $this->service = new PeopleWidgetService( userManager: $this->userManager, groupManager: $this->groupManager, accountManager: $this->accountManager, urlGenerator: $this->urlGenerator, adminTemplateService: $this->adminTemplateService, + profileFields: $this->profileFields, ); }//end setUp() @@ -385,7 +424,7 @@ public function testBirthdateIsNormalisedToIso(): void { ); $this->accountManager->method('getAccount')->willReturn($account); - $result = $this->service->listUsers(); + $result = $this->service->listUsers(viewerId: 'viewer'); $this->assertSame( expected: '1990-06-10', @@ -467,6 +506,96 @@ function (string $pattern, ?int $limit = null, ?int $offset = null) use (&$captu // Helpers // --------------------------------------------------------------- + // --------------------------------------------------------------- + // Search and custom fields (widgets-people-expertise-and-fields) + // --------------------------------------------------------------- + + /** + * REQ-PEX-003 scenario "Sanne finds the subsidies expert": Pieter is not + * on the first page and his name does not contain the query; his tag does. + * + * @return void + */ + public function testSearchFindsPieterByHisTagAcrossTheDirectory(): void { + $pieter = $this->makeUser(uid: 'pieter', display: 'Pieter de Vries'); + $anna = $this->makeUser(uid: 'anna', display: 'Anna Subsidiemedewerker'); + $this->userManager->expects($this->once())->method('search') + ->with('subsidie', PeopleWidgetService::SEARCH_CANDIDATE_CAP) + ->willReturn([$anna]); + $this->userManager->method('get')->willReturnMap([['pieter', $pieter]]); + $this->userManager->expects($this->never())->method('searchDisplayName'); + $this->accountManager->method('getAccount')->willReturn($this->emptyAccount()); + + $this->profileFields->saveDefinitions(raw: [['key' => 'expertise', 'label' => 'Expertise', 'type' => 'tags', 'searchable' => true]]); + $this->profileFields->saveOwnValues(userId: 'pieter', values: ['expertise' => ['subsidies', 'Omgevingswet']]); + + $result = $this->service->listUsers(query: 'subsidie', viewerId: 'sanne'); + + $uids = array_column(array: $result['users'], column_key: 'uid'); + $this->assertSame(expected: ['anna', 'pieter'], actual: $uids); + $this->assertSame(expected: 2, actual: $result['total']); + $this->assertSame( + expected: [['key' => 'expertise', 'label' => 'Expertise', 'type' => 'tags', 'values' => ['subsidies', 'Omgevingswet']]], + actual: $result['users'][1]['customFields'] + ); + $this->assertSame(expected: [], actual: $result['users'][0]['customFields']); + }//end testSearchFindsPieterByHisTagAcrossTheDirectory() + + public function testAOneCharacterQueryIsRefused(): void { + $this->expectException(exception: InvalidArgumentException::class); + $this->service->listUsers(query: 's', viewerId: 'sanne'); + }//end testAOneCharacterQueryIsRefused() + + public function testSearchStaysInsideTheWidgetsGroups(): void { + $pieter = $this->makeUser(uid: 'pieter', display: 'Pieter'); + $karin = $this->makeUser(uid: 'karin', display: 'Karin'); + $this->userManager->method('search')->willReturn([$pieter, $karin]); + $group = $this->createMock(originalClassName: IGroup::class); + $group->method('getUsers')->willReturn([$karin]); + $this->groupManager->method('get')->willReturn($group); + $this->accountManager->method('getAccount')->willReturn($this->emptyAccount()); + + $result = $this->service->listUsers( + filters: [['fieldName' => 'group', 'operator' => 'in', 'values' => ['kcc']]], + query: 'ie', + viewerId: 'sanne' + ); + + $this->assertSame(expected: ['karin'], actual: array_column(array: $result['users'], column_key: 'uid')); + }//end testSearchStaysInsideTheWidgetsGroups() + + /** + * REQ-PEX-004 scenario "Private biography is not searchable": Karin does + * not match on her private biography, and her card does not show it. + * + * @return void + */ + public function testAPrivateBiographyNeitherMatchesNorShows(): void { + $karin = $this->makeUser(uid: 'karin', display: 'Karin'); + $account = $this->makeAccount( + properties: [ + IAccountManager::PROPERTY_BIOGRAPHY => 'Ik weet alles van subsidies', + IAccountManager::PROPERTY_ROLE => 'Beleidsmedewerker', + ], + scopes: [IAccountManager::PROPERTY_BIOGRAPHY => IAccountManager::SCOPE_PRIVATE] + ); + $this->accountManager->method('getAccount')->willReturn($account); + $this->profileFields->mirrorStandardFields(user: $karin); + + $this->userManager->method('search')->willReturn([]); + $this->userManager->method('get')->willReturnMap([['karin', $karin]]); + $searched = $this->service->listUsers(query: 'subsidies', viewerId: 'sanne'); + $this->assertSame(expected: [], actual: $searched['users'], message: 'Karin matched on her private biography'); + + $this->wireDirectory(orderedUsers: [$karin]); + $card = $this->service->listUsers(viewerId: 'sanne')['users'][0]; + $this->assertArrayNotHasKey(key: 'biography', array: $card); + $this->assertSame(expected: 'Beleidsmedewerker', actual: $card['role'], message: 'CONTROL: a local field still shows'); + + $own = $this->service->listUsers(viewerId: 'karin')['users'][0]; + $this->assertSame(expected: 'Ik weet alles van subsidies', actual: $own['biography'], message: 'CONTROL: Karin sees her own biography'); + }//end testAPrivateBiographyNeitherMatchesNorShows() + /** * Wire the user-directory backend for a no-group-filter, * display-name-sorted listing: a bounded `searchDisplayName` that @@ -535,14 +664,15 @@ private function emptyAccount(): IAccount { * * @return IAccount&MockObject */ - private function makeAccount(array $properties): IAccount { + private function makeAccount(array $properties, array $scopes = []): IAccount { $account = $this->createMock(originalClassName: IAccount::class); $account->method('getProperty') ->willReturnCallback( - callback: function (string $name) use ($properties): IAccountProperty { + callback: function (string $name) use ($properties, $scopes): IAccountProperty { $prop = $this->createMock(originalClassName: IAccountProperty::class); $prop->method('getValue')->willReturn($properties[$name] ?? ''); $prop->method('getName')->willReturn($name); + $prop->method('getScope')->willReturn($scopes[$name] ?? IAccountManager::SCOPE_LOCAL); return $prop; } ); diff --git a/tests/Unit/Service/ProfileFieldServiceTest.php b/tests/Unit/Service/ProfileFieldServiceTest.php new file mode 100644 index 000000000..256dff610 --- /dev/null +++ b/tests/Unit/Service/ProfileFieldServiceTest.php @@ -0,0 +1,318 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace Unit\Service; + +use InvalidArgumentException; +use OCA\LaunchPad\Db\AdminSettingMapper; +use OCA\LaunchPad\Service\AdminTemplateService; +use OCA\LaunchPad\Service\ProfileFieldService; +use OCP\Accounts\IAccount; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\IAccountProperty; +use OCP\IUser; +use OCP\LDAP\ILDAPProvider; +use OCP\LDAP\ILDAPProviderFactory; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Unit\Support\InMemoryProfileValues; + +/** + * @SuppressWarnings(PHPMD.TooManyPublicMethods) One test per scenario. + */ +class ProfileFieldServiceTest extends TestCase { + /** + * Stored admin settings. + * + * @var array + */ + private array $settings = []; + + private InMemoryProfileValues $values; + + private $accountManager; + + /** + * Accounts per user id. + * + * @var array + */ + private array $accounts = []; + + private $ldapFactory; + + /** + * Group ids per user. + * + * @var array + */ + private array $groups = []; + + private ProfileFieldService $service; + + protected function setUp(): void { + parent::setUp(); + + $settingMapper = $this->createMock(AdminSettingMapper::class); + $settingMapper->method('getValue')->willReturnCallback( + fn (string $key, mixed $default = null): mixed => $this->settings[$key] ?? $default + ); + $settingMapper->method('setSetting')->willReturnCallback( + function (string $key, mixed $value) { + $this->settings[$key] = $value; + return new \OCA\LaunchPad\Db\AdminSetting(); + } + ); + + $templates = $this->createMock(AdminTemplateService::class); + $templates->method('getUserGroupIdsFor')->willReturnCallback( + fn (string $userId): array => $this->groups[$userId] ?? [] + ); + + $this->values = new InMemoryProfileValues(); + $this->accountManager = $this->createMock(IAccountManager::class); + $this->accountManager->method('getAccount')->willReturnCallback( + fn (IUser $user): IAccount => $this->accounts[$user->getUID()] + ); + $this->ldapFactory = $this->createMock(ILDAPProviderFactory::class); + + $this->service = new ProfileFieldService( + settingMapper: $settingMapper, + valueMapper: $this->values, + accountManager: $this->accountManager, + adminTemplateService: $templates, + ldapProviderFactory: $this->ldapFactory, + logger: $this->createMock(LoggerInterface::class), + ); + }//end setUp() + + /** + * The demo definitions: office (LDAP), cost centre (groups only), expertise (tags). + * + * @return void + */ + private function defineFields(): void { + $this->service->saveDefinitions( + raw: [ + ['key' => 'office', 'label' => 'Kantoorlocatie', 'type' => 'text', 'source' => 'ldap', 'ldapAttribute' => 'physicalDeliveryOfficeName', 'shownInWidget' => true], + ['key' => 'cost_centre', 'label' => 'Kostenplaats', 'type' => 'text', 'source' => 'self', 'searchable' => true, 'visibility' => 'groups'], + ['key' => 'expertise', 'label' => 'Expertise', 'type' => 'tags', 'source' => 'self', 'searchable' => true], + ] + ); + }//end defineFields() + + private function user(string $uid, string $backend = 'Database'): IUser { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn($uid); + $user->method('getBackendClassName')->willReturn($backend); + return $user; + }//end user() + + public function testDefinitionsAreValidatedAndNormalised(): void { + $this->defineFields(); + $definitions = $this->service->getDefinitions(); + + $this->assertCount(3, $definitions); + $this->assertSame('everyone', $definitions[2]['visibility']); + $this->assertFalse($definitions[0]['searchable']); + $this->assertSame('', $definitions[1]['ldapAttribute']); + }//end testDefinitionsAreValidatedAndNormalised() + + public function testMoreThanTenFieldsIsRefused(): void { + $raw = []; + for ($i = 0; $i < 11; $i++) { + $raw[] = ['key' => 'f' . $i, 'label' => 'Field ' . $i]; + } + + $this->expectException(InvalidArgumentException::class); + $this->service->saveDefinitions(raw: $raw); + }//end testMoreThanTenFieldsIsRefused() + + public function testAnLdapFieldNeedsAnAttribute(): void { + $this->expectException(InvalidArgumentException::class); + $this->service->saveDefinitions(raw: [['key' => 'office', 'label' => 'Office', 'source' => 'ldap']]); + }//end testAnLdapFieldNeedsAnAttribute() + + public function testDuplicateKeysAndBadTypesAreRefused(): void { + try { + $this->service->saveDefinitions(raw: [['key' => 'a', 'label' => 'A'], ['key' => 'a', 'label' => 'B']]); + $this->fail('duplicate key accepted'); + } catch (InvalidArgumentException) { + $this->addToAssertionCount(1); + } + + $this->expectException(InvalidArgumentException::class); + $this->service->saveDefinitions(raw: [['key' => 'a', 'label' => 'A', 'type' => 'number']]); + }//end testDuplicateKeysAndBadTypesAreRefused() + + /** + * REQ-PEX-002 scenario "Pieter adds his subjects". + * + * @return void + */ + public function testPieterAddsHisSubjectsAndLdapFieldsStayReadOnly(): void { + $this->defineFields(); + + $fields = $this->service->saveOwnValues( + userId: 'pieter', + values: [ + 'expertise' => ['subsidies', ' Omgevingswet ', 'SUBSIDIES', ''], + 'office' => 'I typed this', + ] + ); + + $byKey = array_column($fields, null, 'key'); + $this->assertSame(['subsidies', 'Omgevingswet'], $byKey['expertise']['values']); + $this->assertSame([], $byKey['office']['values'], 'an LDAP field must not take a self edit'); + $this->assertTrue($byKey['office']['readOnly']); + $this->assertFalse($byKey['expertise']['readOnly']); + }//end testPieterAddsHisSubjectsAndLdapFieldsStayReadOnly() + + public function testUnknownKeysAndWrongShapesAreRefused(): void { + $this->defineFields(); + + try { + $this->service->saveOwnValues(userId: 'pieter', values: ['nope' => 'x']); + $this->fail('unknown key accepted'); + } catch (InvalidArgumentException) { + $this->addToAssertionCount(1); + } + + $this->expectException(InvalidArgumentException::class); + $this->service->saveOwnValues(userId: 'pieter', values: ['expertise' => 'not a list']); + }//end testUnknownKeysAndWrongShapesAreRefused() + + /** + * REQ-PEX-001 scenario "Office location from LDAP", with a stubbed provider. + * + * @return void + */ + public function testLdapFieldsSyncForLdapAccountsOnly(): void { + $this->defineFields(); + $provider = $this->createMock(ILDAPProvider::class); + $provider->method('getMultiValueUserAttribute') + ->with('pieter', 'physicalDeliveryOfficeName') + ->willReturn(['Stadhuis, 3e verdieping', 'ignored second value']); + $this->ldapFactory->method('isAvailable')->willReturn(true); + $this->ldapFactory->method('getLDAPProvider')->willReturn($provider); + + $this->assertSame(0, $this->service->syncLdapFields(user: $this->user(uid: 'sanne')), 'a database account is not read from LDAP'); + $this->assertSame(1, $this->service->syncLdapFields(user: $this->user(uid: 'pieter', backend: 'LDAP'))); + + $shown = $this->service->visibleFieldsFor(viewerId: 'sanne', userIds: ['pieter']); + $this->assertSame( + [['key' => 'office', 'label' => 'Kantoorlocatie', 'type' => 'text', 'values' => ['Stadhuis, 3e verdieping']]], + $shown['pieter'] + ); + }//end testLdapFieldsSyncForLdapAccountsOnly() + + public function testLdapSyncDoesNothingWithoutUserLdap(): void { + $this->defineFields(); + $this->ldapFactory->method('isAvailable')->willReturn(false); + $this->ldapFactory->expects($this->never())->method('getLDAPProvider'); + + $this->assertSame(0, $this->service->syncLdapFields(user: $this->user(uid: 'pieter', backend: 'LDAP'))); + }//end testLdapSyncDoesNothingWithoutUserLdap() + + /** + * REQ-PEX-003: a tag matches on a part of the word, for any signed-in viewer. + * + * @return void + */ + public function testSearchFindsTheSubsidiesExpertByPartOfTheTag(): void { + $this->defineFields(); + $this->service->saveOwnValues(userId: 'pieter', values: ['expertise' => ['subsidies']]); + + $this->assertSame(['pieter'], $this->service->findMatchingUserIds(viewerId: 'sanne', query: 'Subsidie')); + $this->assertSame([], $this->service->findMatchingUserIds(viewerId: null, query: 'subsidie')); + }//end testSearchFindsTheSubsidiesExpertByPartOfTheTag() + + /** + * REQ-PEX-004 scenario "Group-only field". + * + * @return void + */ + public function testAGroupOnlyFieldNeitherShowsNorMatchesOutsideTheGroup(): void { + $this->defineFields(); + $this->service->saveDefinitions( + raw: array_map( + static fn (array $definition): array => array_merge($definition, ['shownInWidget' => true]), + $this->service->getDefinitions() + ) + ); + $this->service->saveOwnValues(userId: 'pieter', values: ['cost_centre' => 'KP-4711']); + $this->groups = ['pieter' => ['finance'], 'sanne' => ['kcc'], 'karin' => ['finance']]; + + $this->assertSame([], $this->service->findMatchingUserIds(viewerId: 'sanne', query: 'kp-47')); + $this->assertArrayNotHasKey('pieter', $this->service->visibleFieldsFor(viewerId: 'sanne', userIds: ['pieter'])); + + $this->assertSame(['pieter'], $this->service->findMatchingUserIds(viewerId: 'karin', query: 'kp-47'), 'CONTROL: a colleague in the group does match'); + $this->assertArrayHasKey('pieter', $this->service->visibleFieldsFor(viewerId: 'karin', userIds: ['pieter'])); + }//end testAGroupOnlyFieldNeitherShowsNorMatchesOutsideTheGroup() + + public function testANotSearchableFieldDoesNotMatch(): void { + $this->service->saveDefinitions(raw: [['key' => 'room', 'label' => 'Room', 'searchable' => false]]); + $this->service->saveOwnValues(userId: 'pieter', values: ['room' => 'B-204']); + + $this->assertSame([], $this->service->findMatchingUserIds(viewerId: 'sanne', query: 'b-204')); + }//end testANotSearchableFieldDoesNotMatch() + + /** + * REQ-PEX-004 scenario "Private biography is not searchable". + * + * @return void + */ + public function testAPrivateBiographyIsMirroredButNeverMatchesForOthers(): void { + $this->mirrorBiography(uid: 'karin', text: 'Ik weet alles van subsidies', scope: IAccountManager::SCOPE_PRIVATE); + $this->mirrorBiography(uid: 'pieter', text: 'Subsidies en fondsen', scope: IAccountManager::SCOPE_LOCAL); + + $this->assertSame(['pieter'], $this->service->findMatchingUserIds(viewerId: 'sanne', query: 'subsidies')); + $this->assertContains('karin', $this->service->findMatchingUserIds(viewerId: 'karin', query: 'subsidies'), 'CONTROL: the owner matches her own private field'); + }//end testAPrivateBiographyIsMirroredButNeverMatchesForOthers() + + public function testDeletingAUserRemovesTheirValues(): void { + $this->defineFields(); + $this->service->saveOwnValues(userId: 'pieter', values: ['expertise' => ['subsidies']]); + $this->service->deleteUser(userId: 'pieter'); + + $this->assertSame([], $this->values->rows); + }//end testDeletingAUserRemovesTheirValues() + + private function mirrorBiography(string $uid, string $text, string $scope): void { + $account = $this->createMock(IAccount::class); + $account->method('getProperty')->willReturnCallback( + function (string $property) use ($text, $scope) { + $prop = $this->createMock(IAccountProperty::class); + $value = ''; + if ($property === IAccountManager::PROPERTY_BIOGRAPHY) { + $value = $text; + } + + $prop->method('getValue')->willReturn($value); + $prop->method('getScope')->willReturn($scope); + return $prop; + } + ); + $this->accounts[$uid] = $account; + + $this->service->mirrorStandardFields(user: $this->user(uid: $uid)); + }//end mirrorBiography() +}//end class diff --git a/tests/Unit/Support/InMemoryProfileValues.php b/tests/Unit/Support/InMemoryProfileValues.php new file mode 100644 index 000000000..7972be1a2 --- /dev/null +++ b/tests/Unit/Support/InMemoryProfileValues.php @@ -0,0 +1,137 @@ + + * @copyright 2026 Conduction b.v. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ + +declare(strict_types=1); + +namespace Unit\Support; + +use OCA\LaunchPad\Db\ProfileValue; +use OCA\LaunchPad\Db\ProfileValueMapper; + +/** + * In-memory profile values. + */ +class InMemoryProfileValues extends ProfileValueMapper { + /** + * Stored rows. + * + * @var ProfileValue[] + */ + public array $rows = []; + + /** + * No database. + */ + public function __construct() { + }//end __construct() + + /** + * Rows of the given users. + * + * @param string[] $userIds User ids. + * + * @return ProfileValue[] + */ + public function findByUsers(array $userIds): array { + return array_values( + array_filter( + $this->rows, + static fn (ProfileValue $row): bool => in_array($row->getUserId(), $userIds, true) + ) + ); + }//end findByUsers() + + /** + * Rows whose lower-cased value contains the needle. + * + * @param string $needle Lower-cased search text. + * + * @return ProfileValue[] + */ + public function search(string $needle): array { + return array_values( + array_filter( + $this->rows, + static fn (ProfileValue $row): bool => str_contains($row->getValueSearch(), $needle) + ) + ); + }//end search() + + /** + * Replace one person's values of one field. + * + * @param string $userId Owner. + * @param string $fieldKey Field key. + * @param string[] $values Values. + * @param string $source Source. + * @param string|null $scope Scope. + * + * @return void + */ + public function replaceValues(string $userId, string $fieldKey, array $values, string $source, ?string $scope = null): void { + $this->deleteField($userId, $fieldKey); + foreach ($values as $value) { + $row = new ProfileValue(); + $row->setUserId($userId); + $row->setFieldKey($fieldKey); + $row->setValue($value); + $row->setValueSearch(mb_strtolower($value)); + $row->setSource($source); + $row->setScope($scope); + $this->rows[] = $row; + } + }//end replaceValues() + + /** + * Delete one person's values of one field. + * + * @param string $userId Owner. + * @param string $fieldKey Field key. + * + * @return int + */ + public function deleteField(string $userId, string $fieldKey): int { + $before = count($this->rows); + $this->rows = array_values( + array_filter( + $this->rows, + static fn (ProfileValue $row): bool => ($row->getUserId() === $userId && $row->getFieldKey() === $fieldKey) === false + ) + ); + + return $before - count($this->rows); + }//end deleteField() + + /** + * Delete every value of a person. + * + * @param string $userId Owner. + * + * @return int + */ + public function deleteByUser(string $userId): int { + $before = count($this->rows); + $this->rows = array_values( + array_filter($this->rows, static fn (ProfileValue $row): bool => $row->getUserId() !== $userId) + ); + + return $before - count($this->rows); + }//end deleteByUser() +}//end class From 96ff1766d21511d77ddf4fe6325f566500eee561 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Wed, 30 Sep 2026 07:46:21 +0200 Subject: [PATCH 02/60] feat(people): search the whole directory from the people widget, show profile fields and tags, and let people fill their own fields A query of two or more characters asks the server; a tag is a button that searches for it and a matching tag is highlighted. A personal settings form edits the person's own fields (LDAP fields read-only) and an admin tab defines them. REQ-PEX-001..003 --- l10n/be.js | 30 +- l10n/be.json | 30 +- l10n/bg.js | 30 +- l10n/bg.json | 30 +- l10n/bs.js | 30 +- l10n/bs.json | 30 +- l10n/ca.js | 30 +- l10n/ca.json | 30 +- l10n/cs.js | 30 +- l10n/cs.json | 30 +- l10n/da.js | 30 +- l10n/da.json | 30 +- l10n/de.js | 30 +- l10n/de.json | 30 +- l10n/el.js | 30 +- l10n/el.json | 30 +- l10n/en.js | 30 +- l10n/en.json | 30 +- l10n/es.js | 30 +- l10n/es.json | 30 +- l10n/et.js | 30 +- l10n/et.json | 30 +- l10n/fi.js | 30 +- l10n/fi.json | 30 +- l10n/fr.js | 30 +- l10n/fr.json | 30 +- l10n/ga.js | 30 +- l10n/ga.json | 30 +- l10n/hr.js | 30 +- l10n/hr.json | 30 +- l10n/hu.js | 30 +- l10n/hu.json | 30 +- l10n/is.js | 30 +- l10n/is.json | 30 +- l10n/it.js | 30 +- l10n/it.json | 30 +- l10n/lb.js | 30 +- l10n/lb.json | 30 +- l10n/lt.js | 30 +- l10n/lt.json | 30 +- l10n/lv.js | 30 +- l10n/lv.json | 30 +- l10n/mk.js | 30 +- l10n/mk.json | 30 +- l10n/mt.js | 30 +- l10n/mt.json | 30 +- l10n/nb.js | 30 +- l10n/nb.json | 30 +- l10n/nl.js | 30 +- l10n/nl.json | 30 +- l10n/pl.js | 30 +- l10n/pl.json | 30 +- l10n/pt.js | 30 +- l10n/pt.json | 30 +- l10n/rm.js | 30 +- l10n/rm.json | 30 +- l10n/ro.js | 30 +- l10n/ro.json | 30 +- l10n/ru.js | 30 +- l10n/ru.json | 30 +- l10n/sk.js | 30 +- l10n/sk.json | 30 +- l10n/sl.js | 30 +- l10n/sl.json | 30 +- l10n/sq.js | 30 +- l10n/sq.json | 30 +- l10n/sr.js | 30 +- l10n/sr.json | 30 +- l10n/sv.js | 30 +- l10n/sv.json | 30 +- l10n/tr.js | 30 +- l10n/tr.json | 30 +- l10n/uk.js | 30 +- l10n/uk.json | 30 +- .../Widgets/Renderers/PeopleWidget.vue | 360 ++++++++++++++---- .../Renderers/__tests__/PeopleWidget.spec.js | 152 ++++++++ src/components/admin/AdminSettings.vue | 9 + .../admin/tabs/ProfileFieldsTab.vue | 243 ++++++++++++ .../tabs/__tests__/ProfileFieldsTab.spec.js | 121 ++++++ src/personal.js | 26 ++ src/views/settings/ProfileFieldsSettings.vue | 205 ++++++++++ .../__tests__/ProfileFieldsSettings.spec.js | 126 ++++++ webpack.config.js | 2 + 83 files changed, 3321 insertions(+), 143 deletions(-) create mode 100644 src/components/Widgets/Renderers/__tests__/PeopleWidget.spec.js create mode 100644 src/components/admin/tabs/ProfileFieldsTab.vue create mode 100644 src/components/admin/tabs/__tests__/ProfileFieldsTab.spec.js create mode 100644 src/personal.js create mode 100644 src/views/settings/ProfileFieldsSettings.vue create mode 100644 src/views/settings/__tests__/ProfileFieldsSettings.spec.js diff --git a/l10n/be.js b/l10n/be.js index 59ae76f16..4fc3bafb1 100644 --- a/l10n/be.js +++ b/l10n/be.js @@ -1284,6 +1284,34 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Квітанцыі аб прачытанні ўверсе панэлі паказваюць, хто пацвердзіў.", "{emoji}: {count} reactions" : "{emoji}: рэакцый {count}", "React with {emoji}" : "Адрэагаваць {emoji}", - "{names} and {count} more" : "{names} і яшчэ {count}" + "{names} and {count} more" : "{names} і яшчэ {count}", + "Search people" : "Пошук людзей", + "Search by name, email or expertise…" : "Пошук па імені, электроннай пошце або экспертызе…", + "Find everyone tagged {tag}" : "Знайсці ўсіх з тэгам {tag}", + "LaunchPad profile" : "Профіль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Калегі бачаць гэтыя палі на вашай картцы ў віджэце людзей і могуць знайсці вас па іх.", + "Your profile fields could not be loaded." : "Не ўдалося загрузіць палі вашага профілю.", + "Not filled in" : "Не запоўнена", + "Filled from your organisation’s directory. You cannot change it here." : "Запоўнена з каталога вашай арганізацыі. Тут змяніць нельга.", + "Type a subject and press Enter" : "Увядзіце тэму і націсніце Enter", + "Your profile fields are saved." : "Палі вашага профілю захаваны.", + "Your profile fields could not be saved." : "Не ўдалося захаваць палі вашага профілю.", + "Profile fields" : "Палі профілю", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Дадатковыя палі на картках калег у віджэце людзей, напрыклад месца працы або экспертыза. Людзі запаўняюць іх у асабістых наладах, або яны бяруцца з атрыбута LDAP.", + "New field" : "Новае поле", + "Tags" : "Тэгі", + "Filled by" : "Хто запаўняе", + "The person" : "Сам чалавек", + "LDAP attribute" : "Атрыбут LDAP", + "Who may see it" : "Хто можа бачыць", + "Everyone" : "Усе", + "People in the same group" : "Людзі з той жа групы", + "Searchable in the people widget" : "Можна шукаць у віджэце людзей", + "Shown on the card" : "Паказваецца на картцы", + "Remove field" : "Выдаліць поле", + "Profile fields saved." : "Палі профілю захаваны.", + "Save profile fields" : "Захаваць палі профілю", + "The profile fields could not be loaded." : "Не ўдалося загрузіць палі профілю.", + "The profile fields could not be saved." : "Не ўдалося захаваць палі профілю." }, "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/l10n/be.json b/l10n/be.json index 857fabbf9..f1b3999ce 100644 --- a/l10n/be.json +++ b/l10n/be.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Квітанцыі аб прачытанні ўверсе панэлі паказваюць, хто пацвердзіў.", "{emoji}: {count} reactions": "{emoji}: рэакцый {count}", "React with {emoji}": "Адрэагаваць {emoji}", - "{names} and {count} more": "{names} і яшчэ {count}" + "{names} and {count} more": "{names} і яшчэ {count}", + "Search people": "Пошук людзей", + "Search by name, email or expertise…": "Пошук па імені, электроннай пошце або экспертызе…", + "Find everyone tagged {tag}": "Знайсці ўсіх з тэгам {tag}", + "LaunchPad profile": "Профіль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Калегі бачаць гэтыя палі на вашай картцы ў віджэце людзей і могуць знайсці вас па іх.", + "Your profile fields could not be loaded.": "Не ўдалося загрузіць палі вашага профілю.", + "Not filled in": "Не запоўнена", + "Filled from your organisation’s directory. You cannot change it here.": "Запоўнена з каталога вашай арганізацыі. Тут змяніць нельга.", + "Type a subject and press Enter": "Увядзіце тэму і націсніце Enter", + "Your profile fields are saved.": "Палі вашага профілю захаваны.", + "Your profile fields could not be saved.": "Не ўдалося захаваць палі вашага профілю.", + "Profile fields": "Палі профілю", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Дадатковыя палі на картках калег у віджэце людзей, напрыклад месца працы або экспертыза. Людзі запаўняюць іх у асабістых наладах, або яны бяруцца з атрыбута LDAP.", + "New field": "Новае поле", + "Tags": "Тэгі", + "Filled by": "Хто запаўняе", + "The person": "Сам чалавек", + "LDAP attribute": "Атрыбут LDAP", + "Who may see it": "Хто можа бачыць", + "Everyone": "Усе", + "People in the same group": "Людзі з той жа групы", + "Searchable in the people widget": "Можна шукаць у віджэце людзей", + "Shown on the card": "Паказваецца на картцы", + "Remove field": "Выдаліць поле", + "Profile fields saved.": "Палі профілю захаваны.", + "Save profile fields": "Захаваць палі профілю", + "The profile fields could not be loaded.": "Не ўдалося загрузіць палі профілю.", + "The profile fields could not be saved.": "Не ўдалося захаваць палі профілю." } } diff --git a/l10n/bg.js b/l10n/bg.js index 30c5ce64f..94a897089 100644 --- a/l10n/bg.js +++ b/l10n/bg.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Разписките за прочитане в горната част на таблото показват кой е потвърдил.", "{emoji}: {count} reactions" : "{emoji}: {count} реакции", "React with {emoji}" : "Реагиране с {emoji}", - "{names} and {count} more" : "{names} и още {count}" + "{names} and {count} more" : "{names} и още {count}", + "Search people" : "Търсене на хора", + "Search by name, email or expertise…" : "Търсене по име, имейл или експертиза…", + "Find everyone tagged {tag}" : "Намери всички с етикет {tag}", + "LaunchPad profile" : "Профил в LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Колегите виждат тези полета на вашата карта в приспособлението за хора и могат да ви намерят по тях.", + "Your profile fields could not be loaded." : "Полетата на профила ви не можаха да се заредят.", + "Not filled in" : "Не е попълнено", + "Filled from your organisation’s directory. You cannot change it here." : "Попълва се от директорията на вашата организация. Не можете да го промените тук.", + "Type a subject and press Enter" : "Въведете тема и натиснете Enter", + "Your profile fields are saved." : "Полетата на профила ви са запазени.", + "Your profile fields could not be saved." : "Полетата на профила ви не можаха да се запазят.", + "Profile fields" : "Полета на профила", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Допълнителни полета в картите на колегите в приспособлението за хора, като местоположение на офиса или експертиза. Хората ги попълват в личните си настройки или те идват от атрибут в LDAP.", + "New field" : "Ново поле", + "Tags" : "Етикети", + "Filled by" : "Попълва се от", + "The person" : "Самият човек", + "LDAP attribute" : "Атрибут в LDAP", + "Who may see it" : "Кой може да го вижда", + "Everyone" : "Всички", + "People in the same group" : "Хората в същата група", + "Searchable in the people widget" : "Може да се търси в приспособлението за хора", + "Shown on the card" : "Показва се на картата", + "Remove field" : "Премахване на полето", + "Profile fields saved." : "Полетата на профила са запазени.", + "Save profile fields" : "Запазване на полетата на профила", + "The profile fields could not be loaded." : "Полетата на профила не можаха да се заредят.", + "The profile fields could not be saved." : "Полетата на профила не можаха да се запазят." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/bg.json b/l10n/bg.json index 779669dc6..8f5c8ea7b 100644 --- a/l10n/bg.json +++ b/l10n/bg.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Разписките за прочитане в горната част на таблото показват кой е потвърдил.", "{emoji}: {count} reactions": "{emoji}: {count} реакции", "React with {emoji}": "Реагиране с {emoji}", - "{names} and {count} more": "{names} и още {count}" + "{names} and {count} more": "{names} и още {count}", + "Search people": "Търсене на хора", + "Search by name, email or expertise…": "Търсене по име, имейл или експертиза…", + "Find everyone tagged {tag}": "Намери всички с етикет {tag}", + "LaunchPad profile": "Профил в LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Колегите виждат тези полета на вашата карта в приспособлението за хора и могат да ви намерят по тях.", + "Your profile fields could not be loaded.": "Полетата на профила ви не можаха да се заредят.", + "Not filled in": "Не е попълнено", + "Filled from your organisation’s directory. You cannot change it here.": "Попълва се от директорията на вашата организация. Не можете да го промените тук.", + "Type a subject and press Enter": "Въведете тема и натиснете Enter", + "Your profile fields are saved.": "Полетата на профила ви са запазени.", + "Your profile fields could not be saved.": "Полетата на профила ви не можаха да се запазят.", + "Profile fields": "Полета на профила", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Допълнителни полета в картите на колегите в приспособлението за хора, като местоположение на офиса или експертиза. Хората ги попълват в личните си настройки или те идват от атрибут в LDAP.", + "New field": "Ново поле", + "Tags": "Етикети", + "Filled by": "Попълва се от", + "The person": "Самият човек", + "LDAP attribute": "Атрибут в LDAP", + "Who may see it": "Кой може да го вижда", + "Everyone": "Всички", + "People in the same group": "Хората в същата група", + "Searchable in the people widget": "Може да се търси в приспособлението за хора", + "Shown on the card": "Показва се на картата", + "Remove field": "Премахване на полето", + "Profile fields saved.": "Полетата на профила са запазени.", + "Save profile fields": "Запазване на полетата на профила", + "The profile fields could not be loaded.": "Полетата на профила не можаха да се заредят.", + "The profile fields could not be saved.": "Полетата на профила не можаха да се запазят." } } diff --git a/l10n/bs.js b/l10n/bs.js index 75355048f..361af2eed 100644 --- a/l10n/bs.js +++ b/l10n/bs.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potvrde čitanja na vrhu kontrolne ploče pokazuju ko je potvrdio.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcija", "React with {emoji}" : "Reaguj sa {emoji}", - "{names} and {count} more" : "{names} i još {count}" + "{names} and {count} more" : "{names} i još {count}", + "Search people" : "Pretraži osobe", + "Search by name, email or expertise…" : "Pretraži po imenu, e-pošti ili stručnosti…", + "Find everyone tagged {tag}" : "Pronađi sve s oznakom {tag}", + "LaunchPad profile" : "LaunchPad profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolege vide ova polja na vašoj kartici u widgetu osoba i mogu vas pronaći po njima.", + "Your profile fields could not be loaded." : "Polja vašeg profila nisu mogla biti učitana.", + "Not filled in" : "Nije popunjeno", + "Filled from your organisation’s directory. You cannot change it here." : "Popunjeno iz imenika vaše organizacije. Ovdje to ne možete promijeniti.", + "Type a subject and press Enter" : "Upišite temu i pritisnite Enter", + "Your profile fields are saved." : "Polja vašeg profila su spremljena.", + "Your profile fields could not be saved." : "Polja vašeg profila nisu mogla biti spremljena.", + "Profile fields" : "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Dodatna polja na karticama kolega u widgetu osoba, poput lokacije ureda ili stručnosti. Osobe ih popunjavaju u svojim osobnim postavkama ili dolaze iz LDAP atributa.", + "New field" : "Novo polje", + "Tags" : "Oznake", + "Filled by" : "Popunjava", + "The person" : "Sama osoba", + "LDAP attribute" : "LDAP atribut", + "Who may see it" : "Tko ga smije vidjeti", + "Everyone" : "Svi", + "People in the same group" : "Osobe u istoj grupi", + "Searchable in the people widget" : "Pretraživo u widgetu osoba", + "Shown on the card" : "Prikazano na kartici", + "Remove field" : "Ukloni polje", + "Profile fields saved." : "Polja profila su spremljena.", + "Save profile fields" : "Spremi polja profila", + "The profile fields could not be loaded." : "Polja profila nisu mogla biti učitana.", + "The profile fields could not be saved." : "Polja profila nisu mogla biti spremljena." }, "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/l10n/bs.json b/l10n/bs.json index dad14796e..3afcedf8a 100644 --- a/l10n/bs.json +++ b/l10n/bs.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potvrde čitanja na vrhu kontrolne ploče pokazuju ko je potvrdio.", "{emoji}: {count} reactions": "{emoji}: {count} reakcija", "React with {emoji}": "Reaguj sa {emoji}", - "{names} and {count} more": "{names} i još {count}" + "{names} and {count} more": "{names} i još {count}", + "Search people": "Pretraži osobe", + "Search by name, email or expertise…": "Pretraži po imenu, e-pošti ili stručnosti…", + "Find everyone tagged {tag}": "Pronađi sve s oznakom {tag}", + "LaunchPad profile": "LaunchPad profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolege vide ova polja na vašoj kartici u widgetu osoba i mogu vas pronaći po njima.", + "Your profile fields could not be loaded.": "Polja vašeg profila nisu mogla biti učitana.", + "Not filled in": "Nije popunjeno", + "Filled from your organisation’s directory. You cannot change it here.": "Popunjeno iz imenika vaše organizacije. Ovdje to ne možete promijeniti.", + "Type a subject and press Enter": "Upišite temu i pritisnite Enter", + "Your profile fields are saved.": "Polja vašeg profila su spremljena.", + "Your profile fields could not be saved.": "Polja vašeg profila nisu mogla biti spremljena.", + "Profile fields": "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Dodatna polja na karticama kolega u widgetu osoba, poput lokacije ureda ili stručnosti. Osobe ih popunjavaju u svojim osobnim postavkama ili dolaze iz LDAP atributa.", + "New field": "Novo polje", + "Tags": "Oznake", + "Filled by": "Popunjava", + "The person": "Sama osoba", + "LDAP attribute": "LDAP atribut", + "Who may see it": "Tko ga smije vidjeti", + "Everyone": "Svi", + "People in the same group": "Osobe u istoj grupi", + "Searchable in the people widget": "Pretraživo u widgetu osoba", + "Shown on the card": "Prikazano na kartici", + "Remove field": "Ukloni polje", + "Profile fields saved.": "Polja profila su spremljena.", + "Save profile fields": "Spremi polja profila", + "The profile fields could not be loaded.": "Polja profila nisu mogla biti učitana.", + "The profile fields could not be saved.": "Polja profila nisu mogla biti spremljena." } } diff --git a/l10n/ca.js b/l10n/ca.js index a6dae35af..bf45de116 100644 --- a/l10n/ca.js +++ b/l10n/ca.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Els justificants de lectura a dalt del tauler mostren qui ha confirmat.", "{emoji}: {count} reactions" : "{emoji}: {count} reaccions", "React with {emoji}" : "Reacciona amb {emoji}", - "{names} and {count} more" : "{names} i {count} més" + "{names} and {count} more" : "{names} i {count} més", + "Search people" : "Cerca persones", + "Search by name, email or expertise…" : "Cerca per nom, correu o especialitat…", + "Find everyone tagged {tag}" : "Troba tothom amb l'etiqueta {tag}", + "LaunchPad profile" : "Perfil de LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Els companys veuen aquests camps a la vostra targeta del giny de persones i us poden trobar per ells.", + "Your profile fields could not be loaded." : "No s'han pogut carregar els camps del vostre perfil.", + "Not filled in" : "No emplenat", + "Filled from your organisation’s directory. You cannot change it here." : "S'omple des del directori de la vostra organització. No ho podeu canviar aquí.", + "Type a subject and press Enter" : "Escriviu un tema i premeu Retorn", + "Your profile fields are saved." : "S'han desat els camps del vostre perfil.", + "Your profile fields could not be saved." : "No s'han pogut desar els camps del vostre perfil.", + "Profile fields" : "Camps del perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Camps addicionals a les targetes dels companys al giny de persones, com ara la ubicació de l'oficina o l'especialitat. Les persones els emplenen a la seva configuració personal, o provenen d'un atribut LDAP.", + "New field" : "Camp nou", + "Tags" : "Etiquetes", + "Filled by" : "Ho emplena", + "The person" : "La persona", + "LDAP attribute" : "Atribut LDAP", + "Who may see it" : "Qui el pot veure", + "Everyone" : "Tothom", + "People in the same group" : "Persones del mateix grup", + "Searchable in the people widget" : "Es pot cercar al giny de persones", + "Shown on the card" : "Es mostra a la targeta", + "Remove field" : "Suprimeix el camp", + "Profile fields saved." : "S'han desat els camps del perfil.", + "Save profile fields" : "Desa els camps del perfil", + "The profile fields could not be loaded." : "No s'han pogut carregar els camps del perfil.", + "The profile fields could not be saved." : "No s'han pogut desar els camps del perfil." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/ca.json b/l10n/ca.json index 8ec3ce4a7..ed8885f1a 100644 --- a/l10n/ca.json +++ b/l10n/ca.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Els justificants de lectura a dalt del tauler mostren qui ha confirmat.", "{emoji}: {count} reactions": "{emoji}: {count} reaccions", "React with {emoji}": "Reacciona amb {emoji}", - "{names} and {count} more": "{names} i {count} més" + "{names} and {count} more": "{names} i {count} més", + "Search people": "Cerca persones", + "Search by name, email or expertise…": "Cerca per nom, correu o especialitat…", + "Find everyone tagged {tag}": "Troba tothom amb l'etiqueta {tag}", + "LaunchPad profile": "Perfil de LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Els companys veuen aquests camps a la vostra targeta del giny de persones i us poden trobar per ells.", + "Your profile fields could not be loaded.": "No s'han pogut carregar els camps del vostre perfil.", + "Not filled in": "No emplenat", + "Filled from your organisation’s directory. You cannot change it here.": "S'omple des del directori de la vostra organització. No ho podeu canviar aquí.", + "Type a subject and press Enter": "Escriviu un tema i premeu Retorn", + "Your profile fields are saved.": "S'han desat els camps del vostre perfil.", + "Your profile fields could not be saved.": "No s'han pogut desar els camps del vostre perfil.", + "Profile fields": "Camps del perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Camps addicionals a les targetes dels companys al giny de persones, com ara la ubicació de l'oficina o l'especialitat. Les persones els emplenen a la seva configuració personal, o provenen d'un atribut LDAP.", + "New field": "Camp nou", + "Tags": "Etiquetes", + "Filled by": "Ho emplena", + "The person": "La persona", + "LDAP attribute": "Atribut LDAP", + "Who may see it": "Qui el pot veure", + "Everyone": "Tothom", + "People in the same group": "Persones del mateix grup", + "Searchable in the people widget": "Es pot cercar al giny de persones", + "Shown on the card": "Es mostra a la targeta", + "Remove field": "Suprimeix el camp", + "Profile fields saved.": "S'han desat els camps del perfil.", + "Save profile fields": "Desa els camps del perfil", + "The profile fields could not be loaded.": "No s'han pogut carregar els camps del perfil.", + "The profile fields could not be saved.": "No s'han pogut desar els camps del perfil." } } diff --git a/l10n/cs.js b/l10n/cs.js index 4f62f348a..d11ca0b25 100644 --- a/l10n/cs.js +++ b/l10n/cs.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potvrzení o přečtení v horní části panelu ukazují, kdo potvrdil.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcí", "React with {emoji}" : "Reagovat pomocí {emoji}", - "{names} and {count} more" : "{names} a další ({count})" + "{names} and {count} more" : "{names} a další ({count})", + "Search people" : "Hledat osoby", + "Search by name, email or expertise…" : "Hledat podle jména, e-mailu nebo odbornosti…", + "Find everyone tagged {tag}" : "Najít všechny se štítkem {tag}", + "LaunchPad profile" : "Profil v LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolegové vidí tato pole na vaší kartě ve widgetu osob a mohou vás podle nich najít.", + "Your profile fields could not be loaded." : "Pole vašeho profilu se nepodařilo načíst.", + "Not filled in" : "Nevyplněno", + "Filled from your organisation’s directory. You cannot change it here." : "Vyplněno z adresáře vaší organizace. Zde to nelze změnit.", + "Type a subject and press Enter" : "Napište téma a stiskněte Enter", + "Your profile fields are saved." : "Pole vašeho profilu jsou uložena.", + "Your profile fields could not be saved." : "Pole vašeho profilu se nepodařilo uložit.", + "Profile fields" : "Pole profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Další pole na kartách kolegů ve widgetu osob, například umístění kanceláře nebo odbornost. Lidé je vyplňují v osobním nastavení, nebo pocházejí z atributu LDAP.", + "New field" : "Nové pole", + "Tags" : "Štítky", + "Filled by" : "Vyplňuje", + "The person" : "Sama osoba", + "LDAP attribute" : "Atribut LDAP", + "Who may see it" : "Kdo ho smí vidět", + "Everyone" : "Všichni", + "People in the same group" : "Lidé ve stejné skupině", + "Searchable in the people widget" : "Vyhledatelné ve widgetu osob", + "Shown on the card" : "Zobrazeno na kartě", + "Remove field" : "Odebrat pole", + "Profile fields saved." : "Pole profilu jsou uložena.", + "Save profile fields" : "Uložit pole profilu", + "The profile fields could not be loaded." : "Pole profilu se nepodařilo načíst.", + "The profile fields could not be saved." : "Pole profilu se nepodařilo uložit." }, "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" ); diff --git a/l10n/cs.json b/l10n/cs.json index 93ba6ec8c..3f64c588c 100644 --- a/l10n/cs.json +++ b/l10n/cs.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potvrzení o přečtení v horní části panelu ukazují, kdo potvrdil.", "{emoji}: {count} reactions": "{emoji}: {count} reakcí", "React with {emoji}": "Reagovat pomocí {emoji}", - "{names} and {count} more": "{names} a další ({count})" + "{names} and {count} more": "{names} a další ({count})", + "Search people": "Hledat osoby", + "Search by name, email or expertise…": "Hledat podle jména, e-mailu nebo odbornosti…", + "Find everyone tagged {tag}": "Najít všechny se štítkem {tag}", + "LaunchPad profile": "Profil v LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolegové vidí tato pole na vaší kartě ve widgetu osob a mohou vás podle nich najít.", + "Your profile fields could not be loaded.": "Pole vašeho profilu se nepodařilo načíst.", + "Not filled in": "Nevyplněno", + "Filled from your organisation’s directory. You cannot change it here.": "Vyplněno z adresáře vaší organizace. Zde to nelze změnit.", + "Type a subject and press Enter": "Napište téma a stiskněte Enter", + "Your profile fields are saved.": "Pole vašeho profilu jsou uložena.", + "Your profile fields could not be saved.": "Pole vašeho profilu se nepodařilo uložit.", + "Profile fields": "Pole profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Další pole na kartách kolegů ve widgetu osob, například umístění kanceláře nebo odbornost. Lidé je vyplňují v osobním nastavení, nebo pocházejí z atributu LDAP.", + "New field": "Nové pole", + "Tags": "Štítky", + "Filled by": "Vyplňuje", + "The person": "Sama osoba", + "LDAP attribute": "Atribut LDAP", + "Who may see it": "Kdo ho smí vidět", + "Everyone": "Všichni", + "People in the same group": "Lidé ve stejné skupině", + "Searchable in the people widget": "Vyhledatelné ve widgetu osob", + "Shown on the card": "Zobrazeno na kartě", + "Remove field": "Odebrat pole", + "Profile fields saved.": "Pole profilu jsou uložena.", + "Save profile fields": "Uložit pole profilu", + "The profile fields could not be loaded.": "Pole profilu se nepodařilo načíst.", + "The profile fields could not be saved.": "Pole profilu se nepodařilo uložit." } } diff --git a/l10n/da.js b/l10n/da.js index cc7305977..ff77c1aaa 100644 --- a/l10n/da.js +++ b/l10n/da.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Læsekvitteringer øverst på dashboardet viser, hvem der har bekræftet.", "{emoji}: {count} reactions" : "{emoji}: {count} reaktioner", "React with {emoji}" : "Reagér med {emoji}", - "{names} and {count} more" : "{names} og {count} til" + "{names} and {count} more" : "{names} og {count} til", + "Search people" : "Søg efter personer", + "Search by name, email or expertise…" : "Søg efter navn, e-mail eller ekspertise…", + "Find everyone tagged {tag}" : "Find alle med mærket {tag}", + "LaunchPad profile" : "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolleger ser disse felter på dit kort i personwidgetten og kan finde dig ud fra dem.", + "Your profile fields could not be loaded." : "Dine profilfelter kunne ikke indlæses.", + "Not filled in" : "Ikke udfyldt", + "Filled from your organisation’s directory. You cannot change it here." : "Udfyldt fra din organisations katalog. Du kan ikke ændre det her.", + "Type a subject and press Enter" : "Skriv et emne, og tryk på Enter", + "Your profile fields are saved." : "Dine profilfelter er gemt.", + "Your profile fields could not be saved." : "Dine profilfelter kunne ikke gemmes.", + "Profile fields" : "Profilfelter", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Ekstra felter på kollegers kort i personwidgetten, fx kontorplacering eller ekspertise. Personerne udfylder dem i deres personlige indstillinger, eller de kommer fra en LDAP-attribut.", + "New field" : "Nyt felt", + "Tags" : "Mærker", + "Filled by" : "Udfyldes af", + "The person" : "Personen selv", + "LDAP attribute" : "LDAP-attribut", + "Who may see it" : "Hvem må se det", + "Everyone" : "Alle", + "People in the same group" : "Personer i samme gruppe", + "Searchable in the people widget" : "Søgbar i personwidgetten", + "Shown on the card" : "Vises på kortet", + "Remove field" : "Fjern felt", + "Profile fields saved." : "Profilfelterne er gemt.", + "Save profile fields" : "Gem profilfelter", + "The profile fields could not be loaded." : "Profilfelterne kunne ikke indlæses.", + "The profile fields could not be saved." : "Profilfelterne kunne ikke gemmes." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/da.json b/l10n/da.json index c95a84279..78fd8908a 100644 --- a/l10n/da.json +++ b/l10n/da.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Læsekvitteringer øverst på dashboardet viser, hvem der har bekræftet.", "{emoji}: {count} reactions": "{emoji}: {count} reaktioner", "React with {emoji}": "Reagér med {emoji}", - "{names} and {count} more": "{names} og {count} til" + "{names} and {count} more": "{names} og {count} til", + "Search people": "Søg efter personer", + "Search by name, email or expertise…": "Søg efter navn, e-mail eller ekspertise…", + "Find everyone tagged {tag}": "Find alle med mærket {tag}", + "LaunchPad profile": "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolleger ser disse felter på dit kort i personwidgetten og kan finde dig ud fra dem.", + "Your profile fields could not be loaded.": "Dine profilfelter kunne ikke indlæses.", + "Not filled in": "Ikke udfyldt", + "Filled from your organisation’s directory. You cannot change it here.": "Udfyldt fra din organisations katalog. Du kan ikke ændre det her.", + "Type a subject and press Enter": "Skriv et emne, og tryk på Enter", + "Your profile fields are saved.": "Dine profilfelter er gemt.", + "Your profile fields could not be saved.": "Dine profilfelter kunne ikke gemmes.", + "Profile fields": "Profilfelter", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Ekstra felter på kollegers kort i personwidgetten, fx kontorplacering eller ekspertise. Personerne udfylder dem i deres personlige indstillinger, eller de kommer fra en LDAP-attribut.", + "New field": "Nyt felt", + "Tags": "Mærker", + "Filled by": "Udfyldes af", + "The person": "Personen selv", + "LDAP attribute": "LDAP-attribut", + "Who may see it": "Hvem må se det", + "Everyone": "Alle", + "People in the same group": "Personer i samme gruppe", + "Searchable in the people widget": "Søgbar i personwidgetten", + "Shown on the card": "Vises på kortet", + "Remove field": "Fjern felt", + "Profile fields saved.": "Profilfelterne er gemt.", + "Save profile fields": "Gem profilfelter", + "The profile fields could not be loaded.": "Profilfelterne kunne ikke indlæses.", + "The profile fields could not be saved.": "Profilfelterne kunne ikke gemmes." } } diff --git a/l10n/de.js b/l10n/de.js index f288c5f85..6063757b5 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Lesebestätigungen oben im Dashboard zeigen, wer bestätigt hat.", "{emoji}: {count} reactions" : "{emoji}: {count} Reaktionen", "React with {emoji}" : "Mit {emoji} reagieren", - "{names} and {count} more" : "{names} und {count} weitere" + "{names} and {count} more" : "{names} und {count} weitere", + "Search people" : "Personen suchen", + "Search by name, email or expertise…" : "Nach Name, E-Mail oder Fachgebiet suchen…", + "Find everyone tagged {tag}" : "Alle mit dem Schlagwort {tag} finden", + "LaunchPad profile" : "LaunchPad-Profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolleginnen und Kollegen sehen diese Felder auf deiner Karte im Personen-Widget und können dich darüber finden.", + "Your profile fields could not be loaded." : "Deine Profilfelder konnten nicht geladen werden.", + "Not filled in" : "Nicht ausgefüllt", + "Filled from your organisation’s directory. You cannot change it here." : "Wird aus dem Verzeichnis deiner Organisation übernommen. Du kannst es hier nicht ändern.", + "Type a subject and press Enter" : "Thema eingeben und Enter drücken", + "Your profile fields are saved." : "Deine Profilfelder sind gespeichert.", + "Your profile fields could not be saved." : "Deine Profilfelder konnten nicht gespeichert werden.", + "Profile fields" : "Profilfelder", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Zusätzliche Felder auf den Karten von Kolleginnen und Kollegen im Personen-Widget, etwa Bürostandort oder Fachgebiet. Personen füllen sie in ihren persönlichen Einstellungen aus, oder sie stammen aus einem LDAP-Attribut.", + "New field" : "Neues Feld", + "Tags" : "Schlagwörter", + "Filled by" : "Ausgefüllt von", + "The person" : "Die Person selbst", + "LDAP attribute" : "LDAP-Attribut", + "Who may see it" : "Wer es sehen darf", + "Everyone" : "Alle", + "People in the same group" : "Personen in derselben Gruppe", + "Searchable in the people widget" : "Im Personen-Widget durchsuchbar", + "Shown on the card" : "Auf der Karte angezeigt", + "Remove field" : "Feld entfernen", + "Profile fields saved." : "Profilfelder gespeichert.", + "Save profile fields" : "Profilfelder speichern", + "The profile fields could not be loaded." : "Die Profilfelder konnten nicht geladen werden.", + "The profile fields could not be saved." : "Die Profilfelder konnten nicht gespeichert werden." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/de.json b/l10n/de.json index 2d10ea448..5468a77de 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Lesebestätigungen oben im Dashboard zeigen, wer bestätigt hat.", "{emoji}: {count} reactions": "{emoji}: {count} Reaktionen", "React with {emoji}": "Mit {emoji} reagieren", - "{names} and {count} more": "{names} und {count} weitere" + "{names} and {count} more": "{names} und {count} weitere", + "Search people": "Personen suchen", + "Search by name, email or expertise…": "Nach Name, E-Mail oder Fachgebiet suchen…", + "Find everyone tagged {tag}": "Alle mit dem Schlagwort {tag} finden", + "LaunchPad profile": "LaunchPad-Profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolleginnen und Kollegen sehen diese Felder auf deiner Karte im Personen-Widget und können dich darüber finden.", + "Your profile fields could not be loaded.": "Deine Profilfelder konnten nicht geladen werden.", + "Not filled in": "Nicht ausgefüllt", + "Filled from your organisation’s directory. You cannot change it here.": "Wird aus dem Verzeichnis deiner Organisation übernommen. Du kannst es hier nicht ändern.", + "Type a subject and press Enter": "Thema eingeben und Enter drücken", + "Your profile fields are saved.": "Deine Profilfelder sind gespeichert.", + "Your profile fields could not be saved.": "Deine Profilfelder konnten nicht gespeichert werden.", + "Profile fields": "Profilfelder", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Zusätzliche Felder auf den Karten von Kolleginnen und Kollegen im Personen-Widget, etwa Bürostandort oder Fachgebiet. Personen füllen sie in ihren persönlichen Einstellungen aus, oder sie stammen aus einem LDAP-Attribut.", + "New field": "Neues Feld", + "Tags": "Schlagwörter", + "Filled by": "Ausgefüllt von", + "The person": "Die Person selbst", + "LDAP attribute": "LDAP-Attribut", + "Who may see it": "Wer es sehen darf", + "Everyone": "Alle", + "People in the same group": "Personen in derselben Gruppe", + "Searchable in the people widget": "Im Personen-Widget durchsuchbar", + "Shown on the card": "Auf der Karte angezeigt", + "Remove field": "Feld entfernen", + "Profile fields saved.": "Profilfelder gespeichert.", + "Save profile fields": "Profilfelder speichern", + "The profile fields could not be loaded.": "Die Profilfelder konnten nicht geladen werden.", + "The profile fields could not be saved.": "Die Profilfelder konnten nicht gespeichert werden." } } diff --git a/l10n/el.js b/l10n/el.js index 7f0b2c758..4fe15f6bc 100644 --- a/l10n/el.js +++ b/l10n/el.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Οι αποδείξεις ανάγνωσης στο πάνω μέρος του πίνακα δείχνουν ποιος επιβεβαίωσε.", "{emoji}: {count} reactions" : "{emoji}: {count} αντιδράσεις", "React with {emoji}" : "Αντίδραση με {emoji}", - "{names} and {count} more" : "{names} και {count} ακόμη" + "{names} and {count} more" : "{names} και {count} ακόμη", + "Search people" : "Αναζήτηση ατόμων", + "Search by name, email or expertise…" : "Αναζήτηση με όνομα, email ή ειδίκευση…", + "Find everyone tagged {tag}" : "Βρες όλους με την ετικέτα {tag}", + "LaunchPad profile" : "Προφίλ LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Οι συνάδελφοι βλέπουν αυτά τα πεδία στην κάρτα σας στο γραφικό στοιχείο ατόμων και μπορούν να σας βρουν μέσω αυτών.", + "Your profile fields could not be loaded." : "Δεν ήταν δυνατή η φόρτωση των πεδίων του προφίλ σας.", + "Not filled in" : "Δεν έχει συμπληρωθεί", + "Filled from your organisation’s directory. You cannot change it here." : "Συμπληρώνεται από τον κατάλογο του οργανισμού σας. Δεν μπορείτε να το αλλάξετε εδώ.", + "Type a subject and press Enter" : "Πληκτρολογήστε ένα θέμα και πατήστε Enter", + "Your profile fields are saved." : "Τα πεδία του προφίλ σας αποθηκεύτηκαν.", + "Your profile fields could not be saved." : "Δεν ήταν δυνατή η αποθήκευση των πεδίων του προφίλ σας.", + "Profile fields" : "Πεδία προφίλ", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Επιπλέον πεδία στις κάρτες συναδέλφων στο γραφικό στοιχείο ατόμων, όπως τοποθεσία γραφείου ή ειδίκευση. Τα άτομα τα συμπληρώνουν στις προσωπικές τους ρυθμίσεις ή προέρχονται από ένα χαρακτηριστικό LDAP.", + "New field" : "Νέο πεδίο", + "Tags" : "Ετικέτες", + "Filled by" : "Συμπληρώνεται από", + "The person" : "Το ίδιο το άτομο", + "LDAP attribute" : "Χαρακτηριστικό LDAP", + "Who may see it" : "Ποιος μπορεί να το δει", + "Everyone" : "Όλοι", + "People in the same group" : "Άτομα στην ίδια ομάδα", + "Searchable in the people widget" : "Με δυνατότητα αναζήτησης στο γραφικό στοιχείο ατόμων", + "Shown on the card" : "Εμφανίζεται στην κάρτα", + "Remove field" : "Αφαίρεση πεδίου", + "Profile fields saved." : "Τα πεδία προφίλ αποθηκεύτηκαν.", + "Save profile fields" : "Αποθήκευση πεδίων προφίλ", + "The profile fields could not be loaded." : "Δεν ήταν δυνατή η φόρτωση των πεδίων προφίλ.", + "The profile fields could not be saved." : "Δεν ήταν δυνατή η αποθήκευση των πεδίων προφίλ." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/el.json b/l10n/el.json index b61edabfc..c4aaf0219 100644 --- a/l10n/el.json +++ b/l10n/el.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Οι αποδείξεις ανάγνωσης στο πάνω μέρος του πίνακα δείχνουν ποιος επιβεβαίωσε.", "{emoji}: {count} reactions": "{emoji}: {count} αντιδράσεις", "React with {emoji}": "Αντίδραση με {emoji}", - "{names} and {count} more": "{names} και {count} ακόμη" + "{names} and {count} more": "{names} και {count} ακόμη", + "Search people": "Αναζήτηση ατόμων", + "Search by name, email or expertise…": "Αναζήτηση με όνομα, email ή ειδίκευση…", + "Find everyone tagged {tag}": "Βρες όλους με την ετικέτα {tag}", + "LaunchPad profile": "Προφίλ LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Οι συνάδελφοι βλέπουν αυτά τα πεδία στην κάρτα σας στο γραφικό στοιχείο ατόμων και μπορούν να σας βρουν μέσω αυτών.", + "Your profile fields could not be loaded.": "Δεν ήταν δυνατή η φόρτωση των πεδίων του προφίλ σας.", + "Not filled in": "Δεν έχει συμπληρωθεί", + "Filled from your organisation’s directory. You cannot change it here.": "Συμπληρώνεται από τον κατάλογο του οργανισμού σας. Δεν μπορείτε να το αλλάξετε εδώ.", + "Type a subject and press Enter": "Πληκτρολογήστε ένα θέμα και πατήστε Enter", + "Your profile fields are saved.": "Τα πεδία του προφίλ σας αποθηκεύτηκαν.", + "Your profile fields could not be saved.": "Δεν ήταν δυνατή η αποθήκευση των πεδίων του προφίλ σας.", + "Profile fields": "Πεδία προφίλ", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Επιπλέον πεδία στις κάρτες συναδέλφων στο γραφικό στοιχείο ατόμων, όπως τοποθεσία γραφείου ή ειδίκευση. Τα άτομα τα συμπληρώνουν στις προσωπικές τους ρυθμίσεις ή προέρχονται από ένα χαρακτηριστικό LDAP.", + "New field": "Νέο πεδίο", + "Tags": "Ετικέτες", + "Filled by": "Συμπληρώνεται από", + "The person": "Το ίδιο το άτομο", + "LDAP attribute": "Χαρακτηριστικό LDAP", + "Who may see it": "Ποιος μπορεί να το δει", + "Everyone": "Όλοι", + "People in the same group": "Άτομα στην ίδια ομάδα", + "Searchable in the people widget": "Με δυνατότητα αναζήτησης στο γραφικό στοιχείο ατόμων", + "Shown on the card": "Εμφανίζεται στην κάρτα", + "Remove field": "Αφαίρεση πεδίου", + "Profile fields saved.": "Τα πεδία προφίλ αποθηκεύτηκαν.", + "Save profile fields": "Αποθήκευση πεδίων προφίλ", + "The profile fields could not be loaded.": "Δεν ήταν δυνατή η φόρτωση των πεδίων προφίλ.", + "The profile fields could not be saved.": "Δεν ήταν δυνατή η αποθήκευση των πεδίων προφίλ." } } diff --git a/l10n/en.js b/l10n/en.js index 37ec679c0..c86a4c71c 100644 --- a/l10n/en.js +++ b/l10n/en.js @@ -1273,7 +1273,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Read receipts at the top of the dashboard show who has confirmed.", "{emoji}: {count} reactions" : "{emoji}: {count} reactions", "React with {emoji}" : "React with {emoji}", - "{names} and {count} more" : "{names} and {count} more" + "{names} and {count} more" : "{names} and {count} more", + "Search people" : "Search people", + "Search by name, email or expertise…" : "Search by name, email or expertise…", + "Find everyone tagged {tag}" : "Find everyone tagged {tag}", + "LaunchPad profile" : "LaunchPad profile", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Colleagues see these fields on your card in the people widget and can find you by them.", + "Your profile fields could not be loaded." : "Your profile fields could not be loaded.", + "Not filled in" : "Not filled in", + "Filled from your organisation’s directory. You cannot change it here." : "Filled from your organisation’s directory. You cannot change it here.", + "Type a subject and press Enter" : "Type a subject and press Enter", + "Your profile fields are saved." : "Your profile fields are saved.", + "Your profile fields could not be saved." : "Your profile fields could not be saved.", + "Profile fields" : "Profile fields", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.", + "New field" : "New field", + "Tags" : "Tags", + "Filled by" : "Filled by", + "The person" : "The person", + "LDAP attribute" : "LDAP attribute", + "Who may see it" : "Who may see it", + "Everyone" : "Everyone", + "People in the same group" : "People in the same group", + "Searchable in the people widget" : "Searchable in the people widget", + "Shown on the card" : "Shown on the card", + "Remove field" : "Remove field", + "Profile fields saved." : "Profile fields saved.", + "Save profile fields" : "Save profile fields", + "The profile fields could not be loaded." : "The profile fields could not be loaded.", + "The profile fields could not be saved." : "The profile fields could not be saved." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/en.json b/l10n/en.json index 98283e8f2..50a16c214 100644 --- a/l10n/en.json +++ b/l10n/en.json @@ -1238,6 +1238,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Read receipts at the top of the dashboard show who has confirmed.", "{emoji}: {count} reactions": "{emoji}: {count} reactions", "React with {emoji}": "React with {emoji}", - "{names} and {count} more": "{names} and {count} more" + "{names} and {count} more": "{names} and {count} more", + "Search people": "Search people", + "Search by name, email or expertise…": "Search by name, email or expertise…", + "Find everyone tagged {tag}": "Find everyone tagged {tag}", + "LaunchPad profile": "LaunchPad profile", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Colleagues see these fields on your card in the people widget and can find you by them.", + "Your profile fields could not be loaded.": "Your profile fields could not be loaded.", + "Not filled in": "Not filled in", + "Filled from your organisation’s directory. You cannot change it here.": "Filled from your organisation’s directory. You cannot change it here.", + "Type a subject and press Enter": "Type a subject and press Enter", + "Your profile fields are saved.": "Your profile fields are saved.", + "Your profile fields could not be saved.": "Your profile fields could not be saved.", + "Profile fields": "Profile fields", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.", + "New field": "New field", + "Tags": "Tags", + "Filled by": "Filled by", + "The person": "The person", + "LDAP attribute": "LDAP attribute", + "Who may see it": "Who may see it", + "Everyone": "Everyone", + "People in the same group": "People in the same group", + "Searchable in the people widget": "Searchable in the people widget", + "Shown on the card": "Shown on the card", + "Remove field": "Remove field", + "Profile fields saved.": "Profile fields saved.", + "Save profile fields": "Save profile fields", + "The profile fields could not be loaded.": "The profile fields could not be loaded.", + "The profile fields could not be saved.": "The profile fields could not be saved." } } diff --git a/l10n/es.js b/l10n/es.js index 9cf89896c..3c4155627 100644 --- a/l10n/es.js +++ b/l10n/es.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Los acuses de lectura en la parte superior del panel muestran quién ha confirmado.", "{emoji}: {count} reactions" : "{emoji}: {count} reacciones", "React with {emoji}" : "Reaccionar con {emoji}", - "{names} and {count} more" : "{names} y {count} más" + "{names} and {count} more" : "{names} y {count} más", + "Search people" : "Buscar personas", + "Search by name, email or expertise…" : "Buscar por nombre, correo o especialidad…", + "Find everyone tagged {tag}" : "Buscar a todos con la etiqueta {tag}", + "LaunchPad profile" : "Perfil de LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Tus compañeros ven estos campos en tu tarjeta del widget de personas y pueden encontrarte por ellos.", + "Your profile fields could not be loaded." : "No se pudieron cargar los campos de tu perfil.", + "Not filled in" : "Sin rellenar", + "Filled from your organisation’s directory. You cannot change it here." : "Se rellena desde el directorio de tu organización. No puedes cambiarlo aquí.", + "Type a subject and press Enter" : "Escribe un tema y pulsa Intro", + "Your profile fields are saved." : "Los campos de tu perfil se han guardado.", + "Your profile fields could not be saved." : "No se pudieron guardar los campos de tu perfil.", + "Profile fields" : "Campos del perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Campos adicionales en las tarjetas de los compañeros del widget de personas, como la ubicación de la oficina o la especialidad. Las personas los rellenan en su configuración personal o proceden de un atributo LDAP.", + "New field" : "Campo nuevo", + "Tags" : "Etiquetas", + "Filled by" : "Lo rellena", + "The person" : "La propia persona", + "LDAP attribute" : "Atributo LDAP", + "Who may see it" : "Quién puede verlo", + "Everyone" : "Todos", + "People in the same group" : "Personas del mismo grupo", + "Searchable in the people widget" : "Se puede buscar en el widget de personas", + "Shown on the card" : "Se muestra en la tarjeta", + "Remove field" : "Quitar campo", + "Profile fields saved." : "Campos del perfil guardados.", + "Save profile fields" : "Guardar campos del perfil", + "The profile fields could not be loaded." : "No se pudieron cargar los campos del perfil.", + "The profile fields could not be saved." : "No se pudieron guardar los campos del perfil." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/es.json b/l10n/es.json index 1e79f347d..b5bb51d96 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Los acuses de lectura en la parte superior del panel muestran quién ha confirmado.", "{emoji}: {count} reactions": "{emoji}: {count} reacciones", "React with {emoji}": "Reaccionar con {emoji}", - "{names} and {count} more": "{names} y {count} más" + "{names} and {count} more": "{names} y {count} más", + "Search people": "Buscar personas", + "Search by name, email or expertise…": "Buscar por nombre, correo o especialidad…", + "Find everyone tagged {tag}": "Buscar a todos con la etiqueta {tag}", + "LaunchPad profile": "Perfil de LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Tus compañeros ven estos campos en tu tarjeta del widget de personas y pueden encontrarte por ellos.", + "Your profile fields could not be loaded.": "No se pudieron cargar los campos de tu perfil.", + "Not filled in": "Sin rellenar", + "Filled from your organisation’s directory. You cannot change it here.": "Se rellena desde el directorio de tu organización. No puedes cambiarlo aquí.", + "Type a subject and press Enter": "Escribe un tema y pulsa Intro", + "Your profile fields are saved.": "Los campos de tu perfil se han guardado.", + "Your profile fields could not be saved.": "No se pudieron guardar los campos de tu perfil.", + "Profile fields": "Campos del perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Campos adicionales en las tarjetas de los compañeros del widget de personas, como la ubicación de la oficina o la especialidad. Las personas los rellenan en su configuración personal o proceden de un atributo LDAP.", + "New field": "Campo nuevo", + "Tags": "Etiquetas", + "Filled by": "Lo rellena", + "The person": "La propia persona", + "LDAP attribute": "Atributo LDAP", + "Who may see it": "Quién puede verlo", + "Everyone": "Todos", + "People in the same group": "Personas del mismo grupo", + "Searchable in the people widget": "Se puede buscar en el widget de personas", + "Shown on the card": "Se muestra en la tarjeta", + "Remove field": "Quitar campo", + "Profile fields saved.": "Campos del perfil guardados.", + "Save profile fields": "Guardar campos del perfil", + "The profile fields could not be loaded.": "No se pudieron cargar los campos del perfil.", + "The profile fields could not be saved.": "No se pudieron guardar los campos del perfil." } } diff --git a/l10n/et.js b/l10n/et.js index c0a83f748..176dbb655 100644 --- a/l10n/et.js +++ b/l10n/et.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Töölaua ülaosas olevad lugemiskinnitused näitavad, kes on kinnitanud.", "{emoji}: {count} reactions" : "{emoji}: {count} reaktsiooni", "React with {emoji}" : "Reageeri: {emoji}", - "{names} and {count} more" : "{names} ja veel {count}" + "{names} and {count} more" : "{names} ja veel {count}", + "Search people" : "Otsi inimesi", + "Search by name, email or expertise…" : "Otsi nime, e-posti või asjatundlikkuse järgi…", + "Find everyone tagged {tag}" : "Leia kõik sildiga {tag}", + "LaunchPad profile" : "LaunchPadi profiil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolleegid näevad neid välju sinu kaardil inimeste vidinas ja saavad sind nende järgi leida.", + "Your profile fields could not be loaded." : "Sinu profiili välju ei õnnestunud laadida.", + "Not filled in" : "Täitmata", + "Filled from your organisation’s directory. You cannot change it here." : "Täidetud sinu organisatsiooni kataloogist. Siin seda muuta ei saa.", + "Type a subject and press Enter" : "Sisesta teema ja vajuta Enter", + "Your profile fields are saved." : "Sinu profiili väljad on salvestatud.", + "Your profile fields could not be saved." : "Sinu profiili välju ei õnnestunud salvestada.", + "Profile fields" : "Profiili väljad", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Lisaväljad kolleegide kaartidel inimeste vidinas, näiteks kontori asukoht või asjatundlikkus. Inimesed täidavad need oma isiklikes seadetes või tulevad need LDAP-atribuudist.", + "New field" : "Uus väli", + "Tags" : "Sildid", + "Filled by" : "Täidab", + "The person" : "Inimene ise", + "LDAP attribute" : "LDAP-atribuut", + "Who may see it" : "Kes võib seda näha", + "Everyone" : "Kõik", + "People in the same group" : "Samas grupis olevad inimesed", + "Searchable in the people widget" : "Otsitav inimeste vidinas", + "Shown on the card" : "Näidatakse kaardil", + "Remove field" : "Eemalda väli", + "Profile fields saved." : "Profiili väljad salvestatud.", + "Save profile fields" : "Salvesta profiili väljad", + "The profile fields could not be loaded." : "Profiili välju ei õnnestunud laadida.", + "The profile fields could not be saved." : "Profiili välju ei õnnestunud salvestada." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/et.json b/l10n/et.json index 11f3fba3b..856cf2a6a 100644 --- a/l10n/et.json +++ b/l10n/et.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Töölaua ülaosas olevad lugemiskinnitused näitavad, kes on kinnitanud.", "{emoji}: {count} reactions": "{emoji}: {count} reaktsiooni", "React with {emoji}": "Reageeri: {emoji}", - "{names} and {count} more": "{names} ja veel {count}" + "{names} and {count} more": "{names} ja veel {count}", + "Search people": "Otsi inimesi", + "Search by name, email or expertise…": "Otsi nime, e-posti või asjatundlikkuse järgi…", + "Find everyone tagged {tag}": "Leia kõik sildiga {tag}", + "LaunchPad profile": "LaunchPadi profiil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolleegid näevad neid välju sinu kaardil inimeste vidinas ja saavad sind nende järgi leida.", + "Your profile fields could not be loaded.": "Sinu profiili välju ei õnnestunud laadida.", + "Not filled in": "Täitmata", + "Filled from your organisation’s directory. You cannot change it here.": "Täidetud sinu organisatsiooni kataloogist. Siin seda muuta ei saa.", + "Type a subject and press Enter": "Sisesta teema ja vajuta Enter", + "Your profile fields are saved.": "Sinu profiili väljad on salvestatud.", + "Your profile fields could not be saved.": "Sinu profiili välju ei õnnestunud salvestada.", + "Profile fields": "Profiili väljad", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Lisaväljad kolleegide kaartidel inimeste vidinas, näiteks kontori asukoht või asjatundlikkus. Inimesed täidavad need oma isiklikes seadetes või tulevad need LDAP-atribuudist.", + "New field": "Uus väli", + "Tags": "Sildid", + "Filled by": "Täidab", + "The person": "Inimene ise", + "LDAP attribute": "LDAP-atribuut", + "Who may see it": "Kes võib seda näha", + "Everyone": "Kõik", + "People in the same group": "Samas grupis olevad inimesed", + "Searchable in the people widget": "Otsitav inimeste vidinas", + "Shown on the card": "Näidatakse kaardil", + "Remove field": "Eemalda väli", + "Profile fields saved.": "Profiili väljad salvestatud.", + "Save profile fields": "Salvesta profiili väljad", + "The profile fields could not be loaded.": "Profiili välju ei õnnestunud laadida.", + "The profile fields could not be saved.": "Profiili välju ei õnnestunud salvestada." } } diff --git a/l10n/fi.js b/l10n/fi.js index 9c99b20e5..cddec8a91 100644 --- a/l10n/fi.js +++ b/l10n/fi.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Koontinäytön yläosan lukukuittaukset näyttävät, kuka on vahvistanut.", "{emoji}: {count} reactions" : "{emoji}: {count} reaktiota", "React with {emoji}" : "Reagoi: {emoji}", - "{names} and {count} more" : "{names} ja {count} muuta" + "{names} and {count} more" : "{names} ja {count} muuta", + "Search people" : "Etsi henkilöitä", + "Search by name, email or expertise…" : "Hae nimellä, sähköpostilla tai osaamisella…", + "Find everyone tagged {tag}" : "Etsi kaikki, joilla on tunniste {tag}", + "LaunchPad profile" : "LaunchPad-profiili", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kollegat näkevät nämä kentät kortillasi henkilöt-pienoisohjelmassa ja voivat löytää sinut niiden avulla.", + "Your profile fields could not be loaded." : "Profiilikenttiäsi ei voitu ladata.", + "Not filled in" : "Ei täytetty", + "Filled from your organisation’s directory. You cannot change it here." : "Täytetty organisaatiosi hakemistosta. Et voi muuttaa sitä täällä.", + "Type a subject and press Enter" : "Kirjoita aihe ja paina Enter", + "Your profile fields are saved." : "Profiilikenttäsi on tallennettu.", + "Your profile fields could not be saved." : "Profiilikenttiäsi ei voitu tallentaa.", + "Profile fields" : "Profiilikentät", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Lisäkentät kollegoiden korteissa henkilöt-pienoisohjelmassa, kuten toimiston sijainti tai osaaminen. Henkilöt täyttävät ne omissa asetuksissaan, tai ne tulevat LDAP-attribuutista.", + "New field" : "Uusi kenttä", + "Tags" : "Tunnisteet", + "Filled by" : "Täyttäjä", + "The person" : "Henkilö itse", + "LDAP attribute" : "LDAP-attribuutti", + "Who may see it" : "Kuka saa nähdä sen", + "Everyone" : "Kaikki", + "People in the same group" : "Saman ryhmän henkilöt", + "Searchable in the people widget" : "Haettavissa henkilöt-pienoisohjelmassa", + "Shown on the card" : "Näytetään kortilla", + "Remove field" : "Poista kenttä", + "Profile fields saved." : "Profiilikentät tallennettu.", + "Save profile fields" : "Tallenna profiilikentät", + "The profile fields could not be loaded." : "Profiilikenttiä ei voitu ladata.", + "The profile fields could not be saved." : "Profiilikenttiä ei voitu tallentaa." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/fi.json b/l10n/fi.json index 399376115..943c32a29 100644 --- a/l10n/fi.json +++ b/l10n/fi.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Koontinäytön yläosan lukukuittaukset näyttävät, kuka on vahvistanut.", "{emoji}: {count} reactions": "{emoji}: {count} reaktiota", "React with {emoji}": "Reagoi: {emoji}", - "{names} and {count} more": "{names} ja {count} muuta" + "{names} and {count} more": "{names} ja {count} muuta", + "Search people": "Etsi henkilöitä", + "Search by name, email or expertise…": "Hae nimellä, sähköpostilla tai osaamisella…", + "Find everyone tagged {tag}": "Etsi kaikki, joilla on tunniste {tag}", + "LaunchPad profile": "LaunchPad-profiili", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kollegat näkevät nämä kentät kortillasi henkilöt-pienoisohjelmassa ja voivat löytää sinut niiden avulla.", + "Your profile fields could not be loaded.": "Profiilikenttiäsi ei voitu ladata.", + "Not filled in": "Ei täytetty", + "Filled from your organisation’s directory. You cannot change it here.": "Täytetty organisaatiosi hakemistosta. Et voi muuttaa sitä täällä.", + "Type a subject and press Enter": "Kirjoita aihe ja paina Enter", + "Your profile fields are saved.": "Profiilikenttäsi on tallennettu.", + "Your profile fields could not be saved.": "Profiilikenttiäsi ei voitu tallentaa.", + "Profile fields": "Profiilikentät", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Lisäkentät kollegoiden korteissa henkilöt-pienoisohjelmassa, kuten toimiston sijainti tai osaaminen. Henkilöt täyttävät ne omissa asetuksissaan, tai ne tulevat LDAP-attribuutista.", + "New field": "Uusi kenttä", + "Tags": "Tunnisteet", + "Filled by": "Täyttäjä", + "The person": "Henkilö itse", + "LDAP attribute": "LDAP-attribuutti", + "Who may see it": "Kuka saa nähdä sen", + "Everyone": "Kaikki", + "People in the same group": "Saman ryhmän henkilöt", + "Searchable in the people widget": "Haettavissa henkilöt-pienoisohjelmassa", + "Shown on the card": "Näytetään kortilla", + "Remove field": "Poista kenttä", + "Profile fields saved.": "Profiilikentät tallennettu.", + "Save profile fields": "Tallenna profiilikentät", + "The profile fields could not be loaded.": "Profiilikenttiä ei voitu ladata.", + "The profile fields could not be saved.": "Profiilikenttiä ei voitu tallentaa." } } diff --git a/l10n/fr.js b/l10n/fr.js index e18e7f107..307678377 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Les accusés de lecture en haut du tableau de bord montrent qui a confirmé.", "{emoji}: {count} reactions" : "{emoji} : {count} réactions", "React with {emoji}" : "Réagir avec {emoji}", - "{names} and {count} more" : "{names} et {count} autres" + "{names} and {count} more" : "{names} et {count} autres", + "Search people" : "Rechercher des personnes", + "Search by name, email or expertise…" : "Rechercher par nom, e-mail ou expertise…", + "Find everyone tagged {tag}" : "Trouver toutes les personnes avec l'étiquette {tag}", + "LaunchPad profile" : "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Vos collègues voient ces champs sur votre carte dans le widget Personnes et peuvent vous trouver grâce à eux.", + "Your profile fields could not be loaded." : "Les champs de votre profil n'ont pas pu être chargés.", + "Not filled in" : "Non renseigné", + "Filled from your organisation’s directory. You cannot change it here." : "Rempli depuis l'annuaire de votre organisation. Vous ne pouvez pas le modifier ici.", + "Type a subject and press Enter" : "Saisissez un sujet et appuyez sur Entrée", + "Your profile fields are saved." : "Les champs de votre profil sont enregistrés.", + "Your profile fields could not be saved." : "Les champs de votre profil n'ont pas pu être enregistrés.", + "Profile fields" : "Champs du profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Champs supplémentaires sur les cartes des collègues dans le widget Personnes, comme le lieu de travail ou l'expertise. Les personnes les remplissent dans leurs paramètres personnels, ou ils proviennent d'un attribut LDAP.", + "New field" : "Nouveau champ", + "Tags" : "Étiquettes", + "Filled by" : "Rempli par", + "The person" : "La personne", + "LDAP attribute" : "Attribut LDAP", + "Who may see it" : "Qui peut le voir", + "Everyone" : "Tout le monde", + "People in the same group" : "Les personnes du même groupe", + "Searchable in the people widget" : "Recherchable dans le widget Personnes", + "Shown on the card" : "Affiché sur la carte", + "Remove field" : "Supprimer le champ", + "Profile fields saved." : "Champs du profil enregistrés.", + "Save profile fields" : "Enregistrer les champs du profil", + "The profile fields could not be loaded." : "Les champs du profil n'ont pas pu être chargés.", + "The profile fields could not be saved." : "Les champs du profil n'ont pas pu être enregistrés." }, "nplurals=2; plural=(n > 1);" ); diff --git a/l10n/fr.json b/l10n/fr.json index 31c837f66..3c6046a8f 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Les accusés de lecture en haut du tableau de bord montrent qui a confirmé.", "{emoji}: {count} reactions": "{emoji} : {count} réactions", "React with {emoji}": "Réagir avec {emoji}", - "{names} and {count} more": "{names} et {count} autres" + "{names} and {count} more": "{names} et {count} autres", + "Search people": "Rechercher des personnes", + "Search by name, email or expertise…": "Rechercher par nom, e-mail ou expertise…", + "Find everyone tagged {tag}": "Trouver toutes les personnes avec l'étiquette {tag}", + "LaunchPad profile": "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Vos collègues voient ces champs sur votre carte dans le widget Personnes et peuvent vous trouver grâce à eux.", + "Your profile fields could not be loaded.": "Les champs de votre profil n'ont pas pu être chargés.", + "Not filled in": "Non renseigné", + "Filled from your organisation’s directory. You cannot change it here.": "Rempli depuis l'annuaire de votre organisation. Vous ne pouvez pas le modifier ici.", + "Type a subject and press Enter": "Saisissez un sujet et appuyez sur Entrée", + "Your profile fields are saved.": "Les champs de votre profil sont enregistrés.", + "Your profile fields could not be saved.": "Les champs de votre profil n'ont pas pu être enregistrés.", + "Profile fields": "Champs du profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Champs supplémentaires sur les cartes des collègues dans le widget Personnes, comme le lieu de travail ou l'expertise. Les personnes les remplissent dans leurs paramètres personnels, ou ils proviennent d'un attribut LDAP.", + "New field": "Nouveau champ", + "Tags": "Étiquettes", + "Filled by": "Rempli par", + "The person": "La personne", + "LDAP attribute": "Attribut LDAP", + "Who may see it": "Qui peut le voir", + "Everyone": "Tout le monde", + "People in the same group": "Les personnes du même groupe", + "Searchable in the people widget": "Recherchable dans le widget Personnes", + "Shown on the card": "Affiché sur la carte", + "Remove field": "Supprimer le champ", + "Profile fields saved.": "Champs du profil enregistrés.", + "Save profile fields": "Enregistrer les champs du profil", + "The profile fields could not be loaded.": "Les champs du profil n'ont pas pu être chargés.", + "The profile fields could not be saved.": "Les champs du profil n'ont pas pu être enregistrés." } } diff --git a/l10n/ga.js b/l10n/ga.js index 8f9f55d31..8ba1d1216 100644 --- a/l10n/ga.js +++ b/l10n/ga.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Taispeánann admhálacha léite ag barr an deais cé a dheimhnigh.", "{emoji}: {count} reactions" : "{emoji}: {count} imoibriú", "React with {emoji}" : "Freagair le {emoji}", - "{names} and {count} more" : "{names} agus {count} eile" + "{names} and {count} more" : "{names} agus {count} eile", + "Search people" : "Cuardaigh daoine", + "Search by name, email or expertise…" : "Cuardaigh de réir ainm, ríomhphost nó saineolas…", + "Find everyone tagged {tag}" : "Aimsigh gach duine leis an gclib {tag}", + "LaunchPad profile" : "Próifíl LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Feiceann comhghleacaithe na réimsí seo ar do chárta sa ghiuirléid daoine agus is féidir leo tú a aimsiú dá réir.", + "Your profile fields could not be loaded." : "Níorbh fhéidir réimsí do phróifíle a lódáil.", + "Not filled in" : "Gan líonadh", + "Filled from your organisation’s directory. You cannot change it here." : "Líonta ó eolaire d'eagraíochta. Ní féidir leat é a athrú anseo.", + "Type a subject and press Enter" : "Clóscríobh ábhar agus brúigh Enter", + "Your profile fields are saved." : "Tá réimsí do phróifíle sábháilte.", + "Your profile fields could not be saved." : "Níorbh fhéidir réimsí do phróifíle a shábháil.", + "Profile fields" : "Réimsí próifíle", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Réimsí breise ar chártaí comhghleacaithe sa ghiuirléid daoine, mar shampla suíomh oifige nó saineolas. Líonann daoine iad ina socruithe pearsanta, nó tagann siad ó aitreabúid LDAP.", + "New field" : "Réimse nua", + "Tags" : "Clibeanna", + "Filled by" : "Líonta ag", + "The person" : "An duine féin", + "LDAP attribute" : "Aitreabúid LDAP", + "Who may see it" : "Cé a fhéadfaidh é a fheiceáil", + "Everyone" : "Gach duine", + "People in the same group" : "Daoine sa ghrúpa céanna", + "Searchable in the people widget" : "Inchuardaithe sa ghiuirléid daoine", + "Shown on the card" : "Taispeántar ar an gcárta", + "Remove field" : "Bain an réimse", + "Profile fields saved." : "Réimsí próifíle sábháilte.", + "Save profile fields" : "Sábháil réimsí próifíle", + "The profile fields could not be loaded." : "Níorbh fhéidir na réimsí próifíle a lódáil.", + "The profile fields could not be saved." : "Níorbh fhéidir na réimsí próifíle a shábháil." }, "nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);" ); diff --git a/l10n/ga.json b/l10n/ga.json index 36856aec8..408ceb33b 100644 --- a/l10n/ga.json +++ b/l10n/ga.json @@ -1263,6 +1263,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Taispeánann admhálacha léite ag barr an deais cé a dheimhnigh.", "{emoji}: {count} reactions": "{emoji}: {count} imoibriú", "React with {emoji}": "Freagair le {emoji}", - "{names} and {count} more": "{names} agus {count} eile" + "{names} and {count} more": "{names} agus {count} eile", + "Search people": "Cuardaigh daoine", + "Search by name, email or expertise…": "Cuardaigh de réir ainm, ríomhphost nó saineolas…", + "Find everyone tagged {tag}": "Aimsigh gach duine leis an gclib {tag}", + "LaunchPad profile": "Próifíl LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Feiceann comhghleacaithe na réimsí seo ar do chárta sa ghiuirléid daoine agus is féidir leo tú a aimsiú dá réir.", + "Your profile fields could not be loaded.": "Níorbh fhéidir réimsí do phróifíle a lódáil.", + "Not filled in": "Gan líonadh", + "Filled from your organisation’s directory. You cannot change it here.": "Líonta ó eolaire d'eagraíochta. Ní féidir leat é a athrú anseo.", + "Type a subject and press Enter": "Clóscríobh ábhar agus brúigh Enter", + "Your profile fields are saved.": "Tá réimsí do phróifíle sábháilte.", + "Your profile fields could not be saved.": "Níorbh fhéidir réimsí do phróifíle a shábháil.", + "Profile fields": "Réimsí próifíle", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Réimsí breise ar chártaí comhghleacaithe sa ghiuirléid daoine, mar shampla suíomh oifige nó saineolas. Líonann daoine iad ina socruithe pearsanta, nó tagann siad ó aitreabúid LDAP.", + "New field": "Réimse nua", + "Tags": "Clibeanna", + "Filled by": "Líonta ag", + "The person": "An duine féin", + "LDAP attribute": "Aitreabúid LDAP", + "Who may see it": "Cé a fhéadfaidh é a fheiceáil", + "Everyone": "Gach duine", + "People in the same group": "Daoine sa ghrúpa céanna", + "Searchable in the people widget": "Inchuardaithe sa ghiuirléid daoine", + "Shown on the card": "Taispeántar ar an gcárta", + "Remove field": "Bain an réimse", + "Profile fields saved.": "Réimsí próifíle sábháilte.", + "Save profile fields": "Sábháil réimsí próifíle", + "The profile fields could not be loaded.": "Níorbh fhéidir na réimsí próifíle a lódáil.", + "The profile fields could not be saved.": "Níorbh fhéidir na réimsí próifíle a shábháil." } } diff --git a/l10n/hr.js b/l10n/hr.js index 7deacf70f..c4b220d61 100644 --- a/l10n/hr.js +++ b/l10n/hr.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potvrde čitanja na vrhu nadzorne ploče pokazuju tko je potvrdio.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcija", "React with {emoji}" : "Reagiraj s {emoji}", - "{names} and {count} more" : "{names} i još {count}" + "{names} and {count} more" : "{names} i još {count}", + "Search people" : "Pretraži osobe", + "Search by name, email or expertise…" : "Pretraži po imenu, e-pošti ili stručnosti…", + "Find everyone tagged {tag}" : "Pronađi sve s oznakom {tag}", + "LaunchPad profile" : "LaunchPad profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolege vide ova polja na vašoj kartici u widgetu osoba i mogu vas pronaći po njima.", + "Your profile fields could not be loaded." : "Polja vašeg profila nije bilo moguće učitati.", + "Not filled in" : "Nije popunjeno", + "Filled from your organisation’s directory. You cannot change it here." : "Popunjeno iz imenika vaše organizacije. Ovdje ga ne možete promijeniti.", + "Type a subject and press Enter" : "Upišite temu i pritisnite Enter", + "Your profile fields are saved." : "Polja vašeg profila su spremljena.", + "Your profile fields could not be saved." : "Polja vašeg profila nije bilo moguće spremiti.", + "Profile fields" : "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Dodatna polja na karticama kolega u widgetu osoba, poput lokacije ureda ili stručnosti. Osobe ih ispunjavaju u osobnim postavkama ili dolaze iz LDAP atributa.", + "New field" : "Novo polje", + "Tags" : "Oznake", + "Filled by" : "Popunjava", + "The person" : "Sama osoba", + "LDAP attribute" : "LDAP atribut", + "Who may see it" : "Ko ga smije vidjeti", + "Everyone" : "Svi", + "People in the same group" : "Osobe u istoj grupi", + "Searchable in the people widget" : "Pretraživo u widgetu osoba", + "Shown on the card" : "Prikazano na kartici", + "Remove field" : "Ukloni polje", + "Profile fields saved." : "Polja profila su spremljena.", + "Save profile fields" : "Spremi polja profila", + "The profile fields could not be loaded." : "Polja profila nije bilo moguće učitati.", + "The profile fields could not be saved." : "Polja profila nije bilo moguće spremiti." }, "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/l10n/hr.json b/l10n/hr.json index 315f901d9..2c565a477 100644 --- a/l10n/hr.json +++ b/l10n/hr.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potvrde čitanja na vrhu nadzorne ploče pokazuju tko je potvrdio.", "{emoji}: {count} reactions": "{emoji}: {count} reakcija", "React with {emoji}": "Reagiraj s {emoji}", - "{names} and {count} more": "{names} i još {count}" + "{names} and {count} more": "{names} i još {count}", + "Search people": "Pretraži osobe", + "Search by name, email or expertise…": "Pretraži po imenu, e-pošti ili stručnosti…", + "Find everyone tagged {tag}": "Pronađi sve s oznakom {tag}", + "LaunchPad profile": "LaunchPad profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolege vide ova polja na vašoj kartici u widgetu osoba i mogu vas pronaći po njima.", + "Your profile fields could not be loaded.": "Polja vašeg profila nije bilo moguće učitati.", + "Not filled in": "Nije popunjeno", + "Filled from your organisation’s directory. You cannot change it here.": "Popunjeno iz imenika vaše organizacije. Ovdje ga ne možete promijeniti.", + "Type a subject and press Enter": "Upišite temu i pritisnite Enter", + "Your profile fields are saved.": "Polja vašeg profila su spremljena.", + "Your profile fields could not be saved.": "Polja vašeg profila nije bilo moguće spremiti.", + "Profile fields": "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Dodatna polja na karticama kolega u widgetu osoba, poput lokacije ureda ili stručnosti. Osobe ih ispunjavaju u osobnim postavkama ili dolaze iz LDAP atributa.", + "New field": "Novo polje", + "Tags": "Oznake", + "Filled by": "Popunjava", + "The person": "Sama osoba", + "LDAP attribute": "LDAP atribut", + "Who may see it": "Ko ga smije vidjeti", + "Everyone": "Svi", + "People in the same group": "Osobe u istoj grupi", + "Searchable in the people widget": "Pretraživo u widgetu osoba", + "Shown on the card": "Prikazano na kartici", + "Remove field": "Ukloni polje", + "Profile fields saved.": "Polja profila su spremljena.", + "Save profile fields": "Spremi polja profila", + "The profile fields could not be loaded.": "Polja profila nije bilo moguće učitati.", + "The profile fields could not be saved.": "Polja profila nije bilo moguće spremiti." } } diff --git a/l10n/hu.js b/l10n/hu.js index 0e3e1cb1d..fc626aa13 100644 --- a/l10n/hu.js +++ b/l10n/hu.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Az irányítópult tetején lévő olvasási nyugták mutatják, ki igazolta.", "{emoji}: {count} reactions" : "{emoji}: {count} reakció", "React with {emoji}" : "Reagálás ezzel: {emoji}", - "{names} and {count} more" : "{names} és még {count}" + "{names} and {count} more" : "{names} és még {count}", + "Search people" : "Személyek keresése", + "Search by name, email or expertise…" : "Keresés név, e-mail vagy szakterület szerint…", + "Find everyone tagged {tag}" : "Mindenki keresése {tag} címkével", + "LaunchPad profile" : "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "A kollégák látják ezeket a mezőket a kártyádon a személyek widgetben, és ezek alapján megtalálhatnak.", + "Your profile fields could not be loaded." : "A profilmezőidet nem sikerült betölteni.", + "Not filled in" : "Nincs kitöltve", + "Filled from your organisation’s directory. You cannot change it here." : "A szervezeted címtárából töltődik ki. Itt nem módosíthatod.", + "Type a subject and press Enter" : "Írj be egy témát, és nyomd meg az Entert", + "Your profile fields are saved." : "A profilmezőid mentve.", + "Your profile fields could not be saved." : "A profilmezőidet nem sikerült menteni.", + "Profile fields" : "Profilmezők", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "További mezők a kollégák kártyáin a személyek widgetben, például irodai helyszín vagy szakterület. Az emberek a személyes beállításaikban töltik ki őket, vagy egy LDAP-attribútumból származnak.", + "New field" : "Új mező", + "Tags" : "Címkék", + "Filled by" : "Kitölti", + "The person" : "Maga a személy", + "LDAP attribute" : "LDAP-attribútum", + "Who may see it" : "Ki láthatja", + "Everyone" : "Mindenki", + "People in the same group" : "Az azonos csoport tagjai", + "Searchable in the people widget" : "Kereshető a személyek widgetben", + "Shown on the card" : "Megjelenik a kártyán", + "Remove field" : "Mező eltávolítása", + "Profile fields saved." : "Profilmezők mentve.", + "Save profile fields" : "Profilmezők mentése", + "The profile fields could not be loaded." : "A profilmezőket nem sikerült betölteni.", + "The profile fields could not be saved." : "A profilmezőket nem sikerült menteni." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/hu.json b/l10n/hu.json index 65657518d..4ca822358 100644 --- a/l10n/hu.json +++ b/l10n/hu.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Az irányítópult tetején lévő olvasási nyugták mutatják, ki igazolta.", "{emoji}: {count} reactions": "{emoji}: {count} reakció", "React with {emoji}": "Reagálás ezzel: {emoji}", - "{names} and {count} more": "{names} és még {count}" + "{names} and {count} more": "{names} és még {count}", + "Search people": "Személyek keresése", + "Search by name, email or expertise…": "Keresés név, e-mail vagy szakterület szerint…", + "Find everyone tagged {tag}": "Mindenki keresése {tag} címkével", + "LaunchPad profile": "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "A kollégák látják ezeket a mezőket a kártyádon a személyek widgetben, és ezek alapján megtalálhatnak.", + "Your profile fields could not be loaded.": "A profilmezőidet nem sikerült betölteni.", + "Not filled in": "Nincs kitöltve", + "Filled from your organisation’s directory. You cannot change it here.": "A szervezeted címtárából töltődik ki. Itt nem módosíthatod.", + "Type a subject and press Enter": "Írj be egy témát, és nyomd meg az Entert", + "Your profile fields are saved.": "A profilmezőid mentve.", + "Your profile fields could not be saved.": "A profilmezőidet nem sikerült menteni.", + "Profile fields": "Profilmezők", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "További mezők a kollégák kártyáin a személyek widgetben, például irodai helyszín vagy szakterület. Az emberek a személyes beállításaikban töltik ki őket, vagy egy LDAP-attribútumból származnak.", + "New field": "Új mező", + "Tags": "Címkék", + "Filled by": "Kitölti", + "The person": "Maga a személy", + "LDAP attribute": "LDAP-attribútum", + "Who may see it": "Ki láthatja", + "Everyone": "Mindenki", + "People in the same group": "Az azonos csoport tagjai", + "Searchable in the people widget": "Kereshető a személyek widgetben", + "Shown on the card": "Megjelenik a kártyán", + "Remove field": "Mező eltávolítása", + "Profile fields saved.": "Profilmezők mentve.", + "Save profile fields": "Profilmezők mentése", + "The profile fields could not be loaded.": "A profilmezőket nem sikerült betölteni.", + "The profile fields could not be saved.": "A profilmezőket nem sikerült menteni." } } diff --git a/l10n/is.js b/l10n/is.js index 21f97d669..64029bd3c 100644 --- a/l10n/is.js +++ b/l10n/is.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Leskvittanir efst á stjórnborðinu sýna hver hefur staðfest.", "{emoji}: {count} reactions" : "{emoji}: {count} viðbrögð", "React with {emoji}" : "Bregðast við með {emoji}", - "{names} and {count} more" : "{names} og {count} til viðbótar" + "{names} and {count} more" : "{names} og {count} til viðbótar", + "Search people" : "Leita að fólki", + "Search by name, email or expertise…" : "Leita eftir nafni, netfangi eða sérþekkingu…", + "Find everyone tagged {tag}" : "Finna alla með merkið {tag}", + "LaunchPad profile" : "LaunchPad-prófíll", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Samstarfsfólk sér þessa reiti á spjaldinu þínu í fólksviðbótinni og getur fundið þig eftir þeim.", + "Your profile fields could not be loaded." : "Ekki tókst að hlaða inn prófílreitunum þínum.", + "Not filled in" : "Ekki útfyllt", + "Filled from your organisation’s directory. You cannot change it here." : "Fyllt út úr skrá fyrirtækisins. Þú getur ekki breytt því hér.", + "Type a subject and press Enter" : "Sláðu inn efni og ýttu á Enter", + "Your profile fields are saved." : "Prófílreitirnir þínir eru vistaðir.", + "Your profile fields could not be saved." : "Ekki tókst að vista prófílreitina þína.", + "Profile fields" : "Prófílreitir", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Viðbótarreitir á spjöldum samstarfsfólks í fólksviðbótinni, svo sem staðsetning skrifstofu eða sérþekking. Fólk fyllir þá út í eigin stillingum, eða þeir koma úr LDAP-eigind.", + "New field" : "Nýr reitur", + "Tags" : "Merki", + "Filled by" : "Útfyllt af", + "The person" : "Viðkomandi sjálfur", + "LDAP attribute" : "LDAP-eigind", + "Who may see it" : "Hver má sjá það", + "Everyone" : "Allir", + "People in the same group" : "Fólk í sama hópi", + "Searchable in the people widget" : "Leitanlegt í fólksviðbótinni", + "Shown on the card" : "Birtist á spjaldinu", + "Remove field" : "Fjarlægja reit", + "Profile fields saved." : "Prófílreitir vistaðir.", + "Save profile fields" : "Vista prófílreiti", + "The profile fields could not be loaded." : "Ekki tókst að hlaða inn prófílreitunum.", + "The profile fields could not be saved." : "Ekki tókst að vista prófílreitina." }, "nplurals=2; plural=(n%10!=1 || n%100==11);" ); diff --git a/l10n/is.json b/l10n/is.json index b3c5075f6..de529d623 100644 --- a/l10n/is.json +++ b/l10n/is.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Leskvittanir efst á stjórnborðinu sýna hver hefur staðfest.", "{emoji}: {count} reactions": "{emoji}: {count} viðbrögð", "React with {emoji}": "Bregðast við með {emoji}", - "{names} and {count} more": "{names} og {count} til viðbótar" + "{names} and {count} more": "{names} og {count} til viðbótar", + "Search people": "Leita að fólki", + "Search by name, email or expertise…": "Leita eftir nafni, netfangi eða sérþekkingu…", + "Find everyone tagged {tag}": "Finna alla með merkið {tag}", + "LaunchPad profile": "LaunchPad-prófíll", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Samstarfsfólk sér þessa reiti á spjaldinu þínu í fólksviðbótinni og getur fundið þig eftir þeim.", + "Your profile fields could not be loaded.": "Ekki tókst að hlaða inn prófílreitunum þínum.", + "Not filled in": "Ekki útfyllt", + "Filled from your organisation’s directory. You cannot change it here.": "Fyllt út úr skrá fyrirtækisins. Þú getur ekki breytt því hér.", + "Type a subject and press Enter": "Sláðu inn efni og ýttu á Enter", + "Your profile fields are saved.": "Prófílreitirnir þínir eru vistaðir.", + "Your profile fields could not be saved.": "Ekki tókst að vista prófílreitina þína.", + "Profile fields": "Prófílreitir", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Viðbótarreitir á spjöldum samstarfsfólks í fólksviðbótinni, svo sem staðsetning skrifstofu eða sérþekking. Fólk fyllir þá út í eigin stillingum, eða þeir koma úr LDAP-eigind.", + "New field": "Nýr reitur", + "Tags": "Merki", + "Filled by": "Útfyllt af", + "The person": "Viðkomandi sjálfur", + "LDAP attribute": "LDAP-eigind", + "Who may see it": "Hver má sjá það", + "Everyone": "Allir", + "People in the same group": "Fólk í sama hópi", + "Searchable in the people widget": "Leitanlegt í fólksviðbótinni", + "Shown on the card": "Birtist á spjaldinu", + "Remove field": "Fjarlægja reit", + "Profile fields saved.": "Prófílreitir vistaðir.", + "Save profile fields": "Vista prófílreiti", + "The profile fields could not be loaded.": "Ekki tókst að hlaða inn prófílreitunum.", + "The profile fields could not be saved.": "Ekki tókst að vista prófílreitina." } } diff --git a/l10n/it.js b/l10n/it.js index 754591227..ab0446c0d 100644 --- a/l10n/it.js +++ b/l10n/it.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Le conferme di lettura in cima alla dashboard mostrano chi ha confermato.", "{emoji}: {count} reactions" : "{emoji}: {count} reazioni", "React with {emoji}" : "Reagisci con {emoji}", - "{names} and {count} more" : "{names} e altri {count}" + "{names} and {count} more" : "{names} e altri {count}", + "Search people" : "Cerca persone", + "Search by name, email or expertise…" : "Cerca per nome, e-mail o competenza…", + "Find everyone tagged {tag}" : "Trova tutti con il tag {tag}", + "LaunchPad profile" : "Profilo LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "I colleghi vedono questi campi sulla tua scheda nel widget persone e possono trovarti tramite essi.", + "Your profile fields could not be loaded." : "Non è stato possibile caricare i campi del tuo profilo.", + "Not filled in" : "Non compilato", + "Filled from your organisation’s directory. You cannot change it here." : "Compilato dalla directory della tua organizzazione. Non puoi modificarlo qui.", + "Type a subject and press Enter" : "Scrivi un argomento e premi Invio", + "Your profile fields are saved." : "I campi del tuo profilo sono salvati.", + "Your profile fields could not be saved." : "Non è stato possibile salvare i campi del tuo profilo.", + "Profile fields" : "Campi del profilo", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Campi aggiuntivi sulle schede dei colleghi nel widget persone, come la sede dell'ufficio o la competenza. Le persone li compilano nelle impostazioni personali, oppure provengono da un attributo LDAP.", + "New field" : "Nuovo campo", + "Tags" : "Tag", + "Filled by" : "Compilato da", + "The person" : "La persona stessa", + "LDAP attribute" : "Attributo LDAP", + "Who may see it" : "Chi può vederlo", + "Everyone" : "Tutti", + "People in the same group" : "Persone dello stesso gruppo", + "Searchable in the people widget" : "Ricercabile nel widget persone", + "Shown on the card" : "Mostrato sulla scheda", + "Remove field" : "Rimuovi campo", + "Profile fields saved." : "Campi del profilo salvati.", + "Save profile fields" : "Salva campi del profilo", + "The profile fields could not be loaded." : "Non è stato possibile caricare i campi del profilo.", + "The profile fields could not be saved." : "Non è stato possibile salvare i campi del profilo." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/it.json b/l10n/it.json index 51683e4fb..fa3dd24fa 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Le conferme di lettura in cima alla dashboard mostrano chi ha confermato.", "{emoji}: {count} reactions": "{emoji}: {count} reazioni", "React with {emoji}": "Reagisci con {emoji}", - "{names} and {count} more": "{names} e altri {count}" + "{names} and {count} more": "{names} e altri {count}", + "Search people": "Cerca persone", + "Search by name, email or expertise…": "Cerca per nome, e-mail o competenza…", + "Find everyone tagged {tag}": "Trova tutti con il tag {tag}", + "LaunchPad profile": "Profilo LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "I colleghi vedono questi campi sulla tua scheda nel widget persone e possono trovarti tramite essi.", + "Your profile fields could not be loaded.": "Non è stato possibile caricare i campi del tuo profilo.", + "Not filled in": "Non compilato", + "Filled from your organisation’s directory. You cannot change it here.": "Compilato dalla directory della tua organizzazione. Non puoi modificarlo qui.", + "Type a subject and press Enter": "Scrivi un argomento e premi Invio", + "Your profile fields are saved.": "I campi del tuo profilo sono salvati.", + "Your profile fields could not be saved.": "Non è stato possibile salvare i campi del tuo profilo.", + "Profile fields": "Campi del profilo", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Campi aggiuntivi sulle schede dei colleghi nel widget persone, come la sede dell'ufficio o la competenza. Le persone li compilano nelle impostazioni personali, oppure provengono da un attributo LDAP.", + "New field": "Nuovo campo", + "Tags": "Tag", + "Filled by": "Compilato da", + "The person": "La persona stessa", + "LDAP attribute": "Attributo LDAP", + "Who may see it": "Chi può vederlo", + "Everyone": "Tutti", + "People in the same group": "Persone dello stesso gruppo", + "Searchable in the people widget": "Ricercabile nel widget persone", + "Shown on the card": "Mostrato sulla scheda", + "Remove field": "Rimuovi campo", + "Profile fields saved.": "Campi del profilo salvati.", + "Save profile fields": "Salva campi del profilo", + "The profile fields could not be loaded.": "Non è stato possibile caricare i campi del profilo.", + "The profile fields could not be saved.": "Non è stato possibile salvare i campi del profilo." } } diff --git a/l10n/lb.js b/l10n/lb.js index 6cfc4cc3b..84faec3ed 100644 --- a/l10n/lb.js +++ b/l10n/lb.js @@ -1284,7 +1284,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Liesquittungen uewen um Dashboard weisen, wie bestätegt huet.", "{emoji}: {count} reactions" : "{emoji}: {count} Reaktiounen", "React with {emoji}" : "Mat {emoji} reagéieren", - "{names} and {count} more" : "{names} an nach {count}" + "{names} and {count} more" : "{names} an nach {count}", + "Search people" : "Leit sichen", + "Search by name, email or expertise…" : "No Numm, E-Mail oder Expertis sichen…", + "Find everyone tagged {tag}" : "All Leit mam Tag {tag} fannen", + "LaunchPad profile" : "LaunchPad-Profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolleegen gesinn dës Felder op denger Kaart am Leit-Widget a kënnen dech doriwwer fannen.", + "Your profile fields could not be loaded." : "Deng Profilfelder konnte net geluede ginn.", + "Not filled in" : "Net ausgefëllt", + "Filled from your organisation’s directory. You cannot change it here." : "Aus dem Verzeechnes vun denger Organisatioun. Du kanns et hei net änneren.", + "Type a subject and press Enter" : "Thema aginn an Enter drécken", + "Your profile fields are saved." : "Deng Profilfelder sinn gespäichert.", + "Your profile fields could not be saved." : "Deng Profilfelder konnte net gespäichert ginn.", + "Profile fields" : "Profilfelder", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Zousätzlech Felder op de Kaarte vu Kolleegen am Leit-Widget, wéi Büro oder Expertis. D'Leit fëllen se an hire perséinlechen Astellungen aus, oder se kommen aus engem LDAP-Attribut.", + "New field" : "Neit Feld", + "Tags" : "Tags", + "Filled by" : "Ausgefëllt vun", + "The person" : "D'Persoun selwer", + "LDAP attribute" : "LDAP-Attribut", + "Who may see it" : "Wien et gesi dierf", + "Everyone" : "Jiddereen", + "People in the same group" : "Leit an der selwechter Grupp", + "Searchable in the people widget" : "Am Leit-Widget sichbar", + "Shown on the card" : "Op der Kaart gewisen", + "Remove field" : "Feld ewechhuelen", + "Profile fields saved." : "Profilfelder gespäichert.", + "Save profile fields" : "Profilfelder späicheren", + "The profile fields could not be loaded." : "D'Profilfelder konnten net geluede ginn.", + "The profile fields could not be saved." : "D'Profilfelder konnten net gespäichert ginn." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/lb.json b/l10n/lb.json index 81d6fd118..e6fc3747f 100644 --- a/l10n/lb.json +++ b/l10n/lb.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Liesquittungen uewen um Dashboard weisen, wie bestätegt huet.", "{emoji}: {count} reactions": "{emoji}: {count} Reaktiounen", "React with {emoji}": "Mat {emoji} reagéieren", - "{names} and {count} more": "{names} an nach {count}" + "{names} and {count} more": "{names} an nach {count}", + "Search people": "Leit sichen", + "Search by name, email or expertise…": "No Numm, E-Mail oder Expertis sichen…", + "Find everyone tagged {tag}": "All Leit mam Tag {tag} fannen", + "LaunchPad profile": "LaunchPad-Profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolleegen gesinn dës Felder op denger Kaart am Leit-Widget a kënnen dech doriwwer fannen.", + "Your profile fields could not be loaded.": "Deng Profilfelder konnte net geluede ginn.", + "Not filled in": "Net ausgefëllt", + "Filled from your organisation’s directory. You cannot change it here.": "Aus dem Verzeechnes vun denger Organisatioun. Du kanns et hei net änneren.", + "Type a subject and press Enter": "Thema aginn an Enter drécken", + "Your profile fields are saved.": "Deng Profilfelder sinn gespäichert.", + "Your profile fields could not be saved.": "Deng Profilfelder konnte net gespäichert ginn.", + "Profile fields": "Profilfelder", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Zousätzlech Felder op de Kaarte vu Kolleegen am Leit-Widget, wéi Büro oder Expertis. D'Leit fëllen se an hire perséinlechen Astellungen aus, oder se kommen aus engem LDAP-Attribut.", + "New field": "Neit Feld", + "Tags": "Tags", + "Filled by": "Ausgefëllt vun", + "The person": "D'Persoun selwer", + "LDAP attribute": "LDAP-Attribut", + "Who may see it": "Wien et gesi dierf", + "Everyone": "Jiddereen", + "People in the same group": "Leit an der selwechter Grupp", + "Searchable in the people widget": "Am Leit-Widget sichbar", + "Shown on the card": "Op der Kaart gewisen", + "Remove field": "Feld ewechhuelen", + "Profile fields saved.": "Profilfelder gespäichert.", + "Save profile fields": "Profilfelder späicheren", + "The profile fields could not be loaded.": "D'Profilfelder konnten net geluede ginn.", + "The profile fields could not be saved.": "D'Profilfelder konnten net gespäichert ginn." } } diff --git a/l10n/lt.js b/l10n/lt.js index fe964afa9..8017d3ed4 100644 --- a/l10n/lt.js +++ b/l10n/lt.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Perskaitymo kvitai suvestinės viršuje rodo, kas patvirtino.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcijos", "React with {emoji}" : "Reaguoti {emoji}", - "{names} and {count} more" : "{names} ir dar {count}" + "{names} and {count} more" : "{names} ir dar {count}", + "Search people" : "Ieškoti žmonių", + "Search by name, email or expertise…" : "Ieškoti pagal vardą, el. paštą ar kompetenciją…", + "Find everyone tagged {tag}" : "Rasti visus su žyma {tag}", + "LaunchPad profile" : "LaunchPad profilis", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolegos mato šiuos laukus jūsų kortelėje žmonių valdiklyje ir gali jus pagal juos rasti.", + "Your profile fields could not be loaded." : "Nepavyko įkelti jūsų profilio laukų.", + "Not filled in" : "Neužpildyta", + "Filled from your organisation’s directory. You cannot change it here." : "Užpildyta iš jūsų organizacijos katalogo. Čia to pakeisti negalite.", + "Type a subject and press Enter" : "Įveskite temą ir paspauskite Enter", + "Your profile fields are saved." : "Jūsų profilio laukai išsaugoti.", + "Your profile fields could not be saved." : "Nepavyko išsaugoti jūsų profilio laukų.", + "Profile fields" : "Profilio laukai", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Papildomi laukai kolegų kortelėse žmonių valdiklyje, pavyzdžiui, biuro vieta ar kompetencija. Žmonės juos užpildo savo asmeniniuose nustatymuose arba jie gaunami iš LDAP atributo.", + "New field" : "Naujas laukas", + "Tags" : "Žymos", + "Filled by" : "Užpildo", + "The person" : "Pats asmuo", + "LDAP attribute" : "LDAP atributas", + "Who may see it" : "Kas gali matyti", + "Everyone" : "Visi", + "People in the same group" : "To paties grupės žmonės", + "Searchable in the people widget" : "Ieškoma žmonių valdiklyje", + "Shown on the card" : "Rodoma kortelėje", + "Remove field" : "Pašalinti lauką", + "Profile fields saved." : "Profilio laukai išsaugoti.", + "Save profile fields" : "Išsaugoti profilio laukus", + "The profile fields could not be loaded." : "Nepavyko įkelti profilio laukų.", + "The profile fields could not be saved." : "Nepavyko išsaugoti profilio laukų." }, "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);" ); diff --git a/l10n/lt.json b/l10n/lt.json index 1949dc682..b0bd59a86 100644 --- a/l10n/lt.json +++ b/l10n/lt.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Perskaitymo kvitai suvestinės viršuje rodo, kas patvirtino.", "{emoji}: {count} reactions": "{emoji}: {count} reakcijos", "React with {emoji}": "Reaguoti {emoji}", - "{names} and {count} more": "{names} ir dar {count}" + "{names} and {count} more": "{names} ir dar {count}", + "Search people": "Ieškoti žmonių", + "Search by name, email or expertise…": "Ieškoti pagal vardą, el. paštą ar kompetenciją…", + "Find everyone tagged {tag}": "Rasti visus su žyma {tag}", + "LaunchPad profile": "LaunchPad profilis", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolegos mato šiuos laukus jūsų kortelėje žmonių valdiklyje ir gali jus pagal juos rasti.", + "Your profile fields could not be loaded.": "Nepavyko įkelti jūsų profilio laukų.", + "Not filled in": "Neužpildyta", + "Filled from your organisation’s directory. You cannot change it here.": "Užpildyta iš jūsų organizacijos katalogo. Čia to pakeisti negalite.", + "Type a subject and press Enter": "Įveskite temą ir paspauskite Enter", + "Your profile fields are saved.": "Jūsų profilio laukai išsaugoti.", + "Your profile fields could not be saved.": "Nepavyko išsaugoti jūsų profilio laukų.", + "Profile fields": "Profilio laukai", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Papildomi laukai kolegų kortelėse žmonių valdiklyje, pavyzdžiui, biuro vieta ar kompetencija. Žmonės juos užpildo savo asmeniniuose nustatymuose arba jie gaunami iš LDAP atributo.", + "New field": "Naujas laukas", + "Tags": "Žymos", + "Filled by": "Užpildo", + "The person": "Pats asmuo", + "LDAP attribute": "LDAP atributas", + "Who may see it": "Kas gali matyti", + "Everyone": "Visi", + "People in the same group": "To paties grupės žmonės", + "Searchable in the people widget": "Ieškoma žmonių valdiklyje", + "Shown on the card": "Rodoma kortelėje", + "Remove field": "Pašalinti lauką", + "Profile fields saved.": "Profilio laukai išsaugoti.", + "Save profile fields": "Išsaugoti profilio laukus", + "The profile fields could not be loaded.": "Nepavyko įkelti profilio laukų.", + "The profile fields could not be saved.": "Nepavyko išsaugoti profilio laukų." } } diff --git a/l10n/lv.js b/l10n/lv.js index c630fb4c2..967b9beb5 100644 --- a/l10n/lv.js +++ b/l10n/lv.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Izlasīšanas apliecinājumi paneļa augšā rāda, kurš ir apstiprinājis.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcijas", "React with {emoji}" : "Reaģēt ar {emoji}", - "{names} and {count} more" : "{names} un vēl {count}" + "{names} and {count} more" : "{names} un vēl {count}", + "Search people" : "Meklēt cilvēkus", + "Search by name, email or expertise…" : "Meklēt pēc vārda, e-pasta vai kompetences…", + "Find everyone tagged {tag}" : "Atrast visus ar birku {tag}", + "LaunchPad profile" : "LaunchPad profils", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolēģi redz šos laukus jūsu kartītē cilvēku logrīkā un var jūs pēc tiem atrast.", + "Your profile fields could not be loaded." : "Neizdevās ielādēt jūsu profila laukus.", + "Not filled in" : "Nav aizpildīts", + "Filled from your organisation’s directory. You cannot change it here." : "Aizpildīts no jūsu organizācijas direktorija. Šeit to mainīt nevar.", + "Type a subject and press Enter" : "Ierakstiet tēmu un nospiediet Enter", + "Your profile fields are saved." : "Jūsu profila lauki ir saglabāti.", + "Your profile fields could not be saved." : "Neizdevās saglabāt jūsu profila laukus.", + "Profile fields" : "Profila lauki", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Papildu lauki kolēģu kartītēs cilvēku logrīkā, piemēram, biroja atrašanās vieta vai kompetence. Cilvēki tos aizpilda savos personīgajos iestatījumos, vai tie nāk no LDAP atribūta.", + "New field" : "Jauns lauks", + "Tags" : "Birkas", + "Filled by" : "Aizpilda", + "The person" : "Pati persona", + "LDAP attribute" : "LDAP atribūts", + "Who may see it" : "Kas drīkst to redzēt", + "Everyone" : "Visi", + "People in the same group" : "Tās pašas grupas cilvēki", + "Searchable in the people widget" : "Meklējams cilvēku logrīkā", + "Shown on the card" : "Rādīts kartītē", + "Remove field" : "Noņemt lauku", + "Profile fields saved." : "Profila lauki saglabāti.", + "Save profile fields" : "Saglabāt profila laukus", + "The profile fields could not be loaded." : "Neizdevās ielādēt profila laukus.", + "The profile fields could not be saved." : "Neizdevās saglabāt profila laukus." }, "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);" ); diff --git a/l10n/lv.json b/l10n/lv.json index b6bfc65d8..e1a6d207b 100644 --- a/l10n/lv.json +++ b/l10n/lv.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Izlasīšanas apliecinājumi paneļa augšā rāda, kurš ir apstiprinājis.", "{emoji}: {count} reactions": "{emoji}: {count} reakcijas", "React with {emoji}": "Reaģēt ar {emoji}", - "{names} and {count} more": "{names} un vēl {count}" + "{names} and {count} more": "{names} un vēl {count}", + "Search people": "Meklēt cilvēkus", + "Search by name, email or expertise…": "Meklēt pēc vārda, e-pasta vai kompetences…", + "Find everyone tagged {tag}": "Atrast visus ar birku {tag}", + "LaunchPad profile": "LaunchPad profils", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolēģi redz šos laukus jūsu kartītē cilvēku logrīkā un var jūs pēc tiem atrast.", + "Your profile fields could not be loaded.": "Neizdevās ielādēt jūsu profila laukus.", + "Not filled in": "Nav aizpildīts", + "Filled from your organisation’s directory. You cannot change it here.": "Aizpildīts no jūsu organizācijas direktorija. Šeit to mainīt nevar.", + "Type a subject and press Enter": "Ierakstiet tēmu un nospiediet Enter", + "Your profile fields are saved.": "Jūsu profila lauki ir saglabāti.", + "Your profile fields could not be saved.": "Neizdevās saglabāt jūsu profila laukus.", + "Profile fields": "Profila lauki", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Papildu lauki kolēģu kartītēs cilvēku logrīkā, piemēram, biroja atrašanās vieta vai kompetence. Cilvēki tos aizpilda savos personīgajos iestatījumos, vai tie nāk no LDAP atribūta.", + "New field": "Jauns lauks", + "Tags": "Birkas", + "Filled by": "Aizpilda", + "The person": "Pati persona", + "LDAP attribute": "LDAP atribūts", + "Who may see it": "Kas drīkst to redzēt", + "Everyone": "Visi", + "People in the same group": "Tās pašas grupas cilvēki", + "Searchable in the people widget": "Meklējams cilvēku logrīkā", + "Shown on the card": "Rādīts kartītē", + "Remove field": "Noņemt lauku", + "Profile fields saved.": "Profila lauki saglabāti.", + "Save profile fields": "Saglabāt profila laukus", + "The profile fields could not be loaded.": "Neizdevās ielādēt profila laukus.", + "The profile fields could not be saved.": "Neizdevās saglabāt profila laukus." } } diff --git a/l10n/mk.js b/l10n/mk.js index 91ae7490c..e7f077905 100644 --- a/l10n/mk.js +++ b/l10n/mk.js @@ -1284,7 +1284,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Потврдите за прочитано на врвот од таблата покажуваат кој потврдил.", "{emoji}: {count} reactions" : "{emoji}: {count} реакции", "React with {emoji}" : "Реагирај со {emoji}", - "{names} and {count} more" : "{names} и уште {count}" + "{names} and {count} more" : "{names} и уште {count}", + "Search people" : "Пребарај луѓе", + "Search by name, email or expertise…" : "Пребарај по име, е-пошта или експертиза…", + "Find everyone tagged {tag}" : "Најди ги сите со ознаката {tag}", + "LaunchPad profile" : "LaunchPad профил", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Колегите ги гледаат овие полиња на вашата картичка во виџетот за луѓе и можат да ве најдат преку нив.", + "Your profile fields could not be loaded." : "Полињата на вашиот профил не можеа да се вчитаат.", + "Not filled in" : "Не е пополнето", + "Filled from your organisation’s directory. You cannot change it here." : "Пополнето од именикот на вашата организација. Не можете да го промените тука.", + "Type a subject and press Enter" : "Внесете тема и притиснете Enter", + "Your profile fields are saved." : "Полињата на вашиот профил се зачувани.", + "Your profile fields could not be saved." : "Полињата на вашиот профил не можеа да се зачуваат.", + "Profile fields" : "Полиња на профилот", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Дополнителни полиња на картичките на колегите во виџетот за луѓе, како локација на канцеларија или експертиза. Луѓето ги пополнуваат во личните поставки или доаѓаат од LDAP атрибут.", + "New field" : "Ново поле", + "Tags" : "Ознаки", + "Filled by" : "Пополнува", + "The person" : "Самата личност", + "LDAP attribute" : "LDAP атрибут", + "Who may see it" : "Кој може да го гледа", + "Everyone" : "Сите", + "People in the same group" : "Луѓе во истата група", + "Searchable in the people widget" : "Пребарливо во виџетот за луѓе", + "Shown on the card" : "Прикажано на картичката", + "Remove field" : "Отстрани поле", + "Profile fields saved." : "Полињата на профилот се зачувани.", + "Save profile fields" : "Зачувај полиња на профилот", + "The profile fields could not be loaded." : "Полињата на профилот не можеа да се вчитаат.", + "The profile fields could not be saved." : "Полињата на профилот не можеа да се зачуваат." }, "nplurals=2; plural=(n%10==1 && n%100!=11 ? 0 : 1);" ); diff --git a/l10n/mk.json b/l10n/mk.json index 974f3963c..967e1c28d 100644 --- a/l10n/mk.json +++ b/l10n/mk.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Потврдите за прочитано на врвот од таблата покажуваат кој потврдил.", "{emoji}: {count} reactions": "{emoji}: {count} реакции", "React with {emoji}": "Реагирај со {emoji}", - "{names} and {count} more": "{names} и уште {count}" + "{names} and {count} more": "{names} и уште {count}", + "Search people": "Пребарај луѓе", + "Search by name, email or expertise…": "Пребарај по име, е-пошта или експертиза…", + "Find everyone tagged {tag}": "Најди ги сите со ознаката {tag}", + "LaunchPad profile": "LaunchPad профил", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Колегите ги гледаат овие полиња на вашата картичка во виџетот за луѓе и можат да ве најдат преку нив.", + "Your profile fields could not be loaded.": "Полињата на вашиот профил не можеа да се вчитаат.", + "Not filled in": "Не е пополнето", + "Filled from your organisation’s directory. You cannot change it here.": "Пополнето од именикот на вашата организација. Не можете да го промените тука.", + "Type a subject and press Enter": "Внесете тема и притиснете Enter", + "Your profile fields are saved.": "Полињата на вашиот профил се зачувани.", + "Your profile fields could not be saved.": "Полињата на вашиот профил не можеа да се зачуваат.", + "Profile fields": "Полиња на профилот", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Дополнителни полиња на картичките на колегите во виџетот за луѓе, како локација на канцеларија или експертиза. Луѓето ги пополнуваат во личните поставки или доаѓаат од LDAP атрибут.", + "New field": "Ново поле", + "Tags": "Ознаки", + "Filled by": "Пополнува", + "The person": "Самата личност", + "LDAP attribute": "LDAP атрибут", + "Who may see it": "Кој може да го гледа", + "Everyone": "Сите", + "People in the same group": "Луѓе во истата група", + "Searchable in the people widget": "Пребарливо во виџетот за луѓе", + "Shown on the card": "Прикажано на картичката", + "Remove field": "Отстрани поле", + "Profile fields saved.": "Полињата на профилот се зачувани.", + "Save profile fields": "Зачувај полиња на профилот", + "The profile fields could not be loaded.": "Полињата на профилот не можеа да се вчитаат.", + "The profile fields could not be saved.": "Полињата на профилот не можеа да се зачуваат." } } diff --git a/l10n/mt.js b/l10n/mt.js index 24a661b6d..21ab65e16 100644 --- a/l10n/mt.js +++ b/l10n/mt.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Ir-rċevuti tal-qari fuq nett tad-dashboard juru min ikkonferma.", "{emoji}: {count} reactions" : "{emoji}: {count} reazzjonijiet", "React with {emoji}" : "Irreaġixxi b'{emoji}", - "{names} and {count} more" : "{names} u {count} oħra" + "{names} and {count} more" : "{names} u {count} oħra", + "Search people" : "Fittex persuni", + "Search by name, email or expertise…" : "Fittex bl-isem, l-email jew il-kompetenza…", + "Find everyone tagged {tag}" : "Sib lil kulħadd bit-tikketta {tag}", + "LaunchPad profile" : "Profil ta' LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Il-kollegi jaraw dawn il-oqsma fuq il-karta tiegħek fil-widget tan-nies u jistgħu jsibuk permezz tagħhom.", + "Your profile fields could not be loaded." : "Il-oqsma tal-profil tiegħek ma setgħux jitgħabbew.", + "Not filled in" : "Mhux mimli", + "Filled from your organisation’s directory. You cannot change it here." : "Mimli mid-direttorju tal-organizzazzjoni tiegħek. Ma tistax tibdlu hawn.", + "Type a subject and press Enter" : "Ikteb suġġett u agħfas Enter", + "Your profile fields are saved." : "Il-oqsma tal-profil tiegħek huma salvati.", + "Your profile fields could not be saved." : "Il-oqsma tal-profil tiegħek ma setgħux jiġu salvati.", + "Profile fields" : "Oqsma tal-profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Oqsma żejda fuq il-karti tal-kollegi fil-widget tan-nies, bħall-post tal-uffiċċju jew il-kompetenza. In-nies jimlewhom fl-issettjar personali tagħhom, jew jiġu minn attribut LDAP.", + "New field" : "Qasam ġdid", + "Tags" : "Tikketti", + "Filled by" : "Jimlieh", + "The person" : "Il-persuna nfisha", + "LDAP attribute" : "Attribut LDAP", + "Who may see it" : "Min jista' jarah", + "Everyone" : "Kulħadd", + "People in the same group" : "Nies fl-istess grupp", + "Searchable in the people widget" : "Jista' jiġi mfittex fil-widget tan-nies", + "Shown on the card" : "Jintwera fuq il-karta", + "Remove field" : "Neħħi l-qasam", + "Profile fields saved." : "Il-oqsma tal-profil ġew salvati.", + "Save profile fields" : "Issejvja l-oqsma tal-profil", + "The profile fields could not be loaded." : "Il-oqsma tal-profil ma setgħux jitgħabbew.", + "The profile fields could not be saved." : "Il-oqsma tal-profil ma setgħux jiġu salvati." }, "nplurals=4; plural=(n==1 ? 0 : n==0 || (n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20) ? 2 : 3);" ); diff --git a/l10n/mt.json b/l10n/mt.json index 3ea26482a..ff0697add 100644 --- a/l10n/mt.json +++ b/l10n/mt.json @@ -1262,6 +1262,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Ir-rċevuti tal-qari fuq nett tad-dashboard juru min ikkonferma.", "{emoji}: {count} reactions": "{emoji}: {count} reazzjonijiet", "React with {emoji}": "Irreaġixxi b'{emoji}", - "{names} and {count} more": "{names} u {count} oħra" + "{names} and {count} more": "{names} u {count} oħra", + "Search people": "Fittex persuni", + "Search by name, email or expertise…": "Fittex bl-isem, l-email jew il-kompetenza…", + "Find everyone tagged {tag}": "Sib lil kulħadd bit-tikketta {tag}", + "LaunchPad profile": "Profil ta' LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Il-kollegi jaraw dawn il-oqsma fuq il-karta tiegħek fil-widget tan-nies u jistgħu jsibuk permezz tagħhom.", + "Your profile fields could not be loaded.": "Il-oqsma tal-profil tiegħek ma setgħux jitgħabbew.", + "Not filled in": "Mhux mimli", + "Filled from your organisation’s directory. You cannot change it here.": "Mimli mid-direttorju tal-organizzazzjoni tiegħek. Ma tistax tibdlu hawn.", + "Type a subject and press Enter": "Ikteb suġġett u agħfas Enter", + "Your profile fields are saved.": "Il-oqsma tal-profil tiegħek huma salvati.", + "Your profile fields could not be saved.": "Il-oqsma tal-profil tiegħek ma setgħux jiġu salvati.", + "Profile fields": "Oqsma tal-profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Oqsma żejda fuq il-karti tal-kollegi fil-widget tan-nies, bħall-post tal-uffiċċju jew il-kompetenza. In-nies jimlewhom fl-issettjar personali tagħhom, jew jiġu minn attribut LDAP.", + "New field": "Qasam ġdid", + "Tags": "Tikketti", + "Filled by": "Jimlieh", + "The person": "Il-persuna nfisha", + "LDAP attribute": "Attribut LDAP", + "Who may see it": "Min jista' jarah", + "Everyone": "Kulħadd", + "People in the same group": "Nies fl-istess grupp", + "Searchable in the people widget": "Jista' jiġi mfittex fil-widget tan-nies", + "Shown on the card": "Jintwera fuq il-karta", + "Remove field": "Neħħi l-qasam", + "Profile fields saved.": "Il-oqsma tal-profil ġew salvati.", + "Save profile fields": "Issejvja l-oqsma tal-profil", + "The profile fields could not be loaded.": "Il-oqsma tal-profil ma setgħux jitgħabbew.", + "The profile fields could not be saved.": "Il-oqsma tal-profil ma setgħux jiġu salvati." } } diff --git a/l10n/nb.js b/l10n/nb.js index 143fe5d35..226a19ce8 100644 --- a/l10n/nb.js +++ b/l10n/nb.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Lesekvitteringer øverst på dashbordet viser hvem som har bekreftet.", "{emoji}: {count} reactions" : "{emoji}: {count} reaksjoner", "React with {emoji}" : "Reager med {emoji}", - "{names} and {count} more" : "{names} og {count} til" + "{names} and {count} more" : "{names} og {count} til", + "Search people" : "Søk etter personer", + "Search by name, email or expertise…" : "Søk etter navn, e-post eller kompetanse…", + "Find everyone tagged {tag}" : "Finn alle med merket {tag}", + "LaunchPad profile" : "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolleger ser disse feltene på kortet ditt i personmodulen og kan finne deg ut fra dem.", + "Your profile fields could not be loaded." : "Profilfeltene dine kunne ikke lastes inn.", + "Not filled in" : "Ikke utfylt", + "Filled from your organisation’s directory. You cannot change it here." : "Fylt ut fra organisasjonens katalog. Du kan ikke endre det her.", + "Type a subject and press Enter" : "Skriv et emne og trykk Enter", + "Your profile fields are saved." : "Profilfeltene dine er lagret.", + "Your profile fields could not be saved." : "Profilfeltene dine kunne ikke lagres.", + "Profile fields" : "Profilfelt", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Ekstra felt på kollegers kort i personmodulen, for eksempel kontorsted eller kompetanse. Personene fyller dem ut i sine personlige innstillinger, eller de kommer fra et LDAP-attributt.", + "New field" : "Nytt felt", + "Tags" : "Merker", + "Filled by" : "Fylles ut av", + "The person" : "Personen selv", + "LDAP attribute" : "LDAP-attributt", + "Who may see it" : "Hvem kan se det", + "Everyone" : "Alle", + "People in the same group" : "Personer i samme gruppe", + "Searchable in the people widget" : "Søkbart i personmodulen", + "Shown on the card" : "Vises på kortet", + "Remove field" : "Fjern felt", + "Profile fields saved." : "Profilfeltene er lagret.", + "Save profile fields" : "Lagre profilfelt", + "The profile fields could not be loaded." : "Profilfeltene kunne ikke lastes inn.", + "The profile fields could not be saved." : "Profilfeltene kunne ikke lagres." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/nb.json b/l10n/nb.json index d46b23e21..60cb3f614 100644 --- a/l10n/nb.json +++ b/l10n/nb.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Lesekvitteringer øverst på dashbordet viser hvem som har bekreftet.", "{emoji}: {count} reactions": "{emoji}: {count} reaksjoner", "React with {emoji}": "Reager med {emoji}", - "{names} and {count} more": "{names} og {count} til" + "{names} and {count} more": "{names} og {count} til", + "Search people": "Søk etter personer", + "Search by name, email or expertise…": "Søk etter navn, e-post eller kompetanse…", + "Find everyone tagged {tag}": "Finn alle med merket {tag}", + "LaunchPad profile": "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolleger ser disse feltene på kortet ditt i personmodulen og kan finne deg ut fra dem.", + "Your profile fields could not be loaded.": "Profilfeltene dine kunne ikke lastes inn.", + "Not filled in": "Ikke utfylt", + "Filled from your organisation’s directory. You cannot change it here.": "Fylt ut fra organisasjonens katalog. Du kan ikke endre det her.", + "Type a subject and press Enter": "Skriv et emne og trykk Enter", + "Your profile fields are saved.": "Profilfeltene dine er lagret.", + "Your profile fields could not be saved.": "Profilfeltene dine kunne ikke lagres.", + "Profile fields": "Profilfelt", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Ekstra felt på kollegers kort i personmodulen, for eksempel kontorsted eller kompetanse. Personene fyller dem ut i sine personlige innstillinger, eller de kommer fra et LDAP-attributt.", + "New field": "Nytt felt", + "Tags": "Merker", + "Filled by": "Fylles ut av", + "The person": "Personen selv", + "LDAP attribute": "LDAP-attributt", + "Who may see it": "Hvem kan se det", + "Everyone": "Alle", + "People in the same group": "Personer i samme gruppe", + "Searchable in the people widget": "Søkbart i personmodulen", + "Shown on the card": "Vises på kortet", + "Remove field": "Fjern felt", + "Profile fields saved.": "Profilfeltene er lagret.", + "Save profile fields": "Lagre profilfelt", + "The profile fields could not be loaded.": "Profilfeltene kunne ikke lastes inn.", + "The profile fields could not be saved.": "Profilfeltene kunne ikke lagres." } } diff --git a/l10n/nl.js b/l10n/nl.js index aa9bd9b1b..59f9b10fa 100644 --- a/l10n/nl.js +++ b/l10n/nl.js @@ -1343,7 +1343,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Leesbevestigingen bovenaan het dashboard tonen wie heeft bevestigd.", "{emoji}: {count} reactions" : "{emoji}: {count} reacties", "React with {emoji}" : "Reageren met {emoji}", - "{names} and {count} more" : "{names} en {count} anderen" + "{names} and {count} more" : "{names} en {count} anderen", + "Search people" : "Personen zoeken", + "Search by name, email or expertise…" : "Zoeken op naam, e-mail of expertise…", + "Find everyone tagged {tag}" : "Iedereen met de tag {tag} zoeken", + "LaunchPad profile" : "LaunchPad-profiel", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Collega's zien deze velden op je kaart in de personenwidget en kunnen je erop vinden.", + "Your profile fields could not be loaded." : "Je profielvelden konden niet worden geladen.", + "Not filled in" : "Niet ingevuld", + "Filled from your organisation’s directory. You cannot change it here." : "Ingevuld vanuit de gebruikerslijst van je organisatie. Je kunt het hier niet wijzigen.", + "Type a subject and press Enter" : "Typ een onderwerp en druk op Enter", + "Your profile fields are saved." : "Je profielvelden zijn opgeslagen.", + "Your profile fields could not be saved." : "Je profielvelden konden niet worden opgeslagen.", + "Profile fields" : "Profielvelden", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Extra velden op de kaarten van collega's in de personenwidget, zoals kantoorlocatie of expertise. Mensen vullen ze in bij hun persoonlijke instellingen, of ze komen uit een LDAP-attribuut.", + "New field" : "Nieuw veld", + "Tags" : "Tags", + "Filled by" : "Ingevuld door", + "The person" : "De persoon zelf", + "LDAP attribute" : "LDAP-attribuut", + "Who may see it" : "Wie het mag zien", + "Everyone" : "Iedereen", + "People in the same group" : "Mensen in dezelfde groep", + "Searchable in the people widget" : "Doorzoekbaar in de personenwidget", + "Shown on the card" : "Getoond op de kaart", + "Remove field" : "Veld verwijderen", + "Profile fields saved." : "Profielvelden opgeslagen.", + "Save profile fields" : "Profielvelden opslaan", + "The profile fields could not be loaded." : "De profielvelden konden niet worden geladen.", + "The profile fields could not be saved." : "De profielvelden konden niet worden opgeslagen." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/nl.json b/l10n/nl.json index 4fbb565ba..c1070d47a 100644 --- a/l10n/nl.json +++ b/l10n/nl.json @@ -1320,6 +1320,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Leesbevestigingen bovenaan het dashboard tonen wie heeft bevestigd.", "{emoji}: {count} reactions": "{emoji}: {count} reacties", "React with {emoji}": "Reageren met {emoji}", - "{names} and {count} more": "{names} en {count} anderen" + "{names} and {count} more": "{names} en {count} anderen", + "Search people": "Personen zoeken", + "Search by name, email or expertise…": "Zoeken op naam, e-mail of expertise…", + "Find everyone tagged {tag}": "Iedereen met de tag {tag} zoeken", + "LaunchPad profile": "LaunchPad-profiel", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Collega's zien deze velden op je kaart in de personenwidget en kunnen je erop vinden.", + "Your profile fields could not be loaded.": "Je profielvelden konden niet worden geladen.", + "Not filled in": "Niet ingevuld", + "Filled from your organisation’s directory. You cannot change it here.": "Ingevuld vanuit de gebruikerslijst van je organisatie. Je kunt het hier niet wijzigen.", + "Type a subject and press Enter": "Typ een onderwerp en druk op Enter", + "Your profile fields are saved.": "Je profielvelden zijn opgeslagen.", + "Your profile fields could not be saved.": "Je profielvelden konden niet worden opgeslagen.", + "Profile fields": "Profielvelden", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Extra velden op de kaarten van collega's in de personenwidget, zoals kantoorlocatie of expertise. Mensen vullen ze in bij hun persoonlijke instellingen, of ze komen uit een LDAP-attribuut.", + "New field": "Nieuw veld", + "Tags": "Tags", + "Filled by": "Ingevuld door", + "The person": "De persoon zelf", + "LDAP attribute": "LDAP-attribuut", + "Who may see it": "Wie het mag zien", + "Everyone": "Iedereen", + "People in the same group": "Mensen in dezelfde groep", + "Searchable in the people widget": "Doorzoekbaar in de personenwidget", + "Shown on the card": "Getoond op de kaart", + "Remove field": "Veld verwijderen", + "Profile fields saved.": "Profielvelden opgeslagen.", + "Save profile fields": "Profielvelden opslaan", + "The profile fields could not be loaded.": "De profielvelden konden niet worden geladen.", + "The profile fields could not be saved.": "De profielvelden konden niet worden opgeslagen." } } diff --git a/l10n/pl.js b/l10n/pl.js index c6f5d07d4..7754a5c2a 100644 --- a/l10n/pl.js +++ b/l10n/pl.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potwierdzenia odczytu u góry pulpitu pokazują, kto potwierdził.", "{emoji}: {count} reactions" : "{emoji}: reakcje: {count}", "React with {emoji}" : "Zareaguj {emoji}", - "{names} and {count} more" : "{names} i jeszcze {count}" + "{names} and {count} more" : "{names} i jeszcze {count}", + "Search people" : "Szukaj osób", + "Search by name, email or expertise…" : "Szukaj według imienia, e-maila lub specjalizacji…", + "Find everyone tagged {tag}" : "Znajdź wszystkich z tagiem {tag}", + "LaunchPad profile" : "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Współpracownicy widzą te pola na Twojej karcie w widżecie osób i mogą Cię po nich znaleźć.", + "Your profile fields could not be loaded." : "Nie udało się wczytać pól Twojego profilu.", + "Not filled in" : "Nie wypełniono", + "Filled from your organisation’s directory. You cannot change it here." : "Wypełniane z katalogu Twojej organizacji. Nie możesz tego tutaj zmienić.", + "Type a subject and press Enter" : "Wpisz temat i naciśnij Enter", + "Your profile fields are saved." : "Pola Twojego profilu zostały zapisane.", + "Your profile fields could not be saved." : "Nie udało się zapisać pól Twojego profilu.", + "Profile fields" : "Pola profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Dodatkowe pola na kartach współpracowników w widżecie osób, np. lokalizacja biura lub specjalizacja. Osoby wypełniają je w ustawieniach osobistych albo pochodzą one z atrybutu LDAP.", + "New field" : "Nowe pole", + "Tags" : "Tagi", + "Filled by" : "Wypełnia", + "The person" : "Sama osoba", + "LDAP attribute" : "Atrybut LDAP", + "Who may see it" : "Kto może to widzieć", + "Everyone" : "Wszyscy", + "People in the same group" : "Osoby z tej samej grupy", + "Searchable in the people widget" : "Można wyszukiwać w widżecie osób", + "Shown on the card" : "Widoczne na karcie", + "Remove field" : "Usuń pole", + "Profile fields saved." : "Pola profilu zapisane.", + "Save profile fields" : "Zapisz pola profilu", + "The profile fields could not be loaded." : "Nie udało się wczytać pól profilu.", + "The profile fields could not be saved." : "Nie udało się zapisać pól profilu." }, "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" ); diff --git a/l10n/pl.json b/l10n/pl.json index 8cf07b857..60814ee56 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potwierdzenia odczytu u góry pulpitu pokazują, kto potwierdził.", "{emoji}: {count} reactions": "{emoji}: reakcje: {count}", "React with {emoji}": "Zareaguj {emoji}", - "{names} and {count} more": "{names} i jeszcze {count}" + "{names} and {count} more": "{names} i jeszcze {count}", + "Search people": "Szukaj osób", + "Search by name, email or expertise…": "Szukaj według imienia, e-maila lub specjalizacji…", + "Find everyone tagged {tag}": "Znajdź wszystkich z tagiem {tag}", + "LaunchPad profile": "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Współpracownicy widzą te pola na Twojej karcie w widżecie osób i mogą Cię po nich znaleźć.", + "Your profile fields could not be loaded.": "Nie udało się wczytać pól Twojego profilu.", + "Not filled in": "Nie wypełniono", + "Filled from your organisation’s directory. You cannot change it here.": "Wypełniane z katalogu Twojej organizacji. Nie możesz tego tutaj zmienić.", + "Type a subject and press Enter": "Wpisz temat i naciśnij Enter", + "Your profile fields are saved.": "Pola Twojego profilu zostały zapisane.", + "Your profile fields could not be saved.": "Nie udało się zapisać pól Twojego profilu.", + "Profile fields": "Pola profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Dodatkowe pola na kartach współpracowników w widżecie osób, np. lokalizacja biura lub specjalizacja. Osoby wypełniają je w ustawieniach osobistych albo pochodzą one z atrybutu LDAP.", + "New field": "Nowe pole", + "Tags": "Tagi", + "Filled by": "Wypełnia", + "The person": "Sama osoba", + "LDAP attribute": "Atrybut LDAP", + "Who may see it": "Kto może to widzieć", + "Everyone": "Wszyscy", + "People in the same group": "Osoby z tej samej grupy", + "Searchable in the people widget": "Można wyszukiwać w widżecie osób", + "Shown on the card": "Widoczne na karcie", + "Remove field": "Usuń pole", + "Profile fields saved.": "Pola profilu zapisane.", + "Save profile fields": "Zapisz pola profilu", + "The profile fields could not be loaded.": "Nie udało się wczytać pól profilu.", + "The profile fields could not be saved.": "Nie udało się zapisać pól profilu." } } diff --git a/l10n/pt.js b/l10n/pt.js index a25bc6a2e..4cdf7ed03 100644 --- a/l10n/pt.js +++ b/l10n/pt.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Os recibos de leitura no topo do painel mostram quem confirmou.", "{emoji}: {count} reactions" : "{emoji}: {count} reações", "React with {emoji}" : "Reagir com {emoji}", - "{names} and {count} more" : "{names} e mais {count}" + "{names} and {count} more" : "{names} e mais {count}", + "Search people" : "Pesquisar pessoas", + "Search by name, email or expertise…" : "Pesquisar por nome, e-mail ou especialidade…", + "Find everyone tagged {tag}" : "Encontrar todos com a etiqueta {tag}", + "LaunchPad profile" : "Perfil do LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Os colegas veem estes campos no seu cartão no widget de pessoas e podem encontrá-lo por eles.", + "Your profile fields could not be loaded." : "Não foi possível carregar os campos do seu perfil.", + "Not filled in" : "Não preenchido", + "Filled from your organisation’s directory. You cannot change it here." : "Preenchido a partir do diretório da sua organização. Não pode alterá-lo aqui.", + "Type a subject and press Enter" : "Escreva um assunto e prima Enter", + "Your profile fields are saved." : "Os campos do seu perfil foram guardados.", + "Your profile fields could not be saved." : "Não foi possível guardar os campos do seu perfil.", + "Profile fields" : "Campos do perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Campos extra nos cartões dos colegas no widget de pessoas, como a localização do escritório ou a especialidade. As pessoas preenchem-nos nas definições pessoais, ou vêm de um atributo LDAP.", + "New field" : "Novo campo", + "Tags" : "Etiquetas", + "Filled by" : "Preenchido por", + "The person" : "A própria pessoa", + "LDAP attribute" : "Atributo LDAP", + "Who may see it" : "Quem o pode ver", + "Everyone" : "Todos", + "People in the same group" : "Pessoas do mesmo grupo", + "Searchable in the people widget" : "Pesquisável no widget de pessoas", + "Shown on the card" : "Mostrado no cartão", + "Remove field" : "Remover campo", + "Profile fields saved." : "Campos do perfil guardados.", + "Save profile fields" : "Guardar campos do perfil", + "The profile fields could not be loaded." : "Não foi possível carregar os campos do perfil.", + "The profile fields could not be saved." : "Não foi possível guardar os campos do perfil." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/pt.json b/l10n/pt.json index c6347a128..41b8a8f8d 100644 --- a/l10n/pt.json +++ b/l10n/pt.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Os recibos de leitura no topo do painel mostram quem confirmou.", "{emoji}: {count} reactions": "{emoji}: {count} reações", "React with {emoji}": "Reagir com {emoji}", - "{names} and {count} more": "{names} e mais {count}" + "{names} and {count} more": "{names} e mais {count}", + "Search people": "Pesquisar pessoas", + "Search by name, email or expertise…": "Pesquisar por nome, e-mail ou especialidade…", + "Find everyone tagged {tag}": "Encontrar todos com a etiqueta {tag}", + "LaunchPad profile": "Perfil do LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Os colegas veem estes campos no seu cartão no widget de pessoas e podem encontrá-lo por eles.", + "Your profile fields could not be loaded.": "Não foi possível carregar os campos do seu perfil.", + "Not filled in": "Não preenchido", + "Filled from your organisation’s directory. You cannot change it here.": "Preenchido a partir do diretório da sua organização. Não pode alterá-lo aqui.", + "Type a subject and press Enter": "Escreva um assunto e prima Enter", + "Your profile fields are saved.": "Os campos do seu perfil foram guardados.", + "Your profile fields could not be saved.": "Não foi possível guardar os campos do seu perfil.", + "Profile fields": "Campos do perfil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Campos extra nos cartões dos colegas no widget de pessoas, como a localização do escritório ou a especialidade. As pessoas preenchem-nos nas definições pessoais, ou vêm de um atributo LDAP.", + "New field": "Novo campo", + "Tags": "Etiquetas", + "Filled by": "Preenchido por", + "The person": "A própria pessoa", + "LDAP attribute": "Atributo LDAP", + "Who may see it": "Quem o pode ver", + "Everyone": "Todos", + "People in the same group": "Pessoas do mesmo grupo", + "Searchable in the people widget": "Pesquisável no widget de pessoas", + "Shown on the card": "Mostrado no cartão", + "Remove field": "Remover campo", + "Profile fields saved.": "Campos do perfil guardados.", + "Save profile fields": "Guardar campos do perfil", + "The profile fields could not be loaded.": "Não foi possível carregar os campos do perfil.", + "The profile fields could not be saved.": "Não foi possível guardar os campos do perfil." } } diff --git a/l10n/rm.js b/l10n/rm.js index f319bafc5..457c0a42f 100644 --- a/l10n/rm.js +++ b/l10n/rm.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Las quittanzas da lectura sisum il dashboard mussan tgi ch'ha confermà.", "{emoji}: {count} reactions" : "{emoji}: {count} reacziuns", "React with {emoji}" : "Reagir cun {emoji}", - "{names} and {count} more" : "{names} ed anc {count}" + "{names} and {count} more" : "{names} ed anc {count}", + "Search people" : "Tschertgar persunas", + "Search by name, email or expertise…" : "Tschertgar tenor num, e-mail u expertisa…", + "Find everyone tagged {tag}" : "Chattar tuts cun la marca {tag}", + "LaunchPad profile" : "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Collegas vesan quests champs sin tia carta en il widget da persunas e pon ta chattar tras quels.", + "Your profile fields could not be loaded." : "I n'è betg reussì da chargiar ils champs da tes profil.", + "Not filled in" : "Betg emplenì", + "Filled from your organisation’s directory. You cannot change it here." : "Emplenì dal register da tia organisaziun. Ti na pos betg midar quai qua.", + "Type a subject and press Enter" : "Endatescha in tema e smatga Enter", + "Your profile fields are saved." : "Ils champs da tes profil èn memorisads.", + "Your profile fields could not be saved." : "I n'è betg reussì da memorisar ils champs da tes profil.", + "Profile fields" : "Champs dal profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Champs supplementars sin las cartas da collegas en il widget da persunas, sco il lieu da biro u l'expertisa. Las persunas als emplenan en lur parameters persunals, u els derivan d'in attribut LDAP.", + "New field" : "Nov champ", + "Tags" : "Marcas", + "Filled by" : "Emplenì da", + "The person" : "La persuna sezza", + "LDAP attribute" : "Attribut LDAP", + "Who may see it" : "Tgi che po al vesair", + "Everyone" : "Tuts", + "People in the same group" : "Persunas en la medema gruppa", + "Searchable in the people widget" : "Tschertgabel en il widget da persunas", + "Shown on the card" : "Mussà sin la carta", + "Remove field" : "Allontanar il champ", + "Profile fields saved." : "Champs dal profil memorisads.", + "Save profile fields" : "Memorisar ils champs dal profil", + "The profile fields could not be loaded." : "I n'è betg reussì da chargiar ils champs dal profil.", + "The profile fields could not be saved." : "I n'è betg reussì da memorisar ils champs dal profil." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/rm.json b/l10n/rm.json index d63967a86..56794d514 100644 --- a/l10n/rm.json +++ b/l10n/rm.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Las quittanzas da lectura sisum il dashboard mussan tgi ch'ha confermà.", "{emoji}: {count} reactions": "{emoji}: {count} reacziuns", "React with {emoji}": "Reagir cun {emoji}", - "{names} and {count} more": "{names} ed anc {count}" + "{names} and {count} more": "{names} ed anc {count}", + "Search people": "Tschertgar persunas", + "Search by name, email or expertise…": "Tschertgar tenor num, e-mail u expertisa…", + "Find everyone tagged {tag}": "Chattar tuts cun la marca {tag}", + "LaunchPad profile": "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Collegas vesan quests champs sin tia carta en il widget da persunas e pon ta chattar tras quels.", + "Your profile fields could not be loaded.": "I n'è betg reussì da chargiar ils champs da tes profil.", + "Not filled in": "Betg emplenì", + "Filled from your organisation’s directory. You cannot change it here.": "Emplenì dal register da tia organisaziun. Ti na pos betg midar quai qua.", + "Type a subject and press Enter": "Endatescha in tema e smatga Enter", + "Your profile fields are saved.": "Ils champs da tes profil èn memorisads.", + "Your profile fields could not be saved.": "I n'è betg reussì da memorisar ils champs da tes profil.", + "Profile fields": "Champs dal profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Champs supplementars sin las cartas da collegas en il widget da persunas, sco il lieu da biro u l'expertisa. Las persunas als emplenan en lur parameters persunals, u els derivan d'in attribut LDAP.", + "New field": "Nov champ", + "Tags": "Marcas", + "Filled by": "Emplenì da", + "The person": "La persuna sezza", + "LDAP attribute": "Attribut LDAP", + "Who may see it": "Tgi che po al vesair", + "Everyone": "Tuts", + "People in the same group": "Persunas en la medema gruppa", + "Searchable in the people widget": "Tschertgabel en il widget da persunas", + "Shown on the card": "Mussà sin la carta", + "Remove field": "Allontanar il champ", + "Profile fields saved.": "Champs dal profil memorisads.", + "Save profile fields": "Memorisar ils champs dal profil", + "The profile fields could not be loaded.": "I n'è betg reussì da chargiar ils champs dal profil.", + "The profile fields could not be saved.": "I n'è betg reussì da memorisar ils champs dal profil." } } diff --git a/l10n/ro.js b/l10n/ro.js index fdfbc2f1f..350c650fa 100644 --- a/l10n/ro.js +++ b/l10n/ro.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Confirmările de citire din partea de sus arată cine a confirmat.", "{emoji}: {count} reactions" : "{emoji}: {count} reacții", "React with {emoji}" : "Reacționează cu {emoji}", - "{names} and {count} more" : "{names} și încă {count}" + "{names} and {count} more" : "{names} și încă {count}", + "Search people" : "Caută persoane", + "Search by name, email or expertise…" : "Caută după nume, e-mail sau expertiză…", + "Find everyone tagged {tag}" : "Găsește pe toți cu eticheta {tag}", + "LaunchPad profile" : "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Colegii văd aceste câmpuri pe cardul tău din widgetul de persoane și te pot găsi după ele.", + "Your profile fields could not be loaded." : "Câmpurile profilului tău nu au putut fi încărcate.", + "Not filled in" : "Necompletat", + "Filled from your organisation’s directory. You cannot change it here." : "Completat din directorul organizației tale. Nu îl poți schimba aici.", + "Type a subject and press Enter" : "Scrie un subiect și apasă Enter", + "Your profile fields are saved." : "Câmpurile profilului tău au fost salvate.", + "Your profile fields could not be saved." : "Câmpurile profilului tău nu au putut fi salvate.", + "Profile fields" : "Câmpuri de profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Câmpuri suplimentare pe cardurile colegilor din widgetul de persoane, cum ar fi locația biroului sau expertiza. Persoanele le completează în setările personale sau provin dintr-un atribut LDAP.", + "New field" : "Câmp nou", + "Tags" : "Etichete", + "Filled by" : "Completat de", + "The person" : "Persoana însăși", + "LDAP attribute" : "Atribut LDAP", + "Who may see it" : "Cine îl poate vedea", + "Everyone" : "Toată lumea", + "People in the same group" : "Persoane din același grup", + "Searchable in the people widget" : "Căutabil în widgetul de persoane", + "Shown on the card" : "Afișat pe card", + "Remove field" : "Elimină câmpul", + "Profile fields saved." : "Câmpurile de profil au fost salvate.", + "Save profile fields" : "Salvează câmpurile de profil", + "The profile fields could not be loaded." : "Câmpurile de profil nu au putut fi încărcate.", + "The profile fields could not be saved." : "Câmpurile de profil nu au putut fi salvate." }, "nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100>0 && n%100<20)) ? 1 : 2);" ); diff --git a/l10n/ro.json b/l10n/ro.json index 915fb9665..bf0d96182 100644 --- a/l10n/ro.json +++ b/l10n/ro.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Confirmările de citire din partea de sus arată cine a confirmat.", "{emoji}: {count} reactions": "{emoji}: {count} reacții", "React with {emoji}": "Reacționează cu {emoji}", - "{names} and {count} more": "{names} și încă {count}" + "{names} and {count} more": "{names} și încă {count}", + "Search people": "Caută persoane", + "Search by name, email or expertise…": "Caută după nume, e-mail sau expertiză…", + "Find everyone tagged {tag}": "Găsește pe toți cu eticheta {tag}", + "LaunchPad profile": "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Colegii văd aceste câmpuri pe cardul tău din widgetul de persoane și te pot găsi după ele.", + "Your profile fields could not be loaded.": "Câmpurile profilului tău nu au putut fi încărcate.", + "Not filled in": "Necompletat", + "Filled from your organisation’s directory. You cannot change it here.": "Completat din directorul organizației tale. Nu îl poți schimba aici.", + "Type a subject and press Enter": "Scrie un subiect și apasă Enter", + "Your profile fields are saved.": "Câmpurile profilului tău au fost salvate.", + "Your profile fields could not be saved.": "Câmpurile profilului tău nu au putut fi salvate.", + "Profile fields": "Câmpuri de profil", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Câmpuri suplimentare pe cardurile colegilor din widgetul de persoane, cum ar fi locația biroului sau expertiza. Persoanele le completează în setările personale sau provin dintr-un atribut LDAP.", + "New field": "Câmp nou", + "Tags": "Etichete", + "Filled by": "Completat de", + "The person": "Persoana însăși", + "LDAP attribute": "Atribut LDAP", + "Who may see it": "Cine îl poate vedea", + "Everyone": "Toată lumea", + "People in the same group": "Persoane din același grup", + "Searchable in the people widget": "Căutabil în widgetul de persoane", + "Shown on the card": "Afișat pe card", + "Remove field": "Elimină câmpul", + "Profile fields saved.": "Câmpurile de profil au fost salvate.", + "Save profile fields": "Salvează câmpurile de profil", + "The profile fields could not be loaded.": "Câmpurile de profil nu au putut fi încărcate.", + "The profile fields could not be saved.": "Câmpurile de profil nu au putut fi salvate." } } diff --git a/l10n/ru.js b/l10n/ru.js index 22206c75a..6eb71e4a6 100644 --- a/l10n/ru.js +++ b/l10n/ru.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Квитанции о прочтении вверху панели показывают, кто подтвердил.", "{emoji}: {count} reactions" : "{emoji}: реакций {count}", "React with {emoji}" : "Отреагировать {emoji}", - "{names} and {count} more" : "{names} и ещё {count}" + "{names} and {count} more" : "{names} и ещё {count}", + "Search people" : "Поиск людей", + "Search by name, email or expertise…" : "Поиск по имени, электронной почте или экспертизе…", + "Find everyone tagged {tag}" : "Найти всех с тегом {tag}", + "LaunchPad profile" : "Профиль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Коллеги видят эти поля на вашей карточке в виджете людей и могут найти вас по ним.", + "Your profile fields could not be loaded." : "Не удалось загрузить поля вашего профиля.", + "Not filled in" : "Не заполнено", + "Filled from your organisation’s directory. You cannot change it here." : "Заполняется из каталога вашей организации. Здесь это изменить нельзя.", + "Type a subject and press Enter" : "Введите тему и нажмите Enter", + "Your profile fields are saved." : "Поля вашего профиля сохранены.", + "Your profile fields could not be saved." : "Не удалось сохранить поля вашего профиля.", + "Profile fields" : "Поля профиля", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Дополнительные поля на карточках коллег в виджете людей, например расположение офиса или экспертиза. Люди заполняют их в личных настройках, или они берутся из атрибута LDAP.", + "New field" : "Новое поле", + "Tags" : "Теги", + "Filled by" : "Кто заполняет", + "The person" : "Сам человек", + "LDAP attribute" : "Атрибут LDAP", + "Who may see it" : "Кто может видеть", + "Everyone" : "Все", + "People in the same group" : "Люди из той же группы", + "Searchable in the people widget" : "Доступно для поиска в виджете людей", + "Shown on the card" : "Показывается на карточке", + "Remove field" : "Удалить поле", + "Profile fields saved." : "Поля профиля сохранены.", + "Save profile fields" : "Сохранить поля профиля", + "The profile fields could not be loaded." : "Не удалось загрузить поля профиля.", + "The profile fields could not be saved." : "Не удалось сохранить поля профиля." }, "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/l10n/ru.json b/l10n/ru.json index 696d4278d..9958f3d25 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Квитанции о прочтении вверху панели показывают, кто подтвердил.", "{emoji}: {count} reactions": "{emoji}: реакций {count}", "React with {emoji}": "Отреагировать {emoji}", - "{names} and {count} more": "{names} и ещё {count}" + "{names} and {count} more": "{names} и ещё {count}", + "Search people": "Поиск людей", + "Search by name, email or expertise…": "Поиск по имени, электронной почте или экспертизе…", + "Find everyone tagged {tag}": "Найти всех с тегом {tag}", + "LaunchPad profile": "Профиль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Коллеги видят эти поля на вашей карточке в виджете людей и могут найти вас по ним.", + "Your profile fields could not be loaded.": "Не удалось загрузить поля вашего профиля.", + "Not filled in": "Не заполнено", + "Filled from your organisation’s directory. You cannot change it here.": "Заполняется из каталога вашей организации. Здесь это изменить нельзя.", + "Type a subject and press Enter": "Введите тему и нажмите Enter", + "Your profile fields are saved.": "Поля вашего профиля сохранены.", + "Your profile fields could not be saved.": "Не удалось сохранить поля вашего профиля.", + "Profile fields": "Поля профиля", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Дополнительные поля на карточках коллег в виджете людей, например расположение офиса или экспертиза. Люди заполняют их в личных настройках, или они берутся из атрибута LDAP.", + "New field": "Новое поле", + "Tags": "Теги", + "Filled by": "Кто заполняет", + "The person": "Сам человек", + "LDAP attribute": "Атрибут LDAP", + "Who may see it": "Кто может видеть", + "Everyone": "Все", + "People in the same group": "Люди из той же группы", + "Searchable in the people widget": "Доступно для поиска в виджете людей", + "Shown on the card": "Показывается на карточке", + "Remove field": "Удалить поле", + "Profile fields saved.": "Поля профиля сохранены.", + "Save profile fields": "Сохранить поля профиля", + "The profile fields could not be loaded.": "Не удалось загрузить поля профиля.", + "The profile fields could not be saved.": "Не удалось сохранить поля профиля." } } diff --git a/l10n/sk.js b/l10n/sk.js index c3bb57879..972c0e9cc 100644 --- a/l10n/sk.js +++ b/l10n/sk.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potvrdenia o prečítaní v hornej časti panela ukazujú, kto potvrdil.", "{emoji}: {count} reactions" : "{emoji}: {count} reakcií", "React with {emoji}" : "Reagovať pomocou {emoji}", - "{names} and {count} more" : "{names} a ďalší ({count})" + "{names} and {count} more" : "{names} a ďalší ({count})", + "Search people" : "Hľadať osoby", + "Search by name, email or expertise…" : "Hľadať podľa mena, e-mailu alebo odbornosti…", + "Find everyone tagged {tag}" : "Nájsť všetkých so štítkom {tag}", + "LaunchPad profile" : "Profil v LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolegovia vidia tieto polia na vašej karte vo widgete osôb a môžu vás podľa nich nájsť.", + "Your profile fields could not be loaded." : "Polia vášho profilu sa nepodarilo načítať.", + "Not filled in" : "Nevyplnené", + "Filled from your organisation’s directory. You cannot change it here." : "Vyplnené z adresára vašej organizácie. Tu to nemôžete zmeniť.", + "Type a subject and press Enter" : "Napíšte tému a stlačte Enter", + "Your profile fields are saved." : "Polia vášho profilu sú uložené.", + "Your profile fields could not be saved." : "Polia vášho profilu sa nepodarilo uložiť.", + "Profile fields" : "Polia profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Ďalšie polia na kartách kolegov vo widgete osôb, napríklad umiestnenie kancelárie alebo odbornosť. Ľudia ich vypĺňajú v osobných nastaveniach, alebo pochádzajú z atribútu LDAP.", + "New field" : "Nové pole", + "Tags" : "Štítky", + "Filled by" : "Vypĺňa", + "The person" : "Samotná osoba", + "LDAP attribute" : "Atribút LDAP", + "Who may see it" : "Kto to smie vidieť", + "Everyone" : "Všetci", + "People in the same group" : "Ľudia v tej istej skupine", + "Searchable in the people widget" : "Vyhľadateľné vo widgete osôb", + "Shown on the card" : "Zobrazené na karte", + "Remove field" : "Odstrániť pole", + "Profile fields saved." : "Polia profilu sú uložené.", + "Save profile fields" : "Uložiť polia profilu", + "The profile fields could not be loaded." : "Polia profilu sa nepodarilo načítať.", + "The profile fields could not be saved." : "Polia profilu sa nepodarilo uložiť." }, "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;" ); diff --git a/l10n/sk.json b/l10n/sk.json index 140f63854..84474ab28 100644 --- a/l10n/sk.json +++ b/l10n/sk.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potvrdenia o prečítaní v hornej časti panela ukazujú, kto potvrdil.", "{emoji}: {count} reactions": "{emoji}: {count} reakcií", "React with {emoji}": "Reagovať pomocou {emoji}", - "{names} and {count} more": "{names} a ďalší ({count})" + "{names} and {count} more": "{names} a ďalší ({count})", + "Search people": "Hľadať osoby", + "Search by name, email or expertise…": "Hľadať podľa mena, e-mailu alebo odbornosti…", + "Find everyone tagged {tag}": "Nájsť všetkých so štítkom {tag}", + "LaunchPad profile": "Profil v LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolegovia vidia tieto polia na vašej karte vo widgete osôb a môžu vás podľa nich nájsť.", + "Your profile fields could not be loaded.": "Polia vášho profilu sa nepodarilo načítať.", + "Not filled in": "Nevyplnené", + "Filled from your organisation’s directory. You cannot change it here.": "Vyplnené z adresára vašej organizácie. Tu to nemôžete zmeniť.", + "Type a subject and press Enter": "Napíšte tému a stlačte Enter", + "Your profile fields are saved.": "Polia vášho profilu sú uložené.", + "Your profile fields could not be saved.": "Polia vášho profilu sa nepodarilo uložiť.", + "Profile fields": "Polia profilu", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Ďalšie polia na kartách kolegov vo widgete osôb, napríklad umiestnenie kancelárie alebo odbornosť. Ľudia ich vypĺňajú v osobných nastaveniach, alebo pochádzajú z atribútu LDAP.", + "New field": "Nové pole", + "Tags": "Štítky", + "Filled by": "Vypĺňa", + "The person": "Samotná osoba", + "LDAP attribute": "Atribút LDAP", + "Who may see it": "Kto to smie vidieť", + "Everyone": "Všetci", + "People in the same group": "Ľudia v tej istej skupine", + "Searchable in the people widget": "Vyhľadateľné vo widgete osôb", + "Shown on the card": "Zobrazené na karte", + "Remove field": "Odstrániť pole", + "Profile fields saved.": "Polia profilu sú uložené.", + "Save profile fields": "Uložiť polia profilu", + "The profile fields could not be loaded.": "Polia profilu sa nepodarilo načítať.", + "The profile fields could not be saved.": "Polia profilu sa nepodarilo uložiť." } } diff --git a/l10n/sl.js b/l10n/sl.js index 71736f3b0..368c7922b 100644 --- a/l10n/sl.js +++ b/l10n/sl.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Potrdila o branju na vrhu nadzorne plošče kažejo, kdo je potrdil.", "{emoji}: {count} reactions" : "{emoji}: {count} odzivov", "React with {emoji}" : "Odzovi se z {emoji}", - "{names} and {count} more" : "{names} in še {count}" + "{names} and {count} more" : "{names} in še {count}", + "Search people" : "Išči osebe", + "Search by name, email or expertise…" : "Išči po imenu, e-pošti ali strokovnem znanju…", + "Find everyone tagged {tag}" : "Najdi vse z oznako {tag}", + "LaunchPad profile" : "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Sodelavci vidijo ta polja na vaši kartici v gradniku oseb in vas lahko po njih najdejo.", + "Your profile fields could not be loaded." : "Polj vašega profila ni bilo mogoče naložiti.", + "Not filled in" : "Ni izpolnjeno", + "Filled from your organisation’s directory. You cannot change it here." : "Izpolnjeno iz imenika vaše organizacije. Tukaj tega ne morete spremeniti.", + "Type a subject and press Enter" : "Vnesite temo in pritisnite Enter", + "Your profile fields are saved." : "Polja vašega profila so shranjena.", + "Your profile fields could not be saved." : "Polj vašega profila ni bilo mogoče shraniti.", + "Profile fields" : "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Dodatna polja na karticah sodelavcev v gradniku oseb, na primer lokacija pisarne ali strokovno znanje. Osebe jih izpolnijo v osebnih nastavitvah ali pa izhajajo iz atributa LDAP.", + "New field" : "Novo polje", + "Tags" : "Oznake", + "Filled by" : "Izpolni", + "The person" : "Oseba sama", + "LDAP attribute" : "Atribut LDAP", + "Who may see it" : "Kdo ga lahko vidi", + "Everyone" : "Vsi", + "People in the same group" : "Osebe v isti skupini", + "Searchable in the people widget" : "Iskalno v gradniku oseb", + "Shown on the card" : "Prikazano na kartici", + "Remove field" : "Odstrani polje", + "Profile fields saved." : "Polja profila so shranjena.", + "Save profile fields" : "Shrani polja profila", + "The profile fields could not be loaded." : "Polj profila ni bilo mogoče naložiti.", + "The profile fields could not be saved." : "Polj profila ni bilo mogoče shraniti." }, "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" ); diff --git a/l10n/sl.json b/l10n/sl.json index 3c01dd9e0..4fadf33d5 100644 --- a/l10n/sl.json +++ b/l10n/sl.json @@ -1262,6 +1262,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Potrdila o branju na vrhu nadzorne plošče kažejo, kdo je potrdil.", "{emoji}: {count} reactions": "{emoji}: {count} odzivov", "React with {emoji}": "Odzovi se z {emoji}", - "{names} and {count} more": "{names} in še {count}" + "{names} and {count} more": "{names} in še {count}", + "Search people": "Išči osebe", + "Search by name, email or expertise…": "Išči po imenu, e-pošti ali strokovnem znanju…", + "Find everyone tagged {tag}": "Najdi vse z oznako {tag}", + "LaunchPad profile": "Profil LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Sodelavci vidijo ta polja na vaši kartici v gradniku oseb in vas lahko po njih najdejo.", + "Your profile fields could not be loaded.": "Polj vašega profila ni bilo mogoče naložiti.", + "Not filled in": "Ni izpolnjeno", + "Filled from your organisation’s directory. You cannot change it here.": "Izpolnjeno iz imenika vaše organizacije. Tukaj tega ne morete spremeniti.", + "Type a subject and press Enter": "Vnesite temo in pritisnite Enter", + "Your profile fields are saved.": "Polja vašega profila so shranjena.", + "Your profile fields could not be saved.": "Polj vašega profila ni bilo mogoče shraniti.", + "Profile fields": "Polja profila", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Dodatna polja na karticah sodelavcev v gradniku oseb, na primer lokacija pisarne ali strokovno znanje. Osebe jih izpolnijo v osebnih nastavitvah ali pa izhajajo iz atributa LDAP.", + "New field": "Novo polje", + "Tags": "Oznake", + "Filled by": "Izpolni", + "The person": "Oseba sama", + "LDAP attribute": "Atribut LDAP", + "Who may see it": "Kdo ga lahko vidi", + "Everyone": "Vsi", + "People in the same group": "Osebe v isti skupini", + "Searchable in the people widget": "Iskalno v gradniku oseb", + "Shown on the card": "Prikazano na kartici", + "Remove field": "Odstrani polje", + "Profile fields saved.": "Polja profila so shranjena.", + "Save profile fields": "Shrani polja profila", + "The profile fields could not be loaded.": "Polj profila ni bilo mogoče naložiti.", + "The profile fields could not be saved.": "Polj profila ni bilo mogoče shraniti." } } diff --git a/l10n/sq.js b/l10n/sq.js index f06671db8..cdcf747d1 100644 --- a/l10n/sq.js +++ b/l10n/sq.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Dëftesat e leximit në krye të panelit tregojnë kush ka konfirmuar.", "{emoji}: {count} reactions" : "{emoji}: {count} reagime", "React with {emoji}" : "Reago me {emoji}", - "{names} and {count} more" : "{names} dhe {count} të tjerë" + "{names} and {count} more" : "{names} dhe {count} të tjerë", + "Search people" : "Kërko persona", + "Search by name, email or expertise…" : "Kërko sipas emrit, email-it ose ekspertizës…", + "Find everyone tagged {tag}" : "Gjej të gjithë me etiketën {tag}", + "LaunchPad profile" : "Profili i LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kolegët i shohin këto fusha në kartën tënde te widget-i i personave dhe mund të të gjejnë përmes tyre.", + "Your profile fields could not be loaded." : "Fushat e profilit tënd nuk u ngarkuan.", + "Not filled in" : "Pa plotësuar", + "Filled from your organisation’s directory. You cannot change it here." : "Plotësohet nga direktoria e organizatës sate. Nuk mund ta ndryshosh këtu.", + "Type a subject and press Enter" : "Shkruaj një temë dhe shtyp Enter", + "Your profile fields are saved." : "Fushat e profilit tënd u ruajtën.", + "Your profile fields could not be saved." : "Fushat e profilit tënd nuk u ruajtën.", + "Profile fields" : "Fushat e profilit", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Fusha shtesë në kartat e kolegëve te widget-i i personave, si vendndodhja e zyrës ose ekspertiza. Personat i plotësojnë në cilësimet e tyre personale, ose vijnë nga një atribut LDAP.", + "New field" : "Fushë e re", + "Tags" : "Etiketa", + "Filled by" : "Plotësohet nga", + "The person" : "Vetë personi", + "LDAP attribute" : "Atribut LDAP", + "Who may see it" : "Kush mund ta shohë", + "Everyone" : "Të gjithë", + "People in the same group" : "Personat në të njëjtin grup", + "Searchable in the people widget" : "I kërkueshëm te widget-i i personave", + "Shown on the card" : "Shfaqet në kartë", + "Remove field" : "Hiq fushën", + "Profile fields saved." : "Fushat e profilit u ruajtën.", + "Save profile fields" : "Ruaj fushat e profilit", + "The profile fields could not be loaded." : "Fushat e profilit nuk u ngarkuan.", + "The profile fields could not be saved." : "Fushat e profilit nuk u ruajtën." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/sq.json b/l10n/sq.json index a7e099047..1fb6fecd0 100644 --- a/l10n/sq.json +++ b/l10n/sq.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Dëftesat e leximit në krye të panelit tregojnë kush ka konfirmuar.", "{emoji}: {count} reactions": "{emoji}: {count} reagime", "React with {emoji}": "Reago me {emoji}", - "{names} and {count} more": "{names} dhe {count} të tjerë" + "{names} and {count} more": "{names} dhe {count} të tjerë", + "Search people": "Kërko persona", + "Search by name, email or expertise…": "Kërko sipas emrit, email-it ose ekspertizës…", + "Find everyone tagged {tag}": "Gjej të gjithë me etiketën {tag}", + "LaunchPad profile": "Profili i LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kolegët i shohin këto fusha në kartën tënde te widget-i i personave dhe mund të të gjejnë përmes tyre.", + "Your profile fields could not be loaded.": "Fushat e profilit tënd nuk u ngarkuan.", + "Not filled in": "Pa plotësuar", + "Filled from your organisation’s directory. You cannot change it here.": "Plotësohet nga direktoria e organizatës sate. Nuk mund ta ndryshosh këtu.", + "Type a subject and press Enter": "Shkruaj një temë dhe shtyp Enter", + "Your profile fields are saved.": "Fushat e profilit tënd u ruajtën.", + "Your profile fields could not be saved.": "Fushat e profilit tënd nuk u ruajtën.", + "Profile fields": "Fushat e profilit", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Fusha shtesë në kartat e kolegëve te widget-i i personave, si vendndodhja e zyrës ose ekspertiza. Personat i plotësojnë në cilësimet e tyre personale, ose vijnë nga një atribut LDAP.", + "New field": "Fushë e re", + "Tags": "Etiketa", + "Filled by": "Plotësohet nga", + "The person": "Vetë personi", + "LDAP attribute": "Atribut LDAP", + "Who may see it": "Kush mund ta shohë", + "Everyone": "Të gjithë", + "People in the same group": "Personat në të njëjtin grup", + "Searchable in the people widget": "I kërkueshëm te widget-i i personave", + "Shown on the card": "Shfaqet në kartë", + "Remove field": "Hiq fushën", + "Profile fields saved.": "Fushat e profilit u ruajtën.", + "Save profile fields": "Ruaj fushat e profilit", + "The profile fields could not be loaded.": "Fushat e profilit nuk u ngarkuan.", + "The profile fields could not be saved.": "Fushat e profilit nuk u ruajtën." } } diff --git a/l10n/sr.js b/l10n/sr.js index 0d60501bc..612b24d10 100644 --- a/l10n/sr.js +++ b/l10n/sr.js @@ -1284,6 +1284,34 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Потврде читања на врху контролне табле показују ко је потврдио.", "{emoji}: {count} reactions" : "{emoji}: {count} реакција", "React with {emoji}" : "Реагуј са {emoji}", - "{names} and {count} more" : "{names} и још {count}" + "{names} and {count} more" : "{names} и још {count}", + "Search people" : "Претражи особе", + "Search by name, email or expertise…" : "Претражи по имену, е-пошти или стручности…", + "Find everyone tagged {tag}" : "Пронађи све са ознаком {tag}", + "LaunchPad profile" : "LaunchPad профил", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Колеге виде ова поља на вашој картици у виџету особа и могу да вас пронађу по њима.", + "Your profile fields could not be loaded." : "Поља вашег профила нису могла да се учитају.", + "Not filled in" : "Није попуњено", + "Filled from your organisation’s directory. You cannot change it here." : "Попуњено из именика ваше организације. Овде то не можете да промените.", + "Type a subject and press Enter" : "Унесите тему и притисните Enter", + "Your profile fields are saved." : "Поља вашег профила су сачувана.", + "Your profile fields could not be saved." : "Поља вашег профила нису могла да се сачувају.", + "Profile fields" : "Поља профила", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Додатна поља на картицама колега у виџету особа, као што су локација канцеларије или стручност. Особе их попуњавају у личним подешавањима или долазе из LDAP атрибута.", + "New field" : "Ново поље", + "Tags" : "Ознаке", + "Filled by" : "Попуњава", + "The person" : "Сама особа", + "LDAP attribute" : "LDAP атрибут", + "Who may see it" : "Ко сме да га види", + "Everyone" : "Сви", + "People in the same group" : "Особе у истој групи", + "Searchable in the people widget" : "Претраживо у виџету особа", + "Shown on the card" : "Приказано на картици", + "Remove field" : "Уклони поље", + "Profile fields saved." : "Поља профила су сачувана.", + "Save profile fields" : "Сачувај поља профила", + "The profile fields could not be loaded." : "Поља профила нису могла да се учитају.", + "The profile fields could not be saved." : "Поља профила нису могла да се сачувају." }, "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/l10n/sr.json b/l10n/sr.json index 96e2004a5..fa807ae69 100644 --- a/l10n/sr.json +++ b/l10n/sr.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Потврде читања на врху контролне табле показују ко је потврдио.", "{emoji}: {count} reactions": "{emoji}: {count} реакција", "React with {emoji}": "Реагуј са {emoji}", - "{names} and {count} more": "{names} и још {count}" + "{names} and {count} more": "{names} и још {count}", + "Search people": "Претражи особе", + "Search by name, email or expertise…": "Претражи по имену, е-пошти или стручности…", + "Find everyone tagged {tag}": "Пронађи све са ознаком {tag}", + "LaunchPad profile": "LaunchPad профил", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Колеге виде ова поља на вашој картици у виџету особа и могу да вас пронађу по њима.", + "Your profile fields could not be loaded.": "Поља вашег профила нису могла да се учитају.", + "Not filled in": "Није попуњено", + "Filled from your organisation’s directory. You cannot change it here.": "Попуњено из именика ваше организације. Овде то не можете да промените.", + "Type a subject and press Enter": "Унесите тему и притисните Enter", + "Your profile fields are saved.": "Поља вашег профила су сачувана.", + "Your profile fields could not be saved.": "Поља вашег профила нису могла да се сачувају.", + "Profile fields": "Поља профила", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Додатна поља на картицама колега у виџету особа, као што су локација канцеларије или стручност. Особе их попуњавају у личним подешавањима или долазе из LDAP атрибута.", + "New field": "Ново поље", + "Tags": "Ознаке", + "Filled by": "Попуњава", + "The person": "Сама особа", + "LDAP attribute": "LDAP атрибут", + "Who may see it": "Ко сме да га види", + "Everyone": "Сви", + "People in the same group": "Особе у истој групи", + "Searchable in the people widget": "Претраживо у виџету особа", + "Shown on the card": "Приказано на картици", + "Remove field": "Уклони поље", + "Profile fields saved.": "Поља профила су сачувана.", + "Save profile fields": "Сачувај поља профила", + "The profile fields could not be loaded.": "Поља профила нису могла да се учитају.", + "The profile fields could not be saved.": "Поља профила нису могла да се сачувају." } } diff --git a/l10n/sv.js b/l10n/sv.js index 96a8c9acd..b00492b8a 100644 --- a/l10n/sv.js +++ b/l10n/sv.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Läskvitton högst upp på instrumentpanelen visar vem som har bekräftat.", "{emoji}: {count} reactions" : "{emoji}: {count} reaktioner", "React with {emoji}" : "Reagera med {emoji}", - "{names} and {count} more" : "{names} och {count} till" + "{names} and {count} more" : "{names} och {count} till", + "Search people" : "Sök personer", + "Search by name, email or expertise…" : "Sök på namn, e-post eller expertis…", + "Find everyone tagged {tag}" : "Hitta alla med taggen {tag}", + "LaunchPad profile" : "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Kollegor ser de här fälten på ditt kort i personwidgeten och kan hitta dig med dem.", + "Your profile fields could not be loaded." : "Dina profilfält kunde inte läsas in.", + "Not filled in" : "Inte ifyllt", + "Filled from your organisation’s directory. You cannot change it here." : "Hämtas från din organisations katalog. Du kan inte ändra det här.", + "Type a subject and press Enter" : "Skriv ett ämne och tryck på Enter", + "Your profile fields are saved." : "Dina profilfält har sparats.", + "Your profile fields could not be saved." : "Dina profilfält kunde inte sparas.", + "Profile fields" : "Profilfält", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Extra fält på kollegors kort i personwidgeten, till exempel kontorsplats eller expertis. Personerna fyller i dem i sina personliga inställningar, eller så kommer de från ett LDAP-attribut.", + "New field" : "Nytt fält", + "Tags" : "Taggar", + "Filled by" : "Fylls i av", + "The person" : "Personen själv", + "LDAP attribute" : "LDAP-attribut", + "Who may see it" : "Vem får se det", + "Everyone" : "Alla", + "People in the same group" : "Personer i samma grupp", + "Searchable in the people widget" : "Sökbart i personwidgeten", + "Shown on the card" : "Visas på kortet", + "Remove field" : "Ta bort fält", + "Profile fields saved." : "Profilfälten har sparats.", + "Save profile fields" : "Spara profilfält", + "The profile fields could not be loaded." : "Profilfälten kunde inte läsas in.", + "The profile fields could not be saved." : "Profilfälten kunde inte sparas." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/sv.json b/l10n/sv.json index 8b7b314d9..01609597c 100644 --- a/l10n/sv.json +++ b/l10n/sv.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Läskvitton högst upp på instrumentpanelen visar vem som har bekräftat.", "{emoji}: {count} reactions": "{emoji}: {count} reaktioner", "React with {emoji}": "Reagera med {emoji}", - "{names} and {count} more": "{names} och {count} till" + "{names} and {count} more": "{names} och {count} till", + "Search people": "Sök personer", + "Search by name, email or expertise…": "Sök på namn, e-post eller expertis…", + "Find everyone tagged {tag}": "Hitta alla med taggen {tag}", + "LaunchPad profile": "LaunchPad-profil", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Kollegor ser de här fälten på ditt kort i personwidgeten och kan hitta dig med dem.", + "Your profile fields could not be loaded.": "Dina profilfält kunde inte läsas in.", + "Not filled in": "Inte ifyllt", + "Filled from your organisation’s directory. You cannot change it here.": "Hämtas från din organisations katalog. Du kan inte ändra det här.", + "Type a subject and press Enter": "Skriv ett ämne och tryck på Enter", + "Your profile fields are saved.": "Dina profilfält har sparats.", + "Your profile fields could not be saved.": "Dina profilfält kunde inte sparas.", + "Profile fields": "Profilfält", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Extra fält på kollegors kort i personwidgeten, till exempel kontorsplats eller expertis. Personerna fyller i dem i sina personliga inställningar, eller så kommer de från ett LDAP-attribut.", + "New field": "Nytt fält", + "Tags": "Taggar", + "Filled by": "Fylls i av", + "The person": "Personen själv", + "LDAP attribute": "LDAP-attribut", + "Who may see it": "Vem får se det", + "Everyone": "Alla", + "People in the same group": "Personer i samma grupp", + "Searchable in the people widget": "Sökbart i personwidgeten", + "Shown on the card": "Visas på kortet", + "Remove field": "Ta bort fält", + "Profile fields saved.": "Profilfälten har sparats.", + "Save profile fields": "Spara profilfält", + "The profile fields could not be loaded.": "Profilfälten kunde inte läsas in.", + "The profile fields could not be saved.": "Profilfälten kunde inte sparas." } } diff --git a/l10n/tr.js b/l10n/tr.js index af83b5161..c6aedbaa1 100644 --- a/l10n/tr.js +++ b/l10n/tr.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Panonun üstündeki okundu bilgileri kimin onayladığını gösterir.", "{emoji}: {count} reactions" : "{emoji}: {count} tepki", "React with {emoji}" : "{emoji} ile tepki ver", - "{names} and {count} more" : "{names} ve {count} kişi daha" + "{names} and {count} more" : "{names} ve {count} kişi daha", + "Search people" : "Kişi ara", + "Search by name, email or expertise…" : "Ada, e-posta veya uzmanlığa göre ara…", + "Find everyone tagged {tag}" : "{tag} etiketli herkesi bul", + "LaunchPad profile" : "LaunchPad profili", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Meslektaşların bu alanları kişiler bileşenindeki kartında görür ve seni bunlarla bulabilir.", + "Your profile fields could not be loaded." : "Profil alanların yüklenemedi.", + "Not filled in" : "Doldurulmadı", + "Filled from your organisation’s directory. You cannot change it here." : "Kuruluşunun dizininden doldurulur. Burada değiştiremezsin.", + "Type a subject and press Enter" : "Bir konu yaz ve Enter'a bas", + "Your profile fields are saved." : "Profil alanların kaydedildi.", + "Your profile fields could not be saved." : "Profil alanların kaydedilemedi.", + "Profile fields" : "Profil alanları", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Kişiler bileşenindeki meslektaş kartlarında ofis konumu veya uzmanlık gibi ek alanlar. Kişiler bunları kişisel ayarlarında doldurur ya da bir LDAP özniteliğinden gelir.", + "New field" : "Yeni alan", + "Tags" : "Etiketler", + "Filled by" : "Dolduran", + "The person" : "Kişinin kendisi", + "LDAP attribute" : "LDAP özniteliği", + "Who may see it" : "Kimler görebilir", + "Everyone" : "Herkes", + "People in the same group" : "Aynı gruptaki kişiler", + "Searchable in the people widget" : "Kişiler bileşeninde aranabilir", + "Shown on the card" : "Kartta gösterilir", + "Remove field" : "Alanı kaldır", + "Profile fields saved." : "Profil alanları kaydedildi.", + "Save profile fields" : "Profil alanlarını kaydet", + "The profile fields could not be loaded." : "Profil alanları yüklenemedi.", + "The profile fields could not be saved." : "Profil alanları kaydedilemedi." }, "nplurals=2; plural=(n != 1);" ); diff --git a/l10n/tr.json b/l10n/tr.json index 400ce5b09..377f35188 100644 --- a/l10n/tr.json +++ b/l10n/tr.json @@ -1260,6 +1260,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Panonun üstündeki okundu bilgileri kimin onayladığını gösterir.", "{emoji}: {count} reactions": "{emoji}: {count} tepki", "React with {emoji}": "{emoji} ile tepki ver", - "{names} and {count} more": "{names} ve {count} kişi daha" + "{names} and {count} more": "{names} ve {count} kişi daha", + "Search people": "Kişi ara", + "Search by name, email or expertise…": "Ada, e-posta veya uzmanlığa göre ara…", + "Find everyone tagged {tag}": "{tag} etiketli herkesi bul", + "LaunchPad profile": "LaunchPad profili", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Meslektaşların bu alanları kişiler bileşenindeki kartında görür ve seni bunlarla bulabilir.", + "Your profile fields could not be loaded.": "Profil alanların yüklenemedi.", + "Not filled in": "Doldurulmadı", + "Filled from your organisation’s directory. You cannot change it here.": "Kuruluşunun dizininden doldurulur. Burada değiştiremezsin.", + "Type a subject and press Enter": "Bir konu yaz ve Enter'a bas", + "Your profile fields are saved.": "Profil alanların kaydedildi.", + "Your profile fields could not be saved.": "Profil alanların kaydedilemedi.", + "Profile fields": "Profil alanları", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Kişiler bileşenindeki meslektaş kartlarında ofis konumu veya uzmanlık gibi ek alanlar. Kişiler bunları kişisel ayarlarında doldurur ya da bir LDAP özniteliğinden gelir.", + "New field": "Yeni alan", + "Tags": "Etiketler", + "Filled by": "Dolduran", + "The person": "Kişinin kendisi", + "LDAP attribute": "LDAP özniteliği", + "Who may see it": "Kimler görebilir", + "Everyone": "Herkes", + "People in the same group": "Aynı gruptaki kişiler", + "Searchable in the people widget": "Kişiler bileşeninde aranabilir", + "Shown on the card": "Kartta gösterilir", + "Remove field": "Alanı kaldır", + "Profile fields saved.": "Profil alanları kaydedildi.", + "Save profile fields": "Profil alanlarını kaydet", + "The profile fields could not be loaded.": "Profil alanları yüklenemedi.", + "The profile fields could not be saved.": "Profil alanları kaydedilemedi." } } diff --git a/l10n/uk.js b/l10n/uk.js index 34458a71c..eee0990e0 100644 --- a/l10n/uk.js +++ b/l10n/uk.js @@ -1293,7 +1293,35 @@ OC.L10N.register( "Read receipts at the top of the dashboard show who has confirmed." : "Квитанції про прочитання вгорі панелі показують, хто підтвердив.", "{emoji}: {count} reactions" : "{emoji}: реакцій {count}", "React with {emoji}" : "Відреагувати {emoji}", - "{names} and {count} more" : "{names} та ще {count}" + "{names} and {count} more" : "{names} та ще {count}", + "Search people" : "Пошук людей", + "Search by name, email or expertise…" : "Пошук за ім'ям, електронною поштою або експертизою…", + "Find everyone tagged {tag}" : "Знайти всіх з тегом {tag}", + "LaunchPad profile" : "Профіль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them." : "Колеги бачать ці поля на вашій картці у віджеті людей і можуть знайти вас за ними.", + "Your profile fields could not be loaded." : "Не вдалося завантажити поля вашого профілю.", + "Not filled in" : "Не заповнено", + "Filled from your organisation’s directory. You cannot change it here." : "Заповнюється з каталогу вашої організації. Тут це змінити не можна.", + "Type a subject and press Enter" : "Введіть тему й натисніть Enter", + "Your profile fields are saved." : "Поля вашого профілю збережено.", + "Your profile fields could not be saved." : "Не вдалося зберегти поля вашого профілю.", + "Profile fields" : "Поля профілю", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute." : "Додаткові поля на картках колег у віджеті людей, наприклад розташування офісу або експертиза. Люди заповнюють їх в особистих налаштуваннях, або вони беруться з атрибута LDAP.", + "New field" : "Нове поле", + "Tags" : "Теги", + "Filled by" : "Хто заповнює", + "The person" : "Сама людина", + "LDAP attribute" : "Атрибут LDAP", + "Who may see it" : "Хто може бачити", + "Everyone" : "Усі", + "People in the same group" : "Люди з тієї ж групи", + "Searchable in the people widget" : "Доступно для пошуку у віджеті людей", + "Shown on the card" : "Показується на картці", + "Remove field" : "Вилучити поле", + "Profile fields saved." : "Поля профілю збережено.", + "Save profile fields" : "Зберегти поля профілю", + "The profile fields could not be loaded." : "Не вдалося завантажити поля профілю.", + "The profile fields could not be saved." : "Не вдалося зберегти поля профілю." }, "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/l10n/uk.json b/l10n/uk.json index 3d9ae2751..50e244f2e 100644 --- a/l10n/uk.json +++ b/l10n/uk.json @@ -1261,6 +1261,34 @@ "Read receipts at the top of the dashboard show who has confirmed.": "Квитанції про прочитання вгорі панелі показують, хто підтвердив.", "{emoji}: {count} reactions": "{emoji}: реакцій {count}", "React with {emoji}": "Відреагувати {emoji}", - "{names} and {count} more": "{names} та ще {count}" + "{names} and {count} more": "{names} та ще {count}", + "Search people": "Пошук людей", + "Search by name, email or expertise…": "Пошук за ім'ям, електронною поштою або експертизою…", + "Find everyone tagged {tag}": "Знайти всіх з тегом {tag}", + "LaunchPad profile": "Профіль LaunchPad", + "Colleagues see these fields on your card in the people widget and can find you by them.": "Колеги бачать ці поля на вашій картці у віджеті людей і можуть знайти вас за ними.", + "Your profile fields could not be loaded.": "Не вдалося завантажити поля вашого профілю.", + "Not filled in": "Не заповнено", + "Filled from your organisation’s directory. You cannot change it here.": "Заповнюється з каталогу вашої організації. Тут це змінити не можна.", + "Type a subject and press Enter": "Введіть тему й натисніть Enter", + "Your profile fields are saved.": "Поля вашого профілю збережено.", + "Your profile fields could not be saved.": "Не вдалося зберегти поля вашого профілю.", + "Profile fields": "Поля профілю", + "Extra fields on colleague cards in the people widget, such as office location or expertise. People fill them in on their personal settings, or they come from an LDAP attribute.": "Додаткові поля на картках колег у віджеті людей, наприклад розташування офісу або експертиза. Люди заповнюють їх в особистих налаштуваннях, або вони беруться з атрибута LDAP.", + "New field": "Нове поле", + "Tags": "Теги", + "Filled by": "Хто заповнює", + "The person": "Сама людина", + "LDAP attribute": "Атрибут LDAP", + "Who may see it": "Хто може бачити", + "Everyone": "Усі", + "People in the same group": "Люди з тієї ж групи", + "Searchable in the people widget": "Доступно для пошуку у віджеті людей", + "Shown on the card": "Показується на картці", + "Remove field": "Вилучити поле", + "Profile fields saved.": "Поля профілю збережено.", + "Save profile fields": "Зберегти поля профілю", + "The profile fields could not be loaded.": "Не вдалося завантажити поля профілю.", + "The profile fields could not be saved.": "Не вдалося зберегти поля профілю." } } diff --git a/src/components/Widgets/Renderers/PeopleWidget.vue b/src/components/Widgets/Renderers/PeopleWidget.vue index c775028d8..c0302f331 100644 --- a/src/components/Widgets/Renderers/PeopleWidget.vue +++ b/src/components/Widgets/Renderers/PeopleWidget.vue @@ -11,7 +11,9 @@ type="search" class="people-widget__search" :aria-label="t('launchpad', 'Search people')" - :placeholder="t('launchpad', 'Search by name or email…')" /> + :placeholder=" + t('launchpad', 'Search by name, email or expertise…') + " />