Skip to content

Commit 793c260

Browse files
TatevikGrtatevikg1
andauthored
EventLog + translator (#356)
* EventLogManager * Log failed logins + translate messages * weblate * test fix * Use translations * Fix pipeline * Weblate * Deprecate DB translation table --------- Co-authored-by: Tatevik <[email protected]>
1 parent dc99df1 commit 793c260

File tree

20 files changed

+492
-26
lines changed

20 files changed

+492
-26
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: I18n Validate
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'resources/translations/**/*.xlf'
7+
- 'composer.lock'
8+
- 'composer.json'
9+
10+
jobs:
11+
validate-xliff:
12+
runs-on: ubuntu-22.04
13+
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
php: ['8.1']
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Setup PHP
24+
uses: shivammathur/setup-php@v2
25+
with:
26+
php-version: ${{ matrix.php }}
27+
extensions: imap, zip
28+
tools: composer:v2
29+
coverage: none
30+
31+
- name: Cache Composer packages
32+
uses: actions/cache@v4
33+
with:
34+
path: |
35+
~/.composer/cache/files
36+
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
37+
restore-keys: |
38+
${{ runner.os }}-composer-${{ matrix.php }}-
39+
40+
- name: Install dependencies (no dev autoloader scripts)
41+
run: |
42+
set -euo pipefail
43+
composer install --no-interaction --no-progress --prefer-dist
44+
45+
- name: Lint XLIFF with Symfony
46+
run: |
47+
set -euo pipefail
48+
# Adjust the directory to match your repo layout
49+
php bin/console lint:xliff resources/translations
50+
51+
- name: Validate XLIFF XML with xmllint
52+
run: |
53+
set -euo pipefail
54+
sudo apt-get update
55+
sudo apt-get install -y --no-install-recommends libxml2-utils
56+
# Adjust root dir; prune vendor; accept spaces/newlines safely
57+
find resources/translations -type f -name '*.xlf' -not -path '*/vendor/*' -print0 \
58+
| xargs -0 -n1 xmllint --noout
59+
60+
- name: Symfony translation sanity (extract dry-run)
61+
run: |
62+
set -euo pipefail
63+
# Show what would be created/updated without writing files
64+
php bin/console translation:extract en \
65+
--format=xlf \
66+
--domain=messages \
67+
--dump-messages \
68+
--no-interaction
69+
# Note: omit --force to keep this a dry-run

.weblate

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# .weblate
2+
---
3+
projects:
4+
- slug: phplist-core
5+
name: phpList core
6+
components:
7+
- slug: messages
8+
name: Messages
9+
files:
10+
# {language} is Weblate’s placeholder (e.g., fr, de, es)
11+
- src: resources/translations/messages.en.xlf
12+
template: true
13+
# Where localized files live (mirrors Symfony layout)
14+
target: resources/translations/messages.{language}.xlf
15+
file_format: xliff
16+
language_code_style: bcp
17+
# Ensure placeholders like %name% are preserved
18+
parse_file_headers: true
19+
check_flags:
20+
- xml-invalid
21+
- placeholders
22+
- urls
23+
- accelerated

config/config.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ parameters:
1010

1111
framework:
1212
#esi: ~
13-
#translator: { fallbacks: ['%locale%'] }
13+
translator:
14+
default_path: '%kernel.project_dir%/resources/translations'
15+
fallbacks: ['%locale%']
16+
1417
secret: '%secret%'
1518
router:
1619
resource: '%kernel.project_dir%/config/routing.yml'

config/services/managers.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ services:
44
autoconfigure: true
55
public: false
66

7+
PhpList\Core\Domain\Configuration\Service\Manager\ConfigManager:
8+
autowire: true
9+
autoconfigure: true
10+
11+
PhpList\Core\Domain\Configuration\Service\Manager\EventLogManager:
12+
autowire: true
13+
autoconfigure: true
14+
715
PhpList\Core\Domain\Identity\Service\SessionManager:
816
autowire: true
917
autoconfigure: true
@@ -80,10 +88,6 @@ services:
8088
autowire: true
8189
autoconfigure: true
8290

83-
PhpList\Core\Domain\Configuration\Service\Manager\ConfigManager:
84-
autowire: true
85-
autoconfigure: true
86-
8791
PhpList\Core\Domain\Messaging\Service\Manager\BounceRuleManager:
8892
autowire: true
8993
autoconfigure: true

config/services/repositories.yml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
services:
2+
PhpList\Core\Domain\Configuration\Repository\ConfigRepository:
3+
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
4+
arguments:
5+
- PhpList\Core\Domain\Configuration\Model\Config
6+
7+
PhpList\Core\Domain\Configuration\Repository\EventLogRepository:
8+
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
9+
arguments:
10+
- PhpList\Core\Domain\Configuration\Model\EventLog
11+
212
PhpList\Core\Domain\Identity\Repository\AdministratorRepository:
313
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
414
arguments:
@@ -66,11 +76,6 @@ services:
6676
arguments:
6777
- PhpList\Core\Domain\Messaging\Model\TemplateImage
6878

69-
PhpList\Core\Domain\Configuration\Repository\ConfigRepository:
70-
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
71-
arguments:
72-
- PhpList\Core\Domain\Configuration\Model\Config
73-
7479
PhpList\Core\Domain\Messaging\Repository\UserMessageBounceRepository:
7580
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
7681
arguments:

config/services/services.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,10 @@ services:
107107
PhpList\Core\Domain\Messaging\Service\BounceActionResolver:
108108
arguments:
109109
- !tagged_iterator { tag: 'phplist.bounce_action_handler' }
110+
111+
# I18n
112+
PhpList\Core\Domain\Common\I18n\SimpleTranslator:
113+
autowire: true
114+
autoconfigure: true
115+
116+
PhpList\Core\Domain\Common\I18n\TranslatorInterface: '@PhpList\Core\Domain\Common\I18n\SimpleTranslator'
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
3+
<file source-language="en" target-language="en" datatype="plaintext" original="messages">
4+
<body>
5+
6+
<!-- Authentication -->
7+
<trans-unit id="auth.not_authorized">
8+
<source>Not authorized</source>
9+
<target>Not authorized</target>
10+
</trans-unit>
11+
12+
<trans-unit id="auth.login_failed">
13+
<source>Failed admin login attempt for '%login%'</source>
14+
<target>Failed admin login attempt for '%login%'</target>
15+
</trans-unit>
16+
17+
<trans-unit id="auth.login_disabled">
18+
<source>Login attempt for disabled admin '%login%'</source>
19+
<target>Login attempt for disabled admin '%login%'</target>
20+
</trans-unit>
21+
22+
<!-- Identity -->
23+
<trans-unit id="identity.admin_not_found">
24+
<source>Administrator not found</source>
25+
<target>Administrator not found</target>
26+
</trans-unit>
27+
28+
<!-- Subscription -->
29+
<trans-unit id="subscription.list_not_found">
30+
<source>Subscriber list not found.</source>
31+
<target>Subscriber list not found.</target>
32+
</trans-unit>
33+
<trans-unit id="subscription.subscriber_not_found">
34+
<source>Subscriber does not exists.</source>
35+
<target>Subscriber does not exists.</target>
36+
</trans-unit>
37+
<trans-unit id="subscription.not_found_for_list_and_subscriber">
38+
<source>Subscription not found for this subscriber and list.</source>
39+
<target>Subscription not found for this subscriber and list.</target>
40+
</trans-unit>
41+
42+
</body>
43+
</file>
44+
</xliff>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Common\I18n;
6+
7+
/**
8+
* Centralized message keys to be used across the application.
9+
* These keys map to translation strings in resources/translations.
10+
*/
11+
final class Messages
12+
{
13+
// Authentication / Authorization
14+
public const AUTH_NOT_AUTHORIZED = 'auth.not_authorized';
15+
public const AUTH_LOGIN_FAILED = 'auth.login_failed';
16+
public const AUTH_LOGIN_DISABLED = 'auth.login_disabled';
17+
18+
// Identity
19+
public const IDENTITY_ADMIN_NOT_FOUND = 'identity.admin_not_found';
20+
21+
// Subscription
22+
public const SUBSCRIPTION_LIST_NOT_FOUND = 'subscription.list_not_found';
23+
public const SUBSCRIPTION_SUBSCRIBER_NOT_FOUND = 'subscription.subscriber_not_found';
24+
public const SUBSCRIPTION_NOT_FOUND_FOR_LIST_AND_SUBSCRIBER = 'subscription.not_found_for_list_and_subscriber';
25+
26+
private function __construct()
27+
{
28+
}
29+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Model\Filter;
6+
7+
use DateTimeInterface;
8+
use PhpList\Core\Domain\Common\Model\Filter\FilterRequestInterface;
9+
10+
class EventLogFilter implements FilterRequestInterface
11+
{
12+
public function __construct(
13+
private readonly ?string $page = null,
14+
private readonly ?DateTimeInterface $dateFrom = null,
15+
private readonly ?DateTimeInterface $dateTo = null,
16+
) {
17+
}
18+
19+
public function getPage(): ?string
20+
{
21+
return $this->page;
22+
}
23+
24+
public function getDateFrom(): ?DateTimeInterface
25+
{
26+
return $this->dateFrom;
27+
}
28+
29+
public function getDateTo(): ?DateTimeInterface
30+
{
31+
return $this->dateTo;
32+
}
33+
}

src/Domain/Configuration/Model/I18n.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
use PhpList\Core\Domain\Common\Model\Interfaces\DomainModel;
99
use PhpList\Core\Domain\Configuration\Repository\I18nRepository;
1010

11+
/**
12+
* @deprecated
13+
*
14+
* Symfony\Contracts\Translation will be used instead.
15+
*/
1116
#[ORM\Entity(repositoryClass: I18nRepository::class)]
1217
#[ORM\Table(name: 'phplist_i18n')]
1318
#[ORM\UniqueConstraint(name: 'lanorigunq', columns: ['lan', 'original'])]

0 commit comments

Comments
 (0)