60db Logo
  • Guides

RTL text and spoken audio in an Arabic-English voice UI

RTL Arabic-English voice UIs need logical text, isolated display spans, stable segment references, and explicit audio alignment.

Editorial date
Reading time
26 min
One logical source remains separate from directional display blocks and an audio reference

TL;DR: Store Arabic-English transcripts in logical order, isolate inserted opposite-direction text with semantic markup, and bind audio through stable segment identity plus an explicit revision-alignment policy. Static text tests can verify serialization and lookup rules, while actual display, clipboard, keyboard, screen-reader and speech outcomes require separate browser or device observations.


An English identifier appears inside an Arabic transcript. The punctuation shifts, so a developer reverses the stored string to make one screenshot look right. Copying the identifier now returns the wrong logical value, and a later transcript revision sends the play control to the wrong audio segment.

Display order, source identity and audio association have become one fragile coordinate system. Fix the boundaries rather than compensating for one rendering result by mutating the source.

Begin with one logical transcript and independent projections. Keep source code points intact, declare language and direction separately, isolate inserted phrases, and use segment identity instead of visual character position for audio lookup.

The multilingual task guide explains the broader task boundary. This guide provides a standard-library static HTML fixture and negative checks for escaping, typed markup metadata and stale audio alignment.

The fixture is synthetic. It does not implement a bidi renderer, play audio, exercise a clipboard or screen reader, establish pronunciation quality or reveal private 60db Agent architecture.

Table of contents

  1. Separate logical order from visual order
  2. Declare language and base direction independently
  3. Isolate inserted identifiers
  4. Bind audio by segment and alignment revision
  5. Run the static fixture generator
  6. Inspect the generated evidence
  7. Test copy and paste at the actual boundary
  8. Review keyboard and reading sequence
  9. Keep identifier policy separate from display
  10. Preserve speech preparation as another projection
  11. Review transcript revisions
  12. Plan a browser and device matrix
  13. Audit the serialized structure before opening a browser
  14. Separate source fidelity from clipboard fidelity
  15. Review alignment evidence after every material revision
  16. Record manual observations as observations
  17. Keep the claim matched to the completed check
  18. Exercise the smallest complete fixture first
  19. Frequently asked questions
  20. Begin with one isolated identifier

Separate logical order from visual order

Logical order describes the source sequence of characters. Visual order describes how the rendering system positions them under the bidirectional layout rules and surrounding context.

The Unicode Bidirectional Algorithm defines display behavior for mixed-direction text. It does not instruct an application to reverse its canonical strings to resemble one observed screen arrangement.

Keep one source representation and derive display from it. A screenshot can look correct while the source string is wrong, just as a correct source can be displayed confusingly when the surrounding direction or isolation is missing.

For identifiers, compare logical values under the declared field policy. Do not compare glyph positions or assume that similar appearance establishes identity. The names and product-label guide explains why visual similarity and approved entity mappings remain different contracts.

For transcripts, preserve stable segment identity independently of text length. A correction can add words before a value without changing which recorded segment the text describes. Character offsets tied to the old rendering can become invalid immediately.

The partial-transcript guide provides the revision boundary. Displaying a revised hypothesis should not silently turn it into a finalized command or restore a canceled spoken response.

A logical transcript supplies display and audio-reference projections independently

Declare language and base direction independently

Language metadata and base direction answer different questions. A language attribute can identify the intended language of content, while direction metadata tells the renderer the paragraph or span's directional context.

The W3C structural RTL guidance recommends semantic direction markup for document structures. Do not infer that setting a language code alone establishes the correct paragraph direction or that CSS appearance supplies the language for assistive technology.

Choose base direction from the field or content contract. A transcript paragraph, a literal identifier and a surrounding English application shell can legitimately use different directional contexts.

The static fixture uses a small allowlist of language and direction values. That is an inspectable teaching subset, not a complete language-tag validator. Untrusted text does not become an attribute value simply because it contains the letters of a locale code.

For content whose direction is genuinely unknown at insertion time, the chosen markup can use automatic direction under the relevant HTML contract. Test the actual content patterns, including strings beginning with numbers or punctuation, rather than assuming every mixed string has an obvious first strong character.

The Arabic digit guide explains why a glyph set does not establish field meaning. A direction choice likewise cannot select calendar, currency or identity context for the value it displays.

