Translatable Inline Lists in Drupal

By mandclu, Mon, 12/04/2023 - 07:17
Bubbles with scribbled text in what appear to be different languages

One of the things that got me started using Drupal was its powerful ability to work with multiple languages. I believe it's still a differentiator for Drupal in an increasingly crowded CMS space, particularly the degree to which all the text that appears on a Drupal site can be translated through the admin interface.

I was recently working on improving the theme output for the text of a recurring rule for Smart Date. In the process I decided to make the output more translatable, and it turned into something of a rabbit hole, so I thought it would be worth documenting, in case it might prove useful to someone else.

The Oxford Comma: an ongoing debate

As I was reviewing the code changes proposed by codebymikey, I noticed that one of the changes would remove the use of the Oxford comma in the section that lists a series of days on which a weekly or daily event will recur, if provided. The Oxford comma (or Serial Comma, as it is sometimes called) is the comma that can appear before the conjunction (usually "and" or "or") in a list of three or more terms, such as "my favourite pies are pumpkin, rhubarb, and lemon meringue."

Whether or not it should be used is an ongoing and sometimes contentious debate, that has even inspired a variety of memes.

Cartoon with the text: "we invited the strippers, JFK, and Stalin" with and without the Oxford comma, showing cartoons that depict JFK, Stalin, and two stripper (with the Oxford comma) and JFK and Stalin as two strippers (without the Oxford comma)

In my own education growing up, I had multiple teachers who insisted that the Oxford comma should always be used, and at least one who said it should never be used. In doing some recent research, most reference I could find preferred to indicate that the Oxford comma can sometimes avoid ambiguity, but steered clear of definitively declaring that it should always or never be used.

More interesting, perhaps, was the discovery that English is one of the few (or maybe the only?) languages in which this is a debate. Most languages consider it a settled matter, and as a matter of convention either always or never use it.

Inline lists in Drupal Smart Date

Smart Date includes a formatter for optimizing the display of recurring events. Instead of showing every instance, you can show a configurable number of upcoming and recent instances, and a text representation of the recurring rule. An example of this last element might be something like:

Monthly on the first weekday, 7 - 8am until Mon, Dec 1 2025

If the recurring rule specifies one or more days of the week on which it should repeat, those will be included too. If there are three or more they'll be formatted as an inline list, using commas and the word "and" as a conjunction:

Daily on Monday, Wednesday, and Friday, 12 - 1pm for 6 times

It's a well understood principle in handling translations that it's a bad idea to assemble parts of a sentence together synthetically and expect that to hold up across languages. To mitigate that, when Smart Date added handling for recurring dates it implemented a twig template to assemble the parts:

<div class="rule-text">
{{ repeat }} {{ day }}{{ month }} {{ time }}{{ limit }}

Eventually that structure was made translatable:

{% trans %}{{ repeat }} {{ day }}{{ month }} {{ time }}{{ limit }}{% endtrans %}

The new changes proposed putting the spaces between parts into separate variables, which would add more flexibility to how the elements could be combined and/or overridden in different ways across languages and to meet the specific needs of different sites.

Was there a similar way to add flexibility to how the inline lists are constructed?

Creating the inline lists in Drupal

My original code used a simple foreach loop to convert the day labels into the phrase:

            $day_output = '';
            foreach ($params['byday'] as $key => $day) {
              if ($key === array_key_last($params['byday'])) {
                $day_output .= $this->t('and') . ' ' . $day_labels[$day];

              else {
                $day_output .= $day_labels[$day] . ', ';

This isn't a great approach for translation, since it doesn't provide any context for the use of the word "and", though you could argue it's a simple enough use case that maybe it could be forgiven. Perhaps more aggregious, however is the fact that the code effectively hard-codes the use of the Oxford comma, and since this formatting happens within the Rule entity PHP class, it's more difficult to override. Since the parts will ultimately be assembled via Twig, a site could probably fix them with a preprocess function, but it will be messy. Since we were refactoring the rule output anyway, I wanted to make it easier.

Twig to the rescue (again)

I considered a few approaches, but ultimately arrived at assembling the days into an inline list using another twig template:

{% for key, value in values -%}
  {{ not loop.first and not loop.last ? ', '|t({}, {context: 'Rule text'}) -}}
  {{ loop.last ? ', and '|t({}, {context: 'Rule text'}) -}}
  {{ value -}}
{% endfor -%}

Putting this all into a Twig template means that any site using Smart Date can easily change the markup by overriding this template. The comma for everything but the last term is kept separate from the Oxford comma, so it's easier to target the Oxford comma specifically, either for overriding, or for translating.

The hyphens at the end of the Twig tags are to strip white space. Their use allows me to make the overall template more readable by breaking the elements onto separate lines. I also decided to make all the commas translatable, since some Eastern languages use a special enumeration comma for inline lists, and Arabic scripts use an inverted comma. Now Drupal and Smart Date can allow sites in these languages to fully support the proper output.

Is there still room for improvement in this code? I'm certain there will be, but one of the best (and sometimes worst) things about web development is that your projects are never really done. If you can see where additional improvements are possible, please drop a comment below, or open an issue on Smart Date, best of all with a Merge Request.




Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.