mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
docs(readme): add Roman Urdu edition (#6499)
* docs(readme): add Roman Urdu edition
Register ur-Latn with a pending website catalog and preserve English command examples.
Script-tag handling follows morluto's shared helper proposed in PR #2043 (c46f606c89).
* test(website): cover completed script-tag page metadata
This commit is contained in:
@@ -541,6 +541,72 @@ class WebsiteMaintenanceChecks(unittest.TestCase):
|
||||
class WebsiteTranslationChecks(unittest.TestCase):
|
||||
"""Exercise source edits, translated evidence and language editions at their consumers."""
|
||||
|
||||
def test_language_inventory_preserves_script_identity(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
(root / "website/locales").mkdir(parents=True)
|
||||
for code in ("ur", "ur-PK", "ur-Latn", "ur-Latn-PK", "hi-Latn"):
|
||||
inventory = [
|
||||
{"code": "en", "name": "English", "readme": "README.md", "dir": "ltr"},
|
||||
{"code": code, "name": "Fixture", "readme": f"docs/readme/README_{code}.md", "dir": "ltr"},
|
||||
]
|
||||
path = root / "website/locales/languages.json"
|
||||
path.write_text(json.dumps(inventory))
|
||||
with self.subTest(code=code):
|
||||
self.assertEqual(languages(root), inventory)
|
||||
for code in ("ur-latn", "ur-LATN", "ur-PK-Latn", "ur/Latn"):
|
||||
inventory[1]["code"] = code
|
||||
path.write_text(json.dumps(inventory))
|
||||
with self.subTest(code=code), self.assertRaisesRegex(ValueError, "Invalid or duplicate language"):
|
||||
languages(root)
|
||||
|
||||
def test_completed_script_tag_pages_pass_search_metadata(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
site = Path(directory)
|
||||
(site / "assets").mkdir()
|
||||
shutil.copyfile(ROOT / "website/_site/assets/social-card.png", site / "assets/social-card.png")
|
||||
shutil.copyfile(ROOT / "website/public/robots.txt", site / "robots.txt")
|
||||
pages = {}
|
||||
for code in ("ur-Latn", "ur-Latn-PK"):
|
||||
path = site / code / "index.html"
|
||||
path.parent.mkdir()
|
||||
url = f"https://rea.tools/{code}/"
|
||||
source = dedent(f'''\
|
||||
<!doctype html>
|
||||
<html lang="{code}" dir="ltr">
|
||||
<head>
|
||||
<title>REA ka ta'aruf</title>
|
||||
<meta name="description" content="REA ko samjhein." />
|
||||
<link rel="canonical" href="{url}" />
|
||||
<link rel="alternate" hreflang="{code}" href="{url}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="REA" />
|
||||
<meta property="og:title" content="REA ka ta'aruf" />
|
||||
<meta property="og:description" content="REA ko samjhein." />
|
||||
<meta property="og:url" content="{url}" />
|
||||
<meta property="og:image" content="https://rea.tools/assets/social-card.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="REA" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="REA ka ta'aruf" />
|
||||
<meta name="twitter:description" content="REA ko samjhein." />
|
||||
<meta name="twitter:image" content="https://rea.tools/assets/social-card.png" />
|
||||
<meta name="twitter:image:alt" content="REA" />
|
||||
</head>
|
||||
<body><h1>REA ka ta'aruf</h1></body>
|
||||
</html>
|
||||
''')
|
||||
path.write_text(source, encoding="utf-8")
|
||||
page = VERIFY.HtmlReferences()
|
||||
page.feed(source)
|
||||
self.assertFalse(page.translation_fallback)
|
||||
self.assertFalse(page.noindex())
|
||||
pages[path] = page
|
||||
PREPARE.prepare_sitemap(site)
|
||||
self.assertEqual(VERIFY.check_search_metadata(site, pages), (2, []))
|
||||
|
||||
@contextlib.contextmanager
|
||||
def translated_project(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
|
||||
@@ -11,6 +11,7 @@ import xml.etree.ElementTree as ET
|
||||
from zipfile import BadZipFile, ZipFile
|
||||
|
||||
from website import NOTES_FIXTURES, SITE_ORIGIN, authored_markdown, page_url, sync_pages
|
||||
from website_i18n import is_language_code
|
||||
|
||||
LEGACY_ORIGIN = "morluto.github.io"
|
||||
SITE_TEXT_URL = re.compile(
|
||||
@@ -179,7 +180,7 @@ def check_search_metadata(site, pages):
|
||||
if not title:
|
||||
errors.append(f"{label}: needs exactly one nonempty head title")
|
||||
first = path.relative_to(site).parts[0]
|
||||
expected_language = first if re.fullmatch(r"[a-z]{2}(?:-[A-Z]{2})?", first) else "en"
|
||||
expected_language = first if is_language_code(first) else "en"
|
||||
if page.translation_fallback:
|
||||
if page.lang != "en" or not page.noindex():
|
||||
errors.append(f"{label}: English translation fallback needs lang=en and noindex")
|
||||
|
||||
@@ -25,6 +25,14 @@ LITERALS = {"REA", "Reverse Engineer Anything", "REA · Reverse Engineer Anythin
|
||||
FALLBACK_NOTICE = "Translation is being updated. Read this page in English for now."
|
||||
|
||||
|
||||
LANGUAGE_CODE = re.compile(r"[a-z]{2}(?:-[A-Z][a-z]{3})?(?:-[A-Z]{2})?")
|
||||
|
||||
|
||||
def is_language_code(value):
|
||||
"""Recognize canonical language, optional script and region inventory codes."""
|
||||
return LANGUAGE_CODE.fullmatch(value) is not None
|
||||
|
||||
|
||||
def readme_edition_paths(root):
|
||||
"""Return repo-relative README editions: root English plus docs/readme translations."""
|
||||
editions = set()
|
||||
@@ -57,7 +65,7 @@ def languages(root):
|
||||
raise ValueError("Each language needs code, name, readme and dir")
|
||||
if not all(isinstance(value, str) and value for value in item.values()):
|
||||
raise ValueError("Language fields must be nonempty strings")
|
||||
if not re.fullmatch(r"[a-z]{2}(?:-[A-Z]{2})?", item["code"]) or item["code"] in codes:
|
||||
if not is_language_code(item["code"]) or item["code"] in codes:
|
||||
raise ValueError(f"Invalid or duplicate language: {item['code']}")
|
||||
if item["dir"] not in ("ltr", "rtl"):
|
||||
raise ValueError(f"Invalid text direction: {item['code']}")
|
||||
|
||||
Reference in New Issue
Block a user