Zum Inhalt springen
Farbschema wählenSprache wählen

Einen neuen Telegram-Befehl einbinden

Der Telegram-Bot ist in vier Schichten aufgebaut, alle in server/src/interfaces/telegram/ und server/src/app/i18n/. Führe die folgenden Schritte der Reihe nach aus.

  1. Befehlsvariante deklarieren.

    Öffne commands.rs und füge dem Command-Enum (abgeleitet mit teloxide::utils::command::BotCommands) eine Variante hinzu:

    #[command(description = "Einzeilige Hilfe, die bei /help angezeigt wird")]
    MyCommand(String), // String = der rohe Argumentstring; () für keine Argumente verwenden

    Das Attribut rename_rule = "lowercase" am Enum bewirkt, dass MyCommand als /mycommand registriert wird.

  2. Eine Route-Variante zu LinkedCommandRoute hinzufügen.

    Direkt unterhalb des Command-Enums befindet sich ein privates LinkedCommandRoute-Enum. Füge einen passenden Zweig hinzu:

    MyCommand { args: &'a str },

    Dann in linked_command_route verdrahten:

    Command::MyCommand(args) => Some(LinkedCommandRoute::MyCommand { args }),
  3. An einen Handler weiterleiten.

    Im match linked_command_route(...)-Block innerhalb von handle_command einen Zweig hinzufügen, der deinen Handler aufruft:

    LinkedCommandRoute::MyCommand { args } => {
    super::commands_workspace_handlers::handle_my_command(
    &bot, chat_id, &state, user_id, locale, args,
    )
    .await?
    }

    Den Handler selbst im passenden Dispatch-Modul platzieren:

    • Einfache Lese-/Aktionsbefehle kommen in commands_dispatch.rs.
    • Workspace-bezogene oder Feature-Auflistungsbefehle kommen in commands_workspace_handlers.rs.

    Ein typischer Handler delegiert direkt an eine Service-Funktion und nutzt den gemeinsamen send_service_result-Helper:

    pub(super) async fn handle_my_command(
    bot: &Bot,
    chat_id: ChatId,
    state: &AppState,
    user_id: Uuid,
    locale: Locale,
    args: &str,
    ) -> ResponseResult<()> {
    send_service_result(
    bot,
    chat_id,
    locale,
    crate::chat::command::my_command(state, user_id, locale, args).await,
    )
    .await
    }

    send_service_result sendet bei Erfolg den ResponsePlan-Text (plain oder HTML) und fällt im Fehlerfall auf die TelegramCommandFailed-Nachricht zurück — der Handler muss Fehler daher nie selbst formatieren.

  4. Fluent-Nachrichtenschlüssel hinzufügen.

    Jeder für Nutzer sichtbare String muss über den typisierten Fluent-Katalog laufen — keine fest codierten Strings in Handlern.

    a. Den Schlüssel in server/src/app/i18n/keys.rs registrieren:

    pub enum MessageKey {
    // ...vorhandene Schlüssel...
    TelegramMyCommandResult,
    TelegramMyCommandUsage,
    }

    Dieselben Varianten dem ALL-Slice und dem id-Match-Zweig im Kebab-Case hinzufügen:

    Self::TelegramMyCommandResult => "telegram-my-command-result",
    Self::TelegramMyCommandUsage => "telegram-my-command-usage",

    Der Unit-Test message_key_ids_are_unique_kebab_case_entries in keys.rs schlägt fehl, wenn eine ID doppelt vorkommt oder ein Nicht-Kebab-Zeichen enthält.

    b. Die Nachricht in beiden Locale-Dateien schreiben:

    server/locales/en/telegram.ftl:

    telegram-my-command-result = Result: { $value }
    telegram-my-command-usage = Usage: /mycommand <argument>

    server/locales/de/telegram.ftl:

    telegram-my-command-result = Ergebnis: { $value }
    telegram-my-command-usage = Nutzung: /mycommand <argument>

    c. Den Schlüssel in der Service-Funktion verwenden:

    // Keine dynamischen Argumente — einfacher Text:
    i18n::text(locale, MessageKey::TelegramMyCommandResult)
    // Mit Substitutionsvariablen:
    i18n::with_args(locale, MessageKey::TelegramMyCommandResult,
    i18n::arg("value", some_string))

    Wenn derselbe formatierte String an mehreren Stellen wiederverwendet wird, einen typisierten Helper in server/src/app/i18n/format.rs hinzufügen (siehe vorhandene Helpers wie telegram_intervention_sent als Vorlage).

  5. Überprüfen.

    Terminal window
    cd server
    cargo check
    cargo test arch
    cargo test -- i18n

    cargo test -- i18n führt den Katalog-Validierungstest (fluent_catalogs_contain_all_typed_keys) aus, der prüft, ob jede MessageKey-Variante einen entsprechenden Eintrag in beiden Locale-Dateien hat.