GH-3: Write a script to check websites trilingual feature#4
GH-3: Write a script to check websites trilingual feature#4ChanukaUOJ wants to merge 20 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new trilingual check to scan websites for English, Sinhala, and Tamil content using BeautifulSoup and Playwright, updating the README and project dependencies accordingly. The review feedback highlights several critical improvements: removing an unnecessary global lock to enable true concurrency, avoiding fragile string interpolation in page.evaluate, correcting the fallback logic for injection tests and URL construction, and preventing the masking of internal exceptions. Additionally, it is recommended to use playwright instead of pytest-playwright in production dependencies, move warning disabling to the module level, enhance the URL localization regex, wrap long lines, and document the Playwright browser installation prerequisite in the README.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Code Review
This pull request introduces a new TrilingualCheck to evaluate whether websites support English, Sinhala, and Tamil, updating the CLI, documentation, and dependencies accordingly. The review feedback highlights several important areas for improvement: resolving a concurrency bottleneck caused by a global Playwright lock, preventing browser resource leaks, securing JavaScript evaluations against injection, refining the English language detection regex to avoid false positives, preserving URL path and query parameters during checks, and exposing actual exception details instead of a hardcoded error message. Additionally, the production dependencies should be updated to use playwright instead of the testing plugin pytest-playwright.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a new TrilingualCheck to verify if websites support English, Sinhala, and Tamil, along with corresponding CLI options, documentation updates, and comprehensive tests. Feedback on the implementation highlights critical concurrency issues with shared instance state (_had_timeout) across threads, potential resource leaks of Chromium processes under exception paths, text duplication bugs in unicode content detection, and a double www. prefix bug in the fallback request logic.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| found_langs.add(soup.html.get('lang').split('-')[0].lower()) | ||
|
|
||
| missing = [lang for lang in LANGUAGE_KEY if lang not in found_langs] | ||
| return (len(missing) == 0, missing) |
There was a problem hiding this comment.
Why do we pass len(missing) == 0 and also missing? Can't we get all the info just from missing?
| if soup.find(id=HTML_GOOGLE_TRANSLATE_ELEMENT): | ||
| return 'google_translate' | ||
| if soup.find(class_=HTML_GOOG_TE_COMBO): | ||
| return 'google_translate' |
There was a problem hiding this comment.
| if soup.find(id=HTML_GOOGLE_TRANSLATE_ELEMENT): | |
| return 'google_translate' | |
| if soup.find(class_=HTML_GOOG_TE_COMBO): | |
| return 'google_translate' | |
| if soup.find(id=HTML_GOOGLE_TRANSLATE_ELEMENT) or soup.find(class_=HTML_GOOG_TE_COMBO): | |
| return 'google_translate' |
| found_langs.add(lang) | ||
|
|
||
| missing = [lang for lang in LANGUAGE_KEY if lang not in found_langs] | ||
| return (len(missing) == 0, missing) |
There was a problem hiding this comment.
Why do we pass len(missing) == 0 and also missing? Can't we get all the info just from missing?
| for link in soup.find_all(HTML_KEY_LINK, rel=HTML_KEY_ALTERNATE): | ||
| hreflang = link.get(HTML_KEY_HREFLANG) | ||
| href = link.get('href') | ||
| if not hreflang: | ||
| continue | ||
| if href: | ||
| absolute_url = urljoin(url, href) | ||
| href_domain = urlparse(absolute_url).netloc | ||
| if href_domain.startswith('www.'): | ||
| href_domain = href_domain[4:] | ||
|
|
||
| # Check if href domain is the same or a subdomain | ||
| if base_domain and not href_domain.endswith(base_domain): | ||
| continue | ||
| hreflangs.append(hreflang) |
There was a problem hiding this comment.
In situations where there is a hreflang but no href it will still be accepted. For example:
<link rel="alternate" hreflang="en" />
Is there a reason for this?
| if len(found_langs) == 3: | ||
| return TrilingualCheckResult(status="TRILINGUAL", error=None, details=", ".join(passed_criteria)) |
There was a problem hiding this comment.
If the basic checks pass then we don't do the deeplink checking. This does not catch the case where only the home page is translated and not the other pages. Better to not return here but continue checking the deeplinks for the same basic checks.
| if re.search(r'(?:/si(?:[/?#]|$)|/ta(?:[/?#]|$)|[?&]lang=(?:si|ta)(?:&|$)|/sinhala|/tamil)', href_lower) or \ | ||
| any(x in text for x in ['sinhala', 'tamil', 'සිංහල', 'தமிழ்']): |
| # Filter out the homepage itself | ||
| internal_links = [l for l in internal_links if l != response.url and l != response.url.rstrip('/')] | ||
|
|
||
| sample_links = internal_links[:5] # The first links are prioritized language links |
There was a problem hiding this comment.
Why are we prioritising language links?
| if len(found_langs) == 3: | ||
| return TrilingualCheckResult(status="TRILINGUAL", error=None, details=", ".join(passed_criteria)) | ||
|
|
||
| # Try deeplink crawling |
There was a problem hiding this comment.
Can you put the deeplink checking in a different function. This run function is quite lengthy
| LANG_STORAGE_FORMATS: list[tuple[list[str], list[str]]] = [ | ||
| (['en', 'si', 'ta'], ['en', 'si', 'ta']), | ||
| (['en-US', 'en-GB', 'si-LK', 'ta-LK', 'ta-IN'], ['en-US', 'si-LK', 'ta-LK']), | ||
| (['en-us', 'en-gb', 'si-lk', 'ta-lk', 'ta-in'], ['en-us', 'si-lk', 'ta-lk']), | ||
| (['English', 'Sinhala', 'Tamil'], ['English', 'Sinhala', 'Tamil']), | ||
| (['english', 'sinhala', 'tamil'], ['english', 'sinhala', 'tamil']), | ||
| ] |
There was a problem hiding this comment.
Only the first column is needed here
| missing_injection = [] | ||
| langs = LANGUAGE_KEY | ||
|
|
||
| for i in range(3): |
There was a problem hiding this comment.
| for i in range(3): | |
| for i in range(len(langs)): |
|
This pr closes #3 |
This PR introduces the
trilingualcheck for WebsiteScorecard, which automatically detects whether websites support Sri Lanka's three official languages (English, Sinhala, and Tamil).Changes
TrilingualCheckinsrc/websitescorecard/checks/trilingual.py.playwrightto the corepyproject.tomldependencies. Movedpytest-playwrightandpytest-mockto[dev]dependencies.README.mdto document the newtrilingualcheck, the required block-letter outputs, and instructions for running the requiredplaywright install chromiumsetup step.base.pyto support the new outputs.Detection Pipeline
The script employs a multi-layered detection strategy to maximise accuracy, falling back to heavier methods only when necessary:
<html lang="X">and<link rel="alternate" hreflang="X">tags./si/,/en/) or query parameters (e.g.,?lang=ta).localStorage(e.g.,i18n,lang) and reload the page to detect locale changes.Robustness & Fixes Included
TRILINGUAL,NON_TRILINGUAL,TIMEOUT,UNREACHABLE) and detailed metadata (trilingual_details).Testing
tests/test_trilingual.py) achieving full coverage of static and headless browser workflows.data/mins_depts_test.csvfile without errors.