37 Audits
🌐

Localization

SEO Auditor

Finds localized pages still showing default-language text

i18nSEOContent
2 credits
Per check
~30 seconds
Average runtime
Active
Status

How it works

  1. Fetch the audited page with 37AuditsBot's user agent, Web Bot Auth signature and the URL's Basic Auth. HTTP 403, HTTP 429 or a Cloudflare challenge is ERROR (590); any other failure is ERROR (500).

  2. Discover the localized versions β€” <link rel="alternate" hreflang="…" href="…"> first; when the page publishes none, <a hreflang href> then <a lang href> switcher links. The page itself, x-default and versions in the page's own language (en-GB for an en-US page) are dropped, and at most maxAlternates (default 10) are kept in document order. No version left is INFORMATION (100): the run is not charged.

  3. Fetch every version in parallel (five at a time, 40 s budget). A version that answers 403, 429, a Cloudflare challenge or a bot wall is WARNING (302); any other non-2xx answer or network error is FAIL (401).

  4. Compare the text β€” the body text nodes of each page outside script, style, noscript, template and svg, whitespace-collapsed, kept when they have at least 3 words containing a letter (or 6 letters in a script without word spaces, such as Japanese). A version's block counts as untranslated when it appears verbatim on the audited page, or when it has at least 8 words and a two-language detector (Lingua, loaded for the audited page's language and the version's only) attributes it to the audited page's language by a clear margin. Detection is skipped, and the reason recorded in data.languageDetection, when either language has no model, the audited page declares no language, or the two pages share a language.
    Text the markup hides at load time is left out of the count first, unless countHiddenText is on: an ancestor with the hidden or inert attribute or aria-hidden="true", an inline style with display:none, visibility:hidden or opacity:0, an <option>, a closed <dialog> or <details>, or a class such as hidden, hide, d-none, invisible or anything ending in -hidden (closed mega-menus, inactive tab panels, validation messages waiting for an error). Untranslated blocks found there are listed on the version's summary check in data.hiddenBlocks with the signal that hid them, so the percentage describes what a visitor sees while nothing is lost. Visually hidden text (sr-only, visually-hidden, screen-reader-text) stays counted: screen readers read it, so an untranslated skip link is a real defect. Text hidden by a stylesheet rule alone cannot be told apart from the markup and stays counted.
    Two further kinds of block are then left out of the count and recorded apart on the version's summary check: blocks that match the ignored terms (data.ignoredBlocks: the ignoredTerms preference plus the site's own name from its host, so "Liferay OEM Partner" or "Liferay vs. Adobe" with both names listed) and blocks that look like a name (data.nameLikeBlocks: at most five words besides connectors such as "vs." or "&", every one capitalised or an acronym, none a function or action word such as "a", "to", "you" or "apply", and no sentence punctuation at the end). "Digital Asset Management", "Gartner Peer Insightsβ„’", "IM Project Manager" and "Diamond Bar, CA 91765" are names; "Create An Account", "Request a demo", "Skip to Main Content" and "All Rights Reserved." are copy and stay counted.

  5. Judge each version β€” untranslated / blocks at or above untranslatedFailPercent (default 50) is FAIL (400); at or above untranslatedWarningPercent (default 5) is WARNING (300). Every version also gets one check per distinct untranslated block, in document order and capped at 50 per version, so the list of strings to translate is always in the result: WARNING (303) when the version reached the warning threshold, INFORMATION (101) when it stays under it. A version whose <html lang> primary subtag differs from the hreflang that points at it is FAIL (402); a page without <html lang> is WARNING (301).

  6. Aggregate β€” ERROR, then FAIL (400, 401, 402), then WARNING, else SUCCESS (200).

Up to five untranslated blocks are kept per version in data.samples, sentence-like copy first (ending punctuation, or mostly lower-case words) and Title Case labels last, so "Please enter a valid email address." is quoted before a product name.

What this auditor validates