Keep these metadata fields in the fixture record. A screenshot without the source markup cannot explain whether an apparent ordering defect came from the literal text, its base direction, an inline boundary or a later layout transformation.

Isolate inserted identifiers

An inserted opposite-direction phrase needs a clear boundary. Without one, neighboring punctuation or numeric text can interact with its directional context in ways that surprise the reader.

The W3C inline bidi guidance describes tightly wrapping opposite-direction content and using direction-aware markup. For unknown inserted direction, it discusses automatic direction and the bdi element.

Treat the entire inserted value as the field unit. A literal identifier can contain punctuation that belongs inside its isolation boundary, while sentence punctuation can belong outside. Decide that ownership from the field contract rather than moving characters until one screenshot looks acceptable.

The reference represents text as immutable runs. An identifier run can be isolated without modifying its source code points. Concatenating the logical run text reconstructs the original fixture string; the wrapper changes the serialized presentation, not the identity value.

The order-ID and email guide provides examples of why punctuation ownership matters. A dot or hyphen can be part of the identifier rather than decoration that a UI may discard.

Do not add invisible controls to canonical identifiers as a general layout workaround. Prefer appropriate markup at the presentation boundary and keep any identifier-specific control policy explicit. Normal prose and canonical IDs can require different treatment.

An opposite-direction identifier is isolated inside its paragraph with an explicit punctuation boundary

Bind audio by segment and alignment revision

A stable segment ID prevents visual offsets from becoming lookup keys. It does not prove that audio associated with an earlier text revision still aligns with the corrected text.

The fixture therefore uses a separate binding with segment identity and reviewed text revision. A binding is usable only when that revision matches the current segment. Otherwise the generated evidence says alignment pending instead of presenting the old association as current.

This is a narrow metadata check. The adapter or reviewer supplying the binding owns the actual alignment claim. Equality of revision numbers cannot prove that the recording contains the displayed words or that a synthesized clip pronounces them correctly.

A revised transcription of the same source recording may legitimately retain the source clip after alignment review. A newly synthesized reply may need a new audio asset. The application must declare which kind of reference it stores rather than using a single vague audio field for both.

The playback evidence guide adds another boundary. A current binding can identify a clip without establishing local playback, acoustic audibility or comprehension.

The static page contains evidence links, not functioning playback controls. It allows a reviewer to inspect the declared binding while keeping actual audio transport and device behavior outside the program's claim.

Run the static fixture generator

Save the complete fence as rtl_fixture.py and run Python 3.12 or later. Standard output is a standalone synthetic HTML document. Redirect it to a chosen local file if you want to perform the manual browser checks; the program itself writes no files or network requests.

Trusted inputs are declared segment metadata and owner-reviewed alignment bindings. The generator owns its supported immutable value shape, escaping, serialized ordering and revision-equality checks. It does not prove browser layout, clipboard behavior, assistive-technology output or audio correctness.

from dataclasses import dataclass, FrozenInstanceError
from html import escape
from html.parser import HTMLParser
import re
import unicodedata


LANGUAGES = ("ar", "en", "und")
DIRECTIONS = ("rtl", "ltr", "auto")
CONTROLS = frozenset(chr(n) for n in
                     (0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
                      0x2066, 0x2067, 0x2068, 0x2069))


def valid_id(value):
    return type(value) is str and re.fullmatch(r"[a-z][a-z0-9-]{0,31}", value) is not None


@dataclass(frozen=True)
class Run:
    text: str
    language: str
    direction: str
    identifier: bool = False

    def __post_init__(self):
        if (type(self.text) is not str or type(self.language) is not str
                or type(self.direction) is not str or self.language not in LANGUAGES
                or self.direction not in DIRECTIONS or type(self.identifier) is not bool):
            raise ValueError("supported text run metadata required")


@dataclass(frozen=True)
class Segment:
    identity: str
    revision: int
    language: str
    direction: str
    runs: tuple

    def __post_init__(self):
        if (not valid_id(self.identity) or type(self.revision) is not int
                or self.revision < 0 or type(self.language) is not str
                or type(self.direction) is not str or self.language not in LANGUAGES
                or self.direction not in DIRECTIONS):
            raise ValueError("supported segment metadata required")
        snapshot = tuple(self.runs)
        if not snapshot or any(type(r) is not Run for r in snapshot):
            raise ValueError("typed runs required")
        object.__setattr__(self, "runs", snapshot)

    @property
    def logical_text(self):
        return "".join(r.text for r in self.runs)


