Order confirmation message is not translatable in custom checkout flow

Created on 19 July 2023, almost 2 years ago

Problem/Motivation

As @Berdir wrote in 💬 translation of completion message (Your order number is...) is being ignored. Fixed , the order confirmation message can now be translated in the checkout flow. But this only works for the "default" checkout flow!

/admin/commerce/config/checkout-flows/manage/default/translate/de/edit shows the confirmation message and allows translating it:

/admin/commerce/config/checkout-flows/manage/my_custom_checkout_flow/translate/de/edit does NOT show anything translatable besides the label:

Steps to reproduce

  1. Create a custom checkout flow
  2. Open the "Translate" page
  3. See there's nothing to translate but the label

Proposed resolution

Provide the translation functionality also for custom checkout flows, not only the default one

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Active

Version

2.0

Component

Checkout

Created by

🇩🇪Germany Anybody Porta Westfalica

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Anybody
  • 🇩🇪Germany Anybody Porta Westfalica
  • 🇩🇪Germany Anybody Porta Westfalica
  • 🇩🇪Germany Anybody Porta Westfalica
  • 🇩🇪Germany Anybody Porta Westfalica
  • 🇩🇪Germany Anybody Porta Westfalica

    Just had a look into the code and this seems to be a logical issue, not a translation issue.

    In commerce_checkout.schema.yml there is:

    commerce_checkout.commerce_checkout_pane.completion_message:
      type: commerce_checkout_pane_configuration
      mapping:
        message:
          type: text_format
          label: 'message'
          translatable: true

    So the completition message is stored (and translated) independently from the checkout flow.
    But the UI to administer it, is within the checkout flow!

    So I think there are two options, to be decided by the Drupal Commerce maintainers:
    a) Move the message out of the flow into a central place, like order settings (/admin/commerce/config/orders/settings) and instead of editing the message in the checkout flow, just link the settings page for editing
    b) Move the completion_message into the checkout flow data structure and make it translatable there. Then the message can be defined and translated individually per checkout flow, as you'd expect it to be the case now.
    That would be the more flexible, but presumably more complex.

    Setting priority back to "Normal" as the message can be set in the default checkout flow for all checkout flows - which is super confusing and unexpected, but works :)

  • 🇩🇪Germany Anybody Porta Westfalica

    Update: Seems I was not totally right in#6 and that isn't used for custom checkout flows. It just uses the untranslated completion_message. So back to Major , as expected functionality is broken and there doesn't seem to be a workaround for multilingual projects needing a custom checkout glow.

  • 🇩🇪Germany Anybody Porta Westfalica

    Okay, finally this seems to be a translation UI / config issue.

    I was able to workaround this be creating a config file with the translation:
    commerce_checkout.commerce_checkout_flow.my_custom_checkout_flow.yml
    with the following content (translation of completion_message):

    label: "My Order Request"
    configuration:
      panes:
        completion_message:
          message:
            value: "This is the translated confirmation message"
            format: full_html
    

    Sorry for the noise, but I hope it helps to follow my steps to find the root cause.

    TL;DR: The UI for the translation of the completion message is missing for custom checkout flows. Translation works with manually created config translation.

  • 🇨🇭Switzerland berdir Switzerland

    what exactly does a custom checkout flow mean? a custom checkout flow plugin? a custom page plugin that subclasses the default one?

    Drupal needs to be able to build the config schema for the definition to understand that something can be translated, if it doesn't work four you then there's a peace missing and you're likely missing some config schema for your custom elements.

    Basically, you are likely missing this for your plugin

    commerce_checkout.commerce_checkout_flow.plugin.multistep_default:
      type: commerce_checkout_flow_with_panes_configuration
    

    that tells drupal that your plugin uses panes and it inherits the configuration definition for them, so it can look that up.

  • 🇩🇪Germany Anybody Porta Westfalica

    Autsch, thank you @Berdir! That was the missing piece!

    With custom checkout flow I meant the config entity that is created by clicking
    /admin/commerce/config/checkout-flows/add in the UI.

    That creates a new entry at admin/commerce/config/checkout-flows additionally to the "default" entry.
    And I thought the bug is somewhere there...

    But I was totally missing that this additional checkout flow is using a different checkout flow plugin extending MultistepDefault.

    I followed these steps: https://docs.drupalcommerce.org/commerce2/developer-guide/checkout/creat...
    Is that tutorial old perhaps, missing that installation config part?

    My commerce_checkout.commerce_checkout_flow.my_custom_checkout_flow.yml looks like this:

    uuid: fa3b104f-ebd4-40d3-a524-542899c9e5b8
    langcode: en
    status: true
    dependencies:
      module:
        - email_registration
    label: 'My custom checkout flow'
    id: my_custom_checkout_flow
    plugin: my_custom_checkout_flow
    configuration:
      display_checkout_progress: true
      display_checkout_progress_breadcrumb_links: false
      guest_order_assign: true
      guest_new_account: false
      guest_new_account_notify: false
      panes:
        email_registration_login:
          allow_guest_checkout: true
          allow_registration: false
          registration_form_mode: register
          step: login
          weight: '0'
        contact_information:
          double_entry: false
          step: order_information
          weight: '1'
        billing_information:
          step: order_information
          weight: '2'
        review:
          step: review
          weight: '3'
        order_summary:
          view: ''
          step: review
          weight: '4'
        completion_message:
          message:
            value: "lorem ipsum"
            format: full_html
          step: complete
          weight: '5'
        email_registration_completion_registration:
          step: complete
          weight: '6'
        completion_register:
          step: _disabled
          weight: '7'
        login:
          allow_guest_checkout: true
          allow_registration: false
          registration_form_mode: register
          step: _disabled
          weight: '8'
    

    and the checkout flow plugin:

    <?php
    
    namespace Drupal\my_custom_checkout_flow\Plugin\Commerce\CheckoutFlow;
    
    use Drupal\my_custom_checkout_flow\Plugin\Commerce\CheckoutFlow\MultistepDefault;
    
    /**
     * Lorem ipsum
     *
     * @CommerceCheckoutFlow(
     *   id = "my_custom_checkout_flow",
     *   label = "Lorem Ipsum",
     * )
     */
    class MyCustomCheckoutFlow extends MultistepDefault {
    
      /**
       * {@inheritdoc}
       */
      public function getSteps() {
        // Note that previous_label and next_label are not the labels
        // shown on the step itself. Instead, they are the labels shown
        // when going back to the step, or proceeding to the step.
        return [
          'login' => [
            'label' => $this->t('Login'),
            'previous_label' => $this->t('Go back'),
            'has_sidebar' => FALSE,
          ],
          'order_information' => [
            'label' => $this->t('Order Request Information'),
            'has_sidebar' => FALSE,
            'previous_label' => $this->t('Go back'),
          ],
          'review' => [
            'label' => $this->t('Review Order Request'),
            'next_label' => $this->t('Review Order Request'),
            'previous_label' => $this->t('Go back'),
            'has_sidebar' => FALSE,
          ],
          'complete' => [
            'label' => $this->t('Thank you for your Order Request!'),
            'next_label' => $this->t('Complete Order Request'),
            'has_sidebar' => FALSE,
          ],
        ];
      }
    
    }
    

    Sorry I had to replace some customer names in the ID's and labels, hope it's still clear

    Thank you very very much for taking a look!

  • 🇨🇭Switzerland berdir Switzerland

    That goes in config/schema/yourmodule.schema.yml.

  • 🇩🇪Germany Anybody Porta Westfalica

    Thaaaaank you @Berdir! That works!

    So indeed that seems to be the missing piece in that tutorial, not easy to find out or self-explaining. Do you see any other way to fix this in code or should I just edit the documentation by a pull request with that example and perhaps a link to this issue for details?

    What do you or the Commerce Guys think?

  • 🇨🇭Switzerland berdir Switzerland

    Updating the documentation definitely helps.

    In general, every single plugin with configuration you create you need to think about config schema, it's not in any way special to this.

  • 🇩🇪Germany Anybody Porta Westfalica

    Thank you @Berdir, I'll do so.

    Indeed, never ran into this case, but I'll remember for the future! I would have expected it's one behind the scenes, but sadly not and makes sense. ;)

    Thank you, I hadn't found this on my own soon, I think.

  • Assigned to Anybody
  • Status changed to Needs work almost 2 years ago
  • 🇩🇪Germany Anybody Porta Westfalica

    For the docs MR as of #12

  • 🇧🇪Belgium RandalV

    Hi,

    Thanks for the issue, it already got us closer to a solution as well.
    However, I notice a small issue in the `commerce_checkout.schema.yml` file.

    commerce_checkout_pane_configuration:
      type: mapping
      mapping:
        display_label:
          type: string
          label: 'Display label'
          translatable: true
        step:
          type: string
          label: 'Step'
        weight:
          type: integer
          label: 'Weight'
        wrapper_element:
          type: string
          label: 'Wrapper element'

    I *think* the `display_label`'s type should be "label" rather than string.
    Currently, the display label is editable in the UI but not translatable.
    Not every plugin provides a display label from its attribute/annotation, and since it is editable in the UI it should also be translatable in the UI.

    I'm not sure if the combination of `type: string` with `translatable: true` does anything, though? I checked the "config schema cheat sheet" PDF file and couldn't find anything.

  • 🇧🇪Belgium RandalV

    Here's a patch that applies the change that works for us.

Production build 0.71.5 2024