Skip to content

Simplify event creation localization and derive default language from ordered list - #4770

Open
SxxAq wants to merge 6 commits into
fossasia:devfrom
SxxAq:feature/simplify-event-localization
Open

Simplify event creation localization and derive default language from ordered list#4770
SxxAq wants to merge 6 commits into
fossasia:devfrom
SxxAq:feature/simplify-event-localization

Conversation

@SxxAq

@SxxAq SxxAq commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR simplifies the event creation localization workflow by removing the redundant Default language dropdown field from the event creation form. The default language is now automatically derived from the first language in the Event languages list.

Additionally, an interactive drag-and-drop tray is introduced so organizers can easily reorder selected languages to control which language acts as the default.

Closes #4697
260806_16h53m17s_screenshot


Key Changes

  1. Template (create.html)

    • Removed the separate Default language dropdown field (basics_form.locale).
    • Added a hidden input (basics-locale) and a drag-and-drop language ordering tray (#language-order-tray).
  2. Front-end JavaScript (event-create.js)

    • Implemented renderOrderTray() to display selected languages as draggable pills with a Default badge on the first pill.
    • Added HTML5 drag-and-drop handlers allowing organizers to reorder language pills.
    • Kept the hidden basics-locale input synchronized with whichever language is first in the tray.
  3. Forms & Views (forms/event.py & views/event.py)

    • Updated EventWizardBasicsForm.clean() and EventCreateView.create_event() with fallback logic to set default_locale to the first language in locales if locale is omitted or invalid.

Acceptance Criteria Verification

  • Event creation form no longer shows a separate Default language dropdown.
  • First selected language in Event languages is saved as the default language.
  • Selected languages can be reordered by drag-and-drop.
  • Reordering languages updates which language is treated as default.
  • Validation ensures at least one language is selected.

Summary by Sourcery

Derive an event’s default language from the ordered list of selected locales and streamline the localization UX in the event creation flow.

New Features:

  • Introduce a drag-and-drop language priority tray that visually indicates the default language based on ordering.
  • Automatically synchronize a hidden default-language field with the first selected locale in the language tray.

Bug Fixes:

  • Ensure events gracefully fall back to the first selected locale when an invalid or missing default locale is submitted.

Enhancements:

  • Remove the separate default-language dropdown from the event creation form, simplifying localization configuration.
  • Align server-side locale selection and event creation logic with the new ordering-based default locale behavior.

Tests:

  • Add tests verifying fallback behavior for invalid default locales and that the first or reordered locale becomes the event’s default.

Copilot AI lite review requested due to automatic review settings August 6, 2026 11:29

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @SxxAq, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Thank you for contributing

Please complete the checklist. Screenshots in the PR description and completed AI reviews are checked automatically.

  • Show what changed — a screenshot or short screen recording of the updated functionality
  • Map structural updates — for architectural work, new directories, or file reorganization, include a diagram in the PR description (component, flow, or directory tree). Optional — only when your PR includes those kinds of changes
  • Request AI feedback — request or receive review from GitHub Copilot, Codex, or other automated reviewers you use

🤖 AI reviews

❌ 2 failed or rate-limited AI reviewers

GitHub Copilot (@copilot-pull-request-reviewer[bot])

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sourcery AI (@sourcery-ai[bot])

you have reached your weekly rate limit of 500000 diff characters.

ℹ️ Does not count toward the checklist

Sourcery AI (@sourcery-ai[bot]) — Sourcery AI code review bot


📎 Attached media (1)

Screenshots and screen recordings

🖼️ Screenshots

260806_16h53m17s_screenshot


Thank you for your contribution feel free to reach out if you have any questions.

@github-actions github-actions Bot added backend Python/Django server-side code common Cross-cutting helpers and eventyay_common UI control Organiser ticketing back-office frontend JS, Vue, CSS, and HTML templates test labels Aug 6, 2026
@sourcery-ai

sourcery-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Event creation localization is refactored so the default language is derived from the ordered list of selected locales, using a new drag‑and‑drop tray and hidden input, with backend fallback logic and tests ensuring the first locale becomes the default.

Sequence diagram for default locale derivation during event creation

sequenceDiagram
    actor Organizer
    participant BrowserForm
    participant EventCreateJS
    participant EventWizardBasicsForm
    participant EventCreateView
    participant Event

    Organizer->>BrowserForm: select foundation_form.locales
    BrowserForm->>EventCreateJS: change event on foundation-locales
    EventCreateJS->>EventCreateJS: syncLocaleOrder()
    EventCreateJS->>EventCreateJS: updateLocaleOrderList()
    EventCreateJS->>BrowserForm: set id_basics-locale (first locale)
    EventCreateJS->>EventCreateJS: renderOrderTray()

    Organizer->>BrowserForm: submit event create form
    BrowserForm->>EventWizardBasicsForm: clean()
    EventWizardBasicsForm->>EventWizardBasicsForm: if data.locale not in self.locales
    EventWizardBasicsForm->>EventWizardBasicsForm: set data.locale = self.locales[0]
    EventWizardBasicsForm-->>EventCreateView: basics_data with locale

    EventCreateView->>EventCreateView: create_event()
    EventCreateView->>EventCreateView: chosen_locale = basics_data.locale or foundation_data.locales[0]
    EventCreateView->>EventCreateView: if chosen_locale not in foundation_data.locales
    EventCreateView->>EventCreateView: chosen_locale = foundation_data.locales[0]
    EventCreateView->>Event: update_language_configuration(locales, content_locales, chosen_locale)
    EventCreateView-->>Organizer: event created with default_locale = first locale
Loading

File-Level Changes

Change Details Files
Front-end locale selection now maintains an explicit ordered list and exposes a drag-and-drop tray that determines the default language via a hidden input value synced to the first locale.
  • Introduced state variables to track current locale order and the currently dragged locale.
  • Replaced direct DOM-based active-language computation with an order-maintaining helper that reconciles checked locales with the tracked order.
  • Added a language label resolver using grid cell metadata or labels to render human-readable names for locale pills.
  • Implemented renderOrderTray to build draggable language items, show a Default badge on the first item, and hide the tray when no locales are selected.
  • Implemented drag-and-drop handlers on tray items to reorder locales and trigger synchronization.
  • Centralized locale-order synchronization in syncLocaleOrder, which updates the hidden default-locale input and re-renders the tray.
  • Updated existing event-create initialization and change/click handlers to use the new synchronization function instead of the old default-language select updating logic.
  • Ensured event i18n field updates still run after locale changes with the new ordering logic.
app/eventyay/static/eventyay-common/js/ui/event-create.js
The event creation template no longer exposes a Default language dropdown; instead it uses a hidden default-locale field plus a visible language-order tray with drag-and-drop UI and help text.
  • Removed the bootstrap-rendered basics_form.locale field from the Localization fieldset.
  • Added a hidden basics-locale input that persists the default locale derived from the tray.
  • Added a language-order wrapper containing label, tray container, and inline CSS to style draggable language pills and default badges.
  • Provided user-facing helper text explaining that the first language in the tray is used as the default and can be changed via drag-and-drop.
app/eventyay/eventyay_common/templates/eventyay_common/events/create.html
Backend form and view logic now derive and validate the default locale from the selected locales, falling back to the first locale when the provided locale is missing or invalid, ensuring compatibility with the new UI.
  • Updated EventWizardBasicsForm.clean to fall back to the first selected locale when the locale is unset or not among allowed locales, only raising validation errors when no locales exist.
  • Adjusted create_event in the event creation view to compute a chosen_locale based on the basics form value or the first foundation locale, and to fall back to the first locale when the provided value is not in the selected list.
  • Changed language context activation and event language configuration to use chosen_locale instead of the raw basics_data['locale'].
  • Kept a safe default ('en') when no locales are present to avoid crashes in edge cases.
app/eventyay/control/forms/event.py
app/eventyay/eventyay_common/views/event.py
Tests for event creation were updated and extended to verify default-locale fallback behavior, first-locale defaulting, and reordering effects on the default locale.
  • Renamed and updated the existing invalid-default-language test to assert that an invalid basics-locale results in the first selected locale being saved as the event default.
  • Adapted test payloads to the split date/time field structure for from/to and presale dates to match current form expectations.
  • Added a test ensuring that when multiple locales are selected, the first in the foundation-locales list becomes the default locale when basics-locale is not explicitly provided.
  • Added a test verifying that when locales are reordered (simulated via basics-locale set to a non-first locale), the chosen default locale matches the reordered first locale as expected by the new drag-and-drop tray UI.
app/tests/tickets/control/test_events.py

Assessment against linked issues

Issue Objective Addressed Explanation
#4697 Remove the separate Default language field from the event creation form UI and derive the default language from the event languages selection instead.
#4697 Use the first language in the ordered Event languages list as the default language, allowing organisers to reorder selected languages via drag and drop, with the reordered first language becoming the event default.
#4697 Preserve existing event creation behavior and validation, specifically preventing event creation without at least one language and keeping localization clear and simple.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@mariobehling mariobehling left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of the issue is that we only have one field instead of two. You are still using two fields.

Only use the following field and implement the option to drag and drop it directly in that field. The first language should have a bold borderline to indicate it is the main language.
Image

Comment thread app/eventyay/eventyay_common/templates/eventyay_common/events/create.html Outdated
Comment thread app/eventyay/control/forms/event.py
@github-actions github-actions Bot added base Shared models, services, and core utilities and removed control Organiser ticketing back-office labels Aug 7, 2026
@SxxAq

SxxAq commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

The goal of the issue is that we only have one field instead of two. You are still using two fields.

Updated.

image

@ArnavBallinCode ArnavBallinCode left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Saksham-Sirohi

Copy link
Copy Markdown
Collaborator

Follow-ups before merge

Looks good overall and matches the intent of #4697. Two small gaps still worth fixing:

1. language-grid.js overwrites the drag-and-drop badges on load

On create, both event-create.js and language-grid.js render into [data-language-grid-badges]. language-grid’s syncBadges() runs after init and replaces the DnD pills with plain badges (no drag handles / default styling) until the next language toggle.

Please either:

  • have language-grid skip badge rendering when the create-page order tray owns it, or
  • move ordering/DnD into language-grid itself so there’s a single owner of the badge list.

2. Persist tray order into foundation-locales on submit

DnD correctly syncs the hidden basics-locale (default language), but the submitted foundation-locales values still follow checkbox/DOM order. After reorder, settings.locales can disagree with the tray even when settings.locale is right.

On sync/submit, rewrite foundation-locales in currentLocaleOrder (same approach as the AJAX i18n-fields path already uses) so the stored language list matches what the organiser sees.

Happy to re-check once these are in.

Comment on lines 97 to 101
<fieldset>
<legend>{% trans "Localization" %}</legend>
{% bootstrap_field foundation_form.locales layout="control" %}
{% bootstrap_field basics_form.locale layout="control" %}
<input type="hidden" name="basics-locale" id="id_basics-locale" value="{{ basics_form.locale.value|default:'' }}">
</fieldset>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No-JS / Progressive Enhancement failure. Replacing the visible <select name="basics-locale"> dropdown with a <input type="hidden" name="basics-locale"> means if JavaScript is disabled or fails to load, basics-locale submits an empty value "". EventWizardBasicsForm rejects empty locale fields with a "This field is required" validation error, rendering the event creation form unusable without JS.

Resolution: Ensure value has a sensible default fallback (e.g. 'en' or foundation_form.locales.value.0) if basics_form.locale.value is empty.

Comment on lines +102 to +107
badge.addEventListener("dragstart", function (e) {
draggedCode = code;
badge.classList.add("dragging");
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/plain", code);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility (a11y) failure. Drag-and-drop reordering relies solely on HTML5 Drag and Drop events (dragstart, dragover, drop). Mouse-only drag-and-drop cannot be operated using keyboard navigation (Tab / Arrow keys) or screen readers.

Resolution: Add keyboard event handlers (ArrowLeft/ArrowRight or reorder buttons) and ARIA attributes (role="option", tabindex="0") so keyboard users can reorder languages.

e.dataTransfer.setData("text/plain", code);
});

badge.addEventListener("dragend", function () {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mobile touch screens unsupported. Standard HTML5 dragstart and drop events do not fire on mobile touch interfaces (iOS Safari / Android Chrome). Mobile users cannot drag badges to reorder default languages.

Resolution: Add touch event listeners or click-to-promote functionality so mobile users can tap a badge to set it as the default language.

Comment on lines +35 to +41
function updateLocaleOrderList() {
var checkedLocales = getCheckedLocalesFromDOM();
var checkedSet = new Set(checkedLocales);

currentLocaleOrder = currentLocaleOrder.filter(function (code) {
return checkedSet.has(code);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State loss on form re-validation. currentLocaleOrder is initialized to [] on script execution. When a form validation error occurs (e.g. missing event name) and the server re-renders the page, updateLocaleOrderList() populates currentLocaleOrder from checkbox DOM order, discarding the custom language order chosen prior to form submission.

Resolution: Read the initial value from id_basics-locale when populating currentLocaleOrder for the first time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Python/Django server-side code base Shared models, services, and core utilities common Cross-cutting helpers and eventyay_common UI frontend JS, Vue, CSS, and HTML templates test

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Simplify event creation localization and use language order for default language

8 participants