@dataclass(frozen=True)
class Binding:
    segment: str
    text_revision: int
    reference: str

    def __post_init__(self):
        if (not valid_id(self.segment) or type(self.text_revision) is not int
                or self.text_revision < 0 or type(self.reference) is not str
                or not self.reference.strip()):
            raise ValueError("reviewed binding metadata required")


def render(segments, bindings):
    segments, bindings = tuple(segments), tuple(bindings)
    if any(type(s) is not Segment for s in segments) or any(type(b) is not Binding for b in bindings):
        raise ValueError("typed fixture values required")
    ids = {s.identity for s in segments}
    if len(ids) != len(segments) or len({b.segment for b in bindings}) != len(bindings):
        raise ValueError("duplicate segment or binding identity")
    if any(b.segment not in ids for b in bindings):
        raise ValueError("binding has no segment")
    by_id = {b.segment: b for b in bindings}
    output = ['<!doctype html><html lang="en" dir="ltr"><head><meta charset="utf-8">',
              '<title>Synthetic Arabic-English transcript fixture</title></head><body>',
              '<h1>Synthetic transcript fixture</h1>',
              '<p>Browser, clipboard, screen-reader and audio outcomes are unmeasured.</p>',
              '<p>Unicode database: ' + escape(unicodedata.unidata_version) + '</p>']
    for segment in segments:
        binding = by_id.get(segment.identity)
        aligned = binding is not None and binding.text_revision == segment.revision
        flagged = any(r.identifier and any(c in CONTROLS for c in r.text)
                      for r in segment.runs)
        output.append('<section id="segment-' + segment.identity + '"><h2>' +
                      escape(segment.identity) + '</h2>')
        output.append('<p class="transcript" data-segment="' + segment.identity +
                      '" data-revision="' + str(segment.revision) + '" lang="' +
                      segment.language + '" dir="' + segment.direction + '">')
        for run in segment.runs:
            tag = 'bdi' if run.identifier else 'span'
            output.append('<' + tag + ' lang="' + run.language + '" dir="' +
                          run.direction + '">' + escape(run.text, quote=True) +
                          '</' + tag + '>')
        output.append('</p>')
        if flagged:
            output.append('<p>Identifier control policy review required.</p>')
        output.append('<a href="#evidence-' + segment.identity + '">Inspect audio binding</a>')
        evidence = binding.reference if aligned else 'Alignment pending'
        output.append('<p id="evidence-' + segment.identity + '">' +
                      escape(evidence, quote=True) + '</p></section>')
    output.append('<!-- Synthetic static fixture; manual outcomes unmeasured. -->')
    output.append('</body></html>')
    return ''.join(output)


class Inspect(HTMLParser):
    def __init__(self):
        super().__init__(convert_charrefs=True)
        self.active = None
        self.transcripts = {}
        self.tags = []
        self.links = []

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        self.tags.append(tag)
        if tag == 'p' and attrs.get('class') == 'transcript':
            self.active = attrs['data-segment']
            self.transcripts[self.active] = ''
        if tag == 'a':
            self.links.append(attrs.get('href'))

    def handle_endtag(self, tag):
        if tag == 'p':
            self.active = None

    def handle_data(self, data):
        if self.active is not None:
            self.transcripts[self.active] += data


def tests():
    source = [Run('مرجع تجريبي: ', 'ar', 'rtl'),
              Run('DEMO-0123', 'en', 'ltr', True), Run('.', 'ar', 'rtl')]
    first = Segment('demo-a', 0, 'ar', 'rtl', source)
    source.clear()
    unsafe = Segment('demo-b', 0, 'en', 'ltr',
                     (Run('<img src=x onerror=alert(1)>', 'en', 'ltr'),))
    binding = Binding('demo-a', 0, 'synthetic-recording-a')
    page = render((first, unsafe), (binding,))
    inspected = Inspect()
    inspected.feed(page)
    assert inspected.transcripts['demo-a'] == first.logical_text
    assert inspected.transcripts['demo-b'] == unsafe.logical_text
    assert 'img' not in inspected.tags and 'script' not in inspected.tags
    assert 'bdi' in inspected.tags
    assert inspected.links == ['#evidence-demo-a', '#evidence-demo-b']
    revised = Segment('demo-a', 1, 'ar', 'rtl',
                      (Run('نص تجريبي أطول: ', 'ar', 'rtl'),
                       Run('DEMO-0456', 'en', 'ltr', True)))
    assert 'Alignment pending' in render((revised,), (binding,))
    assert 'synthetic-recording-a' in render((revised,),
               (Binding('demo-a', 1, 'synthetic-recording-a'),))
    controlled = Segment('demo-control', 0, 'en', 'ltr',
                         (Run('DEMO-\u202e123', 'en', 'ltr', True),))
    assert 'Identifier control policy review required.' in render((controlled,), ())
    assert controlled.logical_text == 'DEMO-\u202e123'
    for bad in (lambda: render((first, first), ()),
                lambda: render((first,), (binding, binding)),
                lambda: render((first,), (Binding('missing', 0, 'demo'),)),
                lambda: Segment('bad\"id', 0, 'ar', 'rtl', first.runs),
                lambda: Segment('valid', True, 'ar', 'rtl', first.runs),
                lambda: Run('text', 'ar\" onclick=bad', 'rtl')):
        try:
            bad()
        except ValueError:
            pass
        else:
            raise AssertionError('invalid fixture accepted')
    for target, field, value in ((first, 'runs', ()),
                                 (first.runs[0], 'text', 'changed')):
        try:
            setattr(target, field, value)
        except FrozenInstanceError:
            pass
        else:
            raise AssertionError('fixture snapshot was writable')
    return page


if __name__ == '__main__':
    print(tests())

The Arabic strings are synthetic display fixtures, not verified dialect utterances or pronunciation references. The generator prints actual inspectable markup, and its serialized text checks preserve the logical run content without claiming that a real browser or assistive technology was exercised.

Inspect the generated evidence

The document keeps transcript sections in the supplied logical sequence. Each section contains a stable segment identity, text revision, declared language/direction and a link to its audio-binding evidence.

The inline identifier uses bdi markup while its literal source remains unchanged. HTML-looking caller text is escaped as text, so the inspection parser observes no injected image or script element in the supported fixture.

The Python Unicode database documentation explains the runtime version printed by the page. That version is execution metadata, not a claim that Python implements browser bidirectional layout.

The revised-text fixture deliberately keeps an old binding and expects alignment pending. A separately supplied binding for the current text revision can restore the declared association after the adapter's actual review. The code tests the revision contract, not the truth of that review.

The generated link is an internal evidence anchor. It does not fetch a caller-supplied URL, start a player or certify the sound of a recording. Keep those boundaries clear when adapting the fixture into an application component.

The observability guide provides the larger tracing framework. Join source text, revision, markup and binding evidence without copying private recordings or identifiers into every log.

Test copy and paste at the actual boundary

A serialized string equality test is useful, but it is not a clipboard test. Browser selection, platform behavior and any copy handler can affect the value actually placed on the clipboard.

Open the generated fixture in the target environment and copy the isolated identifier through the real interaction path. Inspect the pasted logical value in a controlled destination and compare its code points with the expected source, preserving any controls for review rather than relying on visual resemblance.

Keep normal selection and application-provided copy controls as separate cases if both exist. A custom handler may use another field, include a label or normalize the value. Test the code path users actually invoke.

The literal identifier guide explains why a leading zero remains meaningful even when a numeric display looks familiar. The same literal discipline applies across the clipboard boundary.

A copied logical string is compared with the source rather than accepted from appearance alone

Record the actual browser, operating system and interaction method when a clipboard case is executed. This article reports no measured clipboard outcome and does not label its text-parser assertion as an end-to-end copy pass.

Review keyboard and reading sequence

Directionality can affect visual arrangement without changing the meaningful sequence that users need to navigate. Preserve the intended document order and test the actual keyboard and assistive-technology paths separately.

WCAG's meaningful-sequence guidance addresses programmatically determinable reading order where sequence affects meaning. Meeting that principle needs the relevant page structure and actual interaction evidence, not only a screenshot.

The fixture supplies semantic sections, transcript paragraphs and ordinary internal links. Its parser checks emitted link order, but that does not prove a browser's focus traversal or a screen reader's spoken output under a particular configuration.

Use the real review matrix to inspect focus order, segment association and language announcements. Note the exact assistive technology and settings. If the application adds live transcript updates, test how those updates affect reading position rather than assuming a static-page check covers them.

The progressive no-input prompt guide highlights another interaction boundary. A user consuming information through assistive technology may need a task-appropriate timing policy; a transcript's visible direction does not establish readiness to answer.

DOM sequence, keyboard traversal and screen-reader order are independent checks against transcript order

Do not mirror every control mechanically. The meaning of media actions and navigation needs the actual interaction contract. Verify labels, focus and behavior in the intended context rather than deriving action semantics from the paragraph's writing direction.

Keep identifier policy separate from display

Bidirectional controls can affect appearance. The fixture flags selected controls inside identifier runs under its declared policy while preserving the original logical source for inspection.

Unicode security mechanisms describe confusable and mixed-script considerations. A flagged control is evidence for the field's review policy, not proof of malicious intent and not permission to rewrite the identifier silently.

Normal prose and canonical identifiers can have different legitimate requirements. Keep the identifier boundary explicit so a broad display cleanup does not remove meaningful content or introduce an undocumented equality rule.

Unicode normalization defines textual forms, while identity matching remains a separate task contract. A normalized projection can be useful for an approved comparison without replacing the raw literal or proving that two displayed values identify the same entity.

The Arabic name guide provides the related alias boundary. Similar appearance, canonical equivalence and approved catalog identity should remain separate evidence fields.

The static page never uses untrusted source text as an element name or unrestricted attribute. Its small metadata allowlists and generated internal IDs keep text content from becoming structure. A real application must preserve that separation through its own renderer and event handlers.

Preserve speech preparation as another projection

A speech request can need a different representation from the transcript's visual markup. Do not send a reversed display string to a synthesizer or assume that HTML language/direction attributes become speech-engine instructions.

The mixed-script TTS guide explains the adapter boundary. Preserve logical text and construct only supported trusted markup around serialized content, with actual engine support checked separately.

The pronunciation-dictionary guide describes another independent policy. An approved spoken preference can affect rendering while leaving canonical spelling and transcript identity unchanged.

Keep the speech request and output joined through their own identity and revision. A revised transcript label can describe source audio, while a revised generated reply can require newly synthesized output. The audio-binding contract should say which relationship the UI exposes.

The playback acknowledgment guide explains why even a correct speech request and current binding cannot establish that the caller heard or understood the result.

A static layout trial can identify a confusing display or association defect. It cannot validate Arabic pronunciation, dialect authenticity or physical speaker behavior. Use qualified linguistic and listening review when those claims become part of the task.

Review transcript revisions

A transcript revision can change text length, punctuation, segmentation or an intended value. Preserve the source observation and the current revision rather than mutating a supposedly finalized record in place.

The spoken correction guide explains why a repaired value can invalidate earlier confirmation. The UI should reflect the current task state without erasing the fact that an earlier value was displayed or spoken.

The reference's stable segment ID supports lookup across changed text length. Its alignment revision prevents the ID from becoming a shortcut that treats old audio evidence as automatically current.

If segmentation itself changes, the owning adapter needs an explicit split/merge mapping or new segment identities. This fixture does not infer a mapping from visual position. A different DOM index is not evidence that two revisions describe the same clip.

The stale-audio guide provides the delivery boundary for generated speech. Updating a transcript does not cancel audio that another consumer already owns; final media admission needs its own current-state checks.

Segment identity and reviewed text revision govern the audio binding instead of fragile character offsets

Plan a browser and device matrix

Choose the environments that matter for the actual interface, including relevant desktop/mobile browsers, input methods and assistive technologies. The matrix is a test plan until each case has an observed result.

Use the same logical source fixtures across environments. Record direction metadata, isolated spans, punctuation placement and the actual interaction performed. A platform-specific workaround should not quietly change the canonical source and make the comparison meaningless.

The mobile-browser guide illustrates why desktop behavior does not establish device behavior. Layout, selection and audio interactions need their own observations in the supported environment.

Keep the evidence boundaries in the result table. A serialized markup assertion, visual inspection, clipboard comparison, keyboard trial and screen-reader trial are different kinds of checks and can pass or fail independently.

A check in the following table means the evidence can establish the named property at its declared boundary. A cross means it cannot establish that property alone.

Criterion Serialized fixture test Browser interaction Qualified audio review
Preserves logical text in emitted markup ✓ Supported generator contract ✓ If explicitly compared ✗ Different boundary
Establishes actual clipboard output ✗ ✓ Executed copy/paste case ✗
Establishes actual keyboard/screen-reader behavior ✗ ✓ With the relevant technology exercised ✗
Establishes recorded speech quality ✗ ✗ By itself ✓ Under declared review conditions
Proves entity identity or business completion ✗ ✗ ✗

The regression-testing guide explains how to preserve a discovered issue. Retain the original logical fixture, markup and environment details instead of storing only an image of the incorrect display.

Audit the serialized structure before opening a browser

Start with the output the generator actually emits. Inspect the document language, paragraph direction, inline boundaries, generated IDs and evidence links before interpreting a visual result.

The reference keeps text inside escaped content. Its metadata fields use a small supported allowlist, and its internal identifiers use a restricted generated-name grammar. Those choices prevent a caller's transcript from becoming an element name, event-handler attribute or external resource URL.

The inspection parser checks only the supported serialized structure. It can observe that no injected image or script tag was produced by the malicious-looking text fixture. It cannot establish a full browser conformance result or prove the behavior of every possible renderer used by a larger application.

Test the actual renderer integration separately if the fixture is adapted into a framework component. A template can reintroduce unsafe HTML handling even when an earlier helper escaped the string. Preserve the raw value and the exact emitted markup at the integration boundary.

A historical question about English words appearing shuffled in Arabic-script text illustrates the visible symptom. The old editor-specific answers are not the contract for a current web UI; use the cited W3C markup guidance and actual browser observations.

Keep the fixture's source and markup snapshots together. If a later screenshot looks different, those records let a reviewer determine whether the logical value changed or only the display context changed.

Do not add controls to the stored string merely because an output parser preserves them. Serialization fidelity and appropriate identifier policy answer different questions. A value can round-trip exactly while remaining unsuitable for a particular field's accepted repertoire.

Separate source fidelity from clipboard fidelity

The source assertion reconstructs logical text from emitted transcript content. That establishes the generator's own escaping and ordering behavior for the supplied fixture, including the inserted identifier and adjacent punctuation.

The clipboard case begins later. A browser can expose several selection or copy paths, and an application can add a handler that copies a different representation. Record which interaction is under test instead of labeling all of them with one broad copy result.

For a controlled manual comparison, retain the expected logical string outside the displayed component. Copy through the actual user path, paste into a test destination and inspect exact code points or an escaped representation. Comparing two visually similar screenshots would not detect a hidden directional control or a changed zero.

A historical TTS question about non-ASCII characters disappearing supplies a related boundary lesson. A string printed correctly in one process does not prove that every later transport or speech adapter received it unchanged. That old report does not establish a current provider defect.

Keep encoding boundaries explicit when storing a fixture. This program works with Python Unicode strings and emits UTF-8-declared HTML. It preserves logical code points within its supported input shape; it does not claim byte-for-byte preservation of an original recording, request body or independently encoded source file.

If an application must retain original encoded bytes, store those bytes and their declared encoding under the evidence policy. Do not reconstruct them later from a normalized display string and call the reconstruction original evidence.

The phone-identifier guide provides another practical reason for that separation. A correctly displayed field can still lose meaningful structure when copied into a numeric destination.

Review alignment evidence after every material revision

A stable segment identity solves only the lookup problem. It says which logical segment the application is discussing, while the alignment revision says which text state the supplied audio association was reviewed against.

When text changes, keep the current segment revision and old binding separate. The reference shows alignment pending until a binding explicitly matches the current text revision. That prevents a UI from presenting an obsolete association as current merely because the segment ID stayed the same.

The actual review can take different forms depending on the reference type. For a source recording, a reviewer may establish that the same clip still covers the corrected transcript segment. For newly generated speech, the application may need another clip whose content belongs to the new response.

Do not collapse those meanings into a generic cached audio entry. Record whether the reference points to captured source material, a synthesized reply or another declared asset type. A matching ID does not make those assets interchangeable.

The spoken-answer cache guide explains the larger validity boundary. An asset can remain available after the facts or intent that made it useful have changed. Availability alone cannot restore current playback permission.

The fixture does not play either old or new audio. Its internal links expose evidence records only. If a real component adds a player, its final admission must recheck current response ownership, age and any required clear barrier immediately before local submission.

Review split and merge cases explicitly. A transcript engine can divide one segment into several or combine neighboring material. The adapter needs a supported mapping or new identities; deriving the association from a visual index would make the result depend on layout rather than source evidence.

Record manual observations as observations

A test matrix can list expected behavior before execution, but that list is not evidence that any environment passed. Give each executed case an environment identity, input fixture version, interaction method and observed disposition.

For visual inspection, record the actual rendered layout and the logical source used. For keyboard review, record the control sequence and whether focus reaches the intended segment evidence. For screen-reader review, record the actual technology and settings rather than assuming all assistive tools interpret the page identically.

A useful result can remain unresolved. If a reviewer cannot establish the pasted logical value or audio alignment, preserve that missing observation. Do not convert it into a pass simply because the screenshot or printed markup looks plausible.

Keep expected and actual fields separate in the review record. The generator's assertion tells a reviewer what the supported fixture is intended to emit. The browser or device observation tells them what happened in that environment. Combining the two before execution can turn a test plan into fabricated evidence.

A narrow failure should lead to a narrow repair. Incorrect inline punctuation can require a boundary change. Incorrect copy output can involve the copy handler. A stale audio association can require a revision-binding repair. Reversing the source string is not a substitute for locating the affected boundary.

The interruption-safety guide provides the ownership lesson for live interaction. A display correction should not revive audio or authorization that another current event has already invalidated.

Retain the original failing fixture after a repair. A later layout or component change can reintroduce the issue while leaving the core source data untouched. The regression needs both the source contract and the actual integration boundary that failed.

Keep the claim matched to the completed check

Read the final report using the same boundary names as the fixture. A passed serialized-text assertion establishes emitted source fidelity. It does not establish clipboard fidelity, meaningful spoken announcements or an acceptable pronunciation.

A passed browser copy case establishes the observed path in the recorded environment. It does not prove that another platform, input method or custom handler behaves the same way. Expand coverage by adding cases rather than broadening the wording of a single result.

A qualified audio review establishes its own supplied material and listening conditions. It cannot authenticate the named entity or establish that a business action was authorized. Keep the task-outcome boundary separate even when the UI and audio both appear correct.

Public examples should remain synthetic and avoid actual customer names, phone identifiers or clip references. The purpose is to make logical order, markup and revision behavior inspectable, not to reproduce a private conversation in a public artifact.

When reporting a release, name the checks that were completed and the ones still pending. The static program can be complete within its declared contract while a real browser or accessibility review remains unexecuted. That precise limit helps the next engineer continue the work without mistaking an offline fixture for a device benchmark.

Exercise the smallest complete fixture first

Begin the manual trial with one paragraph containing one isolated synthetic identifier and sentence punctuation. Record the expected logical value before opening the page so a later display judgment cannot change what the comparison is supposed to preserve.

Inspect the source metadata next. Confirm the paragraph language, base direction, identifier wrapper and field boundary. Then inspect the actual browser layout. If the punctuation appears incorrect, keep the original source and capture the surrounding markup before attempting a repair.

Move to copy and paste only after the source contract is understood. Use the declared interaction path and a controlled destination that permits logical-string inspection. Keep the actual pasted value as evidence, including an explicit escaped representation when invisible controls could affect interpretation.

Exercise the internal evidence link through the keyboard path. Confirm which segment it references and which alignment revision is presented. The static generator's link-order assertion is a useful precheck, while actual focus and assistive-technology behavior still need the recorded environment.

Then apply a transcript revision that changes text length and the identifier. Retain the earlier audio binding. The fixture should expose alignment pending, demonstrating that stable identity cannot bypass the revision rule. Supply a current reviewed binding only when the owning adapter has established that relationship.

Add the HTML-looking text case to ensure the integration still treats source content as text. A correct string in the helper is insufficient if a later component interprets it as markup. Keep the test at the boundary where the final application renderer emits content.

