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() === '') { 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]; 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(), ]), 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(), 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