8. Slots and translations

Fill the install slot with a walkthrough beside the form, ship its placeholder, and give every string the connector shows its ten translations.

The core renders Agora's install form from the manifest. A creator pasting an API key still appreciates seeing where the key lives in Agora's settings, and that is what the install slot is for.

The contribution

<?php

declare(strict_types=1);

namespace Acme\Connectors\Agora\Ports;

use Subscriby\Connector\Contracts\Ports\UiSlots;
use Subscriby\Connector\Data\SlotContribution;
use Subscriby\Connector\Enums\ConnectorSlot;

final class AgoraUiSlots implements UiSlots
{
    public function slots(): array
    {
        return [
            new SlotContribution(
                slot: ConnectorSlot::Install,
                view: 'connector-agora::slots.install',
                placeholder: 'connector-agora::slots.install-placeholder',
            ),
        ];
    }
}

One contribution, one slot, a view and its placeholder. The kit's slots.well_formed needs exactly this shape; a contribution naming both a view and a component, or neither, is refused by the constructor.

The view and its placeholder

{{-- resources/views/slots/install.blade.php --}}
<div class="rounded-2xl border border-zinc-200 p-4 dark:border-zinc-700">
    <flux:heading size="sm">{{ __('Where to find your API key') }}</flux:heading>
    <flux:text class="mt-1">{{ __('In Agora, open Settings, then API, and create a key with the Boards and Messages permissions. The key starts with agk_.') }}</flux:text>
    <img src="{{ asset('vendor/connector-agora/settings-api.png') }}" alt="{{ __('The API settings page of an Agora forum') }}" class="mt-3 rounded-lg" loading="lazy" />
</div>
{{-- resources/views/slots/install-placeholder.blade.php --}}
<div class="rounded-2xl border border-zinc-200 p-4 dark:border-zinc-700">
    <div class="h-4 w-48 animate-pulse rounded bg-zinc-200 dark:bg-zinc-700"></div>
    <div class="mt-2 h-4 w-full animate-pulse rounded bg-zinc-200 dark:bg-zinc-700"></div>
    <div class="mt-3 aspect-video w-full animate-pulse rounded-lg bg-zinc-200 dark:bg-zinc-700"></div>
</div>

The placeholder mirrors the loaded layout box for box, so the Connect dialog does not jump when the contribution arrives. The view reads nothing but translations and a published asset; it never touches a model or the application's classes. Blade views in the package are published under the connector-agora:: namespace by the SDK's provider.

Every string, ten times

Every __() in the connector is a key in lang/english.json, and the same key exists in the other nine files with a real translation. Collect them from the ports and views of the previous chapters:

{
    "Create an API key on your Agora forum, then paste it here.": "Create an API key on your Agora forum, then paste it here.",
    "Forum address": "Forum address",
    "API key": "API key",
    "Board": "Board",
    "Private board": "Private board",
    "Open the forum": "Open the forum",
    "Pick the board to sell access to for <b>:project</b>.": "Pick the board to sell access to for <b>:project</b>.",
    "Choose a board": "Choose a board",
    "Our bot sent you a private message on your forum with a link. Open it and pick the board.": "Our bot sent you a private message on your forum with a link. Open it and pick the board.",
    "The board no longer exists on the forum.": "The board no longer exists on the forum.",
    "The bot user is not a member of this board.": "The bot user is not a member of this board.",
    "Make the bot user a moderator of this board so it can add and remove members.": "Make the bot user a moderator of this board so it can add and remove members.",
    "You now have access to <b>:count</b> private board(s). Open the forum and they are waiting for you.": "You now have access to <b>:count</b> private board(s). Open the forum and they are waiting for you.",
    "Continue with your forum account": "Continue with your forum account",
    "Send the message \"login :token\" to our bot on the forum, then come back here.": "Send the message \"login :token\" to our bot on the forum, then come back here.",
    "You are signed in as :name. Head back to the portal.": "You are signed in as :name. Head back to the portal.",
    "That code has expired or was already used. Start again from the portal.": "That code has expired or was already used. Start again from the portal.",
    "forum bot": "forum bot",
    "board": "board",
    "forum account": "forum account",
    "board membership": "board membership",
    "forum bots": "forum bots",
    "boards": "boards",
    "API key revoked": "API key revoked",
    "The forum no longer accepts the API key. Create a new one under Settings › API and reconnect.": "The forum no longer accepts the API key. Create a new one under Settings › API and reconnect.",
    "The bot moderates every board it gates": "The bot moderates every board it gates",
    "A board the bot cannot moderate cannot admit or remove members.": "A board the bot cannot moderate cannot admit or remove members.",
    "The forum account no longer exists.": "The forum account no longer exists.",
    "Where to find your API key": "Where to find your API key",
    "In Agora, open Settings, then API, and create a key with the Boards and Messages permissions. The key starts with agk_.": "In Agora, open Settings, then API, and create a key with the Boards and Messages permissions. The key starts with agk_.",
    "The API settings page of an Agora forum": "The API settings page of an Agora forum"
}

The manifest's labels, help texts and steps are keys too, and so are the resource kind's label and portal_label and the listing's tagline, so they go in the same files. Ten files: english, spanish, french, german, italian, portuguese, turkish, hindi, bengali, sinhalese. The application's parity tests scan package language directories and fail on a key present in one file and missing in another.

Placeholders (:project, :count, :token, :name) and the canonical tags (<b>) stay as they are in every language; translators translate the words around them.

A test that reads the code

A small test that walks src/ and resources/ for __('…') calls and asserts each key is present in all ten files catches the missing translation on the developer's machine, which is where Subscriby's own parity test would otherwise catch it during review.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request