Skip to content

[FEATURE] Support text language and direction (lang/dir) in ReST - #1393

Open
linawolf wants to merge 2 commits into
mainfrom
task/container-lang-dir
Open

linawolf wants to merge 2 commits into
mainfrom
task/container-lang-dir

Conversation

@linawolf

@linawolf linawolf commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Resolves #1266
Resolves #1267

Authors had no way to mark a block, a run of inline text, or a whole
page as being in a different language or text direction, so the
rendered HTML never got the lang/dir attributes needed for correct
rendering (e.g. RTL scripts, screen readers, correct font/glyph
shaping). The maintainers asked what concrete output this should
produce.

docutils/Sphinx were checked for prior art before designing this:

  • Document level: neither has any per-document mechanism at all (only
    project-wide build config), so nothing to align with there.
  • Inline level: docutils' own FAQ recommends exactly :rtl:/:ltr:
    roles for this, just via .. role:: boilerplate the author has to
    write themselves; this makes them built-in instead.
  • Block level: docutils has .. class:: language-<tag> and
    .. class:: rtl/ltr, but that's CSS-only styling hooks with no
    real HTML lang/dir attribute, so it doesn't actually address the
    accessibility problem these issues are about. Kept our own
    :lang:/:dir: container options, which do emit real attributes.

This reuses existing mechanisms at three levels rather than inventing
new directives:

  • Block-level: :lang:/:dir: options on the existing .. container::
    / .. div:: directive.
  • Inline-level: new :rtl:/:ltr: roles for pure direction switches,
    and a combined :lang: role (:lang:text (language, direction)) for text tagged with both, following the same trailing-(...)convention as the existing:abbreviation:` role.
  • Document-level: new :lang:/:dir: field-list metadata, mirroring
    the existing :template: field, setting the page's own <html> tag.

dir is validated against ltr/rtl/auto and lang against a loose
BCP 47 shape; both are warn-only diagnostics, never blocking, matching
the ValueType validation philosophy already used elsewhere.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PP4LkejR5PSubbhNmF4RkT

@jaapio jaapio 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.

I think direction should be an enum rather than an arbitrary string, this allows us to be more strict. We can validate the value before we create the enum, and otherwise fall back to auto when the value is invalid.

This will make sure rendering always works even if the userinput is wrong.

Comment thread packages/guides-restructured-text/src/RestructuredText/TextRoles/LangTextRole.php Outdated
linawolf added a commit that referenced this pull request Sep 20, 2026
Review of #1393 asked for both: a direction is one of three things, so
an arbitrary string is the wrong type to carry it in, and the BCP 47
pattern was written out in full in three separate classes.

TextDirection now replaces the string everywhere a direction is carried
-- the container option, the document metadata, the inline node -- so
the three places that accept one no longer each keep their own list of
what is valid. A direction that is none of the three is still reported,
and is now read as "auto" rather than passed through: an attribute the
browser works out for itself is a worse answer than the right one and a
better answer than one that means nothing. Going through the enum also
makes ":dir: RTL" work, which used to warn.

The language tag pattern moves to the Language interface, the one place
the three classes that check a tag now read it from.

Signed-off-by: linawolf
Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@linawolf

Copy link
Copy Markdown
Contributor Author

@jaapio changes applied, please have another look

Resolves #1266
Resolves #1267

Authors had no way to mark a block, a run of inline text, or a whole
page as being in a different language or text direction, so the
rendered HTML never got the lang/dir attributes needed for correct
rendering (e.g. RTL scripts, screen readers, correct font/glyph
shaping). The maintainers asked what concrete output this should
produce.

docutils/Sphinx were checked for prior art before designing this:
- Document level: neither has any per-document mechanism at all (only
  project-wide build config), so nothing to align with there.
- Inline level: docutils' own FAQ recommends exactly `:rtl:`/`:ltr:`
  roles for this, just via `.. role::` boilerplate the author has to
  write themselves; this makes them built-in instead.
- Block level: docutils has `.. class:: language-<tag>` and
  `.. class:: rtl`/`ltr`, but that's CSS-only styling hooks with no
  real HTML lang/dir attribute, so it doesn't actually address the
  accessibility problem these issues are about. Kept our own
  `:lang:`/`:dir:` container options, which do emit real attributes.

This reuses existing mechanisms at three levels rather than inventing
new directives:

- Block-level: `:lang:`/`:dir:` options on the existing `.. container::`
  / `.. div::` directive.
- Inline-level: new `:rtl:`/`:ltr:` roles for pure direction switches,
  and a combined `:lang:` role (`` :lang:`text (language, direction)` ``)
  for text tagged with both, following the same trailing-`(...)`
  convention as the existing `:abbreviation:` role.
- Document-level: new `:lang:`/`:dir:` field-list metadata, mirroring
  the existing `:template:` field, setting the page's own `<html>` tag.

`dir` is validated against ltr/rtl/auto and `lang` against a loose
BCP 47 shape; both are warn-only diagnostics, never blocking, matching
the ValueType validation philosophy already used elsewhere.

Signed-off-by: linawolf
Assisted-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PP4LkejR5PSubbhNmF4RkT
Review of #1393 asked for both: a direction is one of three things, so
an arbitrary string is the wrong type to carry it in, and the BCP 47
pattern was written out in full in three separate classes.

TextDirection now replaces the string everywhere a direction is carried
-- the container option, the document metadata, the inline node -- so
the three places that accept one no longer each keep their own list of
what is valid. A direction that is none of the three is still reported,
and is now read as "auto" rather than passed through: an attribute the
browser works out for itself is a worse answer than the right one and a
better answer than one that means nothing. Going through the enum also
makes ":dir: RTL" work, which used to warn.

The language tag pattern moves to the Language interface, the one place
the three classes that check a tag now read it from.

Signed-off-by: linawolf
Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@linawolf
linawolf force-pushed the task/container-lang-dir branch from dd1eac2 to 486f2cb Compare October 1, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to specify text language in ReST Ability to specify text direction in ReST

2 participants