From 42ff85ae8c8c1b7917f7e9619a6c4ffacf47d166 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:53:47 -0300 Subject: [PATCH 01/15] fix(notification): clarify profile field update message Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Notification/Notifier.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php index b208a43..155c8ef 100644 --- a/lib/Notification/Notifier.php +++ b/lib/Notification/Notifier.php @@ -48,8 +48,9 @@ public function prepare(INotification $notification, string $languageCode): INot } if ($notification->getMessage() === 'profile_field_updated_message') { + // TRANSLATORS %1$s is the actor user ID, %2$s is the affected user ID, %3$s is the profile field label. $notification->setParsedMessage($l10n->t( - '%1$s changed %2$s\'s %3$s profile field.', + '%1$s changed profile field "%3$s" for user %2$s.', $notification->getMessageParameters(), )); } elseif ($notification->getMessage() !== '' && $notification->getParsedMessage() === '') { From 5793e69f2fd2130128e127e37287e464beeb9d2b Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:53:48 -0300 Subject: [PATCH 02/15] fix(service): improve field value validation messages Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- lib/Service/FieldValueService.php | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/Service/FieldValueService.php b/lib/Service/FieldValueService.php index e0934cc..a597e18 100644 --- a/lib/Service/FieldValueService.php +++ b/lib/Service/FieldValueService.php @@ -53,7 +53,7 @@ public function upsert( $valueJson = $this->encodeValue($normalizedValue); $visibility = $currentVisibility ?? FieldExposurePolicy::from($definition->getExposurePolicy())->initialVisibility()->value; if (!FieldVisibility::isValid($visibility)) { - throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported')); + throw new InvalidArgumentException($this->l10n->t('The provided visibility value is not supported.')); } $entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid) ?? new FieldValue(); @@ -145,16 +145,17 @@ public function searchByDefinition( int $offset, ): array { if ($limit < 1 || $limit > self::SEARCH_MAX_LIMIT) { + // TRANSLATORS %d is the maximum supported search limit. throw new InvalidArgumentException($this->l10n->t('limit must be between 1 and %d', [self::SEARCH_MAX_LIMIT])); } if ($offset < 0) { - throw new InvalidArgumentException($this->l10n->t('offset must be greater than or equal to 0')); + throw new InvalidArgumentException($this->l10n->t('The offset must be greater than or equal to 0.')); } $normalizedOperator = strtolower(trim($operator)); if (!in_array($normalizedOperator, [self::SEARCH_OPERATOR_EQ, self::SEARCH_OPERATOR_CONTAINS], true)) { - throw new InvalidArgumentException($this->l10n->t('search operator is not supported')); + throw new InvalidArgumentException($this->l10n->t('The search operator is not supported.')); } $searchValue = $this->normalizeSearchValue($definition, $normalizedOperator, $rawValue); @@ -177,12 +178,12 @@ public function searchByDefinition( public function updateVisibility(FieldDefinition $definition, string $userUid, string $updatedByUid, string $currentVisibility): FieldValue { if (!FieldVisibility::isValid($currentVisibility)) { - throw new InvalidArgumentException($this->l10n->t('current_visibility is not supported')); + throw new InvalidArgumentException($this->l10n->t('The provided visibility value is not supported.')); } $entity = $this->fieldValueMapper->findByFieldDefinitionIdAndUserUid($definition->getId(), $userUid); if ($entity === null) { - throw new InvalidArgumentException($this->l10n->t('field value not found')); + throw new InvalidArgumentException($this->l10n->t('No profile field value was found.')); } $previousValue = $this->extractScalarValue($entity->getValueJson()); @@ -229,7 +230,7 @@ public function serializeForResponse(FieldValue $value): array { */ private function normalizeTextValue(array|string|int|float|bool $rawValue): array { if (is_array($rawValue)) { - throw new InvalidArgumentException($this->l10n->t('text fields expect a scalar value')); + throw new InvalidArgumentException($this->l10n->t('Text fields require a single text value.')); } return ['value' => trim((string)$rawValue)]; @@ -241,12 +242,13 @@ private function normalizeTextValue(array|string|int|float|bool $rawValue): arra */ private function normalizeSelectValue(array|string|int|float|bool $rawValue, FieldDefinition $definition): array { if (!is_string($rawValue)) { - throw new InvalidArgumentException($this->l10n->t('select fields expect a string value')); + throw new InvalidArgumentException($this->l10n->t('Select fields require one of the configured option values.')); } $value = trim($rawValue); $options = json_decode($definition->getOptions() ?? '[]', true); if (!in_array($value, $options, true)) { + // TRANSLATORS %s is an invalid option value provided by the user. throw new InvalidArgumentException($this->l10n->t('"%s" is not a valid option for this field', [$value])); } @@ -259,7 +261,7 @@ private function normalizeSelectValue(array|string|int|float|bool $rawValue, Fie */ private function normalizeNumberValue(array|string|int|float|bool $rawValue): array { if (is_array($rawValue) || is_bool($rawValue) || !is_numeric($rawValue)) { - throw new InvalidArgumentException($this->l10n->t('number fields expect a numeric value')); + throw new InvalidArgumentException($this->l10n->t('Number fields require a numeric value.')); } return ['value' => str_contains((string)$rawValue, '.') ? (float)$rawValue : (int)$rawValue]; @@ -272,7 +274,7 @@ private function encodeValue(array $value): string { try { return json_encode($value, JSON_THROW_ON_ERROR); } catch (JsonException $exception) { - throw new InvalidArgumentException($this->l10n->t('value_json could not be encoded'), 0, $exception); + throw new InvalidArgumentException($this->l10n->t('The stored value payload could not be encoded as JSON.'), 0, $exception); } } @@ -283,11 +285,11 @@ private function decodeValue(string $valueJson): array { try { $decoded = json_decode($valueJson, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $exception) { - throw new InvalidArgumentException($this->l10n->t('value_json could not be decoded'), 0, $exception); + throw new InvalidArgumentException($this->l10n->t('The stored value payload could not be decoded from JSON.'), 0, $exception); } if (!is_array($decoded)) { - throw new InvalidArgumentException($this->l10n->t('value_json must decode to an object payload')); + throw new InvalidArgumentException($this->l10n->t('The stored value payload must decode to a JSON object.')); } return $decoded; @@ -328,13 +330,13 @@ private function normalizeSearchValue(FieldDefinition $definition, string $opera } if (FieldType::from($definition->getType()) !== FieldType::TEXT) { - throw new InvalidArgumentException($this->l10n->t('contains operator is only supported for text fields')); + throw new InvalidArgumentException($this->l10n->t('The "contains" operator is only available for text fields.')); } $normalized = $this->normalizeValue($definition, $rawValue); $value = $normalized['value'] ?? null; if (!is_string($value) || $value === '') { - throw new InvalidArgumentException($this->l10n->t('contains operator requires a non-empty text value')); + throw new InvalidArgumentException($this->l10n->t('The "contains" operator requires a non-empty text value.')); } return ['value' => $value]; From 67dc6b036e1242f7c4401370a0b1f4d6d48344e8 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:53:48 -0300 Subject: [PATCH 03/15] fix(workflow): refine talk conversation operation copy Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .../CreateTalkConversationProfileFieldChangeOperation.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Workflow/CreateTalkConversationProfileFieldChangeOperation.php b/lib/Workflow/CreateTalkConversationProfileFieldChangeOperation.php index 57b87c3..94f9fcc 100644 --- a/lib/Workflow/CreateTalkConversationProfileFieldChangeOperation.php +++ b/lib/Workflow/CreateTalkConversationProfileFieldChangeOperation.php @@ -55,7 +55,7 @@ public function isAvailableForScope(int $scope): bool { #[\Override] public function validateOperation(string $name, array $checks, string $operation): void { if (trim($operation) !== '') { - throw new \UnexpectedValueException($this->l10n->t('This workflow operation does not accept custom configuration')); + throw new \UnexpectedValueException($this->l10n->t('This workflow operation does not support custom configuration.')); } } @@ -90,7 +90,8 @@ public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatch } $this->broker->createConversation( - $this->l10n->t('Profile field change: %1$s for %2$s', [ + // TRANSLATORS %1$s is the profile field label, %2$s is the affected user ID. + $this->l10n->t('Profile field changed: %1$s for user %2$s', [ $fieldLabel, $subject->getUserUid(), ]), From 18a7aa9ecd1aefe994f71e7644dc9b5e74180591 Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:53:48 -0300 Subject: [PATCH 04/15] fix(workflow): refine admin and group notification copy Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- .../NotifyAdminsOrGroupsProfileFieldChangeOperation.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Workflow/NotifyAdminsOrGroupsProfileFieldChangeOperation.php b/lib/Workflow/NotifyAdminsOrGroupsProfileFieldChangeOperation.php index 48a5af3..9fd42ca 100644 --- a/lib/Workflow/NotifyAdminsOrGroupsProfileFieldChangeOperation.php +++ b/lib/Workflow/NotifyAdminsOrGroupsProfileFieldChangeOperation.php @@ -57,7 +57,7 @@ public function isAvailableForScope(int $scope): bool { public function validateOperation(string $name, array $checks, string $operation): void { $config = $this->parseConfig($operation); if ($config === null || $this->resolveRecipientUids($config['targets']) === []) { - throw new \UnexpectedValueException($this->l10n->t('A valid target list is required')); + throw new \UnexpectedValueException($this->l10n->t('A valid recipient list is required.')); } } @@ -85,8 +85,9 @@ public function onEvent(string $eventName, Event $event, IRuleMatcher $ruleMatch foreach ($this->resolveRecipientUids($config['targets']) as $recipientUid) { $subjectText = $this->l10n->t('Profile field updated'); + // TRANSLATORS %1$s is the actor user ID, %2$s is the affected user ID, %3$s is the profile field label. $messageText = $this->l10n->t( - '%1$s changed %2$s\'s %3$s profile field.', + '%1$s changed profile field "%3$s" for user %2$s.', [ $subject->getActorUid(), $subject->getUserUid(), From a9a544811115cc3b226a27d1d9938b31d4713fcf Mon Sep 17 00:00:00 2001 From: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:53:48 -0300 Subject: [PATCH 05/15] feat(admin-ui): refresh support banner messaging Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> --- src/components/AdminSupportBanner.vue | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/AdminSupportBanner.vue b/src/components/AdminSupportBanner.vue index cfff7aa..86b5d36 100644 --- a/src/components/AdminSupportBanner.vue +++ b/src/components/AdminSupportBanner.vue @@ -7,9 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-or-later
-

{{ t('profile_fields', 'Help keep Profile Fields sustainable.') }}

+

{{ t('profile_fields', 'Help sustain Profile Fields development.') }}

{{ t('profile_fields', 'Profile Fields is open source under the AGPL license and maintained by the LibreCode team, creators of LibreSign.') }}

-

{{ t('profile_fields', 'If your organization depends on it, please help us sustain its development and maintenance.') }}

+

{{ t('profile_fields', 'If your organization depends on this app, please help fund ongoing development and maintenance.') }}

@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later