Skip to content

Migrate forms to L10n and add support for DatabaseObjectBuilder #6717

Description

@dtdesign

Migrate remaining ACP forms from I18nHandler to AbstractDatabaseObjectBuilderForm

These ACP forms in lib/acp/form/ still handle multilingual text through the legacy I18nHandler and have not been moved to AbstractDatabaseObjectBuilderForm with TL10nFormField. A form reaches I18nHandler in one of three ways: it calls it directly, it registers fields through AbstractAcpForm::registerI18nValue(), or it uses form builder ->i18n() fields, which go through TI18nFormField.

Plain AbstractForm with direct I18nHandler usage

  • BBCodeAddForm / BBCodeEditForm
  • NoticeAddForm / NoticeEditForm
  • PageAddForm / PageEditForm
  • PaidSubscriptionAddForm / PaidSubscriptionEditForm (title and description, saved through its own saveI18nValue())
  • StyleAddForm / StyleEditForm
  • UserGroupAddForm / UserGroupEditForm (through AbstractOptionListForm)
  • AbstractCategoryAddForm / AbstractCategoryEditForm (abstract, risky transition)

AbstractAcpForm with registerI18nValue()

  • TrophyAddForm / TrophyEditForm (title, description)
  • UserTrophyAddForm / UserTrophyEditForm (description)
  • AbstractCustomOptionForm (optionTitle, optionDescription; abstract, no subclass in Core)

AbstractFormBuilderForm with ->i18n() fields

  • ContactOptionAddForm / ContactOptionEditForm (through AbstractFormOptionAddForm)
  • ContactRecipientAddForm / ContactRecipientEditForm
  • CronjobAddForm / CronjobEditForm (also calls I18nHandler::save() and remove() directly)
  • DevtoolsProjectAddForm / DevtoolsProjectEditForm
  • LabelGroupAddForm / LabelGroupEditForm (also calls I18nHandler::save() and remove() directly)
  • MenuAddForm / MenuEditForm
  • MenuItemAddForm / MenuItemEditForm
  • ReactionTypeAddForm / ReactionTypeEditForm
  • UserOptionCategoryAddForm / UserOptionCategoryEditForm (also calls I18nHandler::save() directly)
  • UserRankAddForm / UserRankEditForm

Notes

  • Check first whether LanguageItemAddForm and DevtoolsProjectAddForm really need multilingual text fields.

Postponed

  • LanguageItemAddForm
    • The i18n implementation is merely used for transport.
  • SmileyAddForm / SmileyEditForm
    • Smileys are a legacy feature, the form is abandoned in place
  • LabelAddForm / LabelEditForm
    • Integrations have deep knowledge of the internal label API, interpreting the title as phrase, serializing it in the modification log and possibly other shenanigans

Blockers: Migrating CategoryAddFormBuilderForm to l10n

Affecting:

  • CategoryAddFormBuilderForm (also calls I18nHandler::save() and remove() directly), along with its subclasses:
    • ArticleCategoryAddForm / ArticleCategoryEditForm
    • MediaCategoryAddForm / MediaCategoryEditForm
    • SmileyCategoryAddForm / SmileyCategoryEditForm
    • TrophyCategoryAddForm / TrophyCategoryEditForm
    • … and about 10 more forms in our products alone, let alone any third party implementations.

This possibly warrants a different base implementation to begin with which also allows us to fix some long-standing issues with the implementation. However, I don’t see this landing in 6.3 by any means since we need to get back to the drawing board first.

  • Category cannot use collections: it extends ProcessibleDatabaseObject, so it must be rebased onto CollectionDatabaseObject with getProcessor() reimplemented. CategoryCache must preload the l10n values.
  • Base class switch causes fatal errors: AbstractDatabaseObjectBuilderForm has typed $formAction/$objectEditLinkController and : void returns. Every subclass redeclaring them breaks (Core Article/Media/Smiley/Trophy, Blog, Calendar, Filebase, Gallery, Database, and third-party subclasses).
  • additionalData is silently lost: the builder save path ignores CustomFormDataProcessor.
    • Article: sortField/sortOrder
    • Calendar: eventColor
    • Database: icon/canContainRecords
    • Listeners: Forum, Event Threads, Support Threads
    • Needs a CategoryBuilder additionalData API?
  • Deletion: the new command must keep ICategoryType::beforeDeletion()/afterDeletion() and the ACL cleanup. Remove the phrase cleanup in CategoryAction::delete().
  • getTitle() overrides reading $this->title: BlogCategory, FilebaseCategory, WsdbCategory.
  • SQL on category.title: TDecoratedCategoryLookupPageHandler.
  • "Import" fallback category (select by title + raw INSERT): Core ArticleImporter/TrophyImporter, Blog EntryImporter, Calendar EventImporter, Filebase FileImporter, Gallery ImageImporter.
  • Install scripts calling CategoryEditor::create(['title' => …]): Blog, Calendar, Filebase, Gallery. Fresh installs fail.
  • AbstractCategoryImporter: keep the title/description + additionalData['i18n'] contract and map it to l10n.
  • Database: WsdbCategoryAddForm/WsdbOptionGroupAddForm read $this->objectAction->getReturnValues(). Use $this->object.
  • Legacy AbstractCategoryAddForm/EditForm: read and write title/description.
  • Data migration: phrase names vary per type prefix. Resolve any existing phrase, delete phrases for all prefixes, use a TEXT column for the description.

Activity

  1. added theissue type on Sep 27, 2026
  2. moved this to Major Task in WoltLab Suite 6.3on Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions