langaccess

Language access on a website, per language

A submitted address is rendered in a headless browser and read the way a visitor's browser would read it. The tool returns a classification of the access the site provides, the languages found, and for each language the mechanism, the URL, and the quoted text supporting the reading. Machine translation is a class of its own, recorded as an offering the site makes and kept separate from text the site itself carries.

Address to measure

Address read
Languages
Translation widget
Pages read

Evidence

MechanismLanguageWhereWords

The classes

english_only. No non-English text was found on the routes the instrument follows. The claim is an absence claim bounded by those routes, and it is worth what the search behind it was worth: every result carries a read-quality record saying how deep that search went, and a thin one goes to a person instead of standing as a verdict.

machine_translate. The site offers a translation widget and no non-English text was found outside the widget's output. Widgets add language links, /es/ paths and in some cases hreflang declarations, the same observable signals a site-authored translation produces. The two are recorded separately because widget output is not the site's own text and is unavailable whenever the widget does not load.

machine_translate_error. The site carries a translation widget, a control on it was operated, and the page did not change. What that establishes is that this automated browser could not obtain a translation through the widget on that date; a widget can work in one browser and not another, so this is not a finding that the widget is broken for every visitor and it is not an absence of language access. Open the site and operate the control before acting on it.

true_multilingual. Non-English text that a browser-side widget cannot have produced: a server-side translation plugin, non-English text in the document the server sent, or a separate page whose content is not a repetition of the English page.

unreachable is a read outcome and not a class of access. The site was not read, owing to a bot wall, a timeout, or an empty response. It is held separate from english_only because a site that blocks the instrument has not been shown to lack language access, and merging the two would record unmeasured sites as measured ones.

The five names are labels and not an order. A site is not better for appearing further down the list, and nothing here ranks one class above another.

The limit of this check

This describes what one website presented to a crawler on one day. It is not a determination of compliance with any federal or state law, with any regulation made under one, or with any professional guidance on interpretation, and this tool holds no threshold at which a site becomes adequate. Nothing here has been reviewed by a lawyer or by any agency, and no part of it should be quoted as a finding of adequacy or of failure.

A website is not a service. Whether a person can obtain help in a language turns on the telephone line, the intake desk, the interpreter roster and the hours at which somebody answers. None of that is stated on a website and none of it is read here. The reading also does not judge how good a translation is, and where it found no text in a language, that covers the pages it opened and nothing else: a page it never opened, a document behind a download link, and content behind a login are all outside it.

The same check, locally

pip install langaccess
python -m playwright install chromium

langaccess https://example.org
langaccess --deep --timeout 240 --json https://example.org
from langaccess import audit

r = audit('https://example.org', deep=True, timeout=240)
r.verdict      # english_only | machine_translate | machine_translate_error
               #  | true_multilingual | unreachable
r.languages    # ['Chinese', 'English', 'Spanish']
r.evidence     # [Evidence(mechanism=..., url=..., quote=..., language=...), ...]

Studies covering more than a handful of sites should use the package directly. This page holds one browser per request and is rate limited accordingly.