Every row maps to one checkRule* method and one CheckCode. CheckCode suffixes use status ranges: 100 information, 200 success, 300–399 warning, 400–499 fail, 500–599 error.

CheckCodeStatusWhen it firesRecommendationWhy it matters
37A-LocalizationAuditor-100INFORMATIONThe page publishes no hreflang alternate and no language-switcher link to another language; nothing is compared and the run is not charged (the check carries notApplicable: true).If the site exists in other languages, add <link rel="alternate" hreflang="…"> for each version to "{url}" so visitors and search engines find them and this audit can compare them.β€”
37A-LocalizationAuditor-101INFORMATIONOne check per distinct text block still in the audited page's language on a localized version that stays under the warning threshold (at most 50 per version, in document order). The version passes; the check lists what is left to translate.Translate "{text}" into {hreflang} on "{variantUrl}".β€”
37A-LocalizationAuditor-300WARNINGA localized version keeps between untranslatedWarningPercent (inclusive) and untranslatedFailPercent (exclusive) of its text blocks in the audited page's language.Translate the remaining {baseLang} strings on "{variantUrl}" (menus, buttons, footer, form messages), starting with "{sample}", "{sample}", "{sample}"; if the {hreflang} version is not ready, remove it from the published alternates until it is.Visitors who pick their language and still meet untranslated menus, buttons or messages read the site as careless; the Liferay 2026 Website Localization Report found 56% of multilingual consumers walked away from a purchase over a poorly adapted site.
37A-LocalizationAuditor-301WARNINGThe audited page, or a fetched localized version, has no lang attribute on <html> (or an empty one).Set <html lang="{hreflang}"> on "{pageUrl}": the hreflang that points at it promises {hreflang}. For the audited page: set <html lang="…"> to the language the page is written in.Without a declared language, screen readers mispronounce the page and search engines may file it under the wrong language, so the translation reaches fewer of the people it was made for.
37A-LocalizationAuditor-302WARNINGA localized version answered HTTP 403, HTTP 429, a Cloudflare challenge or a bot wall, so it could not be compared.Allow 37AuditsBot on {host} (allowlist its user agent or verify its Web Bot Auth signature, see https://www.37audits.com/bot) so the {hreflang} version can be audited.A locale the auditor cannot read is a locale nobody is checking; problems on it stay invisible until a customer finds them.
37A-LocalizationAuditor-303WARNINGOne check per distinct text block still in the audited page's language on a localized version that reached the warning threshold (at most 50 per version, in document order).Translate "{text}" into {hreflang} on "{variantUrl}".Each untranslated menu item, button or message is a moment where a visitor who asked for their language is answered in another one; listing them one by one is what lets a translator fix them.
37A-LocalizationAuditor-400FAILA localized version keeps at least untranslatedFailPercent of its text blocks in the audited page's language.Translate "{variantUrl}" into {hreflang} before offering it as the {hreflang} version, or remove that alternate until the translation exists; today visitors who choose {hreflang} read {baseLang} content such as "{sample}", "{sample}", "{sample}".A language option that opens a page still written in the default language tells the visitor the brand did not bother; most leave, and the Liferay 2026 Website Localization Report found 32% lose trust in the brand itself.
37A-LocalizationAuditor-401FAILA localized version could not be fetched: a network error, a timeout or an HTTP status other than 2xx that is not a block.Fix or remove the {source} link to "{variantUrl}": a visitor choosing {hreflang} currently gets {HTTP 404 / error} instead of the page.A language link that leads to an error page loses the visitor at the moment they asked to be served in their language, and search engines drop broken alternates from results.
37A-LocalizationAuditor-402FAILA localized version declares a primary language on <html lang> other than the one the hreflang (or switcher link) promised for it.Make "{variantUrl}" declare lang="{hreflang}", or point the {hreflang} alternate at the page that really serves that language instead of one declaring {declaredLang}.When the promised and declared languages disagree, search engines show the wrong page to the wrong audience and screen readers read it in the wrong voice.
37A-LocalizationAuditor-500ERRORThe audited page could not be fetched: network error, timeout or a non-2xx status that is not a block.Make "{url}" reachable over HTTP(S) and re-run the audit. Last error was "{error}".β€”
37A-LocalizationAuditor-200SUCCESSAll rules passed. Message is "{url}" ({lang}) and its {n} localized versions ({hreflangs}) each keep text in {lang} under {warningPercent}% of their text blocks (highest: {hreflang} at {percent}%). data.variantSummary lists every version with its percent, untranslatedCount, nameLikeCount and ignoredCount.β€”β€”
37A-LocalizationAuditor-590ERRORThe audited page answered HTTP 403, HTTP 429 or a Cloudflare challenge, so 37AuditsBot was blocked before it could read the page.Allow 37AuditsBot in your firewall or bot protection: allowlist its user agent, or verify its Web Bot Auth signature. See https://www.37audits.com/bot.While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported.

Example messages, measured on https://www.liferay.com/ and https://liferay.dev/ on 2026-10-18:

The result message (also the message of the 200 check) is a summary: the audited URL and its default language, how many localized versions were found, and the verdict in figures for the versions concerned. Check messages carry the detail.

  • result, pass β€” "https://www.liferay.com/" has its default language set to en-US. 6 localized versions (es-ES, it-IT, fr-FR, pt-BR, de-DE, ja-JP) were found; all of them keep untranslated text blocks under 5% (highest: de-DE at 4%).

  • result, untranslated β€” "https://petrobras.com.br/" has its default language set to pt-BR. 1 localized version (en-US) was found; it shows untranslated text blocks at 36% (48 out of 135).

  • 300 β€” "https://www.liferay.com/de/" (de-DE) still shows 36 of its 321 text blocks (11%) in en-US: 35 copied verbatim from "https://www.liferay.com/" and 1 recognised by language detection, e.g. "Request a demo", "by 233 verified users as of September 2026, Source:", "Please enter a valid email address.".

  • 400 β€” "https://dev.liferay.com/es/" (es-ES) is mostly the en-US page: 37 of its 41 text blocks (90%) are still in en-US, 37 copied verbatim from "https://liferay.dev/" and 0 recognised by language detection, e.g. "Explore the Liferay Community Universe.", "The Liferay Community has been integral to our journey.", "Open Source. For Life.".

  • 303 β€” "Please enter a valid email address." is still in en-US on "https://www.liferay.com/de/" (de-DE): it appears verbatim on "https://www.liferay.com/".

  • 101 β€” "Create An Account" is still in en-US on "https://www.liferay.com/es/" (es-ES): it appears verbatim on "https://www.liferay.com/". The version stays under the 5% warning threshold.

  • 100 β€” "https://www.37audits.com/" declares lang="en" and publishes no hreflang alternates or language-switcher links, so there is no localized version to compare.

Findings on a version carry variantUrl, hreflang, source (hreflang or switcher), statusCode, error, blocked, declaredLang, baseUrl, baseLang, totalBlocks, identicalCount, detectedCount, untranslatedCount, distinctUntranslated, percent, warningPercent, failPercent, samples, nameLikeCount, nameLikeBlocks, ignoredCount, ignoredBlocks, hiddenCount, hiddenBlocks (text β†’ hiding signal, such as hidden, aria-hidden, style, <details> or class:atb-tab-panel-hidden) and languageDetection in data. A 303 or 101 finding carries variantUrl, hreflang, baseUrl, baseLang, text, reason (copied or detected), occurrences, xpath (the block's first occurrence on the version, browser style: /html/body/div[2]/footer/span[1], with /text()[n] when the element mixes several text nodes), listed and distinctUntranslated.

Preferences

Set per monitored URL; the defaults apply to Quick Audit.

KeyTypeDefaultRangeEffect
untranslatedWarningPercentinteger51–100Share of a version's text blocks still in the audited page's language from which 300 fires and the per-block list switches from INFORMATION (101) to WARNING (303). Brand and product names that the name heuristic misses count too, so a site with many of them may raise this.
untranslatedFailPercentinteger501–100Share from which 400 fires instead. A value below the warning threshold makes both equal.
maxAlternatesinteger101–20How many localized versions are fetched, in document order. Each one is a request against the audited site.
ignoredTermsstringβ€”β€”Product, company and people names allowed to stay untranslated, one per line or separated by semicolons. A block made only of these terms (plus connectors, numbers and punctuation) is left out of the count and listed in data.ignoredBlocks. The site's own name from its host is always ignored.
countHiddenTextbooleanfalseβ€”Count text the markup hides at load time (closed menus, inactive tabs, validation messages) like visible text. Off, such blocks are left out of the percentage and listed in data.hiddenBlocks instead. Turn it on when menus and messages matter as much as the visible page.

Output Documentation

StatusDescriptionTest logic
INFORMATIONThe page has no localized version to compare, or a passing version still has a few untranslated blocksNo hreflang alternate or switcher link to another language (100; the run is not charged), or one check per untranslated block on a version under the warning threshold (101; the response stays SUCCESS).
SUCCESSEvery localized version is translated and reachableEach version answered 2xx, declares the promised language, and keeps untranslated text under untranslatedWarningPercent (200).
WARNINGSome text is untranslated, a page declares no language, or a version could not be verifiedUntranslated share between the thresholds (300) with one check per untranslated block (303), missing <html lang> (301), or a version that blocked the bot (302).
FAILA version is mostly untranslated, broken, or in the wrong languageUntranslated share at or above untranslatedFailPercent (400), a version that does not resolve (401), or a declared language that contradicts the hreflang (402).
ERRORThe auditor could not compare anythingThe audited page could not be fetched (500) or 37AuditsBot was blocked (590).

Risks and Considerations

What untranslated text costs

  • A visitor who switched to their language and meets English buttons, validation messages or a whole English page reads it as a signal about the brand, not a technical glitch. The Liferay 2026 Website Localization Report puts the cost at lost purchases for 56% of multilingual consumers and lost brand trust for 32%.

  • Search engines index each hreflang version for its audience. A Spanish URL full of English text ranks for neither language well.

Names are set aside, not everything is a name

  • A Title Case block without a function or action word is treated as a name and left out of the count, so a forgotten button written that way ("Download Brochure") is missed; one with such a word ("Create An Account", "Apply Thank You") is counted. Review data.nameLikeBlocks on the summary check when a locale passes unexpectedly, and add genuine names to ignoredTerms when they slip through (a job title containing "and" or "for", a tagline).

  • On liferay.com the heuristic removes 29 of the 51 distinct texts reported on 2026-10-18, leaving the UI strings, the footer and the taglines, and every locale drops from 7–11% to about 3%.

  • Language detection is deliberately conservative: it runs only on blocks of eight words or more and needs a clear margin, because short marketing copy mixing brand names ("Explore o Headless CMS") is otherwise attributed to English.

What this auditor does not judge

  • Tone, idiom, cultural fit, machine-translation quality, and date, currency or address formats: the article's remaining findings need a fluent reader.

  • Only the audited URL and its own localized versions are compared; other pages of the site may differ.

  • Versions in the audited page's own language (en-GB for an en-US page) are skipped, since their text is expected to match.

  • The language detector covers 75 languages; a version in a language without a model is scored by the verbatim comparison alone, which data.languageDetection says.

Cost and load

  • One audit fetches the page plus up to maxAlternates versions, five at a time, so cost is 2. Lower maxAlternates on sites with many locales if the load matters.

This documentation is built and hosted on Mintlify, a developer documentation platform.

Source: docs.37audits.com

Ready to start auditing?

Add this auditor to your monitoring setup and start identifying issues on your websites today.

Β© 2026 37 Audits. All rights reserved. Audit your websites with confidence.

Supported by

Made with ❀️ in Floripa