Finally review the identifier-control case under the declared field policy. Its source remains available while the UI supplies a review warning. The warning does not prove an attack, and removing the control without recording a policy decision would replace fidelity with an undocumented transformation.

This sequence yields several small observations that can be assessed independently. It avoids a large demonstration in which display, copying, reading order and audio all change together and leave the first broken boundary unclear. Extend the matrix only after the basic fixture is reproducible, and preserve every environment's observed result separately from the expected behavior.


Frequently asked questions

Why is visual order different from logical order?

Bidirectional rendering positions mixed-direction characters under a display algorithm and context. The source sequence remains the logical value and should not be reversed to imitate one screenshot.

Should I reverse an Arabic transcript string?

No. Preserve logical source order and fix the presentation metadata or isolation boundary. Reversing storage can break copying, serialization, identity comparison and audio association.

What does dir=rtl control?

It declares a right-to-left base direction for the relevant HTML context. It does not select a language, identify a speaker or establish pronunciation correctness.

How is lang different from dir?

Language metadata identifies the intended language, while direction metadata establishes directional context. Set and test them separately rather than treating either as a substitute for the other.

When should a UI use bdi?

Use an isolation boundary for inserted content under the applicable HTML contract, especially when its direction is unknown. The fixture uses bdi for explicit identifier runs and preserves their logical text.

When is dir=auto appropriate?

Use it when the inserted content's direction is genuinely unknown and the component contract supports automatic direction. Test representative values, including punctuation and numeric prefixes, in the actual browser.

Why do numbers and punctuation move unexpectedly?

Their placement depends on directional context and inline boundaries. Inspect the source, base direction and phrase isolation before mutating or deleting characters to match a screenshot.

Should CSS alone set base direction?

Use semantic direction markup following the document contract. CSS layout can complement it, while language, reading sequence and field identity still need their own explicit structure.

How do I isolate an English order ID?

Wrap the complete field at the presentation boundary with the appropriate direction/isolation markup. Decide which punctuation belongs to the identifier and preserve the original logical value.

What should copy and paste return?

The intended logical field value under the component's copy contract. Verify it through the real clipboard interaction; a serialized text assertion does not establish that outcome.

How should transcript segments reference audio?

Use stable segment identity with an explicit reviewed alignment revision. The reference refuses to present an old binding as current when its text revision differs.

Can character offsets survive revisions?

They can become invalid when text length, segmentation or rendering changes. Do not use visual offsets as a substitute for stable identity and the owning adapter's alignment policy.

How do I expose reading order to assistive technology?

Provide meaningful semantic document sequence and appropriate language metadata. Then exercise the actual screen reader and configuration; the static parser cannot prove its spoken output.

Should playback controls be mirrored?

Do not infer every control's semantics from paragraph direction. Test the intended media actions, labels, focus order and behavior within the actual interaction design.

How should untrusted transcript text be escaped?

Serialize it as text inside trusted structure, keeping element names and attributes under the renderer's contract. The fixture uses escaped content, allowlisted metadata and generated safe internal IDs.

Are bidi controls proof of an attack?

No. Their presence can trigger a declared identifier review policy while preserving raw evidence. Normal prose and canonical identifiers can have different legitimate requirements.

What should identifier equality compare?

Compare logical values under the explicit field policy. Visual resemblance, a direction setting or Unicode normalization alone cannot establish person identity or an approved catalog mapping.

Which checks need a real screen reader?

Reading sequence, language announcements and actual assistive-technology behavior require the technology to be exercised. The fixture verifies only its serialized markup and lookup rules.

Can a static page prove TTS pronunciation?

No. It can preserve source and binding metadata, while pronunciation and acoustic output require a supported speech adapter and qualified listening evidence.

What mobile fixtures belong in the review?

Use the supported browsers, input methods and interaction paths relevant to the application. Preserve logical text and test visual layout, selection, copying, focus and audio association separately.

Begin with one isolated identifier

Run the complete fence and inspect the emitted source. Confirm that untrusted text remains text, the original logical identifier is retained and a stale alignment revision produces pending evidence.

Then open the fixture in an explicitly recorded target environment and execute the manual visual, clipboard and accessibility cases. Keep those observations separate from the standard-library assertions.

The first useful result is one source representation whose display and audio associations can be checked independently. Preserve that contract before adding live transcript updates, speech controls or broader language support.