From 003ea36ec2c065a07f06fcdee6ebe69176bf55e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Sat, 12 Aug 2023 15:35:46 +0200 Subject: [PATCH 1/6] Redirect a talk page when the talk has a different locale set Follow-up to #194 #192 --- site/app/Talks/Talk.php | 7 +++++++ site/app/Talks/TalkFactory.php | 1 + site/app/Talks/Talks.php | 8 ++++++++ site/app/Www/Presenters/TalksPresenter.php | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/site/app/Talks/Talk.php b/site/app/Talks/Talk.php index fbc307f4b..39b1de1a1 100644 --- a/site/app/Talks/Talk.php +++ b/site/app/Talks/Talk.php @@ -13,6 +13,7 @@ class Talk public function __construct( private readonly int $id, private readonly int $localeId, + private readonly string $locale, private readonly ?string $action, private readonly Html $title, private readonly string $titleTexy, @@ -55,6 +56,12 @@ public function getLocaleId(): int } + public function getLocale(): string + { + return $this->locale; + } + + public function getAction(): ?string { return $this->action; diff --git a/site/app/Talks/TalkFactory.php b/site/app/Talks/TalkFactory.php index f204c74a4..7058a7769 100644 --- a/site/app/Talks/TalkFactory.php +++ b/site/app/Talks/TalkFactory.php @@ -26,6 +26,7 @@ public function createFromDatabaseRow(Row $row): Talk return new Talk( $row->id, $row->localeId, + $row->locale, $row->action, $this->texyFormatter->format($row->title), $row->title, diff --git a/site/app/Talks/Talks.php b/site/app/Talks/Talks.php index 43283f621..82f263e75 100644 --- a/site/app/Talks/Talks.php +++ b/site/app/Talks/Talks.php @@ -32,6 +32,7 @@ public function getAll(?int $limit = null): array $query = 'SELECT t.id_talk AS id, t.key_locale AS localeId, + l.locale, t.action, t.title, t.description, @@ -57,6 +58,7 @@ public function getAll(?int $limit = null): array ts.title AS supersededByTitle, t.publish_slides AS publishSlides FROM talks t + LEFT JOIN locales l ON l.id_locale = t.key_locale LEFT JOIN talks ts ON t.key_superseded_by = ts.id_talk WHERE t.date <= NOW() ORDER BY t.date DESC @@ -91,6 +93,7 @@ public function getUpcoming(): array $query = 'SELECT t.id_talk AS id, t.key_locale AS localeId, + l.locale, t.action, t.title, t.description, @@ -116,6 +119,7 @@ public function getUpcoming(): array ts.title AS supersededByTitle, t.publish_slides AS publishSlides FROM talks t + LEFT JOIN locales l ON l.id_locale = t.key_locale LEFT JOIN talks ts ON t.key_superseded_by = ts.id_talk WHERE t.date > NOW() ORDER BY t.date'; @@ -138,6 +142,7 @@ public function get(string $name): Talk 'SELECT t.id_talk AS id, t.key_locale AS localeId, + l.locale, t.action, t.title, t.description, @@ -163,6 +168,7 @@ public function get(string $name): Talk ts.title AS supersededByTitle, t.publish_slides AS publishSlides FROM talks t + LEFT JOIN locales l ON l.id_locale = t.key_locale LEFT JOIN talks ts ON t.key_superseded_by = ts.id_talk WHERE t.action = ?', $name, @@ -185,6 +191,7 @@ public function getById(int $id): Talk 'SELECT t.id_talk AS id, t.key_locale AS localeId, + l.locale, t.action, t.title, t.description, @@ -210,6 +217,7 @@ public function getById(int $id): Talk ts.title AS supersededByTitle, t.publish_slides AS publishSlides FROM talks t + LEFT JOIN locales l ON l.id_locale = t.key_locale LEFT JOIN talks ts ON t.key_superseded_by = ts.id_talk WHERE t.id_talk = ?', $id, diff --git a/site/app/Www/Presenters/TalksPresenter.php b/site/app/Www/Presenters/TalksPresenter.php index 99085d469..53153d521 100644 --- a/site/app/Www/Presenters/TalksPresenter.php +++ b/site/app/Www/Presenters/TalksPresenter.php @@ -3,6 +3,7 @@ namespace MichalSpacekCz\Www\Presenters; +use MichalSpacekCz\Application\LocaleLinkGeneratorInterface; use MichalSpacekCz\Media\Exceptions\ContentTypeException; use MichalSpacekCz\Media\SlidesPlatform; use MichalSpacekCz\Talks\Exceptions\TalkDoesNotExistException; @@ -14,6 +15,7 @@ use MichalSpacekCz\Training\Dates\UpcomingTrainingDates; use Nette\Application\BadRequestException; use Nette\Application\UI\InvalidLinkException; +use Nette\Http\IResponse; class TalksPresenter extends BasePresenter { @@ -23,6 +25,7 @@ public function __construct( private readonly TalkSlides $talkSlides, private readonly UpcomingTrainingDates $upcomingTrainingDates, private readonly TalksListFactory $talksListFactory, + private readonly LocaleLinkGeneratorInterface $localeLinkGenerator, ) { parent::__construct(); } @@ -55,6 +58,9 @@ public function actionTalk(string $name, ?string $slide = null): void { try { $talk = $this->talks->get($name); + if ($talk->getLocale() !== $this->translator->getDefaultLocale()) { + $this->redirectUrl($this->localeLinkGenerator->links(...$this->getLocaleLinksGeneratorParams())[$talk->getLocale()], IResponse::S301_MovedPermanently); + } if ($talk->getSlidesTalkId()) { $slidesTalk = $this->talks->getById($talk->getSlidesTalkId()); $slides = ($slidesTalk->isPublishSlides() ? $this->talkSlides->getSlides($slidesTalk->getId(), $slidesTalk->getFilenamesTalkId()) : []); From 49a312bcfb115bcd0d5de127f0dc8dd2e866e709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Sun, 13 Aug 2023 03:17:40 +0200 Subject: [PATCH 2/6] Remove language codes and names from translations These are not really translated as such and were there just so they're easily accessible in templates. --- site/app/Application/LocaleLink.php | 52 +++++++++++++++++++ site/app/Application/LocaleLinkGenerator.php | 15 ++++-- .../LocaleLinkGeneratorInterface.php | 2 +- site/app/Articles/Blog/BlogPosts.php | 2 +- site/app/Www/Presenters/BasePresenter.php | 7 +-- site/app/Www/Presenters/ErrorPresenter.php | 11 ++-- site/app/Www/Presenters/TalksPresenter.php | 2 +- .../Www/Presenters/templates/@layout.latte | 6 +-- site/app/lang/html.cs_CZ.neon | 3 -- site/app/lang/html.en_US.neon | 3 -- site/app/lang/messages.cs_CZ.neon | 3 -- site/app/lang/messages.en_US.neon | 3 -- site/config/common.neon | 2 +- site/config/parameters.neon | 8 +++ site/config/services.neon | 2 +- .../Application/LocaleLinkGeneratorTest.phpt | 13 ++++- 16 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 site/app/Application/LocaleLink.php diff --git a/site/app/Application/LocaleLink.php b/site/app/Application/LocaleLink.php new file mode 100644 index 000000000..c6d199fd5 --- /dev/null +++ b/site/app/Application/LocaleLink.php @@ -0,0 +1,52 @@ +locale; + } + + + public function getLanguageCode(): string + { + return $this->languageCode; + } + + + public function getLanguageName(): string + { + return $this->languageName; + } + + + public function getUrl(): string + { + return $this->url; + } + + + public function withUrl(string $url): self + { + return new self( + $this->getLocale(), + $this->getLanguageCode(), + $this->getLanguageName(), + $url, + ); + } + +} diff --git a/site/app/Application/LocaleLinkGenerator.php b/site/app/Application/LocaleLinkGenerator.php index 002a88b30..f47685db7 100644 --- a/site/app/Application/LocaleLinkGenerator.php +++ b/site/app/Application/LocaleLinkGenerator.php @@ -20,12 +20,16 @@ class LocaleLinkGenerator implements LocaleLinkGeneratorInterface private const DEFAULT_PARAMS = '*'; + /** + * @param array $languages + */ public function __construct( private readonly RouterFactory $routerFactory, private readonly IRequest $httpRequest, private readonly IPresenterFactory $presenterFactory, private readonly LinkGenerator $linkGenerator, private readonly Translator $translator, + private readonly array $languages, ) { } @@ -35,7 +39,7 @@ public function __construct( * * @param string $destination destination in format "[[[module:]presenter:]action] [#fragment]" * @param array> $params of locale => [name => value] - * @return array of locale => URL + * @return array of locale => URL * @throws InvalidLinkException */ public function links(string $destination, array $params = []): array @@ -48,7 +52,12 @@ public function links(string $destination, array $params = []): array } if (count($router->getRouters())) { $linkGenerator = new LinkGenerator($router, $this->httpRequest->getUrl(), $this->presenterFactory); - $links[$locale] = $linkGenerator->link($destination, $this->getParams($params, $locale)); + $links[$locale] = new LocaleLink( + $locale, + $this->languages[$locale]['code'], + $this->languages[$locale]['name'], + $linkGenerator->link($destination, $this->getParams($params, $locale)), + ); } } } @@ -97,7 +106,7 @@ public function allLinks(string $destination, array $params = []): array } return array_merge( [$locale => $this->linkGenerator->link($destination, $this->getParams($params, $locale))], - $links, + array_map(fn(LocaleLink $localeLink): string => $localeLink->getUrl(), $links), ); } diff --git a/site/app/Application/LocaleLinkGeneratorInterface.php b/site/app/Application/LocaleLinkGeneratorInterface.php index ca300ef71..440b5aef4 100644 --- a/site/app/Application/LocaleLinkGeneratorInterface.php +++ b/site/app/Application/LocaleLinkGeneratorInterface.php @@ -11,7 +11,7 @@ interface LocaleLinkGeneratorInterface /** * @param string $destination destination in format "[[[module:]presenter:]action] [#fragment]" * @param array> $params of locale => [name => value] - * @return array of locale => URL + * @return array of locale => URL * @throws InvalidLinkException */ public function links(string $destination, array $params = []): array; diff --git a/site/app/Articles/Blog/BlogPosts.php b/site/app/Articles/Blog/BlogPosts.php index 3b639b0c1..7580ae675 100644 --- a/site/app/Articles/Blog/BlogPosts.php +++ b/site/app/Articles/Blog/BlogPosts.php @@ -186,7 +186,7 @@ public function enrich(BlogPost $post): void $post->href = $this->linkGenerator->link('Www:Post:', $params); } else { $links = $this->localeLinkGenerator->links('Www:Post:', $this->localeLinkGenerator->defaultParams($params)); - $post->href = $links[$post->locale]; + $post->href = $links[$post->locale]->getUrl(); } } diff --git a/site/app/Www/Presenters/BasePresenter.php b/site/app/Www/Presenters/BasePresenter.php index 8779693ee..5b4822c1d 100644 --- a/site/app/Www/Presenters/BasePresenter.php +++ b/site/app/Www/Presenters/BasePresenter.php @@ -4,6 +4,7 @@ namespace MichalSpacekCz\Www\Presenters; use Contributte\Translation\Translator; +use MichalSpacekCz\Application\LocaleLink; use MichalSpacekCz\Application\LocaleLinkGeneratorInterface; use MichalSpacekCz\Application\Theme; use MichalSpacekCz\User\Manager; @@ -102,11 +103,11 @@ protected function getLocaleLinksGeneratorParams(): array /** * The default locale links. * - * @return string[]|null + * @return array */ - protected function getLocaleLinkDefault(): ?array + protected function getLocaleLinkDefault(): array { - return null; + return []; } diff --git a/site/app/Www/Presenters/ErrorPresenter.php b/site/app/Www/Presenters/ErrorPresenter.php index 19940577e..e75a2a963 100644 --- a/site/app/Www/Presenters/ErrorPresenter.php +++ b/site/app/Www/Presenters/ErrorPresenter.php @@ -5,6 +5,7 @@ use MichalSpacekCz\Application\AppRequest; use MichalSpacekCz\Application\Exceptions\NoOriginalRequestException; +use MichalSpacekCz\Application\LocaleLink; use MichalSpacekCz\Application\LocaleLinkGeneratorInterface; use MichalSpacekCz\EasterEgg\FourOhFourButFound; use Nette\Application\BadRequestException; @@ -60,14 +61,14 @@ public function actionDefault(BadRequestException $exception): void /** * The default locale links. * - * @return string[]|null + * @return array of locale => URL */ - protected function getLocaleLinkDefault(): ?array + protected function getLocaleLinkDefault(): array { + $links = []; // Change the request host to the localized "homepage" host - $links = $this->localeLinkGenerator->links('Www:Homepage:'); - foreach ($links as &$link) { - $link = $this->getHttpRequest()->getUrl()->withHost((new Url($link))->getHost())->getAbsoluteUrl(); + foreach ($this->localeLinkGenerator->links('Www:Homepage:') as $locale => $link) { + $links[$locale] = $link->withUrl($this->getHttpRequest()->getUrl()->withHost((new Url($link->getUrl()))->getHost())->getAbsoluteUrl()); } return $links; } diff --git a/site/app/Www/Presenters/TalksPresenter.php b/site/app/Www/Presenters/TalksPresenter.php index 53153d521..8a579d86c 100644 --- a/site/app/Www/Presenters/TalksPresenter.php +++ b/site/app/Www/Presenters/TalksPresenter.php @@ -59,7 +59,7 @@ public function actionTalk(string $name, ?string $slide = null): void try { $talk = $this->talks->get($name); if ($talk->getLocale() !== $this->translator->getDefaultLocale()) { - $this->redirectUrl($this->localeLinkGenerator->links(...$this->getLocaleLinksGeneratorParams())[$talk->getLocale()], IResponse::S301_MovedPermanently); + $this->redirectUrl($this->localeLinkGenerator->links(...$this->getLocaleLinksGeneratorParams())[$talk->getLocale()]->getUrl(), IResponse::S301_MovedPermanently); } if ($talk->getSlidesTalkId()) { $slidesTalk = $this->talks->getById($talk->getSlidesTalkId()); diff --git a/site/app/Www/Presenters/templates/@layout.latte b/site/app/Www/Presenters/templates/@layout.latte index ad8806608..5200ce572 100644 --- a/site/app/Www/Presenters/templates/@layout.latte +++ b/site/app/Www/Presenters/templates/@layout.latte @@ -50,9 +50,7 @@ - {ifset $localeLinks} - - {/ifset} + {include #feeds} @@ -100,7 +98,7 @@ {icon moon} {icon sun} {if !isset($headerLinks) || $headerLinks !== false} - {icon flag} {_"messages.langs.$language"} + {icon flag} {$localeLink->getLanguageName()} {icon wifi} {_messages.label.upckeys} {icon key} {_messages.label.pulse.passwordstorages} {icon dots-horizontal} {_messages.label.otherprojects} diff --git a/site/app/lang/html.cs_CZ.neon b/site/app/lang/html.cs_CZ.neon index 691bb4f33..d1cb562b2 100644 --- a/site/app/lang/html.cs_CZ.neon +++ b/site/app/lang/html.cs_CZ.neon @@ -27,6 +27,3 @@ id: transcript: prepis attribute: lang: cs -langs: - cs_CZ: cs - en_US: en diff --git a/site/app/lang/html.en_US.neon b/site/app/lang/html.en_US.neon index 1880eaf1f..7272ab013 100644 --- a/site/app/lang/html.en_US.neon +++ b/site/app/lang/html.en_US.neon @@ -27,6 +27,3 @@ id: transcript: transcript attribute: lang: en -langs: - cs_CZ: cs - en_US: en diff --git a/site/app/lang/messages.cs_CZ.neon b/site/app/lang/messages.cs_CZ.neon index 45a07a2f6..a1a396210 100644 --- a/site/app/lang/messages.cs_CZ.neon +++ b/site/app/lang/messages.cs_CZ.neon @@ -1,6 +1,3 @@ -langs: - cs_CZ: Česky - en_US: English title: who: "Kdo?" contact: Kontakt diff --git a/site/app/lang/messages.en_US.neon b/site/app/lang/messages.en_US.neon index ed7a8d292..b1fe3b7ef 100644 --- a/site/app/lang/messages.en_US.neon +++ b/site/app/lang/messages.en_US.neon @@ -1,6 +1,3 @@ -langs: - cs_CZ: Česky - en_US: English title: who: "Who?" contact: Contact diff --git a/site/config/common.neon b/site/config/common.neon index 80ab3e454..7811e12cd 100644 --- a/site/config/common.neon +++ b/site/config/common.neon @@ -62,7 +62,7 @@ database: translation: locales: default: cs_CZ - whitelist: [cs_CZ, en_US] + whitelist: %locales.all% localeResolvers!: [] dirs: - %siteDir%/app/lang diff --git a/site/config/parameters.neon b/site/config/parameters.neon index 6d97a300a..0a311820f 100644 --- a/site/config/parameters.neon +++ b/site/config/parameters.neon @@ -1,5 +1,13 @@ parameters: locales: + all: [cs_CZ, en_US] + languages: + cs_CZ: + code: cs + name: Česky + en_US: + code: en + name: English supported: # The value is a FQDN if it ends with a dot, otherwise the rootDomainMapping.$value domain is appended to the host name admin: diff --git a/site/config/services.neon b/site/config/services.neon index 9ef49e79f..378eee75e 100644 --- a/site/config/services.neon +++ b/site/config/services.neon @@ -1,7 +1,7 @@ services: - MichalSpacekCz\Application\AppRequest - MichalSpacekCz\Application\Error - localeLinkGenerator: MichalSpacekCz\Application\LocaleLinkGenerator + localeLinkGenerator: MichalSpacekCz\Application\LocaleLinkGenerator(languages: %locales.languages%) - MichalSpacekCz\Application\Locales - MichalSpacekCz\Application\RouterFactory(supportedLocales: %locales.supported%, rootDomainMapping: %locales.rootDomainMapping%, translatedRoutes: %translatedRoutes.presenters%) - @MichalSpacekCz\Application\RouterFactory::createRouter diff --git a/site/tests/Application/LocaleLinkGeneratorTest.phpt b/site/tests/Application/LocaleLinkGeneratorTest.phpt index 31a4c22d5..a6611c2ba 100644 --- a/site/tests/Application/LocaleLinkGeneratorTest.phpt +++ b/site/tests/Application/LocaleLinkGeneratorTest.phpt @@ -33,7 +33,16 @@ class LocaleLinkGeneratorTest extends TestCase protected function setUp(): void { - $this->localeLinkGenerator = new LocaleLinkGenerator($this->routerFactory, $this->httpRequest, $this->presenterFactory, $this->linkGenerator, $this->translator); + $this->localeLinkGenerator = new LocaleLinkGenerator($this->routerFactory, $this->httpRequest, $this->presenterFactory, $this->linkGenerator, $this->translator, [ + 'cs_CZ' => [ + 'code' => 'cs', + 'name' => 'Česky', + ], + 'en_US' => [ + 'code' => 'en', + 'name' => 'English', + ], + ]); } @@ -45,7 +54,7 @@ class LocaleLinkGeneratorTest extends TestCase ]; $links = $this->localeLinkGenerator->links('Www:Talks:talk', $params); Assert::same('cs_CZ', $this->translator->getDefaultLocale()); - Assert::same(['en_US' => 'https://www.burger.test/talks/foo'], $links); + Assert::equal(['en_US' => new LocaleLink('en_US', 'en', 'English', 'https://www.burger.test/talks/foo')], $links); } From a0de49bf2ea8e86c941221587c1b85e93e3c65ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Sun, 13 Aug 2023 16:34:30 +0200 Subject: [PATCH 3/6] Show a language & flag icon when a talk's locale is other than default --- site/app/Admin/Presenters/TalksPresenter.php | 1 + .../Admin/Presenters/templates/Talks/default.latte | 12 +++++++----- site/app/Talks/TalksList.php | 8 ++++++++ site/app/Talks/talksList.latte | 7 ++++++- site/app/lang/messages.cs_CZ.neon | 3 +++ site/app/lang/messages.en_US.neon | 3 +++ 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/site/app/Admin/Presenters/TalksPresenter.php b/site/app/Admin/Presenters/TalksPresenter.php index 45d7c3d50..ea8e76848 100644 --- a/site/app/Admin/Presenters/TalksPresenter.php +++ b/site/app/Admin/Presenters/TalksPresenter.php @@ -44,6 +44,7 @@ public function __construct( public function renderDefault(): void { $this->template->pageTitle = $this->translator->translate('messages.title.talks'); + $this->template->defaultLocale = $this->translator->getDefaultLocale(); $this->template->upcomingTalks = $this->talks->getUpcoming(); $this->template->talks = $this->talks->getAll(); } diff --git a/site/app/Admin/Presenters/templates/Talks/default.latte b/site/app/Admin/Presenters/templates/Talks/default.latte index 56255d32a..8d556eff1 100644 --- a/site/app/Admin/Presenters/templates/Talks/default.latte +++ b/site/app/Admin/Presenters/templates/Talks/default.latte @@ -1,10 +1,12 @@ -{define #itemTalk, MichalSpacekCz\Talks\Talk $item, bool $upcoming} -
  • {$item->getTitle()} +{define #itemTalk, MichalSpacekCz\Talks\Talk $item, bool $upcoming, string $defaultLocale} +
  • + {$item->getTitle()} + {icon flag} {_"messages.locales.{$item->getLocale()}"} {$item->getDate()|localeDay}, {$item->getEvent()} {icon images} {icon camera-video} (upravit slajdy) -
  • + {/define} {define #content} @@ -19,11 +21,11 @@
      {foreach $upcomingTalks as $item} {var $upcoming = true} - {include #itemTalk, item: $item, upcoming: $upcoming} + {include #itemTalk, item: $item, upcoming: $upcoming, defaultLocale: $defaultLocale} {/foreach} {foreach $talks as $item} {var $upcoming = false} - {include #itemTalk, item: $item, upcoming: $upcoming} + {include #itemTalk, item: $item, upcoming: $upcoming, defaultLocale: $defaultLocale} {/foreach}
    {/define} diff --git a/site/app/Talks/TalksList.php b/site/app/Talks/TalksList.php index 5f3d3f78a..68bf0cf92 100644 --- a/site/app/Talks/TalksList.php +++ b/site/app/Talks/TalksList.php @@ -3,16 +3,24 @@ namespace MichalSpacekCz\Talks; +use Contributte\Translation\Translator; use MichalSpacekCz\Application\UiControl; class TalksList extends UiControl { + public function __construct( + private readonly Translator $translator, + ) { + } + + /** * @param list $talks */ public function render(array $talks): void { + $this->template->defaultLocale = $this->translator->getDefaultLocale(); $this->template->talks = $talks; $this->template->render(__DIR__ . '/talksList.latte'); } diff --git a/site/app/Talks/talksList.latte b/site/app/Talks/talksList.latte index 2381e16ec..8e1348247 100644 --- a/site/app/Talks/talksList.latte +++ b/site/app/Talks/talksList.latte @@ -1,6 +1,11 @@ {varType MichalSpacekCz\Talks\Talk[] $talks} +{varType string $defaultLocale}

    - {$talk->getTitle()}
    + {$talk->getTitle()} + {if $talk->getLocale() !== $defaultLocale} + {icon flag} {_"messages.locales.{$talk->getLocale()}"} + {/if} +
    {$talk->getDate()|localeDay}, {$talk->getEvent()}{if $talk->getDuration()} ({_messages.talks.durationshort|format:$talk->getDuration()}){/if} {icon images} {icon camera-video} diff --git a/site/app/lang/messages.cs_CZ.neon b/site/app/lang/messages.cs_CZ.neon index a1a396210..8f44abe2e 100644 --- a/site/app/lang/messages.cs_CZ.neon +++ b/site/app/lang/messages.cs_CZ.neon @@ -1,3 +1,6 @@ +locales: + cs_CZ: česky + en_US: anglicky title: who: "Kdo?" contact: Kontakt diff --git a/site/app/lang/messages.en_US.neon b/site/app/lang/messages.en_US.neon index b1fe3b7ef..897497ec1 100644 --- a/site/app/lang/messages.en_US.neon +++ b/site/app/lang/messages.en_US.neon @@ -1,3 +1,6 @@ +locales: + cs_CZ: Czech + en_US: English title: who: "Who?" contact: Contact From 47041a6c05a78778d2261daae9a197975ec494ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Sun, 13 Aug 2023 22:48:15 +0200 Subject: [PATCH 4/6] English talks in the list get a correct link to .com site --- site/app/Talks/Talk.php | 7 +++++++ site/app/Talks/TalkFactory.php | 11 +++++++++++ site/app/Talks/talksList.latte | 4 +++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/site/app/Talks/Talk.php b/site/app/Talks/Talk.php index 39b1de1a1..085d7dda7 100644 --- a/site/app/Talks/Talk.php +++ b/site/app/Talks/Talk.php @@ -15,6 +15,7 @@ public function __construct( private readonly int $localeId, private readonly string $locale, private readonly ?string $action, + private readonly ?string $url, private readonly Html $title, private readonly string $titleTexy, private readonly ?Html $description, @@ -68,6 +69,12 @@ public function getAction(): ?string } + public function getUrl(): ?string + { + return $this->url; + } + + public function getTitle(): Html { return $this->title; diff --git a/site/app/Talks/TalkFactory.php b/site/app/Talks/TalkFactory.php index 7058a7769..2a0c1b373 100644 --- a/site/app/Talks/TalkFactory.php +++ b/site/app/Talks/TalkFactory.php @@ -3,9 +3,12 @@ namespace MichalSpacekCz\Talks; +use Contributte\Translation\Translator; +use MichalSpacekCz\Application\LocaleLinkGeneratorInterface; use MichalSpacekCz\Formatter\TexyFormatter; use MichalSpacekCz\Media\Exceptions\ContentTypeException; use MichalSpacekCz\Media\VideoFactory; +use Nette\Application\UI\InvalidLinkException; use Nette\Database\Row; class TalkFactory @@ -14,20 +17,28 @@ class TalkFactory public function __construct( private readonly TexyFormatter $texyFormatter, private readonly VideoFactory $videoFactory, + private readonly Translator $translator, + private readonly LocaleLinkGeneratorInterface $localeLinkGenerator, ) { } /** * @throws ContentTypeException + * @throws InvalidLinkException */ public function createFromDatabaseRow(Row $row): Talk { + if ($this->translator->getDefaultLocale() !== $row->locale && $row->action) { + $links = $this->localeLinkGenerator->links('Www:Talks:talk', $this->localeLinkGenerator->defaultParams(['name' => $row->action])); + $url = isset($links[$row->locale]) ? $links[$row->locale]->getUrl() : null; + } return new Talk( $row->id, $row->localeId, $row->locale, $row->action, + $url ?? null, $this->texyFormatter->format($row->title), $row->title, $row->description ? $this->texyFormatter->formatBlock($row->description) : null, diff --git a/site/app/Talks/talksList.latte b/site/app/Talks/talksList.latte index 8e1348247..677b55b39 100644 --- a/site/app/Talks/talksList.latte +++ b/site/app/Talks/talksList.latte @@ -1,9 +1,11 @@ {varType MichalSpacekCz\Talks\Talk[] $talks} {varType string $defaultLocale}

    - {$talk->getTitle()} {if $talk->getLocale() !== $defaultLocale} + {$talk->getTitle()} {icon flag} {_"messages.locales.{$talk->getLocale()}"} + {else} + {$talk->getTitle()} {/if}
    {$talk->getDate()|localeDay}, {$talk->getEvent()}{if $talk->getDuration()} ({_messages.talks.durationshort|format:$talk->getDuration()}){/if} From 5e8fea40b58e4446866d5e1f7e23f0d1154b6dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Mon, 14 Aug 2023 02:24:52 +0200 Subject: [PATCH 5/6] Can add a translation group id to a talk When a talk belongs to a translation group then it's fairly easy to find the same talk that has been done in a different language. One talk with two different locales, two different rows, can belong to one group. This is a principle similar to what's used for blog posts. Database tables DDL queries to add the column: ``` ALTER TABLE `talks` ADD `key_translation_group` int unsigned NULL COMMENT 'No foreign key, yet' AFTER `key_locale`; ALTER TABLE `talks` ADD UNIQUE `key_locale_key_translation_group` (`key_locale`, `key_translation_group`); ``` --- site/app/Form/TalkFormFactory.php | 5 +++++ site/app/Talks/Talk.php | 7 +++++++ site/app/Talks/TalkFactory.php | 1 + site/app/Talks/Talks.php | 10 ++++++++++ site/app/Talks/talkInputs.latte | 3 +++ 5 files changed, 26 insertions(+) diff --git a/site/app/Form/TalkFormFactory.php b/site/app/Form/TalkFormFactory.php index b94c87b04..59af4f8e9 100644 --- a/site/app/Form/TalkFormFactory.php +++ b/site/app/Form/TalkFormFactory.php @@ -38,6 +38,8 @@ public function create(callable $onSuccess, ?Talk $talk = null): Form $form = $this->factory->create(); $allTalks = $this->getAllTalksExcept($talk ? (string)$talk->getAction() : null); + $form->addInteger('translationGroup', 'Skupina překladů:') + ->setRequired(false); $form->addSelect('locale', 'Jazyk:', $this->locales->getAllLocales()) ->setRequired('Zadejte prosím jazyk') ->setPrompt('- vyberte -'); @@ -112,6 +114,7 @@ public function create(callable $onSuccess, ?Talk $talk = null): Form $this->talks->update( $talk->getId(), $values->locale, + $values->translationGroup, $values->action, $values->title, $values->description, @@ -145,6 +148,7 @@ public function create(callable $onSuccess, ?Talk $talk = null): Form } else { $talkId = $this->talks->add( $values->locale, + $values->translationGroup, $values->action, $values->title, $values->description, @@ -185,6 +189,7 @@ public function setTalk(Form $form, Talk $talk, SubmitButton $submit): void $values = [ 'action' => $talk->getAction(), 'locale' => $talk->getLocaleId(), + 'translationGroup' => $talk->getTranslationGroupId(), 'title' => $talk->getTitleTexy(), 'description' => $talk->getDescriptionTexy(), 'date' => $talk->getDate()->format('Y-m-d H:i'), diff --git a/site/app/Talks/Talk.php b/site/app/Talks/Talk.php index 085d7dda7..362eb7418 100644 --- a/site/app/Talks/Talk.php +++ b/site/app/Talks/Talk.php @@ -14,6 +14,7 @@ public function __construct( private readonly int $id, private readonly int $localeId, private readonly string $locale, + private readonly ?int $translationGroupId, private readonly ?string $action, private readonly ?string $url, private readonly Html $title, @@ -63,6 +64,12 @@ public function getLocale(): string } + public function getTranslationGroupId(): ?int + { + return $this->translationGroupId; + } + + public function getAction(): ?string { return $this->action; diff --git a/site/app/Talks/TalkFactory.php b/site/app/Talks/TalkFactory.php index 2a0c1b373..fc0a13bd3 100644 --- a/site/app/Talks/TalkFactory.php +++ b/site/app/Talks/TalkFactory.php @@ -37,6 +37,7 @@ public function createFromDatabaseRow(Row $row): Talk $row->id, $row->localeId, $row->locale, + $row->translationGroupId, $row->action, $url ?? null, $this->texyFormatter->format($row->title), diff --git a/site/app/Talks/Talks.php b/site/app/Talks/Talks.php index 82f263e75..597ed9bc3 100644 --- a/site/app/Talks/Talks.php +++ b/site/app/Talks/Talks.php @@ -33,6 +33,7 @@ public function getAll(?int $limit = null): array t.id_talk AS id, t.key_locale AS localeId, l.locale, + t.key_translation_group AS translationGroupId, t.action, t.title, t.description, @@ -94,6 +95,7 @@ public function getUpcoming(): array t.id_talk AS id, t.key_locale AS localeId, l.locale, + t.key_translation_group AS translationGroupId, t.action, t.title, t.description, @@ -143,6 +145,7 @@ public function get(string $name): Talk t.id_talk AS id, t.key_locale AS localeId, l.locale, + t.key_translation_group AS translationGroupId, t.action, t.title, t.description, @@ -192,6 +195,7 @@ public function getById(int $id): Talk t.id_talk AS id, t.key_locale AS localeId, l.locale, + t.key_translation_group AS translationGroupId, t.action, t.title, t.description, @@ -262,6 +266,7 @@ public function getFavorites(): array public function update( int $id, int $localeId, + ?int $translationGroupId, ?string $action, string $title, ?string $description, @@ -286,6 +291,7 @@ public function update( ): void { $params = $this->getAddUpdateParams( $localeId, + $translationGroupId, $action, $title, $description, @@ -319,6 +325,7 @@ public function update( */ public function add( int $localeId, + ?int $translationGroupId, ?string $action, string $title, ?string $description, @@ -343,6 +350,7 @@ public function add( ): int { $params = $this->getAddUpdateParams( $localeId, + $translationGroupId, $action, $title, $description, @@ -389,6 +397,7 @@ public function pageTitle(string $translationKey, Talk $talk): Html */ private function getAddUpdateParams( int $localeId, + ?int $translationGroupId, ?string $action, string $title, ?string $description, @@ -418,6 +427,7 @@ private function getAddUpdateParams( } return [ 'key_locale' => $localeId, + 'key_translation_group' => empty($translationGroupId) ? null : $translationGroupId, 'action' => (empty($action) ? null : $action), 'title' => $title, 'description' => (empty($description) ? null : $description), diff --git a/site/app/Talks/talkInputs.latte b/site/app/Talks/talkInputs.latte index 757ed0086..0f4cf7f38 100644 --- a/site/app/Talks/talkInputs.latte +++ b/site/app/Talks/talkInputs.latte @@ -3,6 +3,9 @@ {varType int $videoThumbnailHeight} {form talk class => "aligned wide"} + + + From a12a6cb03e81e3a8849275838f98508506cb0a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Mon, 14 Aug 2023 04:22:46 +0200 Subject: [PATCH 6/6] Display a direct link to the talk in the other locale, if available And a generic "list all talks" link if not. --- site/app/Talks/TalkLocaleUrls.php | 31 ++++++++ site/app/Www/Presenters/TalksPresenter.php | 24 ++++++ site/config/services.neon | 1 + site/tests/Talks/TalkLocaleUrlsTest.phpt | 85 ++++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 site/app/Talks/TalkLocaleUrls.php create mode 100644 site/tests/Talks/TalkLocaleUrlsTest.phpt diff --git a/site/app/Talks/TalkLocaleUrls.php b/site/app/Talks/TalkLocaleUrls.php new file mode 100644 index 000000000..57889d54f --- /dev/null +++ b/site/app/Talks/TalkLocaleUrls.php @@ -0,0 +1,31 @@ + locale => action + */ + public function get(Talk $talk): array + { + if (!$talk->getTranslationGroupId()) { + return []; + } + return $this->database->fetchPairs( + 'SELECT l.locale, t.action FROM talks t JOIN locales l ON t.key_locale = l.id_locale WHERE t.key_translation_group = ?', + $talk->getTranslationGroupId(), + ); + } + +} diff --git a/site/app/Www/Presenters/TalksPresenter.php b/site/app/Www/Presenters/TalksPresenter.php index 8a579d86c..84578df35 100644 --- a/site/app/Www/Presenters/TalksPresenter.php +++ b/site/app/Www/Presenters/TalksPresenter.php @@ -8,6 +8,7 @@ use MichalSpacekCz\Media\SlidesPlatform; use MichalSpacekCz\Talks\Exceptions\TalkDoesNotExistException; use MichalSpacekCz\Talks\Exceptions\UnknownSlideException; +use MichalSpacekCz\Talks\TalkLocaleUrls; use MichalSpacekCz\Talks\Talks; use MichalSpacekCz\Talks\TalkSlides; use MichalSpacekCz\Talks\TalksList; @@ -20,9 +21,14 @@ class TalksPresenter extends BasePresenter { + /** @var array */ + private array $localeLinkParams = []; + + public function __construct( private readonly Talks $talks, private readonly TalkSlides $talkSlides, + private readonly TalkLocaleUrls $talkLocaleUrls, private readonly UpcomingTrainingDates $upcomingTrainingDates, private readonly TalksListFactory $talksListFactory, private readonly LocaleLinkGeneratorInterface $localeLinkGenerator, @@ -76,6 +82,9 @@ public function actionTalk(string $name, ?string $slide = null): void } catch (UnknownSlideException | TalkDoesNotExistException $e) { throw new BadRequestException($e->getMessage(), previous: $e); } + foreach ($this->talkLocaleUrls->get($talk) as $locale => $action) { + $this->localeLinkParams[$locale] = ['name' => $action]; + } $this->template->pageTitle = $this->talks->pageTitle('messages.title.talk', $talk); $this->template->pageHeader = $talk->getTitle(); @@ -89,6 +98,21 @@ public function actionTalk(string $name, ?string $slide = null): void } + protected function getLocaleLinkAction(): string + { + return (count($this->localeLinkParams) > 1 ? parent::getLocaleLinkAction() : 'Www:Talks:'); + } + + + /** + * @return array + */ + protected function getLocaleLinkParams(): array + { + return $this->localeLinkParams; + } + + protected function createComponentTalksList(string $name): TalksList { return $this->talksListFactory->create(); diff --git a/site/config/services.neon b/site/config/services.neon index 378eee75e..2c6dc8b9a 100644 --- a/site/config/services.neon +++ b/site/config/services.neon @@ -84,6 +84,7 @@ services: - MichalSpacekCz\Tags\Tags - MichalSpacekCz\Talks\TalkFactory(videoFactory: @talkVideoFactory) - MichalSpacekCz\Talks\TalkInputsFactory(videoThumbnails: @talkVideoThumbnails) + - MichalSpacekCz\Talks\TalkLocaleUrls - MichalSpacekCz\Talks\Talks - MichalSpacekCz\Talks\TalkSlides - MichalSpacekCz\Talks\TalksListFactory diff --git a/site/tests/Talks/TalkLocaleUrlsTest.phpt b/site/tests/Talks/TalkLocaleUrlsTest.phpt new file mode 100644 index 000000000..389e370c5 --- /dev/null +++ b/site/tests/Talks/TalkLocaleUrlsTest.phpt @@ -0,0 +1,85 @@ + 'foobar']; + $this->database->setFetchPairsResult($expected); + Assert::same([], $this->talkLocaleUrls->get($this->buildTalk(null))); + Assert::same($expected, $this->talkLocaleUrls->get($this->buildTalk(1337))); + } + + + private function buildTalk(?int $translationGroup): Talk + { + $video = new Video( + null, + null, + null, + null, + null, + null, + 320, + 200, + null, + ); + return new Talk( + 10, + 1, + 'cs_CZ', + $translationGroup, + null, + null, + Html::fromText('title'), + 'title', + null, + null, + new DateTime(), + null, + null, + false, + null, + null, + $video, + null, + Html::fromText('event'), + 'event', + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + false, + ); + } + +} + +$runner->run(TalkLocaleUrlsTest::class);
    {label translationGroup /}{input translationGroup}
    {label locale /}{input locale}