Wiktionary
siwiktionary
https://si.wiktionary.org/wiki/%E0%B7%80%E0%B7%92%E0%B6%9A%E0%B7%8A%E0%B7%82%E0%B6%B1%E0%B6%BB%E0%B7%92:%E0%B6%B8%E0%B7%94%E0%B6%BD%E0%B7%8A_%E0%B6%B4%E0%B7%92%E0%B6%A7%E0%B7%94%E0%B7%80
MediaWiki 1.48.0-wmf.4
case-sensitive
මාධ්යය
විශේෂ
සාකච්ඡාව
පරිශීලක
පරිශීලක සාකච්ඡාව
වික්ෂනරි
වික්ෂනරි සාකච්ඡාව
ගොනුව
ගොනුව සාකච්ඡාව
මාධ්යවිකි
මාධ්යවිකි සාකච්ඡාව
සැකිල්ල
සැකිලි සාකච්ඡාව
උදවු
උදවු සාකච්ඡාව
ප්රවර්ගය
ප්රවර්ග සාකච්ඡාව
TimedText
TimedText talk
Module
Module talk
Event
Event talk
Module:category tree/topic/Science and technology
828
6050
238773
233134
2026-11-11T14:09:33Z
Lee
19
Lee විසින් [[Module:category tree/topic/Sciences]] සිට [[Module:category tree/topic/Science and technology]] වෙත පිටුව ගෙන යන ලදී
233134
Scribunto
text/plain
local labels = {}
labels["විද්යා"] = {
type = "related-to",
description = "default with the",
parents = {"මාතෘකා සියල්ල"},
}
labels["acceleration"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["acoustics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied sciences", "භෞතිකවේදය", "sound"},
}
labels["adjectives"] = {
type = "type",
description = "default",
parents = {"parts of speech"},
}
labels["aeronautics"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
}
labels["aerospace"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "space", "astronautics", "aeronautics"},
}
labels["agriculture"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["ගොවිතැන"] = {
type = "related-to",
description = "default",
parents = {"agriculture"},
}
labels["alchemy"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "pseudoscience", "obsolete scientific theories"},
}
labels["alternative medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine", "pseudoscience"},
}
labels["analytical chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["anatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[anatomy]], the study of the [[body]] and its parts.",
additional = "{{also|Category:{{{langcode}}}:Body parts}}",
parents = {"biology", "medicine"},
}
labels["andrology"] = {
type = "related-to",
description = "default",
parents = {"medicine", "male"},
}
labels["anthropology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[anthropology]], the study of [[human]]s.",
additional = "{{also|Category:{{{langcode}}}:Human}}",
parents = {"zoology", "සමාජවේද"},
}
labels["anti-gravity"] = {
type = "related-to",
description = "default",
parents = {"fictional abilities", "gravity", "science fiction", "space access"},
}
labels["applied sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["arachnology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[arachnology]], the study of [[spider]]s.",
additional = "{{also|Category:{{{langcode}}}:Spiders}}",
parents = {"zoology", "arthropodology"},
}
labels["archaeology"] = {
type = "related-to",
description = "default",
parents = {"anthropology", "විද්යා"},
commonscat = true,
wpcat = true,
}
labels["architectural elements"] = {
type = "set",
description = "default",
parents = {"architecture"},
}
labels["architecture"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "කලාව"},
}
labels["arthropodology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[arthropodology]], the study of [[arthropod]]s.",
additional = "{{also|Category:{{{langcode}}}:Arthropods}}",
parents = {"zoology"},
}
labels["artificial intelligence"] = {
type = "related-to",
description = "default",
parents = {"computer science", "cybernetics"},
}
labels["asterisms"] = {
type = "name",
description = "default",
parents = {"astronomy"},
}
labels["astronautics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied sciences", "space"},
}
labels["astronomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[astronomy]], the study of [[stars]] and other [[celestial bodies]].",
additional = "{{also|Category:{{{langcode}}}:Celestial bodies}}",
parents = {"විද්යා", "space"},
}
labels["astrophysics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය", "astronomy"},
}
labels["aviation"] = {
type = "related-to",
description = "default",
parents = {"aeronautics", "transport"},
}
labels["avionics"] = {
type = "related-to",
description = "default no singularize",
parents = {"aeronautics", "electronics"},
}
labels["Ayurveda"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine", "India"},
}
labels["bacteriology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[bacteriology]], the study of [[bacteria]].",
additional = "{{also|Category:{{{langcode}}}:Bacteria}}",
parents = {"medicine", "microbiology"},
}
labels["ballistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["biases"] = {
type = "set",
description = "{{{langname}}} terms for [[bias|biases]], [[inclination]]s of views towards [[inaccurate]] [[representation]].",
additional = "{{also|Category:{{{langcode}}}:Logical fallacies|Category:{{{langcode}}}:Forms of discrimination}}",
parents = {"psychology", "statistics"},
}
labels["biochemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "biology"},
}
labels["biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[biology]], the study of [[life]].",
additional = "{{also|Category:{{{langcode}}}:Lifeforms}}",
parents = {"විද්යා"},
}
labels["black holes"] = {
type = "related-to",
description = "default",
parents = {"astronomy", "astrophysics", "gravity", "relativity"},
}
labels["botany"] = {
type = "related-to",
description = "=[[botany]], the study of [[plants]]",
additional = "{{also|Category:{{{langcode}}}:Plants}}",
parents = {"biology"},
}
labels["bryology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[bryology]], the study of [[moss]]es and other lower plants.",
additional = "{{also|Category:{{{langcode}}}:Mosses}}",
parents = {"biology", "botany"},
}
labels["cardiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cardiology]], the study of the [[heart]].",
parents = {"medicine", "circulatory system"},
}
labels["carpentry"] = {
type = "related-to",
description = "default",
parents = {"construction", "woodworking"},
}
labels["cartography"] = {
type = "related-to",
description = "default",
parents = {"භූගෝලවේදය"},
}
labels["catalysis"] = {
type = "related-to",
description = "default",
parents = {"chemical processes", "chemical reactions", "physical chemistry"},
}
labels["chemical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "chemistry"},
}
labels["chemical formulae"] = {
type = "name",
description = "default",
parents = {"chemical notation"},
}
labels["chemical notation"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "නාම", "symbols"},
}
labels["chemical reactions"] = {
type = "related-to,set",
description = "default",
parents = {"chemistry"},
}
labels["chemical reagents"] = {
type = "set",
description = "default",
parents = {"chemistry"},
}
labels["chemistry"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["Chinese astronomy"] = {
type = "related-to",
description = "default",
parents = {"astronomy"},
}
labels["Chinese phonetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"phonetics", "Chinese"},
}
labels["classical mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["classical studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "literature", "history"},
}
labels["climatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[climatology]], the study of [[climate]].",
parents = {"earth sciences"},
}
labels["clinical psychology"] = {
type = "related-to",
description = "default",
parents = {"psychology", "pathology"},
}
labels["computational linguistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "computer science"},
}
labels["computer science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "computing"},
}
labels["conchology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[conchology]], the study of mollusc [[shell]]s.",
parents = {"malacology"},
}
labels["constellations"] = {
type = "name",
description = "default",
parents = {"astronomy"},
}
labels["construction"] = {
type = "related-to",
description = "default",
parents = {"engineering", "architecture"},
}
labels["control theory"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "systems"},
}
labels["cosmology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cosmology]], the study of the [[universe]].",
parents = {"astronomy"},
}
labels["criminology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[criminology]], the study of [[crime]].",
additional = "{{also|Category:{{{langcode}}}:Crime}}",
parents = {"sociology", "crime"},
}
labels["cryptography"] = {
type = "related-to",
description = "default",
parents = {"formal sciences", "mathematics", "computer science"},
}
labels["cryptozoology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cryptozoology]], the [[pseudoscientific]] study of mythological creatures.",
additional = "{{also|Category:{{{langcode}}}:Mythological creatures}}",
parents = {"zoology", "paranormal"},
}
labels["crystallography"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය", "crystal"},
}
labels["cultural anthropology"] = {
type = "related-to",
description = "default",
parents = {"anthropology", "සංස්කෘතිය"},
}
labels["cybernetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied mathematics", "systems theory"},
}
labels["cytology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cytology]], the study of cell biology, cell structure, formation, classification and related topics.",
parents = {"biology"},
}
labels["data management"] = {
type = "related-to",
description = "default",
parents = {"information science", "computer science"},
}
labels["demarcation lines"] = {
type = "name",
description = "=political [[demarcation line]]s",
parents = {"politics"},
}
labels["decision theory"] = {
type = "related-to",
description = "default",
parents = {"probability theory", "epistemology"},
}
labels["demography"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "statistics"},
}
labels["dentistry"] = {
type = "related-to",
description = "default",
parents = {"medicine", "teeth"},
}
labels["dermatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[dermatology]], the study of the [[skin]].",
additional = "{{also|Category:{{{langcode}}}:Skin}}",
parents = {"medicine"},
}
labels["developmental biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[developmental biology]], the study of the [[development]] of [[lifeform]]s.",
parents = {"biology"},
}
labels["earth sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["earthquake engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["ecology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ecology]], the study of interaction between [[life]] and its environment.",
parents = {"biology"},
}
labels["economics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[economics]], the study of the [[economy]].",
parents = {"සමාජවේද"},
}
labels["ecosystems"] = {
type = "related-to",
description = "default",
parents = {"ecology", "landforms"},
}
labels["electrencephalography"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[electrencephalography]], the electrical measurement of the [[brain]].",
additional = "{{also|Category:{{{langcode}}}:Brain}}",
parents = {"neuroscience"},
}
labels["electrical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "electricity"},
}
labels["electricity"] = {
type = "related-to",
description = "default",
parents = {"electromagnetism"},
}
labels["electrocardiography"] = {
type = "related-to",
description = "default",
parents = {"cardiology"},
}
labels["electrodynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"electromagnetism"},
}
labels["electrochemistry"] = {
type = "related-to",
description = "default",
parents = {"physical chemistry", "electricity"},
}
labels["electromagnetism"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["element nomenclature"] = {
type = "related-to",
description = "default",
parents = {"chemical notation", "නාම", "chemical elements"},
}
labels["embryology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[embryology]], the study of the [[embryo]].",
parents = {"biology", "developmental biology", "medicine"},
}
labels["emergency medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["endocrinology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[endocrinology]], the study of [[hormones]] and the [[endocrine system]].",
additional = "{{also|Category:{{{langcode}}}:Hormones}}",
parents = {"medicine"},
}
labels["engineering"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "technology"},
}
labels["enterprise engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["entomology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[entomology]], the study of [[insect]]s.",
additional = "{{also|Category:{{{langcode}}}:Insects}}",
parents = {"zoology", "arthropodology"},
}
labels["epidemiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[epidemiology]].",
parents = {"medicine"},
}
labels["ethnography"] = {
type = "related-to",
description = "default",
parents = {"anthropology"},
}
labels["ethnology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ethnology]], the study of [[people]]s.",
parents = {"anthropology"},
}
labels["ethology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ethology]], the study of [[animal]] [[behaviour]].",
parents = {"zoology"},
}
labels["evolutionary theory"] = {
type = "related-to",
description = "default",
parents = {"biology"},
}
labels["flat earth"] = {
type = "related-to",
description = "{{{langname}}} terms used by believers in a flat earth or related to the concept.",
parents = {"pseudoscience", "obsolete scientific theories"},
}
labels["flax"] = {
type = "related-to",
description = "default",
parents = {"agriculture", "Malpighiales order plants"},
}
labels["fluid dynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["forestry"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["functional group prefixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["functional group suffixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["gardens"] = {
type = "type",
description = "=places where plants are grown",
parents = {"home", "horticulture"},
}
labels["gastroenterology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[gastroenterology]], the study of the [[digestive system]].",
parents = {"medicine"},
}
labels["genetics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[genetics]], the study of [[gene]]s.",
parents = {"biology"},
}
labels["භූගෝලවේදය"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geography]], the study of various phenomena found on [[Earth]]'s surface.",
additional = "{{also|Category:{{{langcode}}}:Landforms|Category:{{{langcode}}}:Polities}}",
parents = {"earth sciences"},
}
labels["geological periods"] = {
type = "related-to",
description = "default",
parents = {"geology"},
}
labels["geology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geology]], the study of the solid parts of [[Earth]].",
parents = {"earth sciences"},
}
labels["geomorphology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geomorphology]].",
parents = {"geology"},
}
labels["geopolitics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භූගෝලවේදය", "politics"},
}
labels["geospatial science"] = {
type = "related-to",
description = "default",
parents = {"earth sciences"},
}
labels["gerontology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[gerontology]], the study of [[aging]].",
additional = "{{also|Category:{{{langcode}}}:Age}}",
parents = {"medicine"},
}
labels["grammar"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["grammatical cases"] = {
type = "set",
description = "default",
parents = {"grammar"},
}
labels["grammatical moods"] = {
type = "set",
description = "default",
parents = {"grammar"},
}
labels["gravity"] = {
type = "related-to",
description = "default",
parents = {"acceleration", "astrophysics", "mechanics"},
}
labels["gynaecology"] = {
type = "related-to",
description = "default",
parents = {"medicine", "female"},
}
labels["helminthology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[helminthology]], the study of [[helminth]]s ([[parasitic]] [[worm#Noun|worms]]).",
additional = "{{also|Category:{{{langcode}}}:Flatworms}}",
parents = {"zoology"},
}
labels["hematology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hematology]], the study of [[blood]].",
parents = {"medicine"},
}
labels["hepatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hepatology]], the study of the [[liver]].",
parents = {"medicine"},
}
labels["herpetology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[herpetology]], the study of [[reptile]]s and amphibians.",
additional = "{{also|Category:{{{langcode}}}:Reptiles|Category:{{{langcode}}}:Amphibians}}",
parents = {"zoology"},
}
labels["homeopathy"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine"},
}
labels["horticulture"] = {
type = "related-to",
description = "default",
parents = {"agriculture", "botany"},
}
labels["hydroacoustics"] = {
type = "related-to",
description = "default no singularize",
parents = {"acoustics", "hydrology"},
}
labels["hydrocarbon chain prefixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["hydrocarbon chain suffixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["hydrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hydrology]], the study of [[water]], its movement and distribution.",
additional = "{{also|Category:{{{langcode}}}:Water}}",
parents = {"earth sciences", "water"},
}
labels["ichthyology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ichthyology]], the study of [[fish]].",
additional = "{{also|Category:{{{langcode}}}:Fish}}",
parents = {"zoology"},
}
labels["immunochemistry"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "immunology"},
}
labels["immunology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[immunology]], the study of the [[immune system]].",
parents = {"medicine"},
}
labels["Indo-European studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["information science"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["inorganic chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["interdisciplinary fields"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["isolines"] = {
type = "related-to",
description = "default",
parents = {"cartography", "meteorology"},
}
labels["Lagrange points"] = {
type = "related-to",
description = "default",
parents = {"orbits"},
}
labels["lexicography"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["library science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "education", "information science"},
}
labels["lichenology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[lichenology]], the study of [[lichen]]s.",
additional = "{{also|Category:{{{langcode}}}:Lichens}}",
parents = {"mycology", "phycology"},
}
labels["linguistic morphology"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["වාග්වේදය"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[linguistics]], the study and analysis of [[language]].",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:භාෂාව}}",
parents = {"භාෂාව", "සමාජවේද"},
}
labels["maize (crop)"] = {
type = "related-to",
description = "=[[maize]] (called [[corn]] in North America) as a crop",
additional = "For terms related to maize as a food, see [[:Category:Maize (food)]] and for maize as a plant, see [[:Category:Maize (plant)]].",
parents = {"agriculture", "grains"},
}
labels["malacology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[malacology]], the study of [[mollusk]]s.",
additional = "{{also|Category:{{{langcode}}}:Mollusks}}",
parents = {"zoology"},
}
labels["mammalogy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mammalogy]], the study of [[mammal]]s.",
additional = "{{also|Category:{{{langcode}}}:Mammals}}",
parents = {"zoology"},
}
labels["marine biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[marine biology]], the study of [[life]] in the [[sea]].",
parents = {"biology"},
}
labels["masonry"] = {
type = "related-to",
description = "default",
parents = {"construction"},
}
labels["materials science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "engineering"},
}
labels["mechanical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["medical genetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"medicine", "genetics"},
}
labels["medicine"] = {
type = "related-to",
description = "{{{langname}}} terms that pertain to the the science and practice of [[medicine]].",
parents = {"biology", "healthcare"},
}
labels["metamaterials"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["physical constants"] = {
type = "set",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["machine learning"] = {
type = "related-to",
description = "default",
parents = {"artificial intelligence"},
}
labels["meteorology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[meteorology]], the study of [[weather]].",
additional = "{{also|Category:{{{langcode}}}:Weather}}",
parents = {"earth sciences", "atmosphere"},
}
labels["metrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[metrology]], the science of [[measure|measuring]].",
parents = {"applied sciences"},
wpcat = true,
commonscat=true,
}
labels["microbiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[microbiology]], the study of [[life]] at [[microscopic]] scales, too small for the [[human]] [[eye]].",
parents = {"biology"},
}
labels["microscopy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[microscopy]], the field of using [[microscopes]] for study.",
parents = {"optics", "microbiology"},
}
labels["mineralogy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mineralogy]], the study of [[mineral]]s.",
additional = "{{also|Category:{{{langcode}}}:Minerals}}",
parents = {"geology"},
}
labels["molecular biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[molecular biology]], the study of the [[molecules]] found in [[life]], their functions and effects.",
parents = {"biochemistry", "biology", "genetics"},
}
labels["mycology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mycology]], the study of [[fungi]].",
additional = "{{also|Category:{{{langcode}}}:Fungi}}",
parents = {"biology"},
}
labels["NASA"] = {
type = "related-to",
description = "=the United States National Aeronautics and Space Administration and the US space program",
parents = {"astronautics", "aviation"},
}
labels["nephrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[nephrology]], the study of the [[kidney]]s.",
parents = {"medicine"},
}
labels["neuroanatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neuroanatomy]], the study of the structure and organization of the [[nervous system]].",
parents = {"anatomy", "neurology", "neuroscience"},
}
labels["neurology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neurology]], the study of [[nerves]] and [[neurons]].",
parents = {"medicine", "neuroscience"},
}
labels["neuroscience"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neuroscience]], the study of the [[nervous system]].",
parents = {"biology"},
}
labels["neurosurgery"] = {
type = "related-to",
description = "default",
parents = {"surgery", "neurology"},
}
labels["neutron"] = {
type = "related-to",
description = "default",
parents = {"nuclear physics"},
}
labels["neutron stars"] = {
type = "related-to",
description = "default",
parents = {"neutron", "gravity", "astrophysics", "relativity", "stars"},
}
labels["නාම පද"] = {
type = "related-to",
description = "default",
parents = {"parts of speech"},
}
labels["nuclear energy"] = {
type = "related-to",
description = "default",
parents = {"energy", "nuclear physics", "technology"},
}
labels["nuclear fusion"] = {
type = "related-to",
description = "default",
parents = {"nuclear energy"},
}
labels["nuclear physics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය", "quantum mechanics"},
}
labels["nuclear rocketry"] = {
type = "related-to",
description = "default",
parents = {"nuclear energy", "rocketry", "space access"},
}
labels["obstetrics"] = {
type = "related-to",
description = "default no singularize",
parents = {"developmental biology", "medicine", "pregnancy"},
}
labels["obsolete scientific theories"] = {
type = "set",
description = "{{{langname}}} terms for types or instances of [[obsolete]] [[scientific]] [[theory|theories]] that are no longer, or have never been, widely accepted.",
parents = {"history of science"},
}
labels["oceanography"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["oenology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[oenology]], the study of [[wine]] and [[winemaking]].",
additional = "{{also|Category:{{{langcode}}}:Wine}}",
parents = {"විද්යා"},
}
labels["oncology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[oncology]], the study of [[cancer]].",
parents = {"biology", "medicine", "pathology"},
}
labels["onomastics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[onomastics]], the study of [[name]]s.",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:නාම|:ප්රවර්ගය:{{{langname}}} නාම}}",
parents = {"වාග්වේදය", "නාම"},
}
labels["ophthalmology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ophthalmology]], the study of the [[eye]].",
additional = "{{also|Category:{{{langcode}}}:Eye}}",
parents = {"medicine", "vision"},
}
labels["optics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[optics]], the study of the behaviour of [[light]].",
additional = "{{also|Category:{{{langcode}}}:Light}}",
parents = {"භෞතිකවේදය"},
}
labels["orbits"] = {
type = "related-to",
description = "default",
parents = {"astronautics", "gravity", "space", "curves"},
}
labels["organic chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["orgonomy"] = {
type = "related-to",
description = "=the [[orgone]] theory proposed by [[w:William Reich|William Reich]]",
parents = {"alternative medicine", "pseudoscience"},
}
labels["ornithology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ornithology]], the study of [[birds]].",
additional = "{{also|Category:{{{langcode}}}:Birds}}",
parents = {"zoology"},
}
labels["paleontology"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "geology"},
}
labels["palynology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[palynology]], the study of [[particle]]s and particulate matter.",
parents = {"geology"},
}
labels["paranormal"] = {
type = "related-to",
description = "default with the",
parents = {"pseudoscience"},
}
labels["parapsychology"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "pseudoscience"},
}
labels["parasitology"] = {
type = "related-to",
description = "default",
parents = {"pathology", "zoology"},
}
labels["particle physics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[particle physics]], the study of [[subatomic]] [[particle]]s.",
additional = "{{also|Category:{{{langcode}}}:Subatomic particles}}",
parents = {"භෞතිකවේදය"},
}
labels["parts of speech"] = {
type = "related-to",
description = "=[[part of speech|parts of speech]]",
parents = {"grammar"},
}
labels["pathology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[pathology]], the study of [[disease]].",
additional = "{{also|Category:{{{langcode}}}:Disease}}",
parents = {"medicine", "disease"},
}
labels["petrochemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "chemical engineering", "oil industry", "petroleum"},
}
labels["petrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[petrology]], the study of [[rock]].",
additional = "{{also|Category:{{{langcode}}}:Rocks}}",
parents = {"geology"},
}
labels["pharmacology"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "medicine"},
}
labels["pharmacy"] = {
type = "related-to",
description = "default",
parents = {"medicine", "pharmacology"},
}
labels["phonemes"] = {
type = "set",
description = "=contrastive sounds within a language",
parents = {"phonology"},
}
labels["phonetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["phonology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phonology]], the organisation of [[speech]] sounds within a [[language]].",
parents = {"වාග්වේදය"},
}
labels["photochemistry"] = {
type = "related-to",
description = "default",
parents = {"physical chemistry", "light"},
}
labels["phrenology"] = {
type = "related-to",
description = "default",
parents = {"psychology", "pseudoscience"},
}
labels["phycology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phycology]], the study of [[algae]].",
additional = "{{also|Category:{{{langcode}}}:Algae}}",
parents = {"botany", "microbiology"},
}
labels["physical chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "භෞතිකවේදය"},
}
labels["physical quantities"] = {
type = "set",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["භෞතිකවේදය"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
commonscat = true,
wpcat = true,
}
labels["physiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[physiology]].",
parents = {"biology", "medicine"},
}
labels["phytopathology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phytopathology]], the study of [[disease]] in [[plant]]s.",
additional = "{{also|Category:{{{langcode}}}:Plant diseases}}",
parents = {"pathology", "botany"},
}
labels["planetary nomenclature"] = {
type = "related-to",
description = "default",
parents = {"planetology"},
}
labels["planetology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[planetology]], the study of [[planet]]s.",
additional = "{{also|Category:{{{langcode}}}:Planets}}",
parents = {"astronomy", "geology"},
}
labels["plant anatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in the study of the structure of plants and their parts.",
parents = {"botany", "anatomy"},
}
labels["plastic surgery"] = {
type = "related-to",
description = "default",
parents = {"surgery"},
}
labels["political science"] = {
type = "related-to",
description = "default",
parents = {"සමාජවේද", "politics"},
}
labels["potential theory"] = {
type = "related-to",
description = "default",
parents = {"mathematics"},
}
labels["pragmatics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["prosody"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[prosody]], the study of the [[suprasegmental]] aspects of [[speech]].",
parents = {"වාග්වේදය"},
}
labels["pseudoscience"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["psychiatry"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["psychoanalysis"] = {
type = "related-to",
description = "default no singularize",
parents = {"psychology"},
}
labels["psychology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[psychology]], the study of the [[mind]].",
additional = "{{also|Category:{{{langcode}}}:Mind}}",
parents = {"සමාජවේද"},
}
labels["psychotherapy"] = {
type = "related-to",
description = "default",
parents = {"psychology"},
}
labels["pulmonology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[pulmonology]], the study of the [[respiratory system]], including the [[lung]]s.",
parents = {"medicine"},
}
labels["pyrotechnics"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
}
labels["quantity"] = {
type = "related-to",
description = "default",
parents = {"mathematics"},
}
labels["quantum mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["relativity"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["rheumatology"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["robotics"] = {
type = "related-to",
description = "default no singularize",
parents = {"engineering"},
}
labels["rocketry"] = {
type = "related-to",
description = "default",
parents = {"astronautics"},
}
labels["roofing"] = {
type = "related-to",
description = "default",
parents = {"construction"},
}
labels["rosiculture"] = {
type = "related-to",
description = "default",
parents = {"horticulture"},
}
labels["rotation"] = {
type = "related-to",
description = "default",
parents = {"mechanics", "geometry"},
}
labels["Russian space program"] = {
type = "related-to",
description = "=the Russian and Soviet space programs",
parents = {"astronautics", "aviation"},
}
labels["sales"] = {
type = "related-to",
description = "default no singularize",
parents = {"marketing"},
}
labels["seismology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[seismology]], the study of [[earthquake]]s.",
parents = {"geology"},
}
labels["semantics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["Semitic linguistics"] = {
type = "related-to",
description = "{{{langname}}} terms used in the study and analysis of [[Semitic]] [[language]]s.",
parents = {"වාග්වේදය"},
}
labels["semiotics"] = {
type = "related-to",
description = "default no singularize",
parents = {"සමාජවේද", "වාග්වේදය"},
}
labels["sexology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[sexology]], the study of [[human]] [[sexuality]].",
additional = "{{also|Category:{{{langcode}}}:Sex}}",
parents = {"psychology", "sex", "sociology"},
}
labels["SI units"] = {
type = "related-to",
description = "=[[International System of Units|SI]] [[unit of measure|units of measure]]",
parents = {"units of measure"},
}
labels["signal processing"] = {
type = "related-to",
description = "default",
parents = {"applied mathematics", "telecommunications"},
wpcat = true,
commonscat = true,
}
labels["සමාජවේද"] = {
type = "related-to",
description = "default with the",
parents = {"විද්යා", "සමාජය"},
}
labels["sociolinguistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "sociology"},
}
labels["sociology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[sociology]], the study of [[society]].",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:සමාජය}}",
parents = {"සමාජවේද"},
}
labels["software engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "computer science", "software"},
wpcat = true,
commonscat = true,
}
labels["soil science"] = {
type = "related-to",
description = "default",
parents = {"earth sciences"},
}
labels["sorting algorithms"] = {
type = "set",
description = "default",
parents = {"theory of computing"},
}
labels["sound engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "sound"},
}
labels["space access"] = {
type = "related-to",
description = "default",
parents = {"astronautics"},
}
labels["space sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "space"},
}
labels["spectroscopy"] = {
type = "related-to",
description = "default",
parents = {"analytical chemistry", "optics", "භෞතිකවේදය"},
}
labels["statistical mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["statistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"formal sciences", "mathematics"},
}
labels["surgery"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["surveying"] = {
type = "related-to",
description = "default",
parents = {"භූගෝලවේදය"},
}
labels["systems"] = {
type = "related-to",
description = "default",
parents = {"interdisciplinary fields", "විද්යා", "සමාජය"},
}
labels["systems engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["systems theory"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "systems"},
}
labels["taxonomy"] = {
type = "related-to",
description = "default",
additional = "For individual [[taxa]], see [[:Category:Taxonomic names]].",
parents = {"biology", "evolutionary theory"},
}
labels["taxonomic ranks"] = {
type = "set",
description = "default",
parents = {"taxonomy"},
}
labels["tenses"] = {
type = "related-to",
description = "default",
parents = {"grammar"},
}
labels["teratology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[teratology]], the study of abnormalities in the [[development]] of the [[body]].",
parents = {"developmental biology", "medicine", "pathology", "toxicology"},
}
labels["theory of computing"] = {
type = "related-to",
description = "{{{langname}}} terms used in theoretical discussion of [[computer science]] or [[computing]].",
parents = {"computer science"},
}
labels["thermodynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["tides"] = {
type = "related-to",
description = "default no singularize",
parents = {"gravity", "periodic occurrences"},
}
labels["toxicology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[toxicology]], the study of [[poisons]], [[toxins]] and other substances with negative effects on the [[body]].",
additional = "{{also|Category:{{{langcode}}}:Poisons}}",
parents = {"medicine", "pharmacology"},
}
labels["traditional Chinese medicine"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine"},
}
labels["traffic engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "road transport"},
}
labels["translation studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["traumatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in traumatology, the study of wounds and injuries caused by accidents or violence to a person.",
parents = {"medicine", "pathology"},
}
labels["ufology"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "anti-gravity", "celestial inhabitants"},
}
labels["units of area"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of area|units of area]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of energy"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of energy|units of energy]].",
parents = {"units of measure", "energy"},
commonscat = false,
wpcat = true,
}
labels["units of length"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of length|units of length]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of mass"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of mass|units of mass]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of measure"] = {
type = "set",
description = "{{{langname}}} terms that are [[unit of measure|units of measure]].",
parents = {"quantity", "metrology"},
commonscat = true,
wpcat = "units of measurement",
}
labels["units of time"] = {
type = "set",
description = "{{{langname}}} terms that are [[unit of time|units of time]].",
parents = {"units of measure", "time"},
commonscat = "spans of time",
wpcat = true,
}
labels["urban studies"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "සමාජවේද"},
}
labels["urology"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["verbs"] = {
type = "related-to",
description = "default",
parents = {"parts of speech"},
}
labels["veterinary medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine", "animals"},
}
labels["virology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[virology]], the study of [[virus]]es.",
additional = "{{also|Category:{{{langcode}}}:Viruses}}",
parents = {"medicine", "microbiology", "pathology"},
}
labels["volcanology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[volcanology]], the study of [[volcano]]es.",
parents = {"geology"},
}
labels["zoology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[zoology]], the study of [[animal]]s.",
additional = "{{also|Category:{{{langcode}}}:Animals}}",
parents = {"biology"},
}
labels["zymurgy"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "brewing"},
}
labels["colour and pattern morphs"] = {
type = "set",
description = "{{{langname}}} terms for [[colour]] and [[pattern]] [[morph#Etymology 2|morphs]]",
parents = {"zoology"},
}
labels["geological formations"] = {
type = "set",
description = "{{{langname}}} [[w:geological formation|geological formations]]",
parents = {"geology"},
}
return labels
1l4rz4bcucp5jnue1sz8z61j2zvrni5
238779
238773
2026-11-11T14:17:44Z
Lee
19
"architecture" සිට "ගෘහ නිර්මාණ ශිල්පය" වෙතට
238779
Scribunto
text/plain
local labels = {}
labels["විද්යා"] = {
type = "related-to",
description = "default with the",
parents = {"මාතෘකා සියල්ල"},
}
labels["acceleration"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["acoustics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied sciences", "භෞතිකවේදය", "sound"},
}
labels["adjectives"] = {
type = "type",
description = "default",
parents = {"parts of speech"},
}
labels["aeronautics"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
}
labels["aerospace"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "space", "astronautics", "aeronautics"},
}
labels["agriculture"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["ගොවිතැන"] = {
type = "related-to",
description = "default",
parents = {"agriculture"},
}
labels["alchemy"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "pseudoscience", "obsolete scientific theories"},
}
labels["alternative medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine", "pseudoscience"},
}
labels["analytical chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["anatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[anatomy]], the study of the [[body]] and its parts.",
additional = "{{also|Category:{{{langcode}}}:Body parts}}",
parents = {"biology", "medicine"},
}
labels["andrology"] = {
type = "related-to",
description = "default",
parents = {"medicine", "male"},
}
labels["anthropology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[anthropology]], the study of [[human]]s.",
additional = "{{also|Category:{{{langcode}}}:Human}}",
parents = {"zoology", "සමාජවේද"},
}
labels["anti-gravity"] = {
type = "related-to",
description = "default",
parents = {"fictional abilities", "gravity", "science fiction", "space access"},
}
labels["applied sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["arachnology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[arachnology]], the study of [[spider]]s.",
additional = "{{also|Category:{{{langcode}}}:Spiders}}",
parents = {"zoology", "arthropodology"},
}
labels["archaeology"] = {
type = "related-to",
description = "default",
parents = {"anthropology", "විද්යා"},
commonscat = true,
wpcat = true,
}
labels["architectural elements"] = {
type = "set",
description = "default",
parents = {"ගෘහ නිර්මාණ ශිල්පය"},
}
labels["ගෘහ නිර්මාණ ශිල්පය"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "කලාව"},
}
labels["arthropodology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[arthropodology]], the study of [[arthropod]]s.",
additional = "{{also|Category:{{{langcode}}}:Arthropods}}",
parents = {"zoology"},
}
labels["artificial intelligence"] = {
type = "related-to",
description = "default",
parents = {"computer science", "cybernetics"},
}
labels["asterisms"] = {
type = "name",
description = "default",
parents = {"astronomy"},
}
labels["astronautics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied sciences", "space"},
}
labels["astronomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[astronomy]], the study of [[stars]] and other [[celestial bodies]].",
additional = "{{also|Category:{{{langcode}}}:Celestial bodies}}",
parents = {"විද්යා", "space"},
}
labels["astrophysics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය", "astronomy"},
}
labels["aviation"] = {
type = "related-to",
description = "default",
parents = {"aeronautics", "transport"},
}
labels["avionics"] = {
type = "related-to",
description = "default no singularize",
parents = {"aeronautics", "electronics"},
}
labels["Ayurveda"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine", "India"},
}
labels["bacteriology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[bacteriology]], the study of [[bacteria]].",
additional = "{{also|Category:{{{langcode}}}:Bacteria}}",
parents = {"medicine", "microbiology"},
}
labels["ballistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["biases"] = {
type = "set",
description = "{{{langname}}} terms for [[bias|biases]], [[inclination]]s of views towards [[inaccurate]] [[representation]].",
additional = "{{also|Category:{{{langcode}}}:Logical fallacies|Category:{{{langcode}}}:Forms of discrimination}}",
parents = {"psychology", "statistics"},
}
labels["biochemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "biology"},
}
labels["biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[biology]], the study of [[life]].",
additional = "{{also|Category:{{{langcode}}}:Lifeforms}}",
parents = {"විද්යා"},
}
labels["black holes"] = {
type = "related-to",
description = "default",
parents = {"astronomy", "astrophysics", "gravity", "relativity"},
}
labels["botany"] = {
type = "related-to",
description = "=[[botany]], the study of [[plants]]",
additional = "{{also|Category:{{{langcode}}}:Plants}}",
parents = {"biology"},
}
labels["bryology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[bryology]], the study of [[moss]]es and other lower plants.",
additional = "{{also|Category:{{{langcode}}}:Mosses}}",
parents = {"biology", "botany"},
}
labels["cardiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cardiology]], the study of the [[heart]].",
parents = {"medicine", "circulatory system"},
}
labels["carpentry"] = {
type = "related-to",
description = "default",
parents = {"construction", "woodworking"},
}
labels["cartography"] = {
type = "related-to",
description = "default",
parents = {"භූගෝලවේදය"},
}
labels["catalysis"] = {
type = "related-to",
description = "default",
parents = {"chemical processes", "chemical reactions", "physical chemistry"},
}
labels["chemical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "chemistry"},
}
labels["chemical formulae"] = {
type = "name",
description = "default",
parents = {"chemical notation"},
}
labels["chemical notation"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "නාම", "symbols"},
}
labels["chemical reactions"] = {
type = "related-to,set",
description = "default",
parents = {"chemistry"},
}
labels["chemical reagents"] = {
type = "set",
description = "default",
parents = {"chemistry"},
}
labels["chemistry"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["Chinese astronomy"] = {
type = "related-to",
description = "default",
parents = {"astronomy"},
}
labels["Chinese phonetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"phonetics", "Chinese"},
}
labels["classical mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["classical studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "literature", "history"},
}
labels["climatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[climatology]], the study of [[climate]].",
parents = {"earth sciences"},
}
labels["clinical psychology"] = {
type = "related-to",
description = "default",
parents = {"psychology", "pathology"},
}
labels["computational linguistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "computer science"},
}
labels["computer science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "computing"},
}
labels["conchology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[conchology]], the study of mollusc [[shell]]s.",
parents = {"malacology"},
}
labels["constellations"] = {
type = "name",
description = "default",
parents = {"astronomy"},
}
labels["construction"] = {
type = "related-to",
description = "default",
parents = {"engineering", "ගෘහ නිර්මාණ ශිල්පය"},
}
labels["control theory"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "systems"},
}
labels["cosmology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cosmology]], the study of the [[universe]].",
parents = {"astronomy"},
}
labels["criminology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[criminology]], the study of [[crime]].",
additional = "{{also|Category:{{{langcode}}}:Crime}}",
parents = {"sociology", "crime"},
}
labels["cryptography"] = {
type = "related-to",
description = "default",
parents = {"formal sciences", "mathematics", "computer science"},
}
labels["cryptozoology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cryptozoology]], the [[pseudoscientific]] study of mythological creatures.",
additional = "{{also|Category:{{{langcode}}}:Mythological creatures}}",
parents = {"zoology", "paranormal"},
}
labels["crystallography"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය", "crystal"},
}
labels["cultural anthropology"] = {
type = "related-to",
description = "default",
parents = {"anthropology", "සංස්කෘතිය"},
}
labels["cybernetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"applied mathematics", "systems theory"},
}
labels["cytology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[cytology]], the study of cell biology, cell structure, formation, classification and related topics.",
parents = {"biology"},
}
labels["data management"] = {
type = "related-to",
description = "default",
parents = {"information science", "computer science"},
}
labels["demarcation lines"] = {
type = "name",
description = "=political [[demarcation line]]s",
parents = {"politics"},
}
labels["decision theory"] = {
type = "related-to",
description = "default",
parents = {"probability theory", "epistemology"},
}
labels["demography"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "statistics"},
}
labels["dentistry"] = {
type = "related-to",
description = "default",
parents = {"medicine", "teeth"},
}
labels["dermatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[dermatology]], the study of the [[skin]].",
additional = "{{also|Category:{{{langcode}}}:Skin}}",
parents = {"medicine"},
}
labels["developmental biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[developmental biology]], the study of the [[development]] of [[lifeform]]s.",
parents = {"biology"},
}
labels["earth sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["earthquake engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["ecology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ecology]], the study of interaction between [[life]] and its environment.",
parents = {"biology"},
}
labels["economics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[economics]], the study of the [[economy]].",
parents = {"සමාජවේද"},
}
labels["ecosystems"] = {
type = "related-to",
description = "default",
parents = {"ecology", "landforms"},
}
labels["electrencephalography"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[electrencephalography]], the electrical measurement of the [[brain]].",
additional = "{{also|Category:{{{langcode}}}:Brain}}",
parents = {"neuroscience"},
}
labels["electrical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "electricity"},
}
labels["electricity"] = {
type = "related-to",
description = "default",
parents = {"electromagnetism"},
}
labels["electrocardiography"] = {
type = "related-to",
description = "default",
parents = {"cardiology"},
}
labels["electrodynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"electromagnetism"},
}
labels["electrochemistry"] = {
type = "related-to",
description = "default",
parents = {"physical chemistry", "electricity"},
}
labels["electromagnetism"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["element nomenclature"] = {
type = "related-to",
description = "default",
parents = {"chemical notation", "නාම", "chemical elements"},
}
labels["embryology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[embryology]], the study of the [[embryo]].",
parents = {"biology", "developmental biology", "medicine"},
}
labels["emergency medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["endocrinology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[endocrinology]], the study of [[hormones]] and the [[endocrine system]].",
additional = "{{also|Category:{{{langcode}}}:Hormones}}",
parents = {"medicine"},
}
labels["engineering"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "technology"},
}
labels["enterprise engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["entomology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[entomology]], the study of [[insect]]s.",
additional = "{{also|Category:{{{langcode}}}:Insects}}",
parents = {"zoology", "arthropodology"},
}
labels["epidemiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[epidemiology]].",
parents = {"medicine"},
}
labels["ethnography"] = {
type = "related-to",
description = "default",
parents = {"anthropology"},
}
labels["ethnology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ethnology]], the study of [[people]]s.",
parents = {"anthropology"},
}
labels["ethology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ethology]], the study of [[animal]] [[behaviour]].",
parents = {"zoology"},
}
labels["evolutionary theory"] = {
type = "related-to",
description = "default",
parents = {"biology"},
}
labels["flat earth"] = {
type = "related-to",
description = "{{{langname}}} terms used by believers in a flat earth or related to the concept.",
parents = {"pseudoscience", "obsolete scientific theories"},
}
labels["flax"] = {
type = "related-to",
description = "default",
parents = {"agriculture", "Malpighiales order plants"},
}
labels["fluid dynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["forestry"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["functional group prefixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["functional group suffixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["gardens"] = {
type = "type",
description = "=places where plants are grown",
parents = {"home", "horticulture"},
}
labels["gastroenterology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[gastroenterology]], the study of the [[digestive system]].",
parents = {"medicine"},
}
labels["genetics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[genetics]], the study of [[gene]]s.",
parents = {"biology"},
}
labels["භූගෝලවේදය"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geography]], the study of various phenomena found on [[Earth]]'s surface.",
additional = "{{also|Category:{{{langcode}}}:Landforms|Category:{{{langcode}}}:Polities}}",
parents = {"earth sciences"},
}
labels["geological periods"] = {
type = "related-to",
description = "default",
parents = {"geology"},
}
labels["geology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geology]], the study of the solid parts of [[Earth]].",
parents = {"earth sciences"},
}
labels["geomorphology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[geomorphology]].",
parents = {"geology"},
}
labels["geopolitics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භූගෝලවේදය", "politics"},
}
labels["geospatial science"] = {
type = "related-to",
description = "default",
parents = {"earth sciences"},
}
labels["gerontology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[gerontology]], the study of [[aging]].",
additional = "{{also|Category:{{{langcode}}}:Age}}",
parents = {"medicine"},
}
labels["grammar"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["grammatical cases"] = {
type = "set",
description = "default",
parents = {"grammar"},
}
labels["grammatical moods"] = {
type = "set",
description = "default",
parents = {"grammar"},
}
labels["gravity"] = {
type = "related-to",
description = "default",
parents = {"acceleration", "astrophysics", "mechanics"},
}
labels["gynaecology"] = {
type = "related-to",
description = "default",
parents = {"medicine", "female"},
}
labels["helminthology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[helminthology]], the study of [[helminth]]s ([[parasitic]] [[worm#Noun|worms]]).",
additional = "{{also|Category:{{{langcode}}}:Flatworms}}",
parents = {"zoology"},
}
labels["hematology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hematology]], the study of [[blood]].",
parents = {"medicine"},
}
labels["hepatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hepatology]], the study of the [[liver]].",
parents = {"medicine"},
}
labels["herpetology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[herpetology]], the study of [[reptile]]s and amphibians.",
additional = "{{also|Category:{{{langcode}}}:Reptiles|Category:{{{langcode}}}:Amphibians}}",
parents = {"zoology"},
}
labels["homeopathy"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine"},
}
labels["horticulture"] = {
type = "related-to",
description = "default",
parents = {"agriculture", "botany"},
}
labels["hydroacoustics"] = {
type = "related-to",
description = "default no singularize",
parents = {"acoustics", "hydrology"},
}
labels["hydrocarbon chain prefixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["hydrocarbon chain suffixes"] = {
type = "set",
description = "default",
parents = {"organic chemistry"},
}
labels["hydrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[hydrology]], the study of [[water]], its movement and distribution.",
additional = "{{also|Category:{{{langcode}}}:Water}}",
parents = {"earth sciences", "water"},
}
labels["ichthyology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ichthyology]], the study of [[fish]].",
additional = "{{also|Category:{{{langcode}}}:Fish}}",
parents = {"zoology"},
}
labels["immunochemistry"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "immunology"},
}
labels["immunology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[immunology]], the study of the [[immune system]].",
parents = {"medicine"},
}
labels["Indo-European studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["information science"] = {
type = "related-to",
description = "default",
parents = {"applied sciences"},
}
labels["inorganic chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["interdisciplinary fields"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["isolines"] = {
type = "related-to",
description = "default",
parents = {"cartography", "meteorology"},
}
labels["Lagrange points"] = {
type = "related-to",
description = "default",
parents = {"orbits"},
}
labels["lexicography"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["library science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "education", "information science"},
}
labels["lichenology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[lichenology]], the study of [[lichen]]s.",
additional = "{{also|Category:{{{langcode}}}:Lichens}}",
parents = {"mycology", "phycology"},
}
labels["linguistic morphology"] = {
type = "related-to",
description = "default",
parents = {"වාග්වේදය"},
}
labels["වාග්වේදය"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[linguistics]], the study and analysis of [[language]].",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:භාෂාව}}",
parents = {"භාෂාව", "සමාජවේද"},
}
labels["maize (crop)"] = {
type = "related-to",
description = "=[[maize]] (called [[corn]] in North America) as a crop",
additional = "For terms related to maize as a food, see [[:Category:Maize (food)]] and for maize as a plant, see [[:Category:Maize (plant)]].",
parents = {"agriculture", "grains"},
}
labels["malacology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[malacology]], the study of [[mollusk]]s.",
additional = "{{also|Category:{{{langcode}}}:Mollusks}}",
parents = {"zoology"},
}
labels["mammalogy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mammalogy]], the study of [[mammal]]s.",
additional = "{{also|Category:{{{langcode}}}:Mammals}}",
parents = {"zoology"},
}
labels["marine biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[marine biology]], the study of [[life]] in the [[sea]].",
parents = {"biology"},
}
labels["masonry"] = {
type = "related-to",
description = "default",
parents = {"construction"},
}
labels["materials science"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "engineering"},
}
labels["mechanical engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["medical genetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"medicine", "genetics"},
}
labels["medicine"] = {
type = "related-to",
description = "{{{langname}}} terms that pertain to the the science and practice of [[medicine]].",
parents = {"biology", "healthcare"},
}
labels["metamaterials"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["physical constants"] = {
type = "set",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["machine learning"] = {
type = "related-to",
description = "default",
parents = {"artificial intelligence"},
}
labels["meteorology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[meteorology]], the study of [[weather]].",
additional = "{{also|Category:{{{langcode}}}:Weather}}",
parents = {"earth sciences", "atmosphere"},
}
labels["metrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[metrology]], the science of [[measure|measuring]].",
parents = {"applied sciences"},
wpcat = true,
commonscat=true,
}
labels["microbiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[microbiology]], the study of [[life]] at [[microscopic]] scales, too small for the [[human]] [[eye]].",
parents = {"biology"},
}
labels["microscopy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[microscopy]], the field of using [[microscopes]] for study.",
parents = {"optics", "microbiology"},
}
labels["mineralogy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mineralogy]], the study of [[mineral]]s.",
additional = "{{also|Category:{{{langcode}}}:Minerals}}",
parents = {"geology"},
}
labels["molecular biology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[molecular biology]], the study of the [[molecules]] found in [[life]], their functions and effects.",
parents = {"biochemistry", "biology", "genetics"},
}
labels["mycology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[mycology]], the study of [[fungi]].",
additional = "{{also|Category:{{{langcode}}}:Fungi}}",
parents = {"biology"},
}
labels["NASA"] = {
type = "related-to",
description = "=the United States National Aeronautics and Space Administration and the US space program",
parents = {"astronautics", "aviation"},
}
labels["nephrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[nephrology]], the study of the [[kidney]]s.",
parents = {"medicine"},
}
labels["neuroanatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neuroanatomy]], the study of the structure and organization of the [[nervous system]].",
parents = {"anatomy", "neurology", "neuroscience"},
}
labels["neurology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neurology]], the study of [[nerves]] and [[neurons]].",
parents = {"medicine", "neuroscience"},
}
labels["neuroscience"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[neuroscience]], the study of the [[nervous system]].",
parents = {"biology"},
}
labels["neurosurgery"] = {
type = "related-to",
description = "default",
parents = {"surgery", "neurology"},
}
labels["neutron"] = {
type = "related-to",
description = "default",
parents = {"nuclear physics"},
}
labels["neutron stars"] = {
type = "related-to",
description = "default",
parents = {"neutron", "gravity", "astrophysics", "relativity", "stars"},
}
labels["නාම පද"] = {
type = "related-to",
description = "default",
parents = {"parts of speech"},
}
labels["nuclear energy"] = {
type = "related-to",
description = "default",
parents = {"energy", "nuclear physics", "technology"},
}
labels["nuclear fusion"] = {
type = "related-to",
description = "default",
parents = {"nuclear energy"},
}
labels["nuclear physics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය", "quantum mechanics"},
}
labels["nuclear rocketry"] = {
type = "related-to",
description = "default",
parents = {"nuclear energy", "rocketry", "space access"},
}
labels["obstetrics"] = {
type = "related-to",
description = "default no singularize",
parents = {"developmental biology", "medicine", "pregnancy"},
}
labels["obsolete scientific theories"] = {
type = "set",
description = "{{{langname}}} terms for types or instances of [[obsolete]] [[scientific]] [[theory|theories]] that are no longer, or have never been, widely accepted.",
parents = {"history of science"},
}
labels["oceanography"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["oenology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[oenology]], the study of [[wine]] and [[winemaking]].",
additional = "{{also|Category:{{{langcode}}}:Wine}}",
parents = {"විද්යා"},
}
labels["oncology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[oncology]], the study of [[cancer]].",
parents = {"biology", "medicine", "pathology"},
}
labels["onomastics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[onomastics]], the study of [[name]]s.",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:නාම|:ප්රවර්ගය:{{{langname}}} නාම}}",
parents = {"වාග්වේදය", "නාම"},
}
labels["ophthalmology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ophthalmology]], the study of the [[eye]].",
additional = "{{also|Category:{{{langcode}}}:Eye}}",
parents = {"medicine", "vision"},
}
labels["optics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[optics]], the study of the behaviour of [[light]].",
additional = "{{also|Category:{{{langcode}}}:Light}}",
parents = {"භෞතිකවේදය"},
}
labels["orbits"] = {
type = "related-to",
description = "default",
parents = {"astronautics", "gravity", "space", "curves"},
}
labels["organic chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry"},
}
labels["orgonomy"] = {
type = "related-to",
description = "=the [[orgone]] theory proposed by [[w:William Reich|William Reich]]",
parents = {"alternative medicine", "pseudoscience"},
}
labels["ornithology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[ornithology]], the study of [[birds]].",
additional = "{{also|Category:{{{langcode}}}:Birds}}",
parents = {"zoology"},
}
labels["paleontology"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "geology"},
}
labels["palynology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[palynology]], the study of [[particle]]s and particulate matter.",
parents = {"geology"},
}
labels["paranormal"] = {
type = "related-to",
description = "default with the",
parents = {"pseudoscience"},
}
labels["parapsychology"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "pseudoscience"},
}
labels["parasitology"] = {
type = "related-to",
description = "default",
parents = {"pathology", "zoology"},
}
labels["particle physics"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[particle physics]], the study of [[subatomic]] [[particle]]s.",
additional = "{{also|Category:{{{langcode}}}:Subatomic particles}}",
parents = {"භෞතිකවේදය"},
}
labels["parts of speech"] = {
type = "related-to",
description = "=[[part of speech|parts of speech]]",
parents = {"grammar"},
}
labels["pathology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[pathology]], the study of [[disease]].",
additional = "{{also|Category:{{{langcode}}}:Disease}}",
parents = {"medicine", "disease"},
}
labels["petrochemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "chemical engineering", "oil industry", "petroleum"},
}
labels["petrology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[petrology]], the study of [[rock]].",
additional = "{{also|Category:{{{langcode}}}:Rocks}}",
parents = {"geology"},
}
labels["pharmacology"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "medicine"},
}
labels["pharmacy"] = {
type = "related-to",
description = "default",
parents = {"medicine", "pharmacology"},
}
labels["phonemes"] = {
type = "set",
description = "=contrastive sounds within a language",
parents = {"phonology"},
}
labels["phonetics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["phonology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phonology]], the organisation of [[speech]] sounds within a [[language]].",
parents = {"වාග්වේදය"},
}
labels["photochemistry"] = {
type = "related-to",
description = "default",
parents = {"physical chemistry", "light"},
}
labels["phrenology"] = {
type = "related-to",
description = "default",
parents = {"psychology", "pseudoscience"},
}
labels["phycology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phycology]], the study of [[algae]].",
additional = "{{also|Category:{{{langcode}}}:Algae}}",
parents = {"botany", "microbiology"},
}
labels["physical chemistry"] = {
type = "related-to",
description = "default",
parents = {"chemistry", "භෞතිකවේදය"},
}
labels["physical quantities"] = {
type = "set",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["භෞතිකවේදය"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
commonscat = true,
wpcat = true,
}
labels["physiology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[physiology]].",
parents = {"biology", "medicine"},
}
labels["phytopathology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[phytopathology]], the study of [[disease]] in [[plant]]s.",
additional = "{{also|Category:{{{langcode}}}:Plant diseases}}",
parents = {"pathology", "botany"},
}
labels["planetary nomenclature"] = {
type = "related-to",
description = "default",
parents = {"planetology"},
}
labels["planetology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[planetology]], the study of [[planet]]s.",
additional = "{{also|Category:{{{langcode}}}:Planets}}",
parents = {"astronomy", "geology"},
}
labels["plant anatomy"] = {
type = "related-to",
description = "{{{langname}}} terms used in the study of the structure of plants and their parts.",
parents = {"botany", "anatomy"},
}
labels["plastic surgery"] = {
type = "related-to",
description = "default",
parents = {"surgery"},
}
labels["political science"] = {
type = "related-to",
description = "default",
parents = {"සමාජවේද", "politics"},
}
labels["potential theory"] = {
type = "related-to",
description = "default",
parents = {"mathematics"},
}
labels["pragmatics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["prosody"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[prosody]], the study of the [[suprasegmental]] aspects of [[speech]].",
parents = {"වාග්වේදය"},
}
labels["pseudoscience"] = {
type = "related-to",
description = "default",
parents = {"විද්යා"},
}
labels["psychiatry"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["psychoanalysis"] = {
type = "related-to",
description = "default no singularize",
parents = {"psychology"},
}
labels["psychology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[psychology]], the study of the [[mind]].",
additional = "{{also|Category:{{{langcode}}}:Mind}}",
parents = {"සමාජවේද"},
}
labels["psychotherapy"] = {
type = "related-to",
description = "default",
parents = {"psychology"},
}
labels["pulmonology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[pulmonology]], the study of the [[respiratory system]], including the [[lung]]s.",
parents = {"medicine"},
}
labels["pyrotechnics"] = {
type = "related-to",
description = "default no singularize",
parents = {"විද්යා"},
}
labels["quantity"] = {
type = "related-to",
description = "default",
parents = {"mathematics"},
}
labels["quantum mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["relativity"] = {
type = "related-to",
description = "default",
parents = {"භෞතිකවේදය"},
}
labels["rheumatology"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["robotics"] = {
type = "related-to",
description = "default no singularize",
parents = {"engineering"},
}
labels["rocketry"] = {
type = "related-to",
description = "default",
parents = {"astronautics"},
}
labels["roofing"] = {
type = "related-to",
description = "default",
parents = {"construction"},
}
labels["rosiculture"] = {
type = "related-to",
description = "default",
parents = {"horticulture"},
}
labels["rotation"] = {
type = "related-to",
description = "default",
parents = {"mechanics", "geometry"},
}
labels["Russian space program"] = {
type = "related-to",
description = "=the Russian and Soviet space programs",
parents = {"astronautics", "aviation"},
}
labels["sales"] = {
type = "related-to",
description = "default no singularize",
parents = {"marketing"},
}
labels["seismology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[seismology]], the study of [[earthquake]]s.",
parents = {"geology"},
}
labels["semantics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["Semitic linguistics"] = {
type = "related-to",
description = "{{{langname}}} terms used in the study and analysis of [[Semitic]] [[language]]s.",
parents = {"වාග්වේදය"},
}
labels["semiotics"] = {
type = "related-to",
description = "default no singularize",
parents = {"සමාජවේද", "වාග්වේදය"},
}
labels["sexology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[sexology]], the study of [[human]] [[sexuality]].",
additional = "{{also|Category:{{{langcode}}}:Sex}}",
parents = {"psychology", "sex", "sociology"},
}
labels["SI units"] = {
type = "related-to",
description = "=[[International System of Units|SI]] [[unit of measure|units of measure]]",
parents = {"units of measure"},
}
labels["signal processing"] = {
type = "related-to",
description = "default",
parents = {"applied mathematics", "telecommunications"},
wpcat = true,
commonscat = true,
}
labels["සමාජවේද"] = {
type = "related-to",
description = "default with the",
parents = {"විද්යා", "සමාජය"},
}
labels["sociolinguistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය", "sociology"},
}
labels["sociology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[sociology]], the study of [[society]].",
additional = "{{also|:ප්රවර්ගය:{{{langcode}}}:සමාජය}}",
parents = {"සමාජවේද"},
}
labels["software engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "computer science", "software"},
wpcat = true,
commonscat = true,
}
labels["soil science"] = {
type = "related-to",
description = "default",
parents = {"earth sciences"},
}
labels["sorting algorithms"] = {
type = "set",
description = "default",
parents = {"theory of computing"},
}
labels["sound engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "sound"},
}
labels["space access"] = {
type = "related-to",
description = "default",
parents = {"astronautics"},
}
labels["space sciences"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "space"},
}
labels["spectroscopy"] = {
type = "related-to",
description = "default",
parents = {"analytical chemistry", "optics", "භෞතිකවේදය"},
}
labels["statistical mechanics"] = {
type = "related-to",
description = "default no singularize",
parents = {"mechanics"},
}
labels["statistics"] = {
type = "related-to",
description = "default no singularize",
parents = {"formal sciences", "mathematics"},
}
labels["surgery"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["surveying"] = {
type = "related-to",
description = "default",
parents = {"භූගෝලවේදය"},
}
labels["systems"] = {
type = "related-to",
description = "default",
parents = {"interdisciplinary fields", "විද්යා", "සමාජය"},
}
labels["systems engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering"},
}
labels["systems theory"] = {
type = "related-to",
description = "default",
parents = {"විද්යා", "systems"},
}
labels["taxonomy"] = {
type = "related-to",
description = "default",
additional = "For individual [[taxa]], see [[:Category:Taxonomic names]].",
parents = {"biology", "evolutionary theory"},
}
labels["taxonomic ranks"] = {
type = "set",
description = "default",
parents = {"taxonomy"},
}
labels["tenses"] = {
type = "related-to",
description = "default",
parents = {"grammar"},
}
labels["teratology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[teratology]], the study of abnormalities in the [[development]] of the [[body]].",
parents = {"developmental biology", "medicine", "pathology", "toxicology"},
}
labels["theory of computing"] = {
type = "related-to",
description = "{{{langname}}} terms used in theoretical discussion of [[computer science]] or [[computing]].",
parents = {"computer science"},
}
labels["thermodynamics"] = {
type = "related-to",
description = "default no singularize",
parents = {"භෞතිකවේදය"},
}
labels["tides"] = {
type = "related-to",
description = "default no singularize",
parents = {"gravity", "periodic occurrences"},
}
labels["toxicology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[toxicology]], the study of [[poisons]], [[toxins]] and other substances with negative effects on the [[body]].",
additional = "{{also|Category:{{{langcode}}}:Poisons}}",
parents = {"medicine", "pharmacology"},
}
labels["traditional Chinese medicine"] = {
type = "related-to",
description = "default",
parents = {"alternative medicine"},
}
labels["traffic engineering"] = {
type = "related-to",
description = "default",
parents = {"engineering", "road transport"},
}
labels["translation studies"] = {
type = "related-to",
description = "default no singularize",
parents = {"වාග්වේදය"},
}
labels["traumatology"] = {
type = "related-to",
description = "{{{langname}}} terms used in traumatology, the study of wounds and injuries caused by accidents or violence to a person.",
parents = {"medicine", "pathology"},
}
labels["ufology"] = {
type = "related-to",
description = "default",
parents = {"paranormal", "anti-gravity", "celestial inhabitants"},
}
labels["units of area"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of area|units of area]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of energy"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of energy|units of energy]].",
parents = {"units of measure", "energy"},
commonscat = false,
wpcat = true,
}
labels["units of length"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of length|units of length]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of mass"] = {
type = "set",
description = "{{{langname}}} terms that are [[w:unit of mass|units of mass]].",
parents = {"units of measure"},
commonscat = true,
wpcat = true,
}
labels["units of measure"] = {
type = "set",
description = "{{{langname}}} terms that are [[unit of measure|units of measure]].",
parents = {"quantity", "metrology"},
commonscat = true,
wpcat = "units of measurement",
}
labels["units of time"] = {
type = "set",
description = "{{{langname}}} terms that are [[unit of time|units of time]].",
parents = {"units of measure", "time"},
commonscat = "spans of time",
wpcat = true,
}
labels["urban studies"] = {
type = "related-to",
description = "default",
parents = {"applied sciences", "සමාජවේද"},
}
labels["urology"] = {
type = "related-to",
description = "default",
parents = {"medicine"},
}
labels["verbs"] = {
type = "related-to",
description = "default",
parents = {"parts of speech"},
}
labels["veterinary medicine"] = {
type = "related-to",
description = "default",
parents = {"medicine", "animals"},
}
labels["virology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[virology]], the study of [[virus]]es.",
additional = "{{also|Category:{{{langcode}}}:Viruses}}",
parents = {"medicine", "microbiology", "pathology"},
}
labels["volcanology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[volcanology]], the study of [[volcano]]es.",
parents = {"geology"},
}
labels["zoology"] = {
type = "related-to",
description = "{{{langname}}} terms used in [[zoology]], the study of [[animal]]s.",
additional = "{{also|Category:{{{langcode}}}:Animals}}",
parents = {"biology"},
}
labels["zymurgy"] = {
type = "related-to",
description = "default",
parents = {"biochemistry", "brewing"},
}
labels["colour and pattern morphs"] = {
type = "set",
description = "{{{langname}}} terms for [[colour]] and [[pattern]] [[morph#Etymology 2|morphs]]",
parents = {"zoology"},
}
labels["geological formations"] = {
type = "set",
description = "{{{langname}}} [[w:geological formation|geological formations]]",
parents = {"geology"},
}
return labels
4ubo6x26dnm1f0ldrmy2n9srfv72fe8
Module:category tree/topic/Buildings and structures
828
6057
238786
220865
2026-07-23T19:35:55Z
en>WingerBot
0
explicit 'description = "default"' unnecessary; remove it (manually assisted)
238786
Scribunto
text/plain
local labels = {}
labels["buildings and structures"] = {
type = "type",
description = "=[[building]]s and [[structure]]s",
parents = {"architecture"},
}
labels["animal dwellings"] = {
type = "type",
parents = {"buildings and structures", "zoology"},
}
labels["bridges"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["buildings"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["pyramids"] = {
type = "set,related-to",
parents = {"buildings"},
}
labels["rooms"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["kitchen"] = {
type = "related-to",
parents = {"rooms", "cooking"},
}
labels["ports and harbours"] = {
type = "related-to",
parents = {"buildings and structures", "nautical", "commerce"},
}
labels["shops"] = {
type = "type",
parents = {"buildings", "businesses"},
}
labels["walls and fences"] = {
type = "type",
description = "=[[wall]]s and [[fence]]s",
parents = {"buildings and structures"},
}
labels["toilet (room)"] = {
type = "related-to",
description = "=[[flush toilet]]s or rooms containing flush toilets",
parents = {"hygiene", "rooms"},
}
return labels
2n763btaewrwn483ho43sx0ihlkub0s
238787
238786
2026-11-11T14:25:02Z
Lee
19
[[:en:Module:category_tree/topic/Buildings_and_structures]] වෙතින් එක් සංශෝධනයක්
238786
Scribunto
text/plain
local labels = {}
labels["buildings and structures"] = {
type = "type",
description = "=[[building]]s and [[structure]]s",
parents = {"architecture"},
}
labels["animal dwellings"] = {
type = "type",
parents = {"buildings and structures", "zoology"},
}
labels["bridges"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["buildings"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["pyramids"] = {
type = "set,related-to",
parents = {"buildings"},
}
labels["rooms"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["kitchen"] = {
type = "related-to",
parents = {"rooms", "cooking"},
}
labels["ports and harbours"] = {
type = "related-to",
parents = {"buildings and structures", "nautical", "commerce"},
}
labels["shops"] = {
type = "type",
parents = {"buildings", "businesses"},
}
labels["walls and fences"] = {
type = "type",
description = "=[[wall]]s and [[fence]]s",
parents = {"buildings and structures"},
}
labels["toilet (room)"] = {
type = "related-to",
description = "=[[flush toilet]]s or rooms containing flush toilets",
parents = {"hygiene", "rooms"},
}
return labels
2n763btaewrwn483ho43sx0ihlkub0s
238788
238787
2026-11-11T14:26:21Z
Lee
19
"architecture" සිට "ගෘහ නිර්මාණ ශිල්පය" වෙතට
238788
Scribunto
text/plain
local labels = {}
labels["buildings and structures"] = {
type = "type",
description = "=[[building]]s and [[structure]]s",
parents = {"ගෘහ නිර්මාණ ශිල්පය"},
}
labels["animal dwellings"] = {
type = "type",
parents = {"buildings and structures", "zoology"},
}
labels["bridges"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["buildings"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["pyramids"] = {
type = "set,related-to",
parents = {"buildings"},
}
labels["rooms"] = {
type = "type",
parents = {"buildings and structures"},
}
labels["kitchen"] = {
type = "related-to",
parents = {"rooms", "cooking"},
}
labels["ports and harbours"] = {
type = "related-to",
parents = {"buildings and structures", "nautical", "commerce"},
}
labels["shops"] = {
type = "type",
parents = {"buildings", "businesses"},
}
labels["walls and fences"] = {
type = "type",
description = "=[[wall]]s and [[fence]]s",
parents = {"buildings and structures"},
}
labels["toilet (room)"] = {
type = "related-to",
description = "=[[flush toilet]]s or rooms containing flush toilets",
parents = {"hygiene", "rooms"},
}
return labels
bvudfxhunafwrlt96n12wxzxj3lhojz
Module:languages/documentation
828
6086
238796
210946
2025-12-21T05:28:41Z
en>Benwing2
0
use omit_intro to avoid duplicating the intro in the Language object section
238796
wikitext
text/x-wiki
{{language data search}}
This module is used to retrieve and manage the languages that can have Wiktionary entries, and the information associated with them. See [[Wiktionary:Languages]] for more information.
For the languages and language varieties that may be used in etymologies, see [[Module:etymology languages]]. For language families, which sometimes also appear in etymologies, see [[Module:families]].
This module provides access to other modules. To access the information from within a template, see [[Module:languages/templates]].
The information itself is stored in the various data modules that are subpages of this module. These modules should '''not''' be used directly by any other module, the data should only be accessed through the functions provided by this module.
Data submodules:
* [[Module:languages/data/2|Two-letter codes]]
* Three-letter codes by their first letter: {{#invoke:string/templates|gsub|abcdefghijklmnopqrstuvwxyz|%a|<nowiki /> [[Module:languages/data/3/%1| %1 ]]}}
* [[Module:languages/data/exceptional|Longer codes containing hyphens (<code>-</code>)]]
Extra data submodules (for less frequently used data):
* [[Module:languages/data/2/extra|Two-letter codes]]
* Three-letter codes by their first letter: {{#invoke:string/templates|gsub|abcdefghijklmnopqrstuvwxyz|%a|<nowiki /> [[Module:languages/data/3/%1/extra| %1 ]]}}
* [[Module:languages/data/exceptional/extra|Longer codes containing hyphens (<code>-</code>)]]
==Finding and retrieving languages==
The module exports a number of functions that are used to find languages.
{{module documentation|section_level=3|identifier=^export}}
==Language objects==
A <code class="nf">Language</code> object is returned from one of the functions above. It is a Lua representation of a language and the data associated with it. It has a number of methods that can be called on it, using the <code>:</code> syntax. For example:
<syntaxhighlight lang="lua">
local m_languages = require("Module:languages")
local lang = m_languages.getByCode("fr")
local name = lang:getCanonicalName()
-- "name" will now be "French"
</syntaxhighlight>
{{module documentation|section_level=3|identifier=^Language|omit_intro=1}}
==Error function==
See [[Module:languages/error]].
==Subpages==
{{subpages|Module:languages}}
==See also==
* [[Module:families]]
<includeonly>
{{module cat|-|Language and script,JSON-generating}}
</includeonly>
ozfb44egvrsll6kcf9f1s53umjfstom
238797
238796
2026-11-12T06:05:39Z
Lee
19
[[:en:Module:languages/documentation]] වෙතින් එක් සංශෝධනයක්
238796
wikitext
text/x-wiki
{{language data search}}
This module is used to retrieve and manage the languages that can have Wiktionary entries, and the information associated with them. See [[Wiktionary:Languages]] for more information.
For the languages and language varieties that may be used in etymologies, see [[Module:etymology languages]]. For language families, which sometimes also appear in etymologies, see [[Module:families]].
This module provides access to other modules. To access the information from within a template, see [[Module:languages/templates]].
The information itself is stored in the various data modules that are subpages of this module. These modules should '''not''' be used directly by any other module, the data should only be accessed through the functions provided by this module.
Data submodules:
* [[Module:languages/data/2|Two-letter codes]]
* Three-letter codes by their first letter: {{#invoke:string/templates|gsub|abcdefghijklmnopqrstuvwxyz|%a|<nowiki /> [[Module:languages/data/3/%1| %1 ]]}}
* [[Module:languages/data/exceptional|Longer codes containing hyphens (<code>-</code>)]]
Extra data submodules (for less frequently used data):
* [[Module:languages/data/2/extra|Two-letter codes]]
* Three-letter codes by their first letter: {{#invoke:string/templates|gsub|abcdefghijklmnopqrstuvwxyz|%a|<nowiki /> [[Module:languages/data/3/%1/extra| %1 ]]}}
* [[Module:languages/data/exceptional/extra|Longer codes containing hyphens (<code>-</code>)]]
==Finding and retrieving languages==
The module exports a number of functions that are used to find languages.
{{module documentation|section_level=3|identifier=^export}}
==Language objects==
A <code class="nf">Language</code> object is returned from one of the functions above. It is a Lua representation of a language and the data associated with it. It has a number of methods that can be called on it, using the <code>:</code> syntax. For example:
<syntaxhighlight lang="lua">
local m_languages = require("Module:languages")
local lang = m_languages.getByCode("fr")
local name = lang:getCanonicalName()
-- "name" will now be "French"
</syntaxhighlight>
{{module documentation|section_level=3|identifier=^Language|omit_intro=1}}
==Error function==
See [[Module:languages/error]].
==Subpages==
{{subpages|Module:languages}}
==See also==
* [[Module:families]]
<includeonly>
{{module cat|-|Language and script,JSON-generating}}
</includeonly>
ozfb44egvrsll6kcf9f1s53umjfstom
ප්රවර්ගය:Reconstructed languages
14
6720
238804
27219
2026-09-23T01:20:30Z
en>Benwing2
0
Replaced content with "{{auto cat}}"
238804
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238805
238804
2026-11-12T06:31:35Z
Lee
19
[[:en:Category:Reconstructed_languages]] වෙතින් එක් සංශෝධනයක්
238804
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
සැකිල්ල:cite-book/documentation
10
7090
238743
219747
2026-11-11T11:59:49Z
Pinthura
2424
Bot: Replacing category Citation templates with [[:ප්රවර්ගය:උපහරණ සැකිලි|උපහරණ සැකිලි]]
238743
wikitext
text/x-wiki
{{documentation subpage}}
See {{tl|quote-book}} for usage.
{{citation templates}}
<includeonly>
[[ප්රවර්ගය:උපහරණ සැකිලි]]
[[de:Vorlage:Literatur]]
[[fr:Modèle:ouvrage]]
[[tr:Şablon:kitap kaynağı]]
[[vi:Tiêu bản:Chú thích sách]]
</includeonly>
o3yihr1bwtsigw7u5b4xor2pzon4mut
Module:links/testcases
828
7723
238838
227024
2026-11-01T05:45:06Z
en>FenaBot
0
[[Module:UnitTests]]: preprocess_equals to expands_to, remove show_difference
238838
Scribunto
text/plain
--[=[
Unit tests for [[Module:links]]. Click talk page to run tests.
]=]
local p = require('Module:UnitTests')
local m_links = require('Module:links')
local m_util = require('Module:utilities')
local get_lang_by_code = require("Module:languages").getByCode
local function tag(lang_code, sc_code)
return function (text)
return '<span class="' .. sc_code .. '" lang="' .. lang_code .. '">' .. text .. '</span>'
end
end
local options = { nowiki = true }
function p:check_link(example, expected)
self:expands_to(example, expected, options)
end
function p:test_links()
local frame = mw.getCurrentFrame()
local temp = frame.args.temp or "l"
local compat = frame.args.compat
local lang = compat and "lang=" or ""
local link_examples = {
'anchor',
{
'{{' .. temp .. '|' .. lang .. 'en|-er#Etymology 2|-er}}',
'<span class="Latn" lang="en">[[-er#Etymology 2|-er]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[-er#Etymology 2|-er]]}}',
'<span class="Latn" lang="en">[[-er#Etymology 2|-er]]</span>'
},
'character entity references in link target',
{
'{{' .. temp .. '|' .. lang .. 'nia|wa'a}}',
'<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'nia|wa'a}}',
'<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'ja|恵‌美|恵&#8204;美}}',
'<span class="Jpan" lang="ja">[[恵美#Japanese|恵&#8204;美]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|&}}',
'<span class="None" lang="en">[[Unsupported titles/Amp#English|&]]</span>'
},
'simple linking', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'la|verbum}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span>'
},
'using wikilinks',
{
'{{' .. temp .. '|' .. lang .. 'en|[[God]] be [[with]] [[you]]}}',
'<span class="Latn" lang="en">[[God#English|God]] be [[with#English|with]] [[you#English|you]]</span>'
},
'alternative text',
{
'{{' .. temp .. '|' .. lang .. 'en|go|went}}',
'<span class="Latn" lang="en">[[go#English|went]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|to [[go]]|went}}',
'<span class="Latn" lang="en">to [[go#English|go]]</span>'
},
'sense id',
{
'{{' .. temp .. '|' .. lang .. 'en|go|id=game}}',
'<span class="Latn" lang="en">[[go#English-game|go]]</span>'
},
'constructed terms', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'sjn|mithril}}',
'<span class="Latn" lang="sjn">[[Appendix:Sindarin/mithril|mithril]]</span>'
},
'reconstructed terms', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'ine-pro|*bʰréh₂tēr}}',
'<span class="Latn" lang="ine-pro">[[Reconstruction:Proto-Indo-European/bʰréh₂tēr|*bʰréh₂tēr]]</span>'
},
{
'{{#iferror:{{' .. temp .. '|' .. lang .. 'ine-pro|bʰréh₂tēr}}|Script error}}',
'Script error'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|[[*dьnь]] [[*serda]]}}',
'<span class="Latn" lang="sla-pro">[[Reconstruction:Proto-Slavic/dьnь|*dьnь]] [[Reconstruction:Proto-Slavic/serda|*serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'la|verbum .. [[verbum]] .. [[*verbum]] .. [[*verbum|verbum]] .. [[*verbum|*verba]]}}',
'<span class="Latn" lang="la">verbum .. [[verbum#Latin|verbum]] .. [[Reconstruction:Latin/verbum|*verbum]] .. [[Reconstruction:Latin/verbum|verbum]] .. [[Reconstruction:Latin/verbum|*verba]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[serda]]}}',
'<span class="Latn" lang="sla-pro">*[[Reconstruction:Proto-Slavic/serda|serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[*serda]] .. [[*serda]] .. [[serda]] .. [[*serda|serda]] .. [[*serda|*serda]]}}',
'<span class="Latn" lang="sla-pro">[[Reconstruction:Proto-Slavic/*serda|*serda]] .. [[Reconstruction:Proto-Slavic/*serda|*serda]] .. [[Reconstruction:Proto-Slavic/serda|serda]] .. [[Reconstruction:Proto-Slavic/*serda|serda]] .. [[Reconstruction:Proto-Slavic/*serda|*serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[dьnь|alt1]] [[serda|alt2]]}}',
'<span class="Latn" lang="sla-pro">*[[Reconstruction:Proto-Slavic/dьnь|alt1]] [[Reconstruction:Proto-Slavic/serda|alt2]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'und|[[attested]] .. [[*unattested]] .. [[*unattested|unattested-alt]]}}',
'<span class="Zyyy" lang="und">[[attested|attested]] .. *unattested .. unattested-alt</span>[[Category:Undetermined language links]]'
},
'script detection', -- (lang_obj:findBestScript())
{
'{{' .. temp .. '|' .. lang .. 'sh|српски}} / {{' .. temp .. '|' .. lang .. 'sh|srpski}}',
'<span class="Cyrl" lang="sh">[[српски#Serbo-Croatian|српски]]</span> / <span class="Latn" lang="sh">[[srpski#Serbo-Croatian|srpski]]</span>'
},
'target page\'s title', -- (Language:stripDiacritics())
{
'{{' .. temp .. '|' .. lang .. 'la|verbō}}',
'<span class="Latn" lang="la">[[verbo#Latin|verbō]]</span>'
},
'gender and number', -- ([[Module:gender and number]])
{
'{{' .. temp .. '|' .. lang .. 'la|verbum|g=m}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span> <span class="gender"><abbr title="masculine gender">m</abbr></span>'
},
{
'{{' .. temp .. '|' .. lang .. 'la|verbum|g=m|g2=f}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span> <span class="gender"><abbr title="masculine gender">m</abbr> or <abbr title="feminine gender">f</abbr></span>'
},
'transliteration',
{
'{{' .. temp .. '|' .. lang .. 'ar|كلمة|tr=kalima}}',
'<span class="Arab" lang="ar">[[كلمة#Arabic|كلمة]]</span>‎ <span class="mention-gloss-paren annotation-paren">(</span><span lang="ar-Latn" class="tr Latn">kalima</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'ru|русский}}',
'<span class="Cyrl" lang="ru">[[русский#Russian|русский]]</span> <span class="mention-gloss-paren annotation-paren">(</span><span lang="ru-Latn" class="tr Latn">russkij</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
'gloss',
{
'{{' .. temp .. '|' .. lang .. 'ru|русский|gloss=Russian}}',
'<span class="Cyrl" lang="ru">[[русский#Russian|русский]]</span> <span class="mention-gloss-paren annotation-paren">(</span><span lang="ru-Latn" class="tr Latn">russkij</span>, <span class="mention-gloss-double-quote">“</span><span class="mention-gloss">Russian</span><span class="mention-gloss-double-quote">”</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
'Wikipedia link',
{
'{{' .. temp .. '|' .. lang .. 'en|w:word}}',
'<span class="Latn" lang="en">[[w:word|word]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[w:English language]]}}',
'<span class="Latn" lang="en">[[w:English language|w:English language]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[wikipedia:English language]]}}',
'<span class="Latn" lang="en">[[wikipedia:English language|wikipedia:English language]]</span>'
},
'Linking to titles with special characters: asterisk, slash',
{
'{{' .. temp .. '|' .. lang .. 'mul|/}}',
'<span class="None" lang="mul">[[:/#Translingual|/]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'mul|//}}',
'<span class="None" lang="mul">[[://#Translingual|//]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'mul|*}}',
'<span class="None" lang="mul">[[*#Translingual|*]]</span>'
},
}
self:iterate(link_examples, 'check_link')
end
function p:check_strip_diacritics(lang_code, unstripped, stripped)
local lang_obj = get_lang_by_code(lang_code)
local sc_code = lang_obj:findBestScript(unstripped):getCode()
self:equals(
('[%s] <i class="mention %s" lang="%s">%s</i>'):format(lang_code, sc_code, lang_code, unstripped),
lang_obj:stripDiacritics(unstripped),
stripped,
{ display = tag(lang_code, sc_code) }
)
end
function p:test_remove_diacritics()
-- insert here lines of the form:
local examples = {
{ 'ru', 'ба́бушка', 'бабушка' },
{ 'mk', 'ЃѓЌќ - е́а́́', 'ЃѓЌќ - еа' }, -- [[w:Macedonian alphabet]]
{ 'sh', 'Łł ĆćŃńŹź Ŭŭ - ȁàȃáā ȐȒŔ ѝӣ', 'Łł ĆćŃńŹź Ŭŭ - aaaaa RRR ии' }, -- [[w:Serbian Cyrillic alphabet]] / [[w:Gaj's Latin alphabet]]
{ 'grc', 'ᾱ, ᾱ́, ᾰ̓́', 'α, ά, ἄ' },
}
self:iterate(examples, 'check_strip_diacritics')
end
function p:test_section_link()
local examples = {
{
"w:Hindustani phonology#Vowels [ɛ], [ɛː]",
"[[w:Hindustani phonology#Vowels_%5B%C9%9B%5D,_%5B%C9%9B%CB%90%5D|"
.. "w:Hindustani phonology § Vowels [ɛ], [ɛː]]]"
},
}
self:iterate(
examples,
function (self, page, expected)
self:equals(
mw.text.nowiki(page),
m_links.section_link(page),
expected)
end)
end
return p
8js6qayxmeec0n8b451io6nlm7qypwr
238839
238838
2026-11-12T09:00:09Z
Lee
19
[[:en:Module:links/testcases]] වෙතින් එක් සංශෝධනයක්
238838
Scribunto
text/plain
--[=[
Unit tests for [[Module:links]]. Click talk page to run tests.
]=]
local p = require('Module:UnitTests')
local m_links = require('Module:links')
local m_util = require('Module:utilities')
local get_lang_by_code = require("Module:languages").getByCode
local function tag(lang_code, sc_code)
return function (text)
return '<span class="' .. sc_code .. '" lang="' .. lang_code .. '">' .. text .. '</span>'
end
end
local options = { nowiki = true }
function p:check_link(example, expected)
self:expands_to(example, expected, options)
end
function p:test_links()
local frame = mw.getCurrentFrame()
local temp = frame.args.temp or "l"
local compat = frame.args.compat
local lang = compat and "lang=" or ""
local link_examples = {
'anchor',
{
'{{' .. temp .. '|' .. lang .. 'en|-er#Etymology 2|-er}}',
'<span class="Latn" lang="en">[[-er#Etymology 2|-er]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[-er#Etymology 2|-er]]}}',
'<span class="Latn" lang="en">[[-er#Etymology 2|-er]]</span>'
},
'character entity references in link target',
{
'{{' .. temp .. '|' .. lang .. 'nia|wa'a}}',
'<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'nia|wa'a}}',
'<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'ja|恵‌美|恵&#8204;美}}',
'<span class="Jpan" lang="ja">[[恵美#Japanese|恵&#8204;美]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|&}}',
'<span class="None" lang="en">[[Unsupported titles/Amp#English|&]]</span>'
},
'simple linking', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'la|verbum}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span>'
},
'using wikilinks',
{
'{{' .. temp .. '|' .. lang .. 'en|[[God]] be [[with]] [[you]]}}',
'<span class="Latn" lang="en">[[God#English|God]] be [[with#English|with]] [[you#English|you]]</span>'
},
'alternative text',
{
'{{' .. temp .. '|' .. lang .. 'en|go|went}}',
'<span class="Latn" lang="en">[[go#English|went]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|to [[go]]|went}}',
'<span class="Latn" lang="en">to [[go#English|go]]</span>'
},
'sense id',
{
'{{' .. temp .. '|' .. lang .. 'en|go|id=game}}',
'<span class="Latn" lang="en">[[go#English-game|go]]</span>'
},
'constructed terms', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'sjn|mithril}}',
'<span class="Latn" lang="sjn">[[Appendix:Sindarin/mithril|mithril]]</span>'
},
'reconstructed terms', -- ([[Module:languages]])
{
'{{' .. temp .. '|' .. lang .. 'ine-pro|*bʰréh₂tēr}}',
'<span class="Latn" lang="ine-pro">[[Reconstruction:Proto-Indo-European/bʰréh₂tēr|*bʰréh₂tēr]]</span>'
},
{
'{{#iferror:{{' .. temp .. '|' .. lang .. 'ine-pro|bʰréh₂tēr}}|Script error}}',
'Script error'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|[[*dьnь]] [[*serda]]}}',
'<span class="Latn" lang="sla-pro">[[Reconstruction:Proto-Slavic/dьnь|*dьnь]] [[Reconstruction:Proto-Slavic/serda|*serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'la|verbum .. [[verbum]] .. [[*verbum]] .. [[*verbum|verbum]] .. [[*verbum|*verba]]}}',
'<span class="Latn" lang="la">verbum .. [[verbum#Latin|verbum]] .. [[Reconstruction:Latin/verbum|*verbum]] .. [[Reconstruction:Latin/verbum|verbum]] .. [[Reconstruction:Latin/verbum|*verba]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[serda]]}}',
'<span class="Latn" lang="sla-pro">*[[Reconstruction:Proto-Slavic/serda|serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[*serda]] .. [[*serda]] .. [[serda]] .. [[*serda|serda]] .. [[*serda|*serda]]}}',
'<span class="Latn" lang="sla-pro">[[Reconstruction:Proto-Slavic/*serda|*serda]] .. [[Reconstruction:Proto-Slavic/*serda|*serda]] .. [[Reconstruction:Proto-Slavic/serda|serda]] .. [[Reconstruction:Proto-Slavic/*serda|serda]] .. [[Reconstruction:Proto-Slavic/*serda|*serda]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'sla-pro|*[[dьnь|alt1]] [[serda|alt2]]}}',
'<span class="Latn" lang="sla-pro">*[[Reconstruction:Proto-Slavic/dьnь|alt1]] [[Reconstruction:Proto-Slavic/serda|alt2]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'und|[[attested]] .. [[*unattested]] .. [[*unattested|unattested-alt]]}}',
'<span class="Zyyy" lang="und">[[attested|attested]] .. *unattested .. unattested-alt</span>[[Category:Undetermined language links]]'
},
'script detection', -- (lang_obj:findBestScript())
{
'{{' .. temp .. '|' .. lang .. 'sh|српски}} / {{' .. temp .. '|' .. lang .. 'sh|srpski}}',
'<span class="Cyrl" lang="sh">[[српски#Serbo-Croatian|српски]]</span> / <span class="Latn" lang="sh">[[srpski#Serbo-Croatian|srpski]]</span>'
},
'target page\'s title', -- (Language:stripDiacritics())
{
'{{' .. temp .. '|' .. lang .. 'la|verbō}}',
'<span class="Latn" lang="la">[[verbo#Latin|verbō]]</span>'
},
'gender and number', -- ([[Module:gender and number]])
{
'{{' .. temp .. '|' .. lang .. 'la|verbum|g=m}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span> <span class="gender"><abbr title="masculine gender">m</abbr></span>'
},
{
'{{' .. temp .. '|' .. lang .. 'la|verbum|g=m|g2=f}}',
'<span class="Latn" lang="la">[[verbum#Latin|verbum]]</span> <span class="gender"><abbr title="masculine gender">m</abbr> or <abbr title="feminine gender">f</abbr></span>'
},
'transliteration',
{
'{{' .. temp .. '|' .. lang .. 'ar|كلمة|tr=kalima}}',
'<span class="Arab" lang="ar">[[كلمة#Arabic|كلمة]]</span>‎ <span class="mention-gloss-paren annotation-paren">(</span><span lang="ar-Latn" class="tr Latn">kalima</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'ru|русский}}',
'<span class="Cyrl" lang="ru">[[русский#Russian|русский]]</span> <span class="mention-gloss-paren annotation-paren">(</span><span lang="ru-Latn" class="tr Latn">russkij</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
'gloss',
{
'{{' .. temp .. '|' .. lang .. 'ru|русский|gloss=Russian}}',
'<span class="Cyrl" lang="ru">[[русский#Russian|русский]]</span> <span class="mention-gloss-paren annotation-paren">(</span><span lang="ru-Latn" class="tr Latn">russkij</span>, <span class="mention-gloss-double-quote">“</span><span class="mention-gloss">Russian</span><span class="mention-gloss-double-quote">”</span><span class="mention-gloss-paren annotation-paren">)</span>'
},
'Wikipedia link',
{
'{{' .. temp .. '|' .. lang .. 'en|w:word}}',
'<span class="Latn" lang="en">[[w:word|word]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[w:English language]]}}',
'<span class="Latn" lang="en">[[w:English language|w:English language]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'en|[[wikipedia:English language]]}}',
'<span class="Latn" lang="en">[[wikipedia:English language|wikipedia:English language]]</span>'
},
'Linking to titles with special characters: asterisk, slash',
{
'{{' .. temp .. '|' .. lang .. 'mul|/}}',
'<span class="None" lang="mul">[[:/#Translingual|/]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'mul|//}}',
'<span class="None" lang="mul">[[://#Translingual|//]]</span>'
},
{
'{{' .. temp .. '|' .. lang .. 'mul|*}}',
'<span class="None" lang="mul">[[*#Translingual|*]]</span>'
},
}
self:iterate(link_examples, 'check_link')
end
function p:check_strip_diacritics(lang_code, unstripped, stripped)
local lang_obj = get_lang_by_code(lang_code)
local sc_code = lang_obj:findBestScript(unstripped):getCode()
self:equals(
('[%s] <i class="mention %s" lang="%s">%s</i>'):format(lang_code, sc_code, lang_code, unstripped),
lang_obj:stripDiacritics(unstripped),
stripped,
{ display = tag(lang_code, sc_code) }
)
end
function p:test_remove_diacritics()
-- insert here lines of the form:
local examples = {
{ 'ru', 'ба́бушка', 'бабушка' },
{ 'mk', 'ЃѓЌќ - е́а́́', 'ЃѓЌќ - еа' }, -- [[w:Macedonian alphabet]]
{ 'sh', 'Łł ĆćŃńŹź Ŭŭ - ȁàȃáā ȐȒŔ ѝӣ', 'Łł ĆćŃńŹź Ŭŭ - aaaaa RRR ии' }, -- [[w:Serbian Cyrillic alphabet]] / [[w:Gaj's Latin alphabet]]
{ 'grc', 'ᾱ, ᾱ́, ᾰ̓́', 'α, ά, ἄ' },
}
self:iterate(examples, 'check_strip_diacritics')
end
function p:test_section_link()
local examples = {
{
"w:Hindustani phonology#Vowels [ɛ], [ɛː]",
"[[w:Hindustani phonology#Vowels_%5B%C9%9B%5D,_%5B%C9%9B%CB%90%5D|"
.. "w:Hindustani phonology § Vowels [ɛ], [ɛː]]]"
},
}
self:iterate(
examples,
function (self, page, expected)
self:equals(
mw.text.nowiki(page),
m_links.section_link(page),
expected)
end)
end
return p
8js6qayxmeec0n8b451io6nlm7qypwr
Module:languages
828
7902
238798
228945
2026-10-13T01:43:37Z
en>Benwing2
0
make toJSON return pseudo-family codes not actual family objects
238798
Scribunto
text/plain
--[==[ intro:
This module implements fetching of language-specific information and processing text in a given language.
===Types of languages===
There are two types of languages: full languages and etymology-only languages. The essential difference is that only
full languages appear in L2 headings in vocabulary entries, and hence categories like [[:Category:French nouns]] exist
only for full languages. Etymology-only languages have either a full language or another etymology-only language as
their parent (in the parent-child inheritance sense), and for etymology-only languages with another etymology-only
language as their parent, a full language can always be derived by following the parent links upwards. For example,
"Canadian French", code `fr-CA`, is an etymology-only language whose parent is the full language "French", code `fr`.
An example of an etymology-only language with another etymology-only parent is "Northumbrian Old English", code
`ang-nor`, which has "Anglian Old English", code `ang-ang` as its parent; this is an etymology-only language whose
parent is "Old English", code `ang`, which is a full language. (This is because Northumbrian Old English is considered
a variety of Anglian Old English.) Sometimes the parent is the "Undetermined" language, code `und`; this is the case,
for example, for "substrate" languages such as "Pre-Greek", code `qsb-grc`, and "the BMAC substrate", code `qsb-bma`.
It is important to distinguish language ''parents'' from language ''ancestors''. The parent-child relationship is one
of containment, i.e. if X is a child of Y, X is considered a variety of Y. On the other hand, the ancestor-descendant
relationship is one of descent in time. For example, "Classical Latin", code `la-cla`, and "Late Latin", code `la-lat`,
are both etymology-only languages with "Latin", code `la`, as their parents, because both of the former are varieties
of Latin. However, Late Latin does *NOT* have Classical Latin as its parent because Late Latin is *not* a variety of
Classical Latin; rather, it is a descendant. There is in fact a separate `ancestors` field that is used to express the
ancestor-descendant relationship, and Late Latin's ancestor is given as Classical Latin. It is also important to note
that sometimes an etymology-only language is actually the conceptual ancestor of its parent language. This happens,
for example, with "Old Italian" (code `roa-oit`), which is an etymology-only variant of full language "Italian" (code
`it`), and with "Old Latin" (code `itc-ola`), which is an etymology-only variant of Latin. In both cases, the full
language has the etymology-only variant listed as an ancestor. This allows a Latin term to inherit from Old Latin
using the {{tl|inh}} template (where in this template, "inheritance" refers to ancestral inheritance, i.e. inheritance
in time, rather than in the parent-child sense); likewise for Italian and Old Italian.
Full languages come in three subtypes:
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the
main namespace. There may also be reconstructed terms for the language, which are placed in the
{Reconstruction} namespace and must be prefixed with * to indicate a reconstruction. Most full languages
are natural (not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük,
among others) are also allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with
*. Languages such as Proto-Indo-European and Proto-Germanic are in this category.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in
the Appendix namespace, but they are not reconstructed and therefore should not have *
prefixed in links. Most constructed languages are of this subtype.
Both full languages and etymology-only languages have a {Language} object associated with them, which is fetched using
the {getByCode} function in [[Module:languages]] to convert a language code to a {Language} object. Depending on the
options supplied to this function, etymology-only languages may or may not be accepted, and family codes may be
accepted (returning a {Family} object as described in [[Module:families]]). There are also separate {getByCanonicalName}
functions in [[Module:languages]] and [[Module:etymology languages]] to convert a language's canonical name to a
{Language} object (depending on whether the canonical name refers to a full or etymology-only language).
===Textual representations===
Textual strings belonging to a given language come in several different ''text variants'':
# The ''input text'' is what the user supplies in wikitext, in the parameters to {{tl|m}}, {{tl|l}}, {{tl|ux}},
{{tl|t}}, {{tl|lang}} and the like.
# The ''corrected input text'' is the input text with some corrections and/or normalizations applied, such as
bad-character replacements for certain languages, like replacing `l` or `1` to [[palochka]] in some languages written
in Cyrillic. (FIXME: This currently goes under the name ''display text'' but that will be repurposed below. Also,
[[User:Surjection]] suggests renaming this to ''normalized input text'', but "normalized" is used in a different sense
in [[Module:usex]].)
# The ''display text'' is the text in the form as it will be displayed to the user. This is what appears in headwords,
in usexes, in displayed internal links, etc. This can include accent marks that are removed to form the stripped
display text (see below), as well as embedded bracketed links that are variously processed further. The display text
is generated from the corrected input text by applying language-specific transformations; for most languages, there
will be no such transformations. The general reason for having a difference between input and display text is to allow
for extra information in the input text that is not displayed to the user but is sent to the transliteration module.
Note that having different display and input text is only supported currently through special-casing but will be
generalized. Examples of transformations are: (1) Removing the {{cd|^}} that is used in certain East Asian (and
possibly other unicameral) languages to indicate capitalization of the transliteration (which is currently
special-cased); (2) for Korean, removing or otherwise processing hyphens (which is currently special-cased); (3) for
Arabic, removing a ''sukūn'' diacritic placed over a ''tāʔ marbūṭa'' (like this: ةْ) to indicate that the
''tāʔ marbūṭa'' is pronounced and transliterated as /t/ instead of being silent [NOTE, NOT IMPLEMENTED YET]; (4) for
Thai and Khmer, converting space-separated words to bracketed words and resolving respelling substitutions such as
`[กรีน/กฺรีน]`, which indicate how to transliterate given words [NOTE, NOT IMPLEMENTED YET except in language-specific
templates like {{tl|th-usex}}].
## The ''right-resolved display text'' is the result of removing brackets around one-part embedded links and resolving
two-part embedded links into their right-hand components (i.e. converting two-part links into the displayed form).
The process of right-resolution is what happens when you call {{cd|remove_links()}} in [[Module:links]] on some text.
When applied to the display text, it produces exactly what the user sees, without any link markup.
# The ''stripped display text'' is the result of applying diacritic-stripping to the display text.
## The ''left-resolved stripped display text'' [NEED BETTER NAME] is the result of applying left-resolution to the
stripped display text, i.e. similar to right-resolution but resolving two-part embedded links into their left-hand
components (i.e. the linked-to page). If the display text refers to a single page, the resulting of applying
diacritic stripping and left-resolution produces the ''logical pagename''.
# The ''physical pagename text'' is the result of converting the stripped display text into physical page links. If the
stripped display text contains embedded links, the left side of those links is converted into physical page links;
otherwise, the entire text is considered a pagename and converted in the same fashion. The conversion does three
things: (1) converts characters not allowed in pagenames into their "unsupported title" representation, e.g.
{{cd|Unsupported titles/`gt`}} in place of the logical name {{cd|>}}; (2) handles certain special-cased
unsupported-title logical pagenames, such as {{cd|Unsupported titles/Space}} in place of {{cd|[space]}} and
{{cd|Unsupported titles/Ancient Greek dish}} in place of a very long Greek name for a gourmet dish as found in
Aristophanes; (3) converts "mammoth" pagenames such as [[a]] into their appropriate split component, e.g.
[[a/languages A to L]].
# The ''source translit text'' is the text as supplied to the language-specific {{cd|transliterate()}} method. The form
of the source translit text may need to be language-specific, e.g Thai and Khmer will need the corrected input text,
whereas other languages may need to work off the display text. [FIXME: It's still unclear to me how embedded bracketed
links are handled in the existing code.] In general, embedded links need to be right-resolved (see above), but when
this happens is unclear to me [FIXME]. Some languages have a chop-up-and-paste-together scheme that sends parts of the
text through the transliterate mechanism, and for others (those listed with "cont" in {{cd|substitution}} in
[[Module:languages/data]]) they receive the full input text, but preprocessed in certain ways. (The wisdom of this is
still unclear to me.)
# The ''transliterated text'' (or ''transliteration'') is the result of transliterating the source translit text. Unlike
for all the other text variants except the transcribed text, it is always in the Latin script.
# The ''transcribed text'' (or ''transcription'') is the result of transcribing the source translit text, where
"transcription" here means a close approximation to the phonetic form of the language in languages (e.g. Akkadian,
Sumerian, Ancient Egyptian, maybe Tibetan) that have a wide difference between the written letters and spoken form.
Unlike for all the other text variants other than the transliterated text, it is always in the Latin script.
Currently, the transcribed text is always supplied manually be the user; there is no such thing as a
{{cd|transcribe()}} method on language objects.
# The ''sort key'' is the text used in sort keys for determining the placing of pages in categories they belong to. The
sort key is generated from the pagename or a specified ''sort base'' by lowercasing, doing language-specific
transformations and then uppercasing the result. If the sort base is supplied and is generated from input text, it
needs to be converted to display text, have embedded links removed through right-resolution and have
diacritic-stripping applied.
# There are other text variants that occur in usexes (specifically, there are normalized variants of several of the
above text variants), but we can skip them for now.
The following methods exist on {Language} objects to convert between different text variants:
# {correctInputText} (currently called {makeDisplayText}): This converts input text to corrected input text.
# {stripDiacritics}: This converts to stripped display text. [FIXME: This needs some rethinking. In particular,
{stripDiacritics} is sometimes called on input text, corrected input text or display text (in various paths inside of
[[Module:links]], and, in the case of input text, usually from other modules). We need to make sure we don't try to
convert input text to display text twice, but at the same time we need to support calling it directly on input text
since so many modules do this. This means we need to add a parameter indicating whether the passed-in text is input,
corrected input, or display text; if the former two, we call {correctInputText} ourselves.]
# {logicalToPhysical}: This converts logical pagenames to physical pagenames.
# {transliterate}: This appears to convert input text with embedded brackets removed into a transliteration.
[FIXME: This needs some rethinking. In particular, it calls {processDisplayText} on its input, which won't work
for Thai and Khmer, so we may need language-specific flags indicating whether to pass the input text directly to the
language transliterate method. In addition, I'm not sure how embedded links are handled in the existing translit code;
a lot of callers remove the links themselves before calling {transliterate()}, which I assume is wrong.]
# {makeSortKey}: This converts display text (?) to a sort key. [FIXME: Clarify this.]
]==]
local export = {}
local debug_track_module = "Module:debug/track"
local etymology_languages_data_module = "Module:etymology languages/data"
local families_module = "Module:families"
local headword_page_module = "Module:headword/page"
local json_module = "Module:JSON"
local language_like_module = "Module:language-like"
local languages_data_module = "Module:languages/data"
local languages_data_patterns_module = "Module:languages/data/patterns"
local links_data_module = "Module:links/data"
local load_module = "Module:load"
local scripts_module = "Module:scripts"
local scripts_data_module = "Module:scripts/data"
local string_encode_entities_module = "Module:string/encode entities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local wikimedia_languages_module = "Module:wikimedia languages"
local mw = mw
local string = string
local table = table
local char = string.char
local concat = table.concat
local find = string.find
local floor = math.floor
local get_by_code -- Defined below.
local get_data_module_name -- Defined below.
local get_extra_data_module_name -- Defined below.
local getmetatable = getmetatable
local gmatch = string.gmatch
local gsub = string.gsub
local insert = table.insert
local ipairs = ipairs
local is_known_language_tag = mw.language.isKnownLanguageTag
local make_object -- Defined below.
local match = string.match
local next = next
local pairs = pairs
local remove = table.remove
local require = require
local select = select
local setmetatable = setmetatable
local sub = string.sub
local type = type
local unstrip = mw.text.unstrip
-- Loaded as needed by findBestScript.
local Hans_chars
local Hant_chars
local function check_object(...)
check_object = require(utilities_module).check_object
return check_object(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
local function deep_copy(...)
deep_copy = require(table_module).deepCopy
return deep_copy(...)
end
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function get_L2_sort_key(...)
get_L2_sort_key = require(headword_page_module).get_L2_sort_key
return get_L2_sort_key(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function get_family(...)
get_family = require(families_module).getByCode
return get_family(...)
end
local function get_plaintext(...)
get_plaintext = require(utilities_module).get_plaintext
return get_plaintext(...)
end
local function get_wikimedia_lang(...)
get_wikimedia_lang = require(wikimedia_languages_module).getByCode
return get_wikimedia_lang(...)
end
local function keys_to_list(...)
keys_to_list = require(table_module).keysToList
return keys_to_list(...)
end
local function list_to_set(...)
list_to_set = require(table_module).listToSet
return list_to_set(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function make_family_object(...)
make_family_object = require(families_module).makeObject
return make_family_object(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function safe_require(...)
safe_require = require(load_module).safe_require
return safe_require(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function to_json(...)
to_json = require(json_module).toJSON
return to_json(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ugsub(...)
ugsub = require(string_utilities_module).gsub
return ugsub(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local function uupper(...)
uupper = require(string_utilities_module).upper
return uupper(...)
end
local function track(page)
debug_track("languages/" .. page)
return true
end
local function normalize_code(code)
return load_data(languages_data_module).aliases[code] or code
end
local function check_inputs(self, check, default, ...)
local n = select("#", ...)
if n == 0 then
return false
end
local ret = check(self, (...))
if ret ~= nil then
return ret
elseif n > 1 then
local inputs = {...}
for i = 2, n do
ret = check(self, inputs[i])
if ret ~= nil then
return ret
end
end
end
return default
end
local function make_link(self, target, display)
local prefix, main
if self:getFamilyCode() == "qfa-sub" then
prefix, main = display:match("^(the )(.*)")
if not prefix then
prefix, main = display:match("^(a )(.*)")
end
end
return (prefix or "") .. "[[" .. target .. "|" .. (main or display) .. "]]"
end
-- Convert risky characters to HTML entities, which minimizes interference once returned (e.g. for "sms:a", "<!-- -->" etc.).
local function escape_risky_characters(text)
-- Spacing characters in isolation generally need to be escaped in order to be properly processed by the MediaWiki
-- software.
if umatch(text, "^%s*$") then
return encode_entities(text, text)
end
return encode_entities(text, "!#%&*+/:;<=>?@[\\]_{|}")
end
-- Temporarily convert various formatting characters to PUA to prevent them from being disrupted by the substitution process.
local function doTempSubstitutions(text, subbedChars, keepCarets, noTrim)
-- Clone so that we don't insert any extra patterns into the table in package.loaded. For some reason, using require
-- seems to keep memory use down; probably because the table is always cloned.
local patterns = shallow_copy(require(languages_data_patterns_module))
if keepCarets then
insert(patterns, "((\\+)%^)")
insert(patterns, "((%^))")
end
-- Ensure any whitespace at the beginning and end is temp substituted, to prevent it from being accidentally
-- trimmed. We only want to trim any final spaces added during the substitution process (e.g. by a module), which
-- means we only do this during the first round of temp substitutions.
if not noTrim then
insert(patterns, "^([\128-\191\244]*(%s+))")
insert(patterns, "((%s+)[\128-\191\244]*)$")
end
-- Pre-substitution, of "[[" and "]]", which makes pattern matching more accurate.
text = gsub(text, "%f[%[]%[%[", "\1"):gsub("%f[%]]%]%]", "\2")
local i = #subbedChars
for _, pattern in ipairs(patterns) do
-- Patterns ending in \0 stand are for things like "[[" or "]]"), so the inserted PUA are treated as breaks
-- between terms by modules that scrape info from pages.
local term_divider
pattern = gsub(pattern, "%z$", function(divider)
term_divider = divider == "\0"
return ""
end)
text = gsub(text, pattern, function(...)
local m = {...}
local m1New = m[1]
for k = 2, #m do
local n = i + k - 1
subbedChars[n] = m[k]
local byte2 = floor(n / 4096) % 64 + (term_divider and 128 or 136)
local byte3 = floor(n / 64) % 64 + 128
local byte4 = n % 64 + 128
m1New = gsub(m1New, pattern_escape(m[k]), "\244" .. char(byte2) .. char(byte3) .. char(byte4), 1)
end
i = i + #m - 1
return m1New
end)
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text, subbedChars
end
-- Reinsert any formatting that was temporarily substituted.
local function undoTempSubstitutions(text, subbedChars)
for i = 1, #subbedChars do
local byte2 = floor(i / 4096) % 64 + 128
local byte3 = floor(i / 64) % 64 + 128
local byte4 = i % 64 + 128
text = gsub(text, "\244[" .. char(byte2) .. char(byte2+8) .. "]" .. char(byte3) .. char(byte4),
replacement_escape(subbedChars[i]))
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text
end
-- Check if the raw text is an unsupported title, and if so return that. Otherwise, remove HTML entities. We do the
-- pre-conversion to avoid loading the unsupported title list unnecessarily.
local function checkNoEntities(text)
local textNoEnc = decode_entities(text)
if textNoEnc ~= text and load_data(links_data_module).unsupported_titles[text] then
return text
else
return textNoEnc
end
end
-- If no script object is provided (or if it's invalid or None), get one.
local function checkScript(text, self, sc)
if not check_object("script", true, sc) or sc:getCode() == "None" then
return self:findBestScript(text)
end
return sc
end
local function normalize(text, sc)
text = sc:fixDiscouragedSequences(text)
return sc:toFixedNFD(text)
end
--[=[
Subfunction of iterateSectionSubstitutions(). Process an individual chunk of text according to the specifications in
`substitution_data`. The input parameters are all as in the documentation of iterateSectionSubstitutions() except for
`recursed`, which is set to true if we called ourselves recursively to process a script-specific setting or
script-wide fallback. Returns two values: the processed text and the actual substitution data used to do the
substitutions (same as the `actual_substitution_data` return value to iterateSectionSubstitutions()).
]=]
local function doSubstitutions(self, text, sc, substitution_data, data_field, function_name, recursed)
-- BE CAREFUL in this function because the value at any level can be `false`, which causes no processing to be done
-- and blocks any further fallback processing.
local actual_substitution_data = substitution_data
-- If there are language-specific substitutes given in the data module, use those.
if type(substitution_data) == "table" then
-- If a script is specified, run this function with the script-specific data before continuing.
local sc_code = sc:getCode()
local has_substitution_data = false
if substitution_data[sc_code] ~= nil then
has_substitution_data = true
if substitution_data[sc_code] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[sc_code], data_field,
function_name, true)
end
-- Hant, Hans and Hani are usually treated the same, so add a special case to avoid having to specify each one
-- separately.
elseif sc_code:match("^Han") and substitution_data.Hani ~= nil then
has_substitution_data = true
if substitution_data.Hani then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data.Hani, data_field,
function_name, true)
end
-- Substitution data with key 1 in the outer table may be given as a fallback.
elseif substitution_data[1] ~= nil then
has_substitution_data = true
if substitution_data[1] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[1], data_field,
function_name, true)
end
end
-- Iterate over all strings in the "from" subtable, and gsub with the corresponding string in "to". We work with
-- the NFD decomposed forms, as this simplifies many substitutions.
if substitution_data.from then
has_substitution_data = true
for i, from in ipairs(substitution_data.from) do
-- Normalize each loop, to ensure multi-stage substitutions work correctly.
text = sc:toFixedNFD(text)
text = ugsub(text, sc:toFixedNFD(from), substitution_data.to[i] or "")
end
end
if substitution_data.remove_diacritics then
has_substitution_data = true
text = sc:toFixedNFD(text)
-- Convert exceptions to PUA.
local remove_exceptions, substitutes = substitution_data.remove_exceptions
if remove_exceptions then
substitutes = {}
local i = 0
for _, exception in ipairs(remove_exceptions) do
exception = sc:toFixedNFD(exception)
text = ugsub(text, exception, function(m)
i = i + 1
local subst = u(0x80000 + i)
substitutes[subst] = m
return subst
end)
end
end
-- Strip diacritics.
text = ugsub(text, "[" .. substitution_data.remove_diacritics .. "]", "")
-- Convert exceptions back.
if remove_exceptions then
text = text:gsub("\242[\128-\191]*", substitutes)
end
end
if not has_substitution_data and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
elseif type(substitution_data) == "string" then
-- If there is a dedicated function module, use that.
local module = safe_require("Module:" .. substitution_data)
if module then
-- TODO: translit functions should take objects, not codes.
-- TODO: translit functions should be called with form NFD.
if function_name == "tr" then
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named 'tr'"):format(substitution_data))
end
text = module[function_name](text, self._code, sc:getCode())
elseif function_name == "stripDiacritics" then
-- FIXME, get rid of this arm after renaming makeEntryName -> stripDiacritics.
if module[function_name] then
text = module[function_name](sc:toFixedNFD(text), self, sc)
elseif module.makeEntryName then
text = module.makeEntryName(sc:toFixedNFD(text), self, sc)
else
error(("Internal error: Module [[%s]] has no function named 'stripDiacritics' or 'makeEntryName'"
):format(substitution_data))
end
else
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named '%s'"):format(
substitution_data, function_name))
end
text = module[function_name](sc:toFixedNFD(text), self, sc)
end
else
error("Substitution data '" .. substitution_data .. "' does not match an existing module.")
end
elseif substitution_data == nil and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
-- Don't normalize to NFC if this is the inner loop or if a module returned nil.
if recursed or not text then
return text, actual_substitution_data
end
-- Fix any discouraged sequences created during the substitution process, and normalize into the final form.
return sc:toFixedNFC(sc:fixDiscouragedSequences(text)), actual_substitution_data
end
--[=[
Split the text into sections, based on the presence of temporarily substituted formatting characters, then iterate over
each section to apply substitutions (e.g. transliteration or diacritic stripping). This avoids putting PUA (Private Use
Area) characters through language-specific modules, which may be unequipped for them. This function is passed the
following values:
* `self` (the Language object);
* `text` (the text to process);
* `sc` (the script of the text, which must be specified; callers should call checkScript() as needed to autodetect the
script of the text if not given explicitly by the user);
* `subbedChars` (an array of the same length as the text, indicating which characters have been substituted and by
what, or {nil} if no substitutions are to happen);
* `keepCarets` (DOCUMENT ME);
* `substitution_data` (the data indicating which substitutions to apply, taken directly from `data_field` in the
language's data structure in a submodule of [[Module:languages/data]]);
* `data_field` (the field from which `substitution_data` was fetched, such as {"sort_key"} or {"strip_diacritics"});
* `function_name` (the name of the function to call to do the substitution, in case `substitution_data` specifies a
module to do the substitution);
* `notrim` (don't trim whitespace at the edges of `text`; set when computing the sort key, because whitespace at the
beginning of a sort key is significant and causes the resulting page to be sorted at the beginning of the category
it's in).
Return three values:
# the processed text;
# the value of `subbedChars` that was passed in, possibly modified with additional character substitutions; will be
{nil} if {nil} was passed in;
# the actual substitution data that was used to apply substitutions to `text`; this may be different from the value
of `substitution_data` passed in if that value recursively specified script-specific substitutions or if no
substitution data could be found in the language-specific data (e.g. {nil} was passed in or a structure was passed
in that had no setting for the script given in `sc`), but a script-wide fallback value was set; currently it is
only used by {makeSortKey()}.
]=]
local function iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, substitution_data, data_field,
function_name, notrim)
local sections
-- See [[Module:languages/data]].
if not find(text, "\244") or load_data(languages_data_module).substitution[self._code] == "cont" then
sections = {text}
else
sections = split(text, "\244[\128-\143][\128-\191]*", true)
end
local actual_substitution_data
for _, section in ipairs(sections) do
-- Don't bother processing empty strings or whitespace (which may also not be handled well by dedicated
-- modules).
if gsub(section, "%s+", "") ~= "" then
local sub, this_actual_substitution_data = doSubstitutions(self, section, sc, substitution_data, data_field,
function_name)
actual_substitution_data = this_actual_substitution_data
-- Second round of temporary substitutions, in case any formatting was added by the main substitution
-- process. However, don't do this if the section contains formatting already (as it would have had to have
-- been escaped to reach this stage, and therefore should be given as raw text).
if sub and subbedChars then
local noSub
for _, pattern in ipairs(require(languages_data_patterns_module)) do
if match(section, pattern .. "%z?") then
noSub = true
end
end
if not noSub then
sub, subbedChars = doTempSubstitutions(sub, subbedChars, keepCarets, true)
end
end
if not sub then
text = sub
break
end
text = sub and gsub(text, pattern_escape(section), replacement_escape(sub), 1) or text
end
end
if not notrim then
-- Trim, unless there are only spacing characters, while ignoring any final formatting characters.
-- Do not trim sort keys because spaces at the beginning are significant.
text = text and text:gsub("^([\128-\191\244]*)%s+(%S)", "%1%2"):gsub("(%S)%s+([\128-\191\244]*)$", "%1%2") or
nil
end
return text, subbedChars, actual_substitution_data
end
-- Process carets (and any escapes). Default to simple removal, if no pattern/replacement is given.
local function processCarets(text, pattern, repl)
local rep
repeat
text, rep = gsub(text, "\\\\(\\*^)", "\3%1")
until rep == 0
return (text:gsub("\\^", "\4")
:gsub(pattern or "%^", repl or "")
:gsub("\3", "\\")
:gsub("\4", "^"))
end
local function hasUnescapedCarets(text)
return processCarets(text, "%^", "\1"):find("\1", 1, true) ~= nil
end
local function assertCaretCapitalizationAllowed(text, sc)
if sc:forbidsCaretCapitalization() and hasUnescapedCarets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
local function removeCarets(text, sc)
if text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
return processCarets(text)
end
end
return text
end
local Language = {}
--[==[
Return the language code of the language. Example: {fr"} for French.
]==]
function Language:getCode()
return self._code
end
--[==[
Return the canonical name of the language. This is the name used to represent that language on Wiktionary, and is
guaranteed to be unique to that language alone. Example: {"French"} for French.
]==]
function Language:getCanonicalName()
local name = self._name
if name == nil then
name = self._data[1]
self._name = name
end
return name
end
--[==[
Return the display form of the language. The display form of a language, family or script is the form it takes when
appearing as the <code><var>source</var></code> in categories such as <code>English terms derived from
<var>source</var></code> or <code>English given names from <var>source</var></code>, and is also the displayed text
in `##makeCategoryLink()` links. For full and etymology-only languages, this is the same as the canonical name, but
for families, it reads <code>"<var>name</var> languages"</code> (e.g. {"Indo-Iranian languages"}), and for scripts,
it reads <code>"<var>name</var> script"</code> (e.g. {"Arabic script"}).
]==]
function Language:getDisplayForm()
local form = self._displayForm
if form == nil then
form = self:getCanonicalName()
-- Add article and " substrate" to substrates that lack them.
if self:getFamilyCode() == "qfa-sub" then
if not (sub(form, 1, 4) == "the " or sub(form, 1, 2) == "a ") then
form = "a " .. form
end
if not match(form, " [Ss]ubstrate") then
form = form .. " substrate"
end
end
self._displayForm = form
end
return form
end
--[==[
Return the value which should be used in the HTML `lang=` attribute for tagged text in the language.
]==]
function Language:getHTMLAttribute(sc, region)
local code = self._code
if not find(code, "-", 1, true) then
return code .. "-" .. sc:getCode() .. (region and "-" .. region or "")
end
local parent = self:getParent()
region = region or match(code, "%f[%u][%u-]+%f[%U]")
if parent then
return parent:getHTMLAttribute(sc, region)
end
-- TODO: ISO family codes can also be used.
return "mis-" .. sc:getCode() .. (region and "-" .. region or "")
end
--[==[
Return a list of the aliases that the language is known by, excluding the canonical name. Aliases are synonyms for the
language in question. The names are not guaranteed to be unique, in that sometimes more than one language is known by
the same name. Example: { {"High German", "New High German", "Deutsch"}} for {{lnl|de}}.
]==]
function Language:getAliases()
self:loadInExtraData()
return require(language_like_module).getAliases(self)
end
--[==[
Return a list of the known subvarieties of a given language, excluding subvarieties that have been given explicit
etymology-only language codes. The names are not guaranteed to be unique, in that sometimes a given name refers to a
subvariety of more than one language. Example: { {"Southern Aymara", "Central Aymara"}} for {{lnl|ay}}. Note that the
returned value can have nested tables in it, when a subvariety goes by more than one name. Example:
{ {"North Azerbaijani", "South Azerbaijani", {"Afshar", "Afshari", "Afshar Azerbaijani", "Afchar"}, {"Qashqa'i", "Qashqai", "Kashkay"}, "Sonqor"}}
for {{lnl|az}}. Here, for example, Afshar, Afshari, Afshar Azerbaijani and Afchar all refer to the same subvariety,
whose preferred name is Afshar (the one listed first). To avoid a return value with nested tables in it, specify a
non-{nil} value for the `flatten` parameter; in that case, the return value would be
{ {"North Azerbaijani", "South Azerbaijani", "Afshar", "Afshari", "Afshar Azerbaijani", "Afchar", "Qashqa'i", "Qashqai", "Kashkay", "Sonqor"}}.
]==]
function Language:getVarieties(flatten)
self:loadInExtraData()
return require(language_like_module).getVarieties(self, flatten)
end
--[==[
Return a table of the "other names" that the language is known by, which are listed in the `other_names` field in the
language's extra-data module. It should be noted that the `other_names` field itself is deprecated, and entries listed
there should eventually be moved to either `aliases` or `varieties`, or removed if they refer to larger entities which
the language in question is actually a part of.
]==]
function Language:getOtherNames() -- To be eventually removed, once there are no more uses of the `other_names` field.
self:loadInExtraData()
return require(language_like_module).getOtherNames(self)
end
--[==[
Return a combined table of the canonical name, aliases, varieties and other names of a given language.
]==]
function Language:getAllNames()
self:loadInExtraData()
return require(language_like_module).getAllNames(self)
end
--[==[
Return a table of types as a set (with the types as keys). The possible types are
* {language}: This is a language, either full or etymology-only.
* {full}: This is a "full" (not etymology-only) language, i.e. the union of {regular}, {reconstructed} and
{appendix-constructed}. Note that the types {full} and {etymology-only} also exist for families, so if you want to
check specifically for a full language and you have an object that might be a family, you should use
{hasType("language", "full")} and not simply {hasType("full")}.
* {etymology-only}: This is an etymology-only (not full) language, whose parent is another etymology-only language or a
full language. Note that the types {full} and {etymology-only} also exist for families, so if you want to check
specifically for an etymology-only language and you have an object that might be a family, you should use
{hasType("language", "etymology-only")} and not simply {hasType("etymology-only")}.
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the main
namespace. There may also be reconstructed terms for the language, which are placed in the {Reconstruction}
namespace and must be prefixed with `*` to indicate a reconstruction. Most full languages are natural
(not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük, among others) are also
allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with `*`. Languages
such as Proto-Indo-European and Proto-Germanic are in this category. '''Exception:''' Reconstructed languages can
have entries in the mainspace using the ''anti-asterisk'' feature. This requires that both the headword for the
mainspace term (as specified using {{para|head}}) and links to the term are prefixed with the anti-asterisk
indicator `!!`.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in the Appendix namespace,
but they are not reconstructed and therefore should not have * prefixed in links.
]==]
function Language:getTypes()
local types = self._types
if types == nil then
types = {language = true}
if self:getFullCode() == self._code then
types.full = true
else
types["etymology-only"] = true
end
for t in gmatch(self._data.type, "[^,]+") do
types[t] = true
end
self._types = types
end
return types
end
--[==[
Given a list of types as strings, return {true} if the language has all of them.
]==]
function Language:hasType(...)
Language.hasType = require(language_like_module).hasType
return self:hasType(...)
end
--[==[
Return a list containing `WikimediaLanguage` objects (see [[Module:wikimedia languages]]), which represent languages
and their codes as they are used in Wikimedia projects for interwiki linking and such. More than one object may be
returned, as a single Wiktionary language may correspond to multiple Wikimedia languages. For example, Wiktionary's
single code `sh` (Serbo-Croatian) maps to four Wikimedia codes: `sh` (Serbo-Croatian), `bs` (Bosnian), `hr` (Croatian)
and `sr` (Serbian). The code for the Wikimedia language is retrieved from the `wikimedia_codes` property in the data
modules. If that property is not present, the code of the current language is used. If none of the available codes is
actually a valid Wikimedia code, an empty list is returned.
]==]
function Language:getWikimediaLanguages()
local wm_langs = self._wikimediaLanguageObjects
if wm_langs == nil then
local codes = self:getWikimediaLanguageCodes()
wm_langs = {}
for i = 1, #codes do
wm_langs[i] = get_wikimedia_lang(codes[i])
end
self._wikimediaLanguageObjects = wm_langs
end
return wm_langs
end
function Language:getWikimediaLanguageCodes()
local wm_langs = self._wikimediaLanguageCodes
if wm_langs == nil then
wm_langs = self._data.wikimedia_codes
if wm_langs then
wm_langs = split(wm_langs, ",", true, true)
else
local code = self._code
if is_known_language_tag(code) then
wm_langs = {code}
else
-- Inherit, but only if no codes are specified in the data *and*
-- the language code isn't a valid Wikimedia language code.
local parent = self:getParent()
wm_langs = parent and parent:getWikimediaLanguageCodes() or {}
end
end
self._wikimediaLanguageCodes = wm_langs
end
return wm_langs
end
--[==[
Return the name of the Wikipedia article for the language. `project` specifies the language and project to retrieve
the article from, defaulting to {"enwiki"} for the English Wikipedia. Normally if specified it should be the project
code for a specific-language Wikipedia e.g. "zhwiki" for the Chinese Wikipedia, but it can be any project, including
non-Wikipedia ones. If the project is the English Wikipedia and the property {wikipedia_article} is present in the data
module it will be used first. In all other cases, a sitelink will be generated from {:getWikidataItem} (if set). The
resulting value (or lack of value) is cached so that subsequent calls are fast. If no value could be determined, and
`noCategoryFallback` is {false}, `##Language:getCategoryName` is used as fallback; otherwise, {nil} is returned. Note
that if `noCategoryFallback` is {nil} or omitted, it defaults to {false} if the project is the English Wikipedia,
otherwise to {true}. In other words, under normal circumstances, if the English Wikipedia article couldn't be retrieved,
the return value will fall back to a link to the language's category, but this won't normally happen for any other
project.
]==]
function Language:getWikipediaArticle(noCategoryFallback, project)
Language.getWikipediaArticle = require(language_like_module).getWikipediaArticle
return self:getWikipediaArticle(noCategoryFallback, project)
end
function Language:makeWikipediaLink()
return make_link(self, "w:" .. self:getWikipediaArticle(), self:getCanonicalName())
end
--[==[
Return the name of the Wikimedia Commons category page for the language.
]==]
function Language:getCommonsCategory()
Language.getCommonsCategory = require(language_like_module).getCommonsCategory
return self:getCommonsCategory()
end
--[==[
Return the Wikidata item ID for the language or {nil}. This corresponds to the the second field in the data modules.
]==]
function Language:getWikidataItem()
Language.getWikidataItem = require(language_like_module).getWikidataItem
return self:getWikidataItem()
end
--[==[
Return a list of `Script` objects for all scripts that the language is written in. See [[Module:scripts]].
]==]
function Language:getScripts()
local scripts = self._scriptObjects
if scripts == nil then
local codes = self:getScriptCodes()
if codes[1] == "All" then
scripts = load_data(scripts_data_module)
else
scripts = {}
for i = 1, #codes do
scripts[i] = get_script(codes[i])
end
end
self._scriptObjects = scripts
end
return scripts
end
--[==[
Return the list of script codes in the language's data file.
]==]
function Language:getScriptCodes()
local scripts = self._scriptCodes
if scripts == nil then
scripts = self._data[4]
if scripts then
local codes, n = {}, 0
for code in gmatch(scripts, "[^,]+") do
n = n + 1
-- Special handling of "Hants", which represents "Hani", "Hant" and "Hans" collectively.
if code == "Hants" then
codes[n] = "Hani"
codes[n + 1] = "Hant"
codes[n + 2] = "Hans"
n = n + 2
else
codes[n] = code
end
end
scripts = codes
else
scripts = {"None"}
end
self._scriptCodes = scripts
end
return scripts
end
--[==[
Given some text, iterate through the scripts of a given language trying to find the script that best matches the text.
Return a {Script} object representing the script. If no match is found at all, it returns the {None} script object.
]==]
function Language:findBestScript(text, forceDetect)
if not text or text == "" or text == "-" then
return get_script("None")
end
-- Differs from table returned by getScriptCodes, as Hants is not normalized into its constituents.
local codes = self._bestScriptCodes
if codes == nil then
codes = self._data[4]
codes = codes and split(codes, ",", true, true) or {"None"}
self._bestScriptCodes = codes
end
local first_sc = codes[1]
if first_sc == "All" then
return find_best_script_without_lang(text)
end
local codes_len = #codes
if not (forceDetect or first_sc == "Hants" or codes_len > 1) then
first_sc = get_script(first_sc)
local charset = first_sc.characters
return charset and umatch(text, "[" .. charset .. "]") and first_sc or get_script("None")
end
-- Remove all formatting characters.
text = get_plaintext(text)
-- Remove all spaces and any ASCII punctuation. Some non-ASCII punctuation is script-specific, so can't be removed.
text = ugsub(text, "[%s!\"#%%&'()*,%-./:;?@[\\%]_{}]+", "")
if #text == 0 then
return get_script("None")
end
-- Try to match every script against the text,
-- and return the one with the most matching characters.
local bestcount, bestscript, length = 0
for i = 1, codes_len do
local sc = codes[i]
-- Special case for "Hants", which is a special code that represents whichever of "Hant" or "Hans" best matches,
-- or "Hani" if they match equally. This avoids having to list all three. In addition, "Hants" will be treated
-- as the best match if there is at least one matching character, under the assumption that a Han script is
-- desirable in terms that contain a mix of Han and other scripts (not counting those which use Jpan or Kore).
if sc == "Hants" then
local Hani = get_script("Hani")
if not Hant_chars then
Hant_chars = load_data("Module:zh/data/ts")
Hans_chars = load_data("Module:zh/data/st")
end
local t, s, found = 0, 0
-- This is faster than using mw.ustring.gmatch directly.
for ch in gmatch((ugsub(text, "[" .. Hani.characters .. "]", "\255%0")), "\255(.[\128-\191]*)") do
found = true
if Hant_chars[ch] then
t = t + 1
if Hans_chars[ch] then
s = s + 1
end
elseif Hans_chars[ch] then
s = s + 1
else
t, s = t + 1, s + 1
end
end
if found then
if t == s then
return Hani
end
return get_script(t > s and "Hant" or "Hans")
end
else
sc = get_script(sc)
if not length then
length = ulen(text)
end
-- Count characters by removing everything in the script's charset and comparing to the original length.
local charset = sc.characters
local count = charset and length - ulen((ugsub(text, "[" .. charset .. "]+", ""))) or 0
if count >= length then
return sc
elseif count > bestcount then
bestcount = count
bestscript = sc
end
end
end
-- Return best matching script, or otherwise None.
return bestscript or get_script("None")
end
--[==[
Return a `Family` object for the language family that the language belongs to. See [[Module:families]].
]==]
function Language:getFamily()
local family = self._familyObject
if family == nil then
family = self:getFamilyCode()
-- If the value is nil, it's cached as false.
family = family and get_family(family) or false
self._familyObject = family
end
return family or nil
end
--[==[
Return the family code in the language's data file.
]==]
function Language:getFamilyCode()
local family = self._familyCode
if family == nil then
-- If the value is nil, it's cached as false.
family = self._data[3] or false
self._familyCode = family
end
return family or nil
end
function Language:getFamilyName()
local family = self._familyName
if family == nil then
family = self:getFamily()
-- If the value is nil, it's cached as false.
family = family and family:getCanonicalName() or false
self._familyName = family
end
return family or nil
end
do
local function check_family(self, family)
if type(family) == "table" then
family = family:getCode()
end
if self:getFamilyCode() == family then
return true
end
local self_family = self:getFamily()
if self_family:inFamily(family) then
return true
-- If the family isn't a real family (e.g. creoles) check any ancestors.
elseif self_family:inFamily("qfa-not") then
local ancestors = self:getAncestors()
for _, ancestor in ipairs(ancestors) do
if ancestor:inFamily(family) then
return true
end
end
end
end
--[==[
Check whether the language belongs to `family` (which can be a family code or object). A list of objects can be given in
place of `family`; in that case, return true if the language belongs to any of the specified families. Note that some
languages (in particular, certain creoles) can have multiple immediate ancestors potentially belonging to different
families; in that case, return true if the language belongs to any of the specified families.
]==]
function Language:inFamily(...)
if self:getFamilyCode() == nil then
return false
end
return check_inputs(self, check_family, false, ...)
end
end
function Language:getParent()
local parent = self._parentObject
if parent == nil then
parent = self:getParentCode()
-- If the value is nil, it's cached as false.
parent = parent and get_by_code(parent, nil, true, true) or false
self._parentObject = parent
end
return parent or nil
end
function Language:getParentCode()
local parent = self._parentCode
if parent == nil then
-- If the value is nil, it's cached as false.
parent = self._data.parent or false
self._parentCode = parent
end
return parent or nil
end
function Language:getParentName()
local parent = self._parentName
if parent == nil then
parent = self:getParent()
-- If the value is nil, it's cached as false.
parent = parent and parent:getCanonicalName() or false
self._parentName = parent
end
return parent or nil
end
function Language:getParentChain()
local chain = self._parentChain
if chain == nil then
chain = {}
local parent, n = self:getParent(), 0
while parent do
n = n + 1
chain[n] = parent
parent = parent:getParent()
end
self._parentChain = chain
end
return chain
end
--[==[
Return a list of the pseudo-families (if any) that a language belongs to. The returned value is a list of Family
objects. Pseudo-families are groupings of languages that are not clades but share some geographic, ethnic or other
characteristic (e.g. [[:Category:Papuan languages]], [[:Category:Jewish languages]]).
]==]
function Language:getPseudoFamilies()
self:loadInExtraData()
return require(language_like_module).getPseudoFamilies(self)
end
--[==[
Return a list of the pseudo-family codes (if any) that a language belongs to. The returned value is a list of strings
(family codes). See `##Language:getPseudoFamilies`.
]==]
function Language:getPseudoFamilyCodes()
local codes = {}
for _, family in ipairs(self:getPseudoFamilies()) do
insert(codes, family:getCode())
end
return codes
end
do
local function check_lang(self, lang)
for _, parent in ipairs(self:getParentChain()) do
if (type(lang) == "string" and lang or lang:getCode()) == parent:getCode() then
return true
end
end
end
function Language:hasParent(...)
return check_inputs(self, check_lang, false, ...)
end
end
--[==[
If the language is etymology-only, iterate through parents until a full language or family is found, and the
corresponding object is returned. If the language is a full language, return that language.
]==]
function Language:getFull()
local full = self._fullObject
if full == nil then
full = self:getFullCode()
full = full == self._code and self or get_by_code(full)
self._fullObject = full
end
return full
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and
the corresponding code is returned. If the language is a full language, return that language's code.
]==]
function Language:getFullCode()
return self._fullCode or self._code
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and the
corresponding canonical name is returned. If the language is a full language, return that language's canonical name.
]==]
function Language:getFullName()
local full = self._fullName
if full == nil then
full = self:getFull():getCanonicalName()
self._fullName = full
end
return full
end
--[==[
Return a list of {Language} objects for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestors()
local ancestors = self._ancestorObjects
if ancestors == nil then
ancestors = {}
local ancestor_codes = self:getAncestorCodes()
if #ancestor_codes > 0 then
for _, ancestor in ipairs(ancestor_codes) do
insert(ancestors, get_by_code(ancestor, nil, true))
end
else
local fam = self:getFamily()
local protoLang = fam and fam:getProtoLanguage() or nil
-- For the cases where the current language is the proto-language
-- of its family, or an etymology-only language that is ancestral to that
-- proto-language, we need to step up a level higher right from the
-- start.
if protoLang and (
protoLang:getCode() == self._code or
(self:hasType("etymology-only") and protoLang:hasAncestor(self))
) then
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
while not protoLang and not (not fam or fam:getCode() == "qfa-not") do
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
insert(ancestors, protoLang)
end
self._ancestorObjects = ancestors
end
return ancestors
end
do
-- Avoid a language being its own ancestor via class inheritance. We only need to check for this if the language has
-- inherited an ancestor table from its parent, because we never want to drop ancestors that have been explicitly
-- set in the data. Recursively iterate over ancestors until we either find self or run out. If self is found,
-- return true.
local function check_ancestor(self, lang)
local codes = lang:getAncestorCodes()
if not codes then
return nil
end
for i = 1, #codes do
local code = codes[i]
if code == self._code then
return true
end
local anc = get_by_code(code, nil, true)
if check_ancestor(self, anc) then
return true
end
end
end
--[==[
Return a list of `Language` codes for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestorCodes()
if self._ancestorCodes then
return self._ancestorCodes
end
local data = self._data
local codes = data.ancestors
if codes == nil then
codes = {}
self._ancestorCodes = codes
return codes
end
codes = split(codes, ",", true, true)
self._ancestorCodes = codes
-- If there are no codes or the ancestors weren't inherited data, there's nothing left to check.
if #codes == 0 or self:getData(false, "raw").ancestors ~= nil then
return codes
end
local i = 1
while i <= #codes do
if check_ancestor(self, self) then
remove(codes, i)
else
i = i + 1
end
end
return codes
end
end
--[==[
Given a list of language objects or codes, return true if at least one of them is an ancestor. This includes any
etymology-only children of that ancestor. If the language's ancestor(s) are etymology-only languages, it will also
return true for those language parent(s) (e.g. if Vulgar Latin is the ancestor, it will also return true for its parent,
Latin). However, a parent is excluded from this if the ancestor is also ancestral to that parent (e.g. if Classical
Persian is the ancestor, Persian would return {false}, because Classical Persian is also ancestral to Persian).
]==]
function Language:hasAncestor(...)
local function iterateOverAncestorTree(node, func, parent_check)
local ancestors = node:getAncestors()
local ancestorsParents = {}
for _, ancestor in ipairs(ancestors) do
-- When checking the parents of the other language, and the ancestor is also a parent, skip to the next
-- ancestor, so that we exclude any etymology-only children of that parent that are not directly related
-- (see below).
local ret = (parent_check or not node:hasParent(ancestor)) and
func(ancestor) or iterateOverAncestorTree(ancestor, func, parent_check)
if ret then
return ret
end
end
-- Check the parents of any ancestors. We don't do this if checking the parents of the other language, so that
-- we exclude any etymology-only children of those parents that are not directly related (e.g. if the ancestor
-- is Vulgar Latin and we are checking New Latin, we want it to return false because they are on different
-- ancestral branches. As such, if we're already checking the parent of New Latin (Latin) we don't want to
-- compare it to the parent of the ancestor (Latin), as this would be a false positive; it should be one or the
-- other).
if not parent_check then
return nil
end
for _, ancestor in ipairs(ancestors) do
local ancestorParents = ancestor:getParentChain()
for _, ancestorParent in ipairs(ancestorParents) do
if ancestorParent:getCode() == self._code or ancestorParent:hasAncestor(ancestor) then
break
else
insert(ancestorsParents, ancestorParent)
end
end
end
for _, ancestorParent in ipairs(ancestorsParents) do
local ret = func(ancestorParent)
if ret then
return ret
end
end
end
local function do_iteration(otherlang, parent_check)
-- otherlang can't be self
if (type(otherlang) == "string" and otherlang or otherlang:getCode()) == self._code then
return false
end
repeat
if iterateOverAncestorTree(
self,
function(ancestor)
return ancestor:getCode() == (type(otherlang) == "string" and otherlang or otherlang:getCode())
end,
parent_check
) then
return true
elseif type(otherlang) == "string" then
otherlang = get_by_code(otherlang, nil, true)
end
otherlang = otherlang:getParent()
parent_check = false
until not otherlang
end
local parent_check = true
for _, otherlang in ipairs{...} do
local ret = do_iteration(otherlang, parent_check)
if ret then
return true
end
end
return false
end
do
local function construct_node(lang, memo)
local branch, ancestors = {lang = lang:getCode()}
memo[lang:getCode()] = branch
for _, ancestor in ipairs(lang:getAncestors()) do
if ancestors == nil then
ancestors = {}
end
insert(ancestors, memo[ancestor:getCode()] or construct_node(ancestor, memo))
end
branch.ancestors = ancestors
return branch
end
function Language:getAncestorChain()
local chain = self._ancestorChain
if chain == nil then
chain = construct_node(self, {})
self._ancestorChain = chain
end
return chain
end
end
function Language:getAncestorChainOld()
local chain = self._ancestorChain
if chain == nil then
chain = {}
local step = self
while true do
local ancestors = step:getAncestors()
step = #ancestors == 1 and ancestors[1] or nil
if not step then
break
end
insert(chain, step)
end
self._ancestorChain = chain
end
return chain
end
local function fetch_descendants(self, fmt)
local descendants, family = {}, self:getFamily()
-- Iterate over all three datasets.
for _, data in ipairs{
require("Module:languages/code to canonical name"),
require("Module:etymology languages/code to canonical name"),
require("Module:families/code to canonical name"),
} do
for code in pairs(data) do
local lang = get_by_code(code, nil, true, true)
if not lang then
error(("Internal error: code '%s' can't be fetched"):format(code))
end
-- Test for a descendant. Earlier tests weed out most candidates, while the more intensive tests are only used sparingly.
if (
code ~= self._code and -- Not self.
lang:inFamily(family) and -- In the same family.
(
family:getProtoLanguageCode() == self._code or -- Self is the protolanguage.
self:hasDescendant(lang) or -- Full hasDescendant check.
(lang:getFullCode() == self._code and not self:hasAncestor(lang)) -- Etymology-only child which isn't an ancestor.
)
) then
if fmt == "object" then
insert(descendants, lang)
elseif fmt == "code" then
insert(descendants, code)
elseif fmt == "name" then
insert(descendants, lang:getCanonicalName())
end
end
end
end
return descendants
end
function Language:getDescendants()
local descendants = self._descendantObjects
if descendants == nil then
descendants = fetch_descendants(self, "object")
self._descendantObjects = descendants
end
return descendants
end
function Language:getDescendantCodes()
local descendants = self._descendantCodes
if descendants == nil then
descendants = fetch_descendants(self, "code")
self._descendantCodes = descendants
end
return descendants
end
function Language:getDescendantNames()
local descendants = self._descendantNames
if descendants == nil then
descendants = fetch_descendants(self, "name")
self._descendantNames = descendants
end
return descendants
end
do
local function check_lang(self, lang)
if type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasAncestor(self) then
return true
end
end
function Language:hasDescendant(...)
return check_inputs(self, check_lang, false, ...)
end
end
local function fetch_children(self, fmt)
local m_etym_data = require(etymology_languages_data_module)
local self_code, children = self._code, {}
for code, lang in pairs(m_etym_data) do
local _lang = lang
repeat
local parent = _lang.parent
if parent == self_code then
if fmt == "object" then
insert(children, get_by_code(code, nil, true))
elseif fmt == "code" then
insert(children, code)
elseif fmt == "name" then
insert(children, lang[1])
end
break
end
_lang = m_etym_data[parent]
until not _lang
end
return children
end
function Language:getChildren()
local children = self._childObjects
if children == nil then
children = fetch_children(self, "object")
self._childObjects = children
end
return children
end
function Language:getChildrenCodes()
local children = self._childCodes
if children == nil then
children = fetch_children(self, "code")
self._childCodes = children
end
return children
end
function Language:getChildrenNames()
local children = self._childNames
if children == nil then
children = fetch_children(self, "name")
self._childNames = children
end
return children
end
function Language:hasChild(...)
local lang = ...
if not lang then
return false
elseif type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasParent(self) then
return true
end
return self:hasChild(select(2, ...))
end
--[==[
Return the name of the main category of that language. Example: {French language"} for French, whose category is at
[[:Category:French language]]. Unless optional argument `nocap` is given, the language name at the beginning of the
returned value will be capitalized. This capitalization is correct for category names, but not if the language name is
lowercase and the returned value of this function is used in the middle of a sentence.
]==]
function Language:getCategoryName(nocap)
local name = self._categoryName
if name == nil then
name = self:getCanonicalName()
-- If a substrate, omit any leading article.
if self:getFamilyCode() == "qfa-sub" then
name = name:gsub("^the ", ""):gsub("^a ", "")
end
-- Only add " language" if a full language.
if self:hasType("full") then
-- Unless the canonical name already ends with "language", "lect" or their derivatives, add " language".
if not (match(name, "[Ll]anguage$") or match(name, "[Ll]ect$")) then
name = name .. " language"
end
end
self._categoryName = name
end
if nocap then
return name
end
return mw.getContentLanguage():ucfirst(name)
end
--[==[
Create a link to the category; the link text is the canonical name.
]==]
function Language:makeCategoryLink()
return make_link(self, ":Category:" .. self:getCategoryName(), self:getDisplayForm())
end
function Language:getStandardCharacters(sc)
local standard_chars = self._data.standard_chars
if type(standard_chars) ~= "table" then
return standard_chars
elseif sc and type(sc) ~= "string" then
check_object("script", nil, sc)
sc = sc:getCode()
end
if (not sc) or sc == "None" then
local scripts = {}
for _, script in pairs(standard_chars) do
insert(scripts, script)
end
return concat(scripts)
end
if standard_chars[sc] then
return standard_chars[sc] .. (standard_chars[1] or "")
end
end
--[==[
Strip diacritics from display text `text` (in a language-specific fashion), which is in the script `sc`. If `sc` is
omitted or {nil}, the script is autodetected. This also strips certain punctuation characters from the end and (in the
case of Spanish upside-down question mark and exclamation points) from the beginning; strips any whitespace at the
end of the text or between the text and final stripped punctuation characters; and applies some language-specific
Unicode normalizations to replace discouraged characters with their prescribed alternatives. Return the stripped text.
]==]
function Language:stripDiacritics(text, sc)
if (not text) or text == "" then
return text
end
sc = checkScript(text, self, sc)
text = normalize(text, sc)
-- FIXME, rename makeEntryName to stripDiacritics and get rid of second and third return values
-- everywhere
local _
text, _, _ = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.strip_diacritics or self._data.entry_name, "strip_diacritics", "stripDiacritics")
text = umatch(text, "^[¿¡]?(.-[^%s%p].-)%s*[؟?!;՛՜ ՞ ՟?!︖︕।॥။၊་།]?$") or text
return text
end
--[==[
Convert a ''logical'' pagename (the pagename as it appears to the user, after diacritics and punctuation have been
stripped) to a ''physical'' pagename (the pagename as it appears in the MediaWiki database). Reasons for a difference
between the two are (a) unsupported titles such as `[ ]` (with square brackets in them), `#` (pound/hash sign) and
`¯\_(ツ)_/¯` (with underscores), as well as overly long titles of various sorts; (b) "mammoth" pages that are split into
parts (e.g. `a`, which is split into physical pagenames `a/languages A to L` and `a/languages M to Z`). For almost all
purposes, you should work with logical and not physical pagenames. But there are certain use cases that require physical
pagenames, such as checking the existence of a page or retrieving a page's contents.
`pagename` is the logical pagename to be converted. `is_reconstructed_or_appendix` indicates whether the page is in the
`Reconstruction` or `Appendix` namespaces. If it is omitted or has the value {nil}, the pagename is checked for an
initial asterisk, and if found, the page is assumed to be a `Reconstruction` page. Setting a value of `false` or `true`
to `is_reconstructed_or_appendix` disables this check and allows for mainspace pagenames that begin with an asterisk.
]==]
function Language:logicalToPhysical(pagename, is_reconstructed_or_appendix)
-- FIXME: This probably shouldn't happen but it happens when makeEntryName() receives nil.
if pagename == nil then
track("nil-passed-to-logicalToPhysical")
return nil
end
local initial_asterisk
if is_reconstructed_or_appendix == nil then
local pagename_minus_initial_asterisk
initial_asterisk, pagename_minus_initial_asterisk = pagename:match("^(%*)(.*)$")
if pagename_minus_initial_asterisk then
is_reconstructed_or_appendix = true
pagename = pagename_minus_initial_asterisk
elseif self:hasType("appendix-constructed") then
is_reconstructed_or_appendix = true
end
end
if not is_reconstructed_or_appendix then
-- Check if the pagename is a listed unsupported title.
local unsupportedTitles = load_data(links_data_module).unsupported_titles
if unsupportedTitles[pagename] then
return "Unsupported titles/" .. unsupportedTitles[pagename]
end
end
-- Set `unsupported` as true if certain conditions are met.
local unsupported
-- Check if there's an unsupported character. \239\191\189 is the replacement character U+FFFD, which can't be typed
-- directly here due to an abuse filter. Unix-style dot-slash notation is also unsupported, as it is used for
-- relative paths in links, as are 3 or more consecutive tildes. Note: match is faster with magic
-- characters/charsets; find is faster with plaintext.
if (
match(pagename, "[#<>%[%]_{|}]") or
find(pagename, "\239\191\189") or
match(pagename, "%f[^%z/]%.%.?%f[%z/]") or
find(pagename, "~~~")
) then
unsupported = true
-- If it looks like an interwiki link.
elseif find(pagename, ":") then
local prefix = gsub(pagename, "^:*(.-):.*", ulower)
if (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
unsupported = true
end
end
-- Escape unsupported characters so they can be used in titles. ` is used as a delimiter for this, so a raw use of
-- it in an unsupported title is also escaped here to prevent interference; this is only done with unsupported
-- titles, though, so inclusion won't in itself mean a title is treated as unsupported (which is why it's excluded
-- from the earlier test).
if unsupported then
-- FIXME: This conversion needs to be different for reconstructed pages with unsupported characters. There
-- aren't any currently, but if there ever are, we need to fix this e.g. to put them in something like
-- Reconstruction:Proto-Indo-European/Unsupported titles/`lowbar``num`.
local unsupported_characters = load_data(links_data_module).unsupported_characters
pagename = pagename:gsub("[#<>%[%]_`{|}\239]\191?\189?", unsupported_characters)
:gsub("%f[^%z/]%.%.?%f[%z/]", function(m)
return (gsub(m, "%.", "`period`"))
end)
:gsub("~~~+", function(m)
return (gsub(m, "~", "`tilde`"))
end)
pagename = "Unsupported titles/" .. pagename
elseif not is_reconstructed_or_appendix then
-- Check if this is a mammoth page. If so, which subpage should we link to?
local m_links_data = load_data(links_data_module)
local mammoth_page_type = m_links_data.mammoth_pages[pagename]
if mammoth_page_type then
local canonical_name = self:getFullName()
if canonical_name ~= "Translingual" and canonical_name ~= "English" then
local this_subpage
local L2_sort_key = get_L2_sort_key(canonical_name)
for _, subpage_spec in ipairs(m_links_data.mammoth_page_subpage_types[mammoth_page_type]) do
-- unpack() fails utterly on data loaded using mw.loadData() even if offsets are given
local subpage, pattern = subpage_spec[1], subpage_spec[2]
if pattern == true or L2_sort_key:match(pattern) then
this_subpage = subpage
break
end
end
if not this_subpage then
error(("Internal error: Bad data in mammoth_page_subpage_pages in [[Module:links/data]] for mammoth page %s, type %s; last entry didn't have 'true' in it"):format(
pagename, mammoth_page_type))
end
pagename = pagename .. "/" .. this_subpage
end
end
end
return (initial_asterisk or "") .. pagename
end
--[==[
Strip the diacritics from a display pagename and convert the resulting logical pagename into a physical pagename.
This allows you, for example, to retrieve the contents of the page or check its existence. WARNING: This is deprecated
and will be going away. It is a simple composition of `##Language:stripDiacritics` and `##Language:logicalToPhysical`;
most callers only want the former, and if you need both, call them both yourself.
`text` and `sc` are as in `##Language:stripDiacritics`, and `is_reconstructed_or_appendix` is as in
`##Language:logicalToPhysical`.
]==]
function Language:makeEntryName(text, sc, is_reconstructed_or_appendix)
track("makeEntryName called")
return self:logicalToPhysical(self:stripDiacritics(text, sc), is_reconstructed_or_appendix)
end
--[==[
Generate term alternants (e.g. simplified versions of traditional Chinese terms) using a language-specific method, and
return them as a table. If the language provides no method for generating alternants, return a table containing only the
input term.
]==]
function Language:generateAlternants(text, sc)
local generate_alternants = self._data.generate_alternants
if generate_alternants == nil then
return {text}
end
sc = checkScript(text, self, sc)
return require("Module:" .. generate_alternants).generateAlternants(text, self, sc)
end
--[==[
Create a sort key for the given stripped text, following the rules appropriate for the language. This removes
diacritical marks from the stripped text if they are not considered significant for sorting, and may perform some other
changes. Any initial hyphen is also removed, and anything in parentheses is removed as well. The `sort_key` setting for
each language in the data modules defines the replacements made by this function, or it gives the name of the module
that takes the stripped text and returns a sortkey.
]==]
function Language:makeSortKey(text, sc)
if (not text) or text == "" then
return text
end
if match(text, "<[^<>]+>") then
track("track HTML tag")
end
-- Remove directionality/control characters, bold, italics, soft hyphens, strip markers and HTML tags.
-- FIXME: Partly duplicated with remove_formatting() in [[Module:links]].
text = ugsub(text, "[\194\173\216\156\226\128\142\226\128\143\226\128\170-\226\128\174\226\129\166-\226\129\175]", "")
text = text:gsub("('*)'''(.-'*)'''", "%1%2"):gsub("('*)''(.-'*)''", "%1%2")
text = gsub(unstrip(text), "<[^<>]+>", "")
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
-- Remove initial hyphens and * unless the term only consists of spacing + punctuation characters.
text = ugsub(text, "^([-]*)[-־ـ᠊*]+([-]*)(.*[^%s%p].*)", "%1%2%3")
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text = removeCarets(text, sc)
-- For languages with dotted dotless i, ensure that "İ" is sorted as "i", and "I" is sorted as "ı".
if self:hasDottedDotlessI() then
text = gsub(text, "I\204\135", "i") -- decomposed "İ"
:gsub("I", "ı")
text = sc:toFixedNFD(text)
end
-- Convert to lowercase, make the sortkey, then convert to uppercase. Where the language has dotted dotless i, it is
-- usually not necessary to convert "i" to "İ" and "ı" to "I" first, because "I" will always be interpreted as
-- conventional "I" (not dotless "İ") by any sorting algorithms, which will have been taken into account by the
-- sortkey substitutions themselves. However, if no sortkey substitutions have been specified, then conversion is
-- necessary so as to prevent "i" and "ı" both being sorted as "I".
--
-- An exception is made for scripts that (sometimes) sort by scraping page content, as that means they are sensitive
-- to changes in capitalization (as it changes the target page).
if not sc:sortByScraping() then
text = ulower(text)
end
local actual_substitution_data, _
-- Don't trim whitespace here because it's significant at the beginning of a sort key or sort base.
text, _, actual_substitution_data = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.sort_key, "sort_key", "makeSortKey", "notrim")
if not sc:sortByScraping() then
if self:hasDottedDotlessI() and not actual_substitution_data then
text = text:gsub("ı", "I"):gsub("i", "İ")
text = sc:toFixedNFC(text)
end
text = uupper(text)
end
-- Remove parentheses, as long as they are either preceded or followed by something.
text = gsub(text, "(.)[()]+", "%1"):gsub("[()]+(.)", "%1")
text = escape_risky_characters(text)
return text
end
--[==[
Create the form used as as a basis for display text and transliteration. FIXME: Rename to correctInputText().
]==]
local function processDisplayText(text, self, sc, keepCarets, keepPrefixes)
local subbedChars = {}
text, subbedChars = doTempSubstitutions(text, subbedChars, keepCarets)
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, self._data.display_text,
"display_text", "makeDisplayText")
text = removeCarets(text, sc)
-- Remove any interwiki link prefixes (unless they have been escaped or this has been disabled).
if find(text, ":") and not keepPrefixes then
local rep
repeat
text, rep = gsub(text, "\\\\(\\*:)", "\3%1")
until rep == 0
text = gsub(text, "\\:", "\4")
while true do
local prefix = gsub(text, "^(.-):.+", function(m1)
return (gsub(m1, "\244[\128-\191]*", ""))
end)
-- Check if the prefix is an interwiki, though ignore capitalised Wiktionary:, which is a namespace.
if not prefix or prefix == text or prefix == "Wiktionary"
or not (load_data("Module:data/interwikis")[ulower(prefix)] or prefix == "") then
break
end
text = gsub(text, "^(.-):(.*)", function(m1, m2)
local ret = {}
for subbedChar in gmatch(m1, "\244[\128-\191]*") do
insert(ret, subbedChar)
end
return concat(ret) .. m2
end)
end
text = gsub(text, "\3", "\\"):gsub("\4", ":")
end
return text, subbedChars
end
--[==[
Make the display text (i.e. what is displayed on the page).
]==]
function Language:makeDisplayText(text, sc, keepPrefixes)
if not text or text == "" then
return text
end
local subbedChars
text, subbedChars = processDisplayText(text, self, sc, nil, keepPrefixes)
text = escape_risky_characters(text)
return undoTempSubstitutions(text, subbedChars)
end
--[==[
Transliterate the text from the given script into Latin script (see [[Wiktionary:Transliteration and romanization]]).
The language must have the `translit` property for this to work; if it is not present, {nil} is returned.
The `sc` parameter is handled by the transliteration module, and how it is handled is specific to that module. Some
transliteration modules may tolerate {nil} as the script, others require it to be one of the possible scripts that the
module can transliterate, and will throw an error if it's not one of them. For this reason, the `sc` parameter should
always be provided when writing non-language-specific code.
The `module_override` parameter is used to override the default module that is used to provide the transliteration.
This is useful in cases where you need to demonstrate a particular module in use, but there is no default module yet,
or you want to demonstrate an alternative version of a transliteration module before making it official. It should not
be used in real modules or templates, only for testing. All uses of this parameter are tracked by
[[Wiktionary:Tracking/languages/module_override]].
'''Known bugs''':
* This function assumes {tr(s1) .. tr(s2) == tr(s1 .. s2)}. When this assertion fails, wikitext markups like
<nowiki>'''</nowiki> can cause wrong transliterations.
* HTML entities like `&apos;`, often used to escape wikitext markups, do not work.
]==]
function Language:transliterate(text, sc, module_override)
-- If there is no text, or the language doesn't have transliteration data and there's no override, return nil.
if not text or text == "" or text == "-" then
return text
end
-- If the script is not transliteratable (and no override is given), return nil.
sc = checkScript(text, self, sc)
if not (sc:isTransliterated() or module_override) then
-- temporary tracking to see if/when this gets triggered
track("non-transliterable")
track("non-transliterable/" .. self._code)
track("non-transliterable/" .. sc:getCode())
track("non-transliterable/" .. sc:getCode() .. "/" .. self._code)
return nil
end
-- Remove any strip markers.
text = unstrip(text)
-- Do not process the formatting into PUA characters for certain languages.
local processed = load_data(languages_data_module).substitution[self._code] ~= "none"
-- Get the display text with the keepCarets flag set.
local subbedChars
if processed then
text, subbedChars = processDisplayText(text, self, sc, true)
end
-- Transliterate (using the module override if applicable).
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, true, module_override or
self._data.translit, "translit", "tr")
if not text then
return nil
end
-- Incomplete transliterations return nil.
local charset = sc.characters
if charset and umatch(text, "[" .. charset .. "]") then
-- Remove any characters in Latin, which includes Latin characters also included in other scripts (as these are
-- false positives), as well as any PUA substitutions. Anything remaining should only be script code "None"
-- (e.g. numerals).
local check_text = ugsub(text, "[" .. get_script("Latn").characters .. "-]+", "")
-- Set none_is_last_resort_only flag, so that any non-None chars will cause a script other than "None" to be
-- returned.
if find_best_script_without_lang(check_text, true):getCode() ~= "None" then
return nil
end
end
if processed then
text = escape_risky_characters(text)
text = undoTempSubstitutions(text, subbedChars)
end
-- If allowed for this script, capitalize transliteration letters preceded by ^ and remove the caret.
if text and text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
text = processCarets(text, "%^([\128-\191\244]*%*?)([^\128-\191\244][\128-\191]*)", function(m1, m2)
return m1 .. uupper(m2)
end)
end
end
-- Track module overrides.
if module_override ~= nil then
track("module_override")
end
return text
end
do
local function handle_language_spec(self, spec, sc)
local ret = self["_" .. spec]
if ret == nil then
ret = self._data[spec]
if type(ret) == "string" then
ret = list_to_set(split(ret, ",", true, true))
end
self["_" .. spec] = ret
end
if type(ret) == "table" then
ret = ret[sc:getCode()]
end
return not not ret
end
function Language:overrideManualTranslit(sc)
return handle_language_spec(self, "override_translit", sc)
end
function Language:link_tr(sc)
return handle_language_spec(self, "link_tr", sc)
end
end
--[==[
Return {true} if the language has a transliteration module, or {false} if it doesn't.
]==]
function Language:hasTranslit()
return not not self._data.translit
end
--[==[
Return {true} if the language uses the letters I/ı and İ/i, or {false} if it doesn't.]==]
function Language:hasDottedDotlessI()
return not not self._data.dotted_dotless_i
end
function Language:toJSON(opts)
local strip_diacritics, strip_diacritics_patterns, strip_diacritics_remove_diacritics = self._data.strip_diacritics
if strip_diacritics then
if strip_diacritics.from then
strip_diacritics_patterns = {}
for i, from in ipairs(strip_diacritics.from) do
insert(strip_diacritics_patterns, {from = from, to = strip_diacritics.to[i] or ""})
end
end
strip_diacritics_remove_diacritics = strip_diacritics.remove_diacritics
end
-- mainCode should only end up non-nil if dontCanonicalizeAliases is passed to make_object().
-- props should either contain zero-argument functions to compute the value, or the value itself.
local props = {
ancestors = function() return self:getAncestorCodes() end,
canonicalName = function() return self:getCanonicalName() end,
categoryName = function() return self:getCategoryName("nocap") end,
code = self._code,
mainCode = self._mainCode,
parent = function() return self:getParentCode() end,
full = function() return self:getFullCode() end,
stripDiacriticsPatterns = strip_diacritics_patterns,
stripDiacriticsRemoveDiacritics = strip_diacritics_remove_diacritics,
family = function() return self:getFamilyCode() end,
aliases = function() return self:getAliases() end,
varieties = function() return self:getVarieties() end,
otherNames = function() return self:getOtherNames() end,
pseudoFamilies = function() return self:getPseudoFamilyCodes() end,
scripts = function() return self:getScriptCodes() end,
type = function() return keys_to_list(self:getTypes()) end,
wikimediaLanguages = function() return self:getWikimediaLanguageCodes() end,
wikidataItem = function() return self:getWikidataItem() end,
wikipediaArticle = function() return self:getWikipediaArticle(true) end,
}
local ret = {}
for prop, val in pairs(props) do
if not opts.skip_fields or not opts.skip_fields[prop] then
if type(val) == "function" then
ret[prop] = val()
else
ret[prop] = val
end
end
end
-- Use `deep_copy` when returning a table, so that there are no editing restrictions imposed by `mw.loadData`.
return opts and opts.lua_table and deep_copy(ret) or to_json(ret, opts)
end
function export.getDataModuleName(code)
local letter = match(code, "^(%l)%l%l?$")
return "Module:" .. (
letter == nil and "languages/data/exceptional" or
#code == 2 and "languages/data/2" or
"languages/data/3/" .. letter
)
end
get_data_module_name = export.getDataModuleName
function export.getExtraDataModuleName(code)
return get_data_module_name(code) .. "/extra"
end
get_extra_data_module_name = export.getExtraDataModuleName
do
local function make_stack(data)
local key_types = {
[2] = "unique",
aliases = "unique",
other_names = "unique",
type = "append",
varieties = "unique",
wikipedia_article = "unique",
wikimedia_codes = "unique"
}
local function __index(self, k)
local stack, key_type = getmetatable(self), key_types[k]
-- Data that isn't inherited from the parent.
if key_type == "unique" then
local v = stack[stack[make_stack]][k]
if v == nil then
local layer = stack[0]
if layer then -- Could be false if there's no extra data.
v = layer[k]
end
end
return v
-- Data that is appended by each generation.
elseif key_type == "append" then
local parts, offset, n = {}, 0, stack[make_stack]
for i = 1, n do
local part = stack[i][k]
if part == nil then
offset = offset + 1
else
parts[i - offset] = part
end
end
return offset ~= n and concat(parts, ",") or nil
end
local n = stack[make_stack]
while true do
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
local v = layer[k]
if v ~= nil then
return v
end
n = n - 1
end
end
local function __newindex()
error("table is read-only")
end
local function __pairs(self)
-- Iterate down the stack, caching keys to avoid duplicate returns.
local stack, seen = getmetatable(self), {}
local n = stack[make_stack]
local iter, state, k, v = pairs(stack[n])
return function()
repeat
repeat
k = iter(state, k)
if k == nil then
n = n - 1
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
iter, state, k = pairs(layer)
end
until not (k == nil or seen[k])
-- Get the value via a lookup, as the one returned by the
-- iterator will be the raw value from the current layer,
-- which may not be the one __index will return for that
-- key. Also memoize the key in `seen` (even if the lookup
-- returns nil) so that it doesn't get looked up again.
-- TODO: store values in `self`, avoiding the need to create
-- the `seen` table. The iterator will need to iterate over
-- `self` with `next` first to find these on future loops.
v, seen[k] = self[k], true
until v ~= nil
return k, v
end
end
local __ipairs = require(table_module).indexIpairs
function make_stack(data)
local stack = {
data,
[make_stack] = 1, -- stores the length and acts as a sentinel to confirm a given metatable is a stack.
__index = __index,
__newindex = __newindex,
__pairs = __pairs,
__ipairs = __ipairs,
}
stack.__metatable = stack
return setmetatable({}, stack), stack
end
return make_stack(data)
end
local function get_stack(data)
local stack = getmetatable(data)
return stack and type(stack) == "table" and stack[make_stack] and stack or nil
end
--[==[
<span style="color: var(--wikt-palette-red,#BA0000)">This function is not for use in entries or other content pages.</span>
Return a blob of data about the language. The format of this blob is undocumented, and perhaps unstable; it's intended
for things like the module's own unit-tests, which are "close friends" with the module and will be kept up-to-date as
the format changes. If `extra` is set, any extra data in the relevant `/extra` module will be included. (Note that it
will be included anyway if it has already been loaded into the language object.) If `raw` is set, then the returned data
will not contain any data inherited from parent objects.
-- Do NOT use these methods!
-- All uses should be pre-approved on the talk page!
]==]
function Language:getData(extra, raw)
if extra then
self:loadInExtraData()
end
local data = self._data
-- If raw is not set, just return the data.
if not raw then
return data
end
local stack = get_stack(data)
-- If there isn't a stack or its length is 1, return the data. Extra data (if any) will be included, as it's
-- stored at key 0 and doesn't affect the reported length.
if stack == nil then
return data
end
local n = stack[make_stack]
if n == 1 then
return data
end
extra = stack[0]
-- If there isn't any extra data, return the top layer of the stack.
if extra == nil then
return stack[n]
end
-- If there is, return a new stack which has the top layer at key 1 and the extra data at key 0.
data, stack = make_stack(stack[n])
stack[0] = extra
return data
end
function Language:loadInExtraData()
-- Only full languages have extra data.
if not self:hasType("language", "full") then
return
end
local data = self._data
-- If there's no stack, create one.
local stack = get_stack(self._data)
if stack == nil then
data, stack = make_stack(data)
-- If already loaded, return.
elseif stack[0] ~= nil then
return
end
self._data = data
-- Load extra data from the relevant module and add it to the stack at key 0, so that the __index and __pairs
-- metamethods will pick it up, since they iterate down the stack until they run out of layers.
local code = self._code
local modulename = get_extra_data_module_name(code)
-- No data cached as false.
stack[0] = modulename and load_data(modulename)[code] or false
end
--[==[
Return the name of the module containing the language's data, e.g. [[Module:languages/data/3/k]] for three-letter codes
beginning with `k`.
]==]
function Language:getDataModuleName()
local name = self._dataModuleName
if name == nil then
name = self:hasType("etymology-only") and etymology_languages_data_module or
get_data_module_name(self._mainCode or self._code)
self._dataModuleName = name
end
return name
end
--[==[
Return the name of the module containing the language's extra data, e.g. [[Module:languages/data/3/k/extra]] for
three-letter codes beginning with `k`.
]==]
function Language:getExtraDataModuleName()
local name = self._extraDataModuleName
if name == nil then
name = not self:hasType("etymology-only") and get_extra_data_module_name(self._mainCode or self._code) or false
self._extraDataModuleName = name
end
return name or nil
end
function export.makeObject(code, data, dontCanonicalizeAliases)
local data_type = type(data)
if data_type ~= "table" then
error(("bad argument #2 to 'makeObject' (table expected, got %s)"):format(data_type))
end
-- Convert any aliases.
local input_code = code
code = normalize_code(code)
input_code = dontCanonicalizeAliases and input_code or code
local parent
if data.parent then
parent = get_by_code(data.parent, nil, true, true)
else
parent = Language
end
parent.__index = parent
local lang = {_code = input_code}
-- This can only happen if dontCanonicalizeAliases is passed to make_object().
if code ~= input_code then
lang._mainCode = code
end
local parent_data = parent._data
if parent_data == nil then
-- Full code is the same as the code.
lang._fullCode = parent._code or code
else
-- Copy full code.
lang._fullCode = parent._fullCode
local stack = get_stack(parent_data)
if stack == nil then
parent_data, stack = make_stack(parent_data)
end
-- Insert the input data as the new top layer of the stack.
local n = stack[make_stack] + 1
data, stack[n], stack[make_stack] = parent_data, data, n
end
lang._data = data
return setmetatable(lang, parent)
end
make_object = export.makeObject
end
--[==[
Find the language whose code matches the one provided. If it exists, return a `Language` object representing the
language. Otherwise, return {nil}, unless `paramForError` is given, in which case an error is generated. If
`paramForError` is {true}, a generic error message mentioning the bad code is generated; otherwise `paramForError`
should be a string or number specifying the parameter that the code came from, and this parameter will be mentioned
in the error message along with the bad code. If `allowEtymLang` is specified, etymology-only language codes are allowed
and looked up along with full language codes. If `allowFamily` is specified, language family codes are allowed and
looked up along with normal language codes.
]==]
function export.getByCode(code, paramForError, allowEtymLang, allowFamily)
-- [[ Track uses of paramForError, ultimately so it can be removed, as error-handling should be done by
-- [[Module:parameters]], not here. ]] -- I (Benwing) disagree; that is an idealistic goal unlikely to be achievable
-- realistically.
if paramForError ~= nil then
track("paramForError")
end
if type(code) ~= "string" then
local typ
if not code then
typ = "nil"
elseif check_object("language", true, code) then
typ = "a language object"
elseif check_object("family", true, code) then
typ = "a family object"
else
typ = "a " .. type(code)
end
error("The function getByCode expects a string as its first argument, but received " .. typ .. ".")
end
local m_data = load_data(languages_data_module)
if m_data.aliases[code] or m_data.track[code] then
track(code)
end
local norm_code = normalize_code(code)
-- Get the data, checking for etymology-only languages if allowEtymLang is set.
local data = load_data(get_data_module_name(norm_code))[norm_code] or
allowEtymLang and load_data(etymology_languages_data_module)[norm_code]
-- If no data was found and allowFamily is set, check the family data. If the main family data was found, make the
-- object with [[Module:families]] instead, as family objects have different methods. However, if it's an
-- etymology-only family, use make_object in this module (which handles object inheritance), and the
-- family-specific methods will be inherited from the parent object.
if data == nil and allowFamily then
data = load_data("Module:families/data")[norm_code]
if data ~= nil then
if data.parent == nil then
return make_family_object(norm_code, data)
elseif not allowEtymLang then
data = nil
end
end
end
local retval = code and data and make_object(code, data)
if not retval and paramForError then
require("Module:languages/errorGetBy").code(code, paramForError, allowEtymLang, allowFamily)
end
return retval
end
get_by_code = export.getByCode
--[==[
Find the language whose canonical name (the name used to represent that language on Wiktionary) or other name matches
the one provided. If it exists, return a `Language` object representing the language. Otherwise, return {nil}, unless
`paramForError` is given, in which case an error is generated. If `allowEtymLang` is specified, etymology-only language
codes are allowed and looked up along with full language codes. If `allowFamily` is specified, language family codes are
allowed and looked up along with normal language codes. The canonical name of languages should always be unique (it is
an error for two languages on Wiktionary to share the same canonical name), so this is guaranteed to give at most one
result. This function is powered by [[Module:languages/canonical names]], which contains a pre-generated mapping of
full-language canonical names to codes. It is generated by going through the [[:Category:Language data modules]] for
full languages. When `allowEtymLang` is specified for the above function, [[Module:etymology languages/canonical names]]
may also be used, and when `allowFamily` is specified for the above function, [[Module:families/canonical names]] may
also be used.
]==]
function export.getByCanonicalName(name, errorIfInvalid, allowEtymLang, allowFamily)
local byName = load_data("Module:languages/canonical names")
local code = byName and byName[name]
if not code and allowEtymLang then
byName = load_data("Module:etymology languages/canonical names")
code = byName and byName[name] or
byName[gsub(name, " [Ss]ubstrate$", "")] or
byName[gsub(name, "^a ", "")] or
byName[gsub(name, "^a ", ""):gsub(" [Ss]ubstrate$", "")] or
-- For etymology families like "ira-pro".
-- FIXME: This is not ideal, as it allows " languages" to be appended to any etymology-only language, too.
byName[match(name, "^(.*) languages$")]
end
if not code and allowFamily then
byName = load_data("Module:families/canonical names")
code = byName[name] or byName[match(name, "^(.*) languages$")]
end
local retval = code and get_by_code(code, errorIfInvalid, allowEtymLang, allowFamily)
if not retval and errorIfInvalid then
require("Module:languages/errorGetBy").canonicalName(name, allowEtymLang, allowFamily)
end
return retval
end
--[==[
Used by [[Module:languages/data/2]] (et al.) and [[Module:etymology languages/data]], [[Module:families/data]],
[[Module:scripts/data]] and [[Module:writing systems/data]] to finalize the data into the format that is actually returned.
]==]
function export.finalizeData(data, main_type, variety)
local fields = {"type"}
if main_type == "language" then
insert(fields, 4) -- script codes
insert(fields, "ancestors")
insert(fields, "link_tr")
insert(fields, "override_translit")
insert(fields, "wikimedia_codes")
elseif main_type == "script" then
insert(fields, 3) -- writing system codes
end -- Families and writing systems have no extra fields to process.
local fields_len = #fields
for _, entity in next, data do
if variety then
-- Move parent from 3 to "parent" and family from "family" to 3. These are different for the sake of
-- convenience, since very few varieties have the family specified, whereas all of them have a parent.
entity.parent, entity[3] = entity[3], entity.family
entity.family = nil
-- Give the type "regular" iff not a variety and no other types are assigned.
elseif not (entity.type or entity.parent) then
entity.type = "regular"
end
for i = 1, fields_len do
local key = fields[i]
local field = entity[key]
if field and type(field) == "string" then
entity[key] = gsub(field, "%s*,%s*", ",")
end
end
end
return data
end
--[==[
For backwards compatibility only; modules should require the error themselves.
]==]
function export.err(lang_code, param, code_desc, template_tag, not_real_lang)
return require("Module:languages/error")(lang_code, param, code_desc, template_tag, not_real_lang)
end
return export
hpv2812x1no7s0in85n3ihzut5wc4jx
238799
238798
2026-11-12T06:06:45Z
Lee
19
[[:en:Module:languages]] වෙතින් එක් සංශෝධනයක්
238798
Scribunto
text/plain
--[==[ intro:
This module implements fetching of language-specific information and processing text in a given language.
===Types of languages===
There are two types of languages: full languages and etymology-only languages. The essential difference is that only
full languages appear in L2 headings in vocabulary entries, and hence categories like [[:Category:French nouns]] exist
only for full languages. Etymology-only languages have either a full language or another etymology-only language as
their parent (in the parent-child inheritance sense), and for etymology-only languages with another etymology-only
language as their parent, a full language can always be derived by following the parent links upwards. For example,
"Canadian French", code `fr-CA`, is an etymology-only language whose parent is the full language "French", code `fr`.
An example of an etymology-only language with another etymology-only parent is "Northumbrian Old English", code
`ang-nor`, which has "Anglian Old English", code `ang-ang` as its parent; this is an etymology-only language whose
parent is "Old English", code `ang`, which is a full language. (This is because Northumbrian Old English is considered
a variety of Anglian Old English.) Sometimes the parent is the "Undetermined" language, code `und`; this is the case,
for example, for "substrate" languages such as "Pre-Greek", code `qsb-grc`, and "the BMAC substrate", code `qsb-bma`.
It is important to distinguish language ''parents'' from language ''ancestors''. The parent-child relationship is one
of containment, i.e. if X is a child of Y, X is considered a variety of Y. On the other hand, the ancestor-descendant
relationship is one of descent in time. For example, "Classical Latin", code `la-cla`, and "Late Latin", code `la-lat`,
are both etymology-only languages with "Latin", code `la`, as their parents, because both of the former are varieties
of Latin. However, Late Latin does *NOT* have Classical Latin as its parent because Late Latin is *not* a variety of
Classical Latin; rather, it is a descendant. There is in fact a separate `ancestors` field that is used to express the
ancestor-descendant relationship, and Late Latin's ancestor is given as Classical Latin. It is also important to note
that sometimes an etymology-only language is actually the conceptual ancestor of its parent language. This happens,
for example, with "Old Italian" (code `roa-oit`), which is an etymology-only variant of full language "Italian" (code
`it`), and with "Old Latin" (code `itc-ola`), which is an etymology-only variant of Latin. In both cases, the full
language has the etymology-only variant listed as an ancestor. This allows a Latin term to inherit from Old Latin
using the {{tl|inh}} template (where in this template, "inheritance" refers to ancestral inheritance, i.e. inheritance
in time, rather than in the parent-child sense); likewise for Italian and Old Italian.
Full languages come in three subtypes:
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the
main namespace. There may also be reconstructed terms for the language, which are placed in the
{Reconstruction} namespace and must be prefixed with * to indicate a reconstruction. Most full languages
are natural (not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük,
among others) are also allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with
*. Languages such as Proto-Indo-European and Proto-Germanic are in this category.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in
the Appendix namespace, but they are not reconstructed and therefore should not have *
prefixed in links. Most constructed languages are of this subtype.
Both full languages and etymology-only languages have a {Language} object associated with them, which is fetched using
the {getByCode} function in [[Module:languages]] to convert a language code to a {Language} object. Depending on the
options supplied to this function, etymology-only languages may or may not be accepted, and family codes may be
accepted (returning a {Family} object as described in [[Module:families]]). There are also separate {getByCanonicalName}
functions in [[Module:languages]] and [[Module:etymology languages]] to convert a language's canonical name to a
{Language} object (depending on whether the canonical name refers to a full or etymology-only language).
===Textual representations===
Textual strings belonging to a given language come in several different ''text variants'':
# The ''input text'' is what the user supplies in wikitext, in the parameters to {{tl|m}}, {{tl|l}}, {{tl|ux}},
{{tl|t}}, {{tl|lang}} and the like.
# The ''corrected input text'' is the input text with some corrections and/or normalizations applied, such as
bad-character replacements for certain languages, like replacing `l` or `1` to [[palochka]] in some languages written
in Cyrillic. (FIXME: This currently goes under the name ''display text'' but that will be repurposed below. Also,
[[User:Surjection]] suggests renaming this to ''normalized input text'', but "normalized" is used in a different sense
in [[Module:usex]].)
# The ''display text'' is the text in the form as it will be displayed to the user. This is what appears in headwords,
in usexes, in displayed internal links, etc. This can include accent marks that are removed to form the stripped
display text (see below), as well as embedded bracketed links that are variously processed further. The display text
is generated from the corrected input text by applying language-specific transformations; for most languages, there
will be no such transformations. The general reason for having a difference between input and display text is to allow
for extra information in the input text that is not displayed to the user but is sent to the transliteration module.
Note that having different display and input text is only supported currently through special-casing but will be
generalized. Examples of transformations are: (1) Removing the {{cd|^}} that is used in certain East Asian (and
possibly other unicameral) languages to indicate capitalization of the transliteration (which is currently
special-cased); (2) for Korean, removing or otherwise processing hyphens (which is currently special-cased); (3) for
Arabic, removing a ''sukūn'' diacritic placed over a ''tāʔ marbūṭa'' (like this: ةْ) to indicate that the
''tāʔ marbūṭa'' is pronounced and transliterated as /t/ instead of being silent [NOTE, NOT IMPLEMENTED YET]; (4) for
Thai and Khmer, converting space-separated words to bracketed words and resolving respelling substitutions such as
`[กรีน/กฺรีน]`, which indicate how to transliterate given words [NOTE, NOT IMPLEMENTED YET except in language-specific
templates like {{tl|th-usex}}].
## The ''right-resolved display text'' is the result of removing brackets around one-part embedded links and resolving
two-part embedded links into their right-hand components (i.e. converting two-part links into the displayed form).
The process of right-resolution is what happens when you call {{cd|remove_links()}} in [[Module:links]] on some text.
When applied to the display text, it produces exactly what the user sees, without any link markup.
# The ''stripped display text'' is the result of applying diacritic-stripping to the display text.
## The ''left-resolved stripped display text'' [NEED BETTER NAME] is the result of applying left-resolution to the
stripped display text, i.e. similar to right-resolution but resolving two-part embedded links into their left-hand
components (i.e. the linked-to page). If the display text refers to a single page, the resulting of applying
diacritic stripping and left-resolution produces the ''logical pagename''.
# The ''physical pagename text'' is the result of converting the stripped display text into physical page links. If the
stripped display text contains embedded links, the left side of those links is converted into physical page links;
otherwise, the entire text is considered a pagename and converted in the same fashion. The conversion does three
things: (1) converts characters not allowed in pagenames into their "unsupported title" representation, e.g.
{{cd|Unsupported titles/`gt`}} in place of the logical name {{cd|>}}; (2) handles certain special-cased
unsupported-title logical pagenames, such as {{cd|Unsupported titles/Space}} in place of {{cd|[space]}} and
{{cd|Unsupported titles/Ancient Greek dish}} in place of a very long Greek name for a gourmet dish as found in
Aristophanes; (3) converts "mammoth" pagenames such as [[a]] into their appropriate split component, e.g.
[[a/languages A to L]].
# The ''source translit text'' is the text as supplied to the language-specific {{cd|transliterate()}} method. The form
of the source translit text may need to be language-specific, e.g Thai and Khmer will need the corrected input text,
whereas other languages may need to work off the display text. [FIXME: It's still unclear to me how embedded bracketed
links are handled in the existing code.] In general, embedded links need to be right-resolved (see above), but when
this happens is unclear to me [FIXME]. Some languages have a chop-up-and-paste-together scheme that sends parts of the
text through the transliterate mechanism, and for others (those listed with "cont" in {{cd|substitution}} in
[[Module:languages/data]]) they receive the full input text, but preprocessed in certain ways. (The wisdom of this is
still unclear to me.)
# The ''transliterated text'' (or ''transliteration'') is the result of transliterating the source translit text. Unlike
for all the other text variants except the transcribed text, it is always in the Latin script.
# The ''transcribed text'' (or ''transcription'') is the result of transcribing the source translit text, where
"transcription" here means a close approximation to the phonetic form of the language in languages (e.g. Akkadian,
Sumerian, Ancient Egyptian, maybe Tibetan) that have a wide difference between the written letters and spoken form.
Unlike for all the other text variants other than the transliterated text, it is always in the Latin script.
Currently, the transcribed text is always supplied manually be the user; there is no such thing as a
{{cd|transcribe()}} method on language objects.
# The ''sort key'' is the text used in sort keys for determining the placing of pages in categories they belong to. The
sort key is generated from the pagename or a specified ''sort base'' by lowercasing, doing language-specific
transformations and then uppercasing the result. If the sort base is supplied and is generated from input text, it
needs to be converted to display text, have embedded links removed through right-resolution and have
diacritic-stripping applied.
# There are other text variants that occur in usexes (specifically, there are normalized variants of several of the
above text variants), but we can skip them for now.
The following methods exist on {Language} objects to convert between different text variants:
# {correctInputText} (currently called {makeDisplayText}): This converts input text to corrected input text.
# {stripDiacritics}: This converts to stripped display text. [FIXME: This needs some rethinking. In particular,
{stripDiacritics} is sometimes called on input text, corrected input text or display text (in various paths inside of
[[Module:links]], and, in the case of input text, usually from other modules). We need to make sure we don't try to
convert input text to display text twice, but at the same time we need to support calling it directly on input text
since so many modules do this. This means we need to add a parameter indicating whether the passed-in text is input,
corrected input, or display text; if the former two, we call {correctInputText} ourselves.]
# {logicalToPhysical}: This converts logical pagenames to physical pagenames.
# {transliterate}: This appears to convert input text with embedded brackets removed into a transliteration.
[FIXME: This needs some rethinking. In particular, it calls {processDisplayText} on its input, which won't work
for Thai and Khmer, so we may need language-specific flags indicating whether to pass the input text directly to the
language transliterate method. In addition, I'm not sure how embedded links are handled in the existing translit code;
a lot of callers remove the links themselves before calling {transliterate()}, which I assume is wrong.]
# {makeSortKey}: This converts display text (?) to a sort key. [FIXME: Clarify this.]
]==]
local export = {}
local debug_track_module = "Module:debug/track"
local etymology_languages_data_module = "Module:etymology languages/data"
local families_module = "Module:families"
local headword_page_module = "Module:headword/page"
local json_module = "Module:JSON"
local language_like_module = "Module:language-like"
local languages_data_module = "Module:languages/data"
local languages_data_patterns_module = "Module:languages/data/patterns"
local links_data_module = "Module:links/data"
local load_module = "Module:load"
local scripts_module = "Module:scripts"
local scripts_data_module = "Module:scripts/data"
local string_encode_entities_module = "Module:string/encode entities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local wikimedia_languages_module = "Module:wikimedia languages"
local mw = mw
local string = string
local table = table
local char = string.char
local concat = table.concat
local find = string.find
local floor = math.floor
local get_by_code -- Defined below.
local get_data_module_name -- Defined below.
local get_extra_data_module_name -- Defined below.
local getmetatable = getmetatable
local gmatch = string.gmatch
local gsub = string.gsub
local insert = table.insert
local ipairs = ipairs
local is_known_language_tag = mw.language.isKnownLanguageTag
local make_object -- Defined below.
local match = string.match
local next = next
local pairs = pairs
local remove = table.remove
local require = require
local select = select
local setmetatable = setmetatable
local sub = string.sub
local type = type
local unstrip = mw.text.unstrip
-- Loaded as needed by findBestScript.
local Hans_chars
local Hant_chars
local function check_object(...)
check_object = require(utilities_module).check_object
return check_object(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
local function deep_copy(...)
deep_copy = require(table_module).deepCopy
return deep_copy(...)
end
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function get_L2_sort_key(...)
get_L2_sort_key = require(headword_page_module).get_L2_sort_key
return get_L2_sort_key(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function get_family(...)
get_family = require(families_module).getByCode
return get_family(...)
end
local function get_plaintext(...)
get_plaintext = require(utilities_module).get_plaintext
return get_plaintext(...)
end
local function get_wikimedia_lang(...)
get_wikimedia_lang = require(wikimedia_languages_module).getByCode
return get_wikimedia_lang(...)
end
local function keys_to_list(...)
keys_to_list = require(table_module).keysToList
return keys_to_list(...)
end
local function list_to_set(...)
list_to_set = require(table_module).listToSet
return list_to_set(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function make_family_object(...)
make_family_object = require(families_module).makeObject
return make_family_object(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function safe_require(...)
safe_require = require(load_module).safe_require
return safe_require(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function to_json(...)
to_json = require(json_module).toJSON
return to_json(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ugsub(...)
ugsub = require(string_utilities_module).gsub
return ugsub(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local function uupper(...)
uupper = require(string_utilities_module).upper
return uupper(...)
end
local function track(page)
debug_track("languages/" .. page)
return true
end
local function normalize_code(code)
return load_data(languages_data_module).aliases[code] or code
end
local function check_inputs(self, check, default, ...)
local n = select("#", ...)
if n == 0 then
return false
end
local ret = check(self, (...))
if ret ~= nil then
return ret
elseif n > 1 then
local inputs = {...}
for i = 2, n do
ret = check(self, inputs[i])
if ret ~= nil then
return ret
end
end
end
return default
end
local function make_link(self, target, display)
local prefix, main
if self:getFamilyCode() == "qfa-sub" then
prefix, main = display:match("^(the )(.*)")
if not prefix then
prefix, main = display:match("^(a )(.*)")
end
end
return (prefix or "") .. "[[" .. target .. "|" .. (main or display) .. "]]"
end
-- Convert risky characters to HTML entities, which minimizes interference once returned (e.g. for "sms:a", "<!-- -->" etc.).
local function escape_risky_characters(text)
-- Spacing characters in isolation generally need to be escaped in order to be properly processed by the MediaWiki
-- software.
if umatch(text, "^%s*$") then
return encode_entities(text, text)
end
return encode_entities(text, "!#%&*+/:;<=>?@[\\]_{|}")
end
-- Temporarily convert various formatting characters to PUA to prevent them from being disrupted by the substitution process.
local function doTempSubstitutions(text, subbedChars, keepCarets, noTrim)
-- Clone so that we don't insert any extra patterns into the table in package.loaded. For some reason, using require
-- seems to keep memory use down; probably because the table is always cloned.
local patterns = shallow_copy(require(languages_data_patterns_module))
if keepCarets then
insert(patterns, "((\\+)%^)")
insert(patterns, "((%^))")
end
-- Ensure any whitespace at the beginning and end is temp substituted, to prevent it from being accidentally
-- trimmed. We only want to trim any final spaces added during the substitution process (e.g. by a module), which
-- means we only do this during the first round of temp substitutions.
if not noTrim then
insert(patterns, "^([\128-\191\244]*(%s+))")
insert(patterns, "((%s+)[\128-\191\244]*)$")
end
-- Pre-substitution, of "[[" and "]]", which makes pattern matching more accurate.
text = gsub(text, "%f[%[]%[%[", "\1"):gsub("%f[%]]%]%]", "\2")
local i = #subbedChars
for _, pattern in ipairs(patterns) do
-- Patterns ending in \0 stand are for things like "[[" or "]]"), so the inserted PUA are treated as breaks
-- between terms by modules that scrape info from pages.
local term_divider
pattern = gsub(pattern, "%z$", function(divider)
term_divider = divider == "\0"
return ""
end)
text = gsub(text, pattern, function(...)
local m = {...}
local m1New = m[1]
for k = 2, #m do
local n = i + k - 1
subbedChars[n] = m[k]
local byte2 = floor(n / 4096) % 64 + (term_divider and 128 or 136)
local byte3 = floor(n / 64) % 64 + 128
local byte4 = n % 64 + 128
m1New = gsub(m1New, pattern_escape(m[k]), "\244" .. char(byte2) .. char(byte3) .. char(byte4), 1)
end
i = i + #m - 1
return m1New
end)
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text, subbedChars
end
-- Reinsert any formatting that was temporarily substituted.
local function undoTempSubstitutions(text, subbedChars)
for i = 1, #subbedChars do
local byte2 = floor(i / 4096) % 64 + 128
local byte3 = floor(i / 64) % 64 + 128
local byte4 = i % 64 + 128
text = gsub(text, "\244[" .. char(byte2) .. char(byte2+8) .. "]" .. char(byte3) .. char(byte4),
replacement_escape(subbedChars[i]))
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text
end
-- Check if the raw text is an unsupported title, and if so return that. Otherwise, remove HTML entities. We do the
-- pre-conversion to avoid loading the unsupported title list unnecessarily.
local function checkNoEntities(text)
local textNoEnc = decode_entities(text)
if textNoEnc ~= text and load_data(links_data_module).unsupported_titles[text] then
return text
else
return textNoEnc
end
end
-- If no script object is provided (or if it's invalid or None), get one.
local function checkScript(text, self, sc)
if not check_object("script", true, sc) or sc:getCode() == "None" then
return self:findBestScript(text)
end
return sc
end
local function normalize(text, sc)
text = sc:fixDiscouragedSequences(text)
return sc:toFixedNFD(text)
end
--[=[
Subfunction of iterateSectionSubstitutions(). Process an individual chunk of text according to the specifications in
`substitution_data`. The input parameters are all as in the documentation of iterateSectionSubstitutions() except for
`recursed`, which is set to true if we called ourselves recursively to process a script-specific setting or
script-wide fallback. Returns two values: the processed text and the actual substitution data used to do the
substitutions (same as the `actual_substitution_data` return value to iterateSectionSubstitutions()).
]=]
local function doSubstitutions(self, text, sc, substitution_data, data_field, function_name, recursed)
-- BE CAREFUL in this function because the value at any level can be `false`, which causes no processing to be done
-- and blocks any further fallback processing.
local actual_substitution_data = substitution_data
-- If there are language-specific substitutes given in the data module, use those.
if type(substitution_data) == "table" then
-- If a script is specified, run this function with the script-specific data before continuing.
local sc_code = sc:getCode()
local has_substitution_data = false
if substitution_data[sc_code] ~= nil then
has_substitution_data = true
if substitution_data[sc_code] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[sc_code], data_field,
function_name, true)
end
-- Hant, Hans and Hani are usually treated the same, so add a special case to avoid having to specify each one
-- separately.
elseif sc_code:match("^Han") and substitution_data.Hani ~= nil then
has_substitution_data = true
if substitution_data.Hani then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data.Hani, data_field,
function_name, true)
end
-- Substitution data with key 1 in the outer table may be given as a fallback.
elseif substitution_data[1] ~= nil then
has_substitution_data = true
if substitution_data[1] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[1], data_field,
function_name, true)
end
end
-- Iterate over all strings in the "from" subtable, and gsub with the corresponding string in "to". We work with
-- the NFD decomposed forms, as this simplifies many substitutions.
if substitution_data.from then
has_substitution_data = true
for i, from in ipairs(substitution_data.from) do
-- Normalize each loop, to ensure multi-stage substitutions work correctly.
text = sc:toFixedNFD(text)
text = ugsub(text, sc:toFixedNFD(from), substitution_data.to[i] or "")
end
end
if substitution_data.remove_diacritics then
has_substitution_data = true
text = sc:toFixedNFD(text)
-- Convert exceptions to PUA.
local remove_exceptions, substitutes = substitution_data.remove_exceptions
if remove_exceptions then
substitutes = {}
local i = 0
for _, exception in ipairs(remove_exceptions) do
exception = sc:toFixedNFD(exception)
text = ugsub(text, exception, function(m)
i = i + 1
local subst = u(0x80000 + i)
substitutes[subst] = m
return subst
end)
end
end
-- Strip diacritics.
text = ugsub(text, "[" .. substitution_data.remove_diacritics .. "]", "")
-- Convert exceptions back.
if remove_exceptions then
text = text:gsub("\242[\128-\191]*", substitutes)
end
end
if not has_substitution_data and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
elseif type(substitution_data) == "string" then
-- If there is a dedicated function module, use that.
local module = safe_require("Module:" .. substitution_data)
if module then
-- TODO: translit functions should take objects, not codes.
-- TODO: translit functions should be called with form NFD.
if function_name == "tr" then
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named 'tr'"):format(substitution_data))
end
text = module[function_name](text, self._code, sc:getCode())
elseif function_name == "stripDiacritics" then
-- FIXME, get rid of this arm after renaming makeEntryName -> stripDiacritics.
if module[function_name] then
text = module[function_name](sc:toFixedNFD(text), self, sc)
elseif module.makeEntryName then
text = module.makeEntryName(sc:toFixedNFD(text), self, sc)
else
error(("Internal error: Module [[%s]] has no function named 'stripDiacritics' or 'makeEntryName'"
):format(substitution_data))
end
else
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named '%s'"):format(
substitution_data, function_name))
end
text = module[function_name](sc:toFixedNFD(text), self, sc)
end
else
error("Substitution data '" .. substitution_data .. "' does not match an existing module.")
end
elseif substitution_data == nil and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
-- Don't normalize to NFC if this is the inner loop or if a module returned nil.
if recursed or not text then
return text, actual_substitution_data
end
-- Fix any discouraged sequences created during the substitution process, and normalize into the final form.
return sc:toFixedNFC(sc:fixDiscouragedSequences(text)), actual_substitution_data
end
--[=[
Split the text into sections, based on the presence of temporarily substituted formatting characters, then iterate over
each section to apply substitutions (e.g. transliteration or diacritic stripping). This avoids putting PUA (Private Use
Area) characters through language-specific modules, which may be unequipped for them. This function is passed the
following values:
* `self` (the Language object);
* `text` (the text to process);
* `sc` (the script of the text, which must be specified; callers should call checkScript() as needed to autodetect the
script of the text if not given explicitly by the user);
* `subbedChars` (an array of the same length as the text, indicating which characters have been substituted and by
what, or {nil} if no substitutions are to happen);
* `keepCarets` (DOCUMENT ME);
* `substitution_data` (the data indicating which substitutions to apply, taken directly from `data_field` in the
language's data structure in a submodule of [[Module:languages/data]]);
* `data_field` (the field from which `substitution_data` was fetched, such as {"sort_key"} or {"strip_diacritics"});
* `function_name` (the name of the function to call to do the substitution, in case `substitution_data` specifies a
module to do the substitution);
* `notrim` (don't trim whitespace at the edges of `text`; set when computing the sort key, because whitespace at the
beginning of a sort key is significant and causes the resulting page to be sorted at the beginning of the category
it's in).
Return three values:
# the processed text;
# the value of `subbedChars` that was passed in, possibly modified with additional character substitutions; will be
{nil} if {nil} was passed in;
# the actual substitution data that was used to apply substitutions to `text`; this may be different from the value
of `substitution_data` passed in if that value recursively specified script-specific substitutions or if no
substitution data could be found in the language-specific data (e.g. {nil} was passed in or a structure was passed
in that had no setting for the script given in `sc`), but a script-wide fallback value was set; currently it is
only used by {makeSortKey()}.
]=]
local function iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, substitution_data, data_field,
function_name, notrim)
local sections
-- See [[Module:languages/data]].
if not find(text, "\244") or load_data(languages_data_module).substitution[self._code] == "cont" then
sections = {text}
else
sections = split(text, "\244[\128-\143][\128-\191]*", true)
end
local actual_substitution_data
for _, section in ipairs(sections) do
-- Don't bother processing empty strings or whitespace (which may also not be handled well by dedicated
-- modules).
if gsub(section, "%s+", "") ~= "" then
local sub, this_actual_substitution_data = doSubstitutions(self, section, sc, substitution_data, data_field,
function_name)
actual_substitution_data = this_actual_substitution_data
-- Second round of temporary substitutions, in case any formatting was added by the main substitution
-- process. However, don't do this if the section contains formatting already (as it would have had to have
-- been escaped to reach this stage, and therefore should be given as raw text).
if sub and subbedChars then
local noSub
for _, pattern in ipairs(require(languages_data_patterns_module)) do
if match(section, pattern .. "%z?") then
noSub = true
end
end
if not noSub then
sub, subbedChars = doTempSubstitutions(sub, subbedChars, keepCarets, true)
end
end
if not sub then
text = sub
break
end
text = sub and gsub(text, pattern_escape(section), replacement_escape(sub), 1) or text
end
end
if not notrim then
-- Trim, unless there are only spacing characters, while ignoring any final formatting characters.
-- Do not trim sort keys because spaces at the beginning are significant.
text = text and text:gsub("^([\128-\191\244]*)%s+(%S)", "%1%2"):gsub("(%S)%s+([\128-\191\244]*)$", "%1%2") or
nil
end
return text, subbedChars, actual_substitution_data
end
-- Process carets (and any escapes). Default to simple removal, if no pattern/replacement is given.
local function processCarets(text, pattern, repl)
local rep
repeat
text, rep = gsub(text, "\\\\(\\*^)", "\3%1")
until rep == 0
return (text:gsub("\\^", "\4")
:gsub(pattern or "%^", repl or "")
:gsub("\3", "\\")
:gsub("\4", "^"))
end
local function hasUnescapedCarets(text)
return processCarets(text, "%^", "\1"):find("\1", 1, true) ~= nil
end
local function assertCaretCapitalizationAllowed(text, sc)
if sc:forbidsCaretCapitalization() and hasUnescapedCarets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
local function removeCarets(text, sc)
if text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
return processCarets(text)
end
end
return text
end
local Language = {}
--[==[
Return the language code of the language. Example: {fr"} for French.
]==]
function Language:getCode()
return self._code
end
--[==[
Return the canonical name of the language. This is the name used to represent that language on Wiktionary, and is
guaranteed to be unique to that language alone. Example: {"French"} for French.
]==]
function Language:getCanonicalName()
local name = self._name
if name == nil then
name = self._data[1]
self._name = name
end
return name
end
--[==[
Return the display form of the language. The display form of a language, family or script is the form it takes when
appearing as the <code><var>source</var></code> in categories such as <code>English terms derived from
<var>source</var></code> or <code>English given names from <var>source</var></code>, and is also the displayed text
in `##makeCategoryLink()` links. For full and etymology-only languages, this is the same as the canonical name, but
for families, it reads <code>"<var>name</var> languages"</code> (e.g. {"Indo-Iranian languages"}), and for scripts,
it reads <code>"<var>name</var> script"</code> (e.g. {"Arabic script"}).
]==]
function Language:getDisplayForm()
local form = self._displayForm
if form == nil then
form = self:getCanonicalName()
-- Add article and " substrate" to substrates that lack them.
if self:getFamilyCode() == "qfa-sub" then
if not (sub(form, 1, 4) == "the " or sub(form, 1, 2) == "a ") then
form = "a " .. form
end
if not match(form, " [Ss]ubstrate") then
form = form .. " substrate"
end
end
self._displayForm = form
end
return form
end
--[==[
Return the value which should be used in the HTML `lang=` attribute for tagged text in the language.
]==]
function Language:getHTMLAttribute(sc, region)
local code = self._code
if not find(code, "-", 1, true) then
return code .. "-" .. sc:getCode() .. (region and "-" .. region or "")
end
local parent = self:getParent()
region = region or match(code, "%f[%u][%u-]+%f[%U]")
if parent then
return parent:getHTMLAttribute(sc, region)
end
-- TODO: ISO family codes can also be used.
return "mis-" .. sc:getCode() .. (region and "-" .. region or "")
end
--[==[
Return a list of the aliases that the language is known by, excluding the canonical name. Aliases are synonyms for the
language in question. The names are not guaranteed to be unique, in that sometimes more than one language is known by
the same name. Example: { {"High German", "New High German", "Deutsch"}} for {{lnl|de}}.
]==]
function Language:getAliases()
self:loadInExtraData()
return require(language_like_module).getAliases(self)
end
--[==[
Return a list of the known subvarieties of a given language, excluding subvarieties that have been given explicit
etymology-only language codes. The names are not guaranteed to be unique, in that sometimes a given name refers to a
subvariety of more than one language. Example: { {"Southern Aymara", "Central Aymara"}} for {{lnl|ay}}. Note that the
returned value can have nested tables in it, when a subvariety goes by more than one name. Example:
{ {"North Azerbaijani", "South Azerbaijani", {"Afshar", "Afshari", "Afshar Azerbaijani", "Afchar"}, {"Qashqa'i", "Qashqai", "Kashkay"}, "Sonqor"}}
for {{lnl|az}}. Here, for example, Afshar, Afshari, Afshar Azerbaijani and Afchar all refer to the same subvariety,
whose preferred name is Afshar (the one listed first). To avoid a return value with nested tables in it, specify a
non-{nil} value for the `flatten` parameter; in that case, the return value would be
{ {"North Azerbaijani", "South Azerbaijani", "Afshar", "Afshari", "Afshar Azerbaijani", "Afchar", "Qashqa'i", "Qashqai", "Kashkay", "Sonqor"}}.
]==]
function Language:getVarieties(flatten)
self:loadInExtraData()
return require(language_like_module).getVarieties(self, flatten)
end
--[==[
Return a table of the "other names" that the language is known by, which are listed in the `other_names` field in the
language's extra-data module. It should be noted that the `other_names` field itself is deprecated, and entries listed
there should eventually be moved to either `aliases` or `varieties`, or removed if they refer to larger entities which
the language in question is actually a part of.
]==]
function Language:getOtherNames() -- To be eventually removed, once there are no more uses of the `other_names` field.
self:loadInExtraData()
return require(language_like_module).getOtherNames(self)
end
--[==[
Return a combined table of the canonical name, aliases, varieties and other names of a given language.
]==]
function Language:getAllNames()
self:loadInExtraData()
return require(language_like_module).getAllNames(self)
end
--[==[
Return a table of types as a set (with the types as keys). The possible types are
* {language}: This is a language, either full or etymology-only.
* {full}: This is a "full" (not etymology-only) language, i.e. the union of {regular}, {reconstructed} and
{appendix-constructed}. Note that the types {full} and {etymology-only} also exist for families, so if you want to
check specifically for a full language and you have an object that might be a family, you should use
{hasType("language", "full")} and not simply {hasType("full")}.
* {etymology-only}: This is an etymology-only (not full) language, whose parent is another etymology-only language or a
full language. Note that the types {full} and {etymology-only} also exist for families, so if you want to check
specifically for an etymology-only language and you have an object that might be a family, you should use
{hasType("language", "etymology-only")} and not simply {hasType("etymology-only")}.
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the main
namespace. There may also be reconstructed terms for the language, which are placed in the {Reconstruction}
namespace and must be prefixed with `*` to indicate a reconstruction. Most full languages are natural
(not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük, among others) are also
allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with `*`. Languages
such as Proto-Indo-European and Proto-Germanic are in this category. '''Exception:''' Reconstructed languages can
have entries in the mainspace using the ''anti-asterisk'' feature. This requires that both the headword for the
mainspace term (as specified using {{para|head}}) and links to the term are prefixed with the anti-asterisk
indicator `!!`.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in the Appendix namespace,
but they are not reconstructed and therefore should not have * prefixed in links.
]==]
function Language:getTypes()
local types = self._types
if types == nil then
types = {language = true}
if self:getFullCode() == self._code then
types.full = true
else
types["etymology-only"] = true
end
for t in gmatch(self._data.type, "[^,]+") do
types[t] = true
end
self._types = types
end
return types
end
--[==[
Given a list of types as strings, return {true} if the language has all of them.
]==]
function Language:hasType(...)
Language.hasType = require(language_like_module).hasType
return self:hasType(...)
end
--[==[
Return a list containing `WikimediaLanguage` objects (see [[Module:wikimedia languages]]), which represent languages
and their codes as they are used in Wikimedia projects for interwiki linking and such. More than one object may be
returned, as a single Wiktionary language may correspond to multiple Wikimedia languages. For example, Wiktionary's
single code `sh` (Serbo-Croatian) maps to four Wikimedia codes: `sh` (Serbo-Croatian), `bs` (Bosnian), `hr` (Croatian)
and `sr` (Serbian). The code for the Wikimedia language is retrieved from the `wikimedia_codes` property in the data
modules. If that property is not present, the code of the current language is used. If none of the available codes is
actually a valid Wikimedia code, an empty list is returned.
]==]
function Language:getWikimediaLanguages()
local wm_langs = self._wikimediaLanguageObjects
if wm_langs == nil then
local codes = self:getWikimediaLanguageCodes()
wm_langs = {}
for i = 1, #codes do
wm_langs[i] = get_wikimedia_lang(codes[i])
end
self._wikimediaLanguageObjects = wm_langs
end
return wm_langs
end
function Language:getWikimediaLanguageCodes()
local wm_langs = self._wikimediaLanguageCodes
if wm_langs == nil then
wm_langs = self._data.wikimedia_codes
if wm_langs then
wm_langs = split(wm_langs, ",", true, true)
else
local code = self._code
if is_known_language_tag(code) then
wm_langs = {code}
else
-- Inherit, but only if no codes are specified in the data *and*
-- the language code isn't a valid Wikimedia language code.
local parent = self:getParent()
wm_langs = parent and parent:getWikimediaLanguageCodes() or {}
end
end
self._wikimediaLanguageCodes = wm_langs
end
return wm_langs
end
--[==[
Return the name of the Wikipedia article for the language. `project` specifies the language and project to retrieve
the article from, defaulting to {"enwiki"} for the English Wikipedia. Normally if specified it should be the project
code for a specific-language Wikipedia e.g. "zhwiki" for the Chinese Wikipedia, but it can be any project, including
non-Wikipedia ones. If the project is the English Wikipedia and the property {wikipedia_article} is present in the data
module it will be used first. In all other cases, a sitelink will be generated from {:getWikidataItem} (if set). The
resulting value (or lack of value) is cached so that subsequent calls are fast. If no value could be determined, and
`noCategoryFallback` is {false}, `##Language:getCategoryName` is used as fallback; otherwise, {nil} is returned. Note
that if `noCategoryFallback` is {nil} or omitted, it defaults to {false} if the project is the English Wikipedia,
otherwise to {true}. In other words, under normal circumstances, if the English Wikipedia article couldn't be retrieved,
the return value will fall back to a link to the language's category, but this won't normally happen for any other
project.
]==]
function Language:getWikipediaArticle(noCategoryFallback, project)
Language.getWikipediaArticle = require(language_like_module).getWikipediaArticle
return self:getWikipediaArticle(noCategoryFallback, project)
end
function Language:makeWikipediaLink()
return make_link(self, "w:" .. self:getWikipediaArticle(), self:getCanonicalName())
end
--[==[
Return the name of the Wikimedia Commons category page for the language.
]==]
function Language:getCommonsCategory()
Language.getCommonsCategory = require(language_like_module).getCommonsCategory
return self:getCommonsCategory()
end
--[==[
Return the Wikidata item ID for the language or {nil}. This corresponds to the the second field in the data modules.
]==]
function Language:getWikidataItem()
Language.getWikidataItem = require(language_like_module).getWikidataItem
return self:getWikidataItem()
end
--[==[
Return a list of `Script` objects for all scripts that the language is written in. See [[Module:scripts]].
]==]
function Language:getScripts()
local scripts = self._scriptObjects
if scripts == nil then
local codes = self:getScriptCodes()
if codes[1] == "All" then
scripts = load_data(scripts_data_module)
else
scripts = {}
for i = 1, #codes do
scripts[i] = get_script(codes[i])
end
end
self._scriptObjects = scripts
end
return scripts
end
--[==[
Return the list of script codes in the language's data file.
]==]
function Language:getScriptCodes()
local scripts = self._scriptCodes
if scripts == nil then
scripts = self._data[4]
if scripts then
local codes, n = {}, 0
for code in gmatch(scripts, "[^,]+") do
n = n + 1
-- Special handling of "Hants", which represents "Hani", "Hant" and "Hans" collectively.
if code == "Hants" then
codes[n] = "Hani"
codes[n + 1] = "Hant"
codes[n + 2] = "Hans"
n = n + 2
else
codes[n] = code
end
end
scripts = codes
else
scripts = {"None"}
end
self._scriptCodes = scripts
end
return scripts
end
--[==[
Given some text, iterate through the scripts of a given language trying to find the script that best matches the text.
Return a {Script} object representing the script. If no match is found at all, it returns the {None} script object.
]==]
function Language:findBestScript(text, forceDetect)
if not text or text == "" or text == "-" then
return get_script("None")
end
-- Differs from table returned by getScriptCodes, as Hants is not normalized into its constituents.
local codes = self._bestScriptCodes
if codes == nil then
codes = self._data[4]
codes = codes and split(codes, ",", true, true) or {"None"}
self._bestScriptCodes = codes
end
local first_sc = codes[1]
if first_sc == "All" then
return find_best_script_without_lang(text)
end
local codes_len = #codes
if not (forceDetect or first_sc == "Hants" or codes_len > 1) then
first_sc = get_script(first_sc)
local charset = first_sc.characters
return charset and umatch(text, "[" .. charset .. "]") and first_sc or get_script("None")
end
-- Remove all formatting characters.
text = get_plaintext(text)
-- Remove all spaces and any ASCII punctuation. Some non-ASCII punctuation is script-specific, so can't be removed.
text = ugsub(text, "[%s!\"#%%&'()*,%-./:;?@[\\%]_{}]+", "")
if #text == 0 then
return get_script("None")
end
-- Try to match every script against the text,
-- and return the one with the most matching characters.
local bestcount, bestscript, length = 0
for i = 1, codes_len do
local sc = codes[i]
-- Special case for "Hants", which is a special code that represents whichever of "Hant" or "Hans" best matches,
-- or "Hani" if they match equally. This avoids having to list all three. In addition, "Hants" will be treated
-- as the best match if there is at least one matching character, under the assumption that a Han script is
-- desirable in terms that contain a mix of Han and other scripts (not counting those which use Jpan or Kore).
if sc == "Hants" then
local Hani = get_script("Hani")
if not Hant_chars then
Hant_chars = load_data("Module:zh/data/ts")
Hans_chars = load_data("Module:zh/data/st")
end
local t, s, found = 0, 0
-- This is faster than using mw.ustring.gmatch directly.
for ch in gmatch((ugsub(text, "[" .. Hani.characters .. "]", "\255%0")), "\255(.[\128-\191]*)") do
found = true
if Hant_chars[ch] then
t = t + 1
if Hans_chars[ch] then
s = s + 1
end
elseif Hans_chars[ch] then
s = s + 1
else
t, s = t + 1, s + 1
end
end
if found then
if t == s then
return Hani
end
return get_script(t > s and "Hant" or "Hans")
end
else
sc = get_script(sc)
if not length then
length = ulen(text)
end
-- Count characters by removing everything in the script's charset and comparing to the original length.
local charset = sc.characters
local count = charset and length - ulen((ugsub(text, "[" .. charset .. "]+", ""))) or 0
if count >= length then
return sc
elseif count > bestcount then
bestcount = count
bestscript = sc
end
end
end
-- Return best matching script, or otherwise None.
return bestscript or get_script("None")
end
--[==[
Return a `Family` object for the language family that the language belongs to. See [[Module:families]].
]==]
function Language:getFamily()
local family = self._familyObject
if family == nil then
family = self:getFamilyCode()
-- If the value is nil, it's cached as false.
family = family and get_family(family) or false
self._familyObject = family
end
return family or nil
end
--[==[
Return the family code in the language's data file.
]==]
function Language:getFamilyCode()
local family = self._familyCode
if family == nil then
-- If the value is nil, it's cached as false.
family = self._data[3] or false
self._familyCode = family
end
return family or nil
end
function Language:getFamilyName()
local family = self._familyName
if family == nil then
family = self:getFamily()
-- If the value is nil, it's cached as false.
family = family and family:getCanonicalName() or false
self._familyName = family
end
return family or nil
end
do
local function check_family(self, family)
if type(family) == "table" then
family = family:getCode()
end
if self:getFamilyCode() == family then
return true
end
local self_family = self:getFamily()
if self_family:inFamily(family) then
return true
-- If the family isn't a real family (e.g. creoles) check any ancestors.
elseif self_family:inFamily("qfa-not") then
local ancestors = self:getAncestors()
for _, ancestor in ipairs(ancestors) do
if ancestor:inFamily(family) then
return true
end
end
end
end
--[==[
Check whether the language belongs to `family` (which can be a family code or object). A list of objects can be given in
place of `family`; in that case, return true if the language belongs to any of the specified families. Note that some
languages (in particular, certain creoles) can have multiple immediate ancestors potentially belonging to different
families; in that case, return true if the language belongs to any of the specified families.
]==]
function Language:inFamily(...)
if self:getFamilyCode() == nil then
return false
end
return check_inputs(self, check_family, false, ...)
end
end
function Language:getParent()
local parent = self._parentObject
if parent == nil then
parent = self:getParentCode()
-- If the value is nil, it's cached as false.
parent = parent and get_by_code(parent, nil, true, true) or false
self._parentObject = parent
end
return parent or nil
end
function Language:getParentCode()
local parent = self._parentCode
if parent == nil then
-- If the value is nil, it's cached as false.
parent = self._data.parent or false
self._parentCode = parent
end
return parent or nil
end
function Language:getParentName()
local parent = self._parentName
if parent == nil then
parent = self:getParent()
-- If the value is nil, it's cached as false.
parent = parent and parent:getCanonicalName() or false
self._parentName = parent
end
return parent or nil
end
function Language:getParentChain()
local chain = self._parentChain
if chain == nil then
chain = {}
local parent, n = self:getParent(), 0
while parent do
n = n + 1
chain[n] = parent
parent = parent:getParent()
end
self._parentChain = chain
end
return chain
end
--[==[
Return a list of the pseudo-families (if any) that a language belongs to. The returned value is a list of Family
objects. Pseudo-families are groupings of languages that are not clades but share some geographic, ethnic or other
characteristic (e.g. [[:Category:Papuan languages]], [[:Category:Jewish languages]]).
]==]
function Language:getPseudoFamilies()
self:loadInExtraData()
return require(language_like_module).getPseudoFamilies(self)
end
--[==[
Return a list of the pseudo-family codes (if any) that a language belongs to. The returned value is a list of strings
(family codes). See `##Language:getPseudoFamilies`.
]==]
function Language:getPseudoFamilyCodes()
local codes = {}
for _, family in ipairs(self:getPseudoFamilies()) do
insert(codes, family:getCode())
end
return codes
end
do
local function check_lang(self, lang)
for _, parent in ipairs(self:getParentChain()) do
if (type(lang) == "string" and lang or lang:getCode()) == parent:getCode() then
return true
end
end
end
function Language:hasParent(...)
return check_inputs(self, check_lang, false, ...)
end
end
--[==[
If the language is etymology-only, iterate through parents until a full language or family is found, and the
corresponding object is returned. If the language is a full language, return that language.
]==]
function Language:getFull()
local full = self._fullObject
if full == nil then
full = self:getFullCode()
full = full == self._code and self or get_by_code(full)
self._fullObject = full
end
return full
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and
the corresponding code is returned. If the language is a full language, return that language's code.
]==]
function Language:getFullCode()
return self._fullCode or self._code
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and the
corresponding canonical name is returned. If the language is a full language, return that language's canonical name.
]==]
function Language:getFullName()
local full = self._fullName
if full == nil then
full = self:getFull():getCanonicalName()
self._fullName = full
end
return full
end
--[==[
Return a list of {Language} objects for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestors()
local ancestors = self._ancestorObjects
if ancestors == nil then
ancestors = {}
local ancestor_codes = self:getAncestorCodes()
if #ancestor_codes > 0 then
for _, ancestor in ipairs(ancestor_codes) do
insert(ancestors, get_by_code(ancestor, nil, true))
end
else
local fam = self:getFamily()
local protoLang = fam and fam:getProtoLanguage() or nil
-- For the cases where the current language is the proto-language
-- of its family, or an etymology-only language that is ancestral to that
-- proto-language, we need to step up a level higher right from the
-- start.
if protoLang and (
protoLang:getCode() == self._code or
(self:hasType("etymology-only") and protoLang:hasAncestor(self))
) then
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
while not protoLang and not (not fam or fam:getCode() == "qfa-not") do
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
insert(ancestors, protoLang)
end
self._ancestorObjects = ancestors
end
return ancestors
end
do
-- Avoid a language being its own ancestor via class inheritance. We only need to check for this if the language has
-- inherited an ancestor table from its parent, because we never want to drop ancestors that have been explicitly
-- set in the data. Recursively iterate over ancestors until we either find self or run out. If self is found,
-- return true.
local function check_ancestor(self, lang)
local codes = lang:getAncestorCodes()
if not codes then
return nil
end
for i = 1, #codes do
local code = codes[i]
if code == self._code then
return true
end
local anc = get_by_code(code, nil, true)
if check_ancestor(self, anc) then
return true
end
end
end
--[==[
Return a list of `Language` codes for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestorCodes()
if self._ancestorCodes then
return self._ancestorCodes
end
local data = self._data
local codes = data.ancestors
if codes == nil then
codes = {}
self._ancestorCodes = codes
return codes
end
codes = split(codes, ",", true, true)
self._ancestorCodes = codes
-- If there are no codes or the ancestors weren't inherited data, there's nothing left to check.
if #codes == 0 or self:getData(false, "raw").ancestors ~= nil then
return codes
end
local i = 1
while i <= #codes do
if check_ancestor(self, self) then
remove(codes, i)
else
i = i + 1
end
end
return codes
end
end
--[==[
Given a list of language objects or codes, return true if at least one of them is an ancestor. This includes any
etymology-only children of that ancestor. If the language's ancestor(s) are etymology-only languages, it will also
return true for those language parent(s) (e.g. if Vulgar Latin is the ancestor, it will also return true for its parent,
Latin). However, a parent is excluded from this if the ancestor is also ancestral to that parent (e.g. if Classical
Persian is the ancestor, Persian would return {false}, because Classical Persian is also ancestral to Persian).
]==]
function Language:hasAncestor(...)
local function iterateOverAncestorTree(node, func, parent_check)
local ancestors = node:getAncestors()
local ancestorsParents = {}
for _, ancestor in ipairs(ancestors) do
-- When checking the parents of the other language, and the ancestor is also a parent, skip to the next
-- ancestor, so that we exclude any etymology-only children of that parent that are not directly related
-- (see below).
local ret = (parent_check or not node:hasParent(ancestor)) and
func(ancestor) or iterateOverAncestorTree(ancestor, func, parent_check)
if ret then
return ret
end
end
-- Check the parents of any ancestors. We don't do this if checking the parents of the other language, so that
-- we exclude any etymology-only children of those parents that are not directly related (e.g. if the ancestor
-- is Vulgar Latin and we are checking New Latin, we want it to return false because they are on different
-- ancestral branches. As such, if we're already checking the parent of New Latin (Latin) we don't want to
-- compare it to the parent of the ancestor (Latin), as this would be a false positive; it should be one or the
-- other).
if not parent_check then
return nil
end
for _, ancestor in ipairs(ancestors) do
local ancestorParents = ancestor:getParentChain()
for _, ancestorParent in ipairs(ancestorParents) do
if ancestorParent:getCode() == self._code or ancestorParent:hasAncestor(ancestor) then
break
else
insert(ancestorsParents, ancestorParent)
end
end
end
for _, ancestorParent in ipairs(ancestorsParents) do
local ret = func(ancestorParent)
if ret then
return ret
end
end
end
local function do_iteration(otherlang, parent_check)
-- otherlang can't be self
if (type(otherlang) == "string" and otherlang or otherlang:getCode()) == self._code then
return false
end
repeat
if iterateOverAncestorTree(
self,
function(ancestor)
return ancestor:getCode() == (type(otherlang) == "string" and otherlang or otherlang:getCode())
end,
parent_check
) then
return true
elseif type(otherlang) == "string" then
otherlang = get_by_code(otherlang, nil, true)
end
otherlang = otherlang:getParent()
parent_check = false
until not otherlang
end
local parent_check = true
for _, otherlang in ipairs{...} do
local ret = do_iteration(otherlang, parent_check)
if ret then
return true
end
end
return false
end
do
local function construct_node(lang, memo)
local branch, ancestors = {lang = lang:getCode()}
memo[lang:getCode()] = branch
for _, ancestor in ipairs(lang:getAncestors()) do
if ancestors == nil then
ancestors = {}
end
insert(ancestors, memo[ancestor:getCode()] or construct_node(ancestor, memo))
end
branch.ancestors = ancestors
return branch
end
function Language:getAncestorChain()
local chain = self._ancestorChain
if chain == nil then
chain = construct_node(self, {})
self._ancestorChain = chain
end
return chain
end
end
function Language:getAncestorChainOld()
local chain = self._ancestorChain
if chain == nil then
chain = {}
local step = self
while true do
local ancestors = step:getAncestors()
step = #ancestors == 1 and ancestors[1] or nil
if not step then
break
end
insert(chain, step)
end
self._ancestorChain = chain
end
return chain
end
local function fetch_descendants(self, fmt)
local descendants, family = {}, self:getFamily()
-- Iterate over all three datasets.
for _, data in ipairs{
require("Module:languages/code to canonical name"),
require("Module:etymology languages/code to canonical name"),
require("Module:families/code to canonical name"),
} do
for code in pairs(data) do
local lang = get_by_code(code, nil, true, true)
if not lang then
error(("Internal error: code '%s' can't be fetched"):format(code))
end
-- Test for a descendant. Earlier tests weed out most candidates, while the more intensive tests are only used sparingly.
if (
code ~= self._code and -- Not self.
lang:inFamily(family) and -- In the same family.
(
family:getProtoLanguageCode() == self._code or -- Self is the protolanguage.
self:hasDescendant(lang) or -- Full hasDescendant check.
(lang:getFullCode() == self._code and not self:hasAncestor(lang)) -- Etymology-only child which isn't an ancestor.
)
) then
if fmt == "object" then
insert(descendants, lang)
elseif fmt == "code" then
insert(descendants, code)
elseif fmt == "name" then
insert(descendants, lang:getCanonicalName())
end
end
end
end
return descendants
end
function Language:getDescendants()
local descendants = self._descendantObjects
if descendants == nil then
descendants = fetch_descendants(self, "object")
self._descendantObjects = descendants
end
return descendants
end
function Language:getDescendantCodes()
local descendants = self._descendantCodes
if descendants == nil then
descendants = fetch_descendants(self, "code")
self._descendantCodes = descendants
end
return descendants
end
function Language:getDescendantNames()
local descendants = self._descendantNames
if descendants == nil then
descendants = fetch_descendants(self, "name")
self._descendantNames = descendants
end
return descendants
end
do
local function check_lang(self, lang)
if type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasAncestor(self) then
return true
end
end
function Language:hasDescendant(...)
return check_inputs(self, check_lang, false, ...)
end
end
local function fetch_children(self, fmt)
local m_etym_data = require(etymology_languages_data_module)
local self_code, children = self._code, {}
for code, lang in pairs(m_etym_data) do
local _lang = lang
repeat
local parent = _lang.parent
if parent == self_code then
if fmt == "object" then
insert(children, get_by_code(code, nil, true))
elseif fmt == "code" then
insert(children, code)
elseif fmt == "name" then
insert(children, lang[1])
end
break
end
_lang = m_etym_data[parent]
until not _lang
end
return children
end
function Language:getChildren()
local children = self._childObjects
if children == nil then
children = fetch_children(self, "object")
self._childObjects = children
end
return children
end
function Language:getChildrenCodes()
local children = self._childCodes
if children == nil then
children = fetch_children(self, "code")
self._childCodes = children
end
return children
end
function Language:getChildrenNames()
local children = self._childNames
if children == nil then
children = fetch_children(self, "name")
self._childNames = children
end
return children
end
function Language:hasChild(...)
local lang = ...
if not lang then
return false
elseif type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasParent(self) then
return true
end
return self:hasChild(select(2, ...))
end
--[==[
Return the name of the main category of that language. Example: {French language"} for French, whose category is at
[[:Category:French language]]. Unless optional argument `nocap` is given, the language name at the beginning of the
returned value will be capitalized. This capitalization is correct for category names, but not if the language name is
lowercase and the returned value of this function is used in the middle of a sentence.
]==]
function Language:getCategoryName(nocap)
local name = self._categoryName
if name == nil then
name = self:getCanonicalName()
-- If a substrate, omit any leading article.
if self:getFamilyCode() == "qfa-sub" then
name = name:gsub("^the ", ""):gsub("^a ", "")
end
-- Only add " language" if a full language.
if self:hasType("full") then
-- Unless the canonical name already ends with "language", "lect" or their derivatives, add " language".
if not (match(name, "[Ll]anguage$") or match(name, "[Ll]ect$")) then
name = name .. " language"
end
end
self._categoryName = name
end
if nocap then
return name
end
return mw.getContentLanguage():ucfirst(name)
end
--[==[
Create a link to the category; the link text is the canonical name.
]==]
function Language:makeCategoryLink()
return make_link(self, ":Category:" .. self:getCategoryName(), self:getDisplayForm())
end
function Language:getStandardCharacters(sc)
local standard_chars = self._data.standard_chars
if type(standard_chars) ~= "table" then
return standard_chars
elseif sc and type(sc) ~= "string" then
check_object("script", nil, sc)
sc = sc:getCode()
end
if (not sc) or sc == "None" then
local scripts = {}
for _, script in pairs(standard_chars) do
insert(scripts, script)
end
return concat(scripts)
end
if standard_chars[sc] then
return standard_chars[sc] .. (standard_chars[1] or "")
end
end
--[==[
Strip diacritics from display text `text` (in a language-specific fashion), which is in the script `sc`. If `sc` is
omitted or {nil}, the script is autodetected. This also strips certain punctuation characters from the end and (in the
case of Spanish upside-down question mark and exclamation points) from the beginning; strips any whitespace at the
end of the text or between the text and final stripped punctuation characters; and applies some language-specific
Unicode normalizations to replace discouraged characters with their prescribed alternatives. Return the stripped text.
]==]
function Language:stripDiacritics(text, sc)
if (not text) or text == "" then
return text
end
sc = checkScript(text, self, sc)
text = normalize(text, sc)
-- FIXME, rename makeEntryName to stripDiacritics and get rid of second and third return values
-- everywhere
local _
text, _, _ = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.strip_diacritics or self._data.entry_name, "strip_diacritics", "stripDiacritics")
text = umatch(text, "^[¿¡]?(.-[^%s%p].-)%s*[؟?!;՛՜ ՞ ՟?!︖︕।॥။၊་།]?$") or text
return text
end
--[==[
Convert a ''logical'' pagename (the pagename as it appears to the user, after diacritics and punctuation have been
stripped) to a ''physical'' pagename (the pagename as it appears in the MediaWiki database). Reasons for a difference
between the two are (a) unsupported titles such as `[ ]` (with square brackets in them), `#` (pound/hash sign) and
`¯\_(ツ)_/¯` (with underscores), as well as overly long titles of various sorts; (b) "mammoth" pages that are split into
parts (e.g. `a`, which is split into physical pagenames `a/languages A to L` and `a/languages M to Z`). For almost all
purposes, you should work with logical and not physical pagenames. But there are certain use cases that require physical
pagenames, such as checking the existence of a page or retrieving a page's contents.
`pagename` is the logical pagename to be converted. `is_reconstructed_or_appendix` indicates whether the page is in the
`Reconstruction` or `Appendix` namespaces. If it is omitted or has the value {nil}, the pagename is checked for an
initial asterisk, and if found, the page is assumed to be a `Reconstruction` page. Setting a value of `false` or `true`
to `is_reconstructed_or_appendix` disables this check and allows for mainspace pagenames that begin with an asterisk.
]==]
function Language:logicalToPhysical(pagename, is_reconstructed_or_appendix)
-- FIXME: This probably shouldn't happen but it happens when makeEntryName() receives nil.
if pagename == nil then
track("nil-passed-to-logicalToPhysical")
return nil
end
local initial_asterisk
if is_reconstructed_or_appendix == nil then
local pagename_minus_initial_asterisk
initial_asterisk, pagename_minus_initial_asterisk = pagename:match("^(%*)(.*)$")
if pagename_minus_initial_asterisk then
is_reconstructed_or_appendix = true
pagename = pagename_minus_initial_asterisk
elseif self:hasType("appendix-constructed") then
is_reconstructed_or_appendix = true
end
end
if not is_reconstructed_or_appendix then
-- Check if the pagename is a listed unsupported title.
local unsupportedTitles = load_data(links_data_module).unsupported_titles
if unsupportedTitles[pagename] then
return "Unsupported titles/" .. unsupportedTitles[pagename]
end
end
-- Set `unsupported` as true if certain conditions are met.
local unsupported
-- Check if there's an unsupported character. \239\191\189 is the replacement character U+FFFD, which can't be typed
-- directly here due to an abuse filter. Unix-style dot-slash notation is also unsupported, as it is used for
-- relative paths in links, as are 3 or more consecutive tildes. Note: match is faster with magic
-- characters/charsets; find is faster with plaintext.
if (
match(pagename, "[#<>%[%]_{|}]") or
find(pagename, "\239\191\189") or
match(pagename, "%f[^%z/]%.%.?%f[%z/]") or
find(pagename, "~~~")
) then
unsupported = true
-- If it looks like an interwiki link.
elseif find(pagename, ":") then
local prefix = gsub(pagename, "^:*(.-):.*", ulower)
if (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
unsupported = true
end
end
-- Escape unsupported characters so they can be used in titles. ` is used as a delimiter for this, so a raw use of
-- it in an unsupported title is also escaped here to prevent interference; this is only done with unsupported
-- titles, though, so inclusion won't in itself mean a title is treated as unsupported (which is why it's excluded
-- from the earlier test).
if unsupported then
-- FIXME: This conversion needs to be different for reconstructed pages with unsupported characters. There
-- aren't any currently, but if there ever are, we need to fix this e.g. to put them in something like
-- Reconstruction:Proto-Indo-European/Unsupported titles/`lowbar``num`.
local unsupported_characters = load_data(links_data_module).unsupported_characters
pagename = pagename:gsub("[#<>%[%]_`{|}\239]\191?\189?", unsupported_characters)
:gsub("%f[^%z/]%.%.?%f[%z/]", function(m)
return (gsub(m, "%.", "`period`"))
end)
:gsub("~~~+", function(m)
return (gsub(m, "~", "`tilde`"))
end)
pagename = "Unsupported titles/" .. pagename
elseif not is_reconstructed_or_appendix then
-- Check if this is a mammoth page. If so, which subpage should we link to?
local m_links_data = load_data(links_data_module)
local mammoth_page_type = m_links_data.mammoth_pages[pagename]
if mammoth_page_type then
local canonical_name = self:getFullName()
if canonical_name ~= "Translingual" and canonical_name ~= "English" then
local this_subpage
local L2_sort_key = get_L2_sort_key(canonical_name)
for _, subpage_spec in ipairs(m_links_data.mammoth_page_subpage_types[mammoth_page_type]) do
-- unpack() fails utterly on data loaded using mw.loadData() even if offsets are given
local subpage, pattern = subpage_spec[1], subpage_spec[2]
if pattern == true or L2_sort_key:match(pattern) then
this_subpage = subpage
break
end
end
if not this_subpage then
error(("Internal error: Bad data in mammoth_page_subpage_pages in [[Module:links/data]] for mammoth page %s, type %s; last entry didn't have 'true' in it"):format(
pagename, mammoth_page_type))
end
pagename = pagename .. "/" .. this_subpage
end
end
end
return (initial_asterisk or "") .. pagename
end
--[==[
Strip the diacritics from a display pagename and convert the resulting logical pagename into a physical pagename.
This allows you, for example, to retrieve the contents of the page or check its existence. WARNING: This is deprecated
and will be going away. It is a simple composition of `##Language:stripDiacritics` and `##Language:logicalToPhysical`;
most callers only want the former, and if you need both, call them both yourself.
`text` and `sc` are as in `##Language:stripDiacritics`, and `is_reconstructed_or_appendix` is as in
`##Language:logicalToPhysical`.
]==]
function Language:makeEntryName(text, sc, is_reconstructed_or_appendix)
track("makeEntryName called")
return self:logicalToPhysical(self:stripDiacritics(text, sc), is_reconstructed_or_appendix)
end
--[==[
Generate term alternants (e.g. simplified versions of traditional Chinese terms) using a language-specific method, and
return them as a table. If the language provides no method for generating alternants, return a table containing only the
input term.
]==]
function Language:generateAlternants(text, sc)
local generate_alternants = self._data.generate_alternants
if generate_alternants == nil then
return {text}
end
sc = checkScript(text, self, sc)
return require("Module:" .. generate_alternants).generateAlternants(text, self, sc)
end
--[==[
Create a sort key for the given stripped text, following the rules appropriate for the language. This removes
diacritical marks from the stripped text if they are not considered significant for sorting, and may perform some other
changes. Any initial hyphen is also removed, and anything in parentheses is removed as well. The `sort_key` setting for
each language in the data modules defines the replacements made by this function, or it gives the name of the module
that takes the stripped text and returns a sortkey.
]==]
function Language:makeSortKey(text, sc)
if (not text) or text == "" then
return text
end
if match(text, "<[^<>]+>") then
track("track HTML tag")
end
-- Remove directionality/control characters, bold, italics, soft hyphens, strip markers and HTML tags.
-- FIXME: Partly duplicated with remove_formatting() in [[Module:links]].
text = ugsub(text, "[\194\173\216\156\226\128\142\226\128\143\226\128\170-\226\128\174\226\129\166-\226\129\175]", "")
text = text:gsub("('*)'''(.-'*)'''", "%1%2"):gsub("('*)''(.-'*)''", "%1%2")
text = gsub(unstrip(text), "<[^<>]+>", "")
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
-- Remove initial hyphens and * unless the term only consists of spacing + punctuation characters.
text = ugsub(text, "^([-]*)[-־ـ᠊*]+([-]*)(.*[^%s%p].*)", "%1%2%3")
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text = removeCarets(text, sc)
-- For languages with dotted dotless i, ensure that "İ" is sorted as "i", and "I" is sorted as "ı".
if self:hasDottedDotlessI() then
text = gsub(text, "I\204\135", "i") -- decomposed "İ"
:gsub("I", "ı")
text = sc:toFixedNFD(text)
end
-- Convert to lowercase, make the sortkey, then convert to uppercase. Where the language has dotted dotless i, it is
-- usually not necessary to convert "i" to "İ" and "ı" to "I" first, because "I" will always be interpreted as
-- conventional "I" (not dotless "İ") by any sorting algorithms, which will have been taken into account by the
-- sortkey substitutions themselves. However, if no sortkey substitutions have been specified, then conversion is
-- necessary so as to prevent "i" and "ı" both being sorted as "I".
--
-- An exception is made for scripts that (sometimes) sort by scraping page content, as that means they are sensitive
-- to changes in capitalization (as it changes the target page).
if not sc:sortByScraping() then
text = ulower(text)
end
local actual_substitution_data, _
-- Don't trim whitespace here because it's significant at the beginning of a sort key or sort base.
text, _, actual_substitution_data = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.sort_key, "sort_key", "makeSortKey", "notrim")
if not sc:sortByScraping() then
if self:hasDottedDotlessI() and not actual_substitution_data then
text = text:gsub("ı", "I"):gsub("i", "İ")
text = sc:toFixedNFC(text)
end
text = uupper(text)
end
-- Remove parentheses, as long as they are either preceded or followed by something.
text = gsub(text, "(.)[()]+", "%1"):gsub("[()]+(.)", "%1")
text = escape_risky_characters(text)
return text
end
--[==[
Create the form used as as a basis for display text and transliteration. FIXME: Rename to correctInputText().
]==]
local function processDisplayText(text, self, sc, keepCarets, keepPrefixes)
local subbedChars = {}
text, subbedChars = doTempSubstitutions(text, subbedChars, keepCarets)
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, self._data.display_text,
"display_text", "makeDisplayText")
text = removeCarets(text, sc)
-- Remove any interwiki link prefixes (unless they have been escaped or this has been disabled).
if find(text, ":") and not keepPrefixes then
local rep
repeat
text, rep = gsub(text, "\\\\(\\*:)", "\3%1")
until rep == 0
text = gsub(text, "\\:", "\4")
while true do
local prefix = gsub(text, "^(.-):.+", function(m1)
return (gsub(m1, "\244[\128-\191]*", ""))
end)
-- Check if the prefix is an interwiki, though ignore capitalised Wiktionary:, which is a namespace.
if not prefix or prefix == text or prefix == "Wiktionary"
or not (load_data("Module:data/interwikis")[ulower(prefix)] or prefix == "") then
break
end
text = gsub(text, "^(.-):(.*)", function(m1, m2)
local ret = {}
for subbedChar in gmatch(m1, "\244[\128-\191]*") do
insert(ret, subbedChar)
end
return concat(ret) .. m2
end)
end
text = gsub(text, "\3", "\\"):gsub("\4", ":")
end
return text, subbedChars
end
--[==[
Make the display text (i.e. what is displayed on the page).
]==]
function Language:makeDisplayText(text, sc, keepPrefixes)
if not text or text == "" then
return text
end
local subbedChars
text, subbedChars = processDisplayText(text, self, sc, nil, keepPrefixes)
text = escape_risky_characters(text)
return undoTempSubstitutions(text, subbedChars)
end
--[==[
Transliterate the text from the given script into Latin script (see [[Wiktionary:Transliteration and romanization]]).
The language must have the `translit` property for this to work; if it is not present, {nil} is returned.
The `sc` parameter is handled by the transliteration module, and how it is handled is specific to that module. Some
transliteration modules may tolerate {nil} as the script, others require it to be one of the possible scripts that the
module can transliterate, and will throw an error if it's not one of them. For this reason, the `sc` parameter should
always be provided when writing non-language-specific code.
The `module_override` parameter is used to override the default module that is used to provide the transliteration.
This is useful in cases where you need to demonstrate a particular module in use, but there is no default module yet,
or you want to demonstrate an alternative version of a transliteration module before making it official. It should not
be used in real modules or templates, only for testing. All uses of this parameter are tracked by
[[Wiktionary:Tracking/languages/module_override]].
'''Known bugs''':
* This function assumes {tr(s1) .. tr(s2) == tr(s1 .. s2)}. When this assertion fails, wikitext markups like
<nowiki>'''</nowiki> can cause wrong transliterations.
* HTML entities like `&apos;`, often used to escape wikitext markups, do not work.
]==]
function Language:transliterate(text, sc, module_override)
-- If there is no text, or the language doesn't have transliteration data and there's no override, return nil.
if not text or text == "" or text == "-" then
return text
end
-- If the script is not transliteratable (and no override is given), return nil.
sc = checkScript(text, self, sc)
if not (sc:isTransliterated() or module_override) then
-- temporary tracking to see if/when this gets triggered
track("non-transliterable")
track("non-transliterable/" .. self._code)
track("non-transliterable/" .. sc:getCode())
track("non-transliterable/" .. sc:getCode() .. "/" .. self._code)
return nil
end
-- Remove any strip markers.
text = unstrip(text)
-- Do not process the formatting into PUA characters for certain languages.
local processed = load_data(languages_data_module).substitution[self._code] ~= "none"
-- Get the display text with the keepCarets flag set.
local subbedChars
if processed then
text, subbedChars = processDisplayText(text, self, sc, true)
end
-- Transliterate (using the module override if applicable).
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, true, module_override or
self._data.translit, "translit", "tr")
if not text then
return nil
end
-- Incomplete transliterations return nil.
local charset = sc.characters
if charset and umatch(text, "[" .. charset .. "]") then
-- Remove any characters in Latin, which includes Latin characters also included in other scripts (as these are
-- false positives), as well as any PUA substitutions. Anything remaining should only be script code "None"
-- (e.g. numerals).
local check_text = ugsub(text, "[" .. get_script("Latn").characters .. "-]+", "")
-- Set none_is_last_resort_only flag, so that any non-None chars will cause a script other than "None" to be
-- returned.
if find_best_script_without_lang(check_text, true):getCode() ~= "None" then
return nil
end
end
if processed then
text = escape_risky_characters(text)
text = undoTempSubstitutions(text, subbedChars)
end
-- If allowed for this script, capitalize transliteration letters preceded by ^ and remove the caret.
if text and text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
text = processCarets(text, "%^([\128-\191\244]*%*?)([^\128-\191\244][\128-\191]*)", function(m1, m2)
return m1 .. uupper(m2)
end)
end
end
-- Track module overrides.
if module_override ~= nil then
track("module_override")
end
return text
end
do
local function handle_language_spec(self, spec, sc)
local ret = self["_" .. spec]
if ret == nil then
ret = self._data[spec]
if type(ret) == "string" then
ret = list_to_set(split(ret, ",", true, true))
end
self["_" .. spec] = ret
end
if type(ret) == "table" then
ret = ret[sc:getCode()]
end
return not not ret
end
function Language:overrideManualTranslit(sc)
return handle_language_spec(self, "override_translit", sc)
end
function Language:link_tr(sc)
return handle_language_spec(self, "link_tr", sc)
end
end
--[==[
Return {true} if the language has a transliteration module, or {false} if it doesn't.
]==]
function Language:hasTranslit()
return not not self._data.translit
end
--[==[
Return {true} if the language uses the letters I/ı and İ/i, or {false} if it doesn't.]==]
function Language:hasDottedDotlessI()
return not not self._data.dotted_dotless_i
end
function Language:toJSON(opts)
local strip_diacritics, strip_diacritics_patterns, strip_diacritics_remove_diacritics = self._data.strip_diacritics
if strip_diacritics then
if strip_diacritics.from then
strip_diacritics_patterns = {}
for i, from in ipairs(strip_diacritics.from) do
insert(strip_diacritics_patterns, {from = from, to = strip_diacritics.to[i] or ""})
end
end
strip_diacritics_remove_diacritics = strip_diacritics.remove_diacritics
end
-- mainCode should only end up non-nil if dontCanonicalizeAliases is passed to make_object().
-- props should either contain zero-argument functions to compute the value, or the value itself.
local props = {
ancestors = function() return self:getAncestorCodes() end,
canonicalName = function() return self:getCanonicalName() end,
categoryName = function() return self:getCategoryName("nocap") end,
code = self._code,
mainCode = self._mainCode,
parent = function() return self:getParentCode() end,
full = function() return self:getFullCode() end,
stripDiacriticsPatterns = strip_diacritics_patterns,
stripDiacriticsRemoveDiacritics = strip_diacritics_remove_diacritics,
family = function() return self:getFamilyCode() end,
aliases = function() return self:getAliases() end,
varieties = function() return self:getVarieties() end,
otherNames = function() return self:getOtherNames() end,
pseudoFamilies = function() return self:getPseudoFamilyCodes() end,
scripts = function() return self:getScriptCodes() end,
type = function() return keys_to_list(self:getTypes()) end,
wikimediaLanguages = function() return self:getWikimediaLanguageCodes() end,
wikidataItem = function() return self:getWikidataItem() end,
wikipediaArticle = function() return self:getWikipediaArticle(true) end,
}
local ret = {}
for prop, val in pairs(props) do
if not opts.skip_fields or not opts.skip_fields[prop] then
if type(val) == "function" then
ret[prop] = val()
else
ret[prop] = val
end
end
end
-- Use `deep_copy` when returning a table, so that there are no editing restrictions imposed by `mw.loadData`.
return opts and opts.lua_table and deep_copy(ret) or to_json(ret, opts)
end
function export.getDataModuleName(code)
local letter = match(code, "^(%l)%l%l?$")
return "Module:" .. (
letter == nil and "languages/data/exceptional" or
#code == 2 and "languages/data/2" or
"languages/data/3/" .. letter
)
end
get_data_module_name = export.getDataModuleName
function export.getExtraDataModuleName(code)
return get_data_module_name(code) .. "/extra"
end
get_extra_data_module_name = export.getExtraDataModuleName
do
local function make_stack(data)
local key_types = {
[2] = "unique",
aliases = "unique",
other_names = "unique",
type = "append",
varieties = "unique",
wikipedia_article = "unique",
wikimedia_codes = "unique"
}
local function __index(self, k)
local stack, key_type = getmetatable(self), key_types[k]
-- Data that isn't inherited from the parent.
if key_type == "unique" then
local v = stack[stack[make_stack]][k]
if v == nil then
local layer = stack[0]
if layer then -- Could be false if there's no extra data.
v = layer[k]
end
end
return v
-- Data that is appended by each generation.
elseif key_type == "append" then
local parts, offset, n = {}, 0, stack[make_stack]
for i = 1, n do
local part = stack[i][k]
if part == nil then
offset = offset + 1
else
parts[i - offset] = part
end
end
return offset ~= n and concat(parts, ",") or nil
end
local n = stack[make_stack]
while true do
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
local v = layer[k]
if v ~= nil then
return v
end
n = n - 1
end
end
local function __newindex()
error("table is read-only")
end
local function __pairs(self)
-- Iterate down the stack, caching keys to avoid duplicate returns.
local stack, seen = getmetatable(self), {}
local n = stack[make_stack]
local iter, state, k, v = pairs(stack[n])
return function()
repeat
repeat
k = iter(state, k)
if k == nil then
n = n - 1
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
iter, state, k = pairs(layer)
end
until not (k == nil or seen[k])
-- Get the value via a lookup, as the one returned by the
-- iterator will be the raw value from the current layer,
-- which may not be the one __index will return for that
-- key. Also memoize the key in `seen` (even if the lookup
-- returns nil) so that it doesn't get looked up again.
-- TODO: store values in `self`, avoiding the need to create
-- the `seen` table. The iterator will need to iterate over
-- `self` with `next` first to find these on future loops.
v, seen[k] = self[k], true
until v ~= nil
return k, v
end
end
local __ipairs = require(table_module).indexIpairs
function make_stack(data)
local stack = {
data,
[make_stack] = 1, -- stores the length and acts as a sentinel to confirm a given metatable is a stack.
__index = __index,
__newindex = __newindex,
__pairs = __pairs,
__ipairs = __ipairs,
}
stack.__metatable = stack
return setmetatable({}, stack), stack
end
return make_stack(data)
end
local function get_stack(data)
local stack = getmetatable(data)
return stack and type(stack) == "table" and stack[make_stack] and stack or nil
end
--[==[
<span style="color: var(--wikt-palette-red,#BA0000)">This function is not for use in entries or other content pages.</span>
Return a blob of data about the language. The format of this blob is undocumented, and perhaps unstable; it's intended
for things like the module's own unit-tests, which are "close friends" with the module and will be kept up-to-date as
the format changes. If `extra` is set, any extra data in the relevant `/extra` module will be included. (Note that it
will be included anyway if it has already been loaded into the language object.) If `raw` is set, then the returned data
will not contain any data inherited from parent objects.
-- Do NOT use these methods!
-- All uses should be pre-approved on the talk page!
]==]
function Language:getData(extra, raw)
if extra then
self:loadInExtraData()
end
local data = self._data
-- If raw is not set, just return the data.
if not raw then
return data
end
local stack = get_stack(data)
-- If there isn't a stack or its length is 1, return the data. Extra data (if any) will be included, as it's
-- stored at key 0 and doesn't affect the reported length.
if stack == nil then
return data
end
local n = stack[make_stack]
if n == 1 then
return data
end
extra = stack[0]
-- If there isn't any extra data, return the top layer of the stack.
if extra == nil then
return stack[n]
end
-- If there is, return a new stack which has the top layer at key 1 and the extra data at key 0.
data, stack = make_stack(stack[n])
stack[0] = extra
return data
end
function Language:loadInExtraData()
-- Only full languages have extra data.
if not self:hasType("language", "full") then
return
end
local data = self._data
-- If there's no stack, create one.
local stack = get_stack(self._data)
if stack == nil then
data, stack = make_stack(data)
-- If already loaded, return.
elseif stack[0] ~= nil then
return
end
self._data = data
-- Load extra data from the relevant module and add it to the stack at key 0, so that the __index and __pairs
-- metamethods will pick it up, since they iterate down the stack until they run out of layers.
local code = self._code
local modulename = get_extra_data_module_name(code)
-- No data cached as false.
stack[0] = modulename and load_data(modulename)[code] or false
end
--[==[
Return the name of the module containing the language's data, e.g. [[Module:languages/data/3/k]] for three-letter codes
beginning with `k`.
]==]
function Language:getDataModuleName()
local name = self._dataModuleName
if name == nil then
name = self:hasType("etymology-only") and etymology_languages_data_module or
get_data_module_name(self._mainCode or self._code)
self._dataModuleName = name
end
return name
end
--[==[
Return the name of the module containing the language's extra data, e.g. [[Module:languages/data/3/k/extra]] for
three-letter codes beginning with `k`.
]==]
function Language:getExtraDataModuleName()
local name = self._extraDataModuleName
if name == nil then
name = not self:hasType("etymology-only") and get_extra_data_module_name(self._mainCode or self._code) or false
self._extraDataModuleName = name
end
return name or nil
end
function export.makeObject(code, data, dontCanonicalizeAliases)
local data_type = type(data)
if data_type ~= "table" then
error(("bad argument #2 to 'makeObject' (table expected, got %s)"):format(data_type))
end
-- Convert any aliases.
local input_code = code
code = normalize_code(code)
input_code = dontCanonicalizeAliases and input_code or code
local parent
if data.parent then
parent = get_by_code(data.parent, nil, true, true)
else
parent = Language
end
parent.__index = parent
local lang = {_code = input_code}
-- This can only happen if dontCanonicalizeAliases is passed to make_object().
if code ~= input_code then
lang._mainCode = code
end
local parent_data = parent._data
if parent_data == nil then
-- Full code is the same as the code.
lang._fullCode = parent._code or code
else
-- Copy full code.
lang._fullCode = parent._fullCode
local stack = get_stack(parent_data)
if stack == nil then
parent_data, stack = make_stack(parent_data)
end
-- Insert the input data as the new top layer of the stack.
local n = stack[make_stack] + 1
data, stack[n], stack[make_stack] = parent_data, data, n
end
lang._data = data
return setmetatable(lang, parent)
end
make_object = export.makeObject
end
--[==[
Find the language whose code matches the one provided. If it exists, return a `Language` object representing the
language. Otherwise, return {nil}, unless `paramForError` is given, in which case an error is generated. If
`paramForError` is {true}, a generic error message mentioning the bad code is generated; otherwise `paramForError`
should be a string or number specifying the parameter that the code came from, and this parameter will be mentioned
in the error message along with the bad code. If `allowEtymLang` is specified, etymology-only language codes are allowed
and looked up along with full language codes. If `allowFamily` is specified, language family codes are allowed and
looked up along with normal language codes.
]==]
function export.getByCode(code, paramForError, allowEtymLang, allowFamily)
-- [[ Track uses of paramForError, ultimately so it can be removed, as error-handling should be done by
-- [[Module:parameters]], not here. ]] -- I (Benwing) disagree; that is an idealistic goal unlikely to be achievable
-- realistically.
if paramForError ~= nil then
track("paramForError")
end
if type(code) ~= "string" then
local typ
if not code then
typ = "nil"
elseif check_object("language", true, code) then
typ = "a language object"
elseif check_object("family", true, code) then
typ = "a family object"
else
typ = "a " .. type(code)
end
error("The function getByCode expects a string as its first argument, but received " .. typ .. ".")
end
local m_data = load_data(languages_data_module)
if m_data.aliases[code] or m_data.track[code] then
track(code)
end
local norm_code = normalize_code(code)
-- Get the data, checking for etymology-only languages if allowEtymLang is set.
local data = load_data(get_data_module_name(norm_code))[norm_code] or
allowEtymLang and load_data(etymology_languages_data_module)[norm_code]
-- If no data was found and allowFamily is set, check the family data. If the main family data was found, make the
-- object with [[Module:families]] instead, as family objects have different methods. However, if it's an
-- etymology-only family, use make_object in this module (which handles object inheritance), and the
-- family-specific methods will be inherited from the parent object.
if data == nil and allowFamily then
data = load_data("Module:families/data")[norm_code]
if data ~= nil then
if data.parent == nil then
return make_family_object(norm_code, data)
elseif not allowEtymLang then
data = nil
end
end
end
local retval = code and data and make_object(code, data)
if not retval and paramForError then
require("Module:languages/errorGetBy").code(code, paramForError, allowEtymLang, allowFamily)
end
return retval
end
get_by_code = export.getByCode
--[==[
Find the language whose canonical name (the name used to represent that language on Wiktionary) or other name matches
the one provided. If it exists, return a `Language` object representing the language. Otherwise, return {nil}, unless
`paramForError` is given, in which case an error is generated. If `allowEtymLang` is specified, etymology-only language
codes are allowed and looked up along with full language codes. If `allowFamily` is specified, language family codes are
allowed and looked up along with normal language codes. The canonical name of languages should always be unique (it is
an error for two languages on Wiktionary to share the same canonical name), so this is guaranteed to give at most one
result. This function is powered by [[Module:languages/canonical names]], which contains a pre-generated mapping of
full-language canonical names to codes. It is generated by going through the [[:Category:Language data modules]] for
full languages. When `allowEtymLang` is specified for the above function, [[Module:etymology languages/canonical names]]
may also be used, and when `allowFamily` is specified for the above function, [[Module:families/canonical names]] may
also be used.
]==]
function export.getByCanonicalName(name, errorIfInvalid, allowEtymLang, allowFamily)
local byName = load_data("Module:languages/canonical names")
local code = byName and byName[name]
if not code and allowEtymLang then
byName = load_data("Module:etymology languages/canonical names")
code = byName and byName[name] or
byName[gsub(name, " [Ss]ubstrate$", "")] or
byName[gsub(name, "^a ", "")] or
byName[gsub(name, "^a ", ""):gsub(" [Ss]ubstrate$", "")] or
-- For etymology families like "ira-pro".
-- FIXME: This is not ideal, as it allows " languages" to be appended to any etymology-only language, too.
byName[match(name, "^(.*) languages$")]
end
if not code and allowFamily then
byName = load_data("Module:families/canonical names")
code = byName[name] or byName[match(name, "^(.*) languages$")]
end
local retval = code and get_by_code(code, errorIfInvalid, allowEtymLang, allowFamily)
if not retval and errorIfInvalid then
require("Module:languages/errorGetBy").canonicalName(name, allowEtymLang, allowFamily)
end
return retval
end
--[==[
Used by [[Module:languages/data/2]] (et al.) and [[Module:etymology languages/data]], [[Module:families/data]],
[[Module:scripts/data]] and [[Module:writing systems/data]] to finalize the data into the format that is actually returned.
]==]
function export.finalizeData(data, main_type, variety)
local fields = {"type"}
if main_type == "language" then
insert(fields, 4) -- script codes
insert(fields, "ancestors")
insert(fields, "link_tr")
insert(fields, "override_translit")
insert(fields, "wikimedia_codes")
elseif main_type == "script" then
insert(fields, 3) -- writing system codes
end -- Families and writing systems have no extra fields to process.
local fields_len = #fields
for _, entity in next, data do
if variety then
-- Move parent from 3 to "parent" and family from "family" to 3. These are different for the sake of
-- convenience, since very few varieties have the family specified, whereas all of them have a parent.
entity.parent, entity[3] = entity[3], entity.family
entity.family = nil
-- Give the type "regular" iff not a variety and no other types are assigned.
elseif not (entity.type or entity.parent) then
entity.type = "regular"
end
for i = 1, fields_len do
local key = fields[i]
local field = entity[key]
if field and type(field) == "string" then
entity[key] = gsub(field, "%s*,%s*", ",")
end
end
end
return data
end
--[==[
For backwards compatibility only; modules should require the error themselves.
]==]
function export.err(lang_code, param, code_desc, template_tag, not_real_lang)
return require("Module:languages/error")(lang_code, param, code_desc, template_tag, not_real_lang)
end
return export
hpv2812x1no7s0in85n3ihzut5wc4jx
238800
238799
2026-11-12T06:08:12Z
Lee
19
පැරණි සංස්කරණයකින් ගත් කොටස්...
238800
Scribunto
text/plain
--[==[ intro:
This module implements fetching of language-specific information and processing text in a given language.
===Types of languages===
There are two types of languages: full languages and etymology-only languages. The essential difference is that only
full languages appear in L2 headings in vocabulary entries, and hence categories like [[:Category:French nouns]] exist
only for full languages. Etymology-only languages have either a full language or another etymology-only language as
their parent (in the parent-child inheritance sense), and for etymology-only languages with another etymology-only
language as their parent, a full language can always be derived by following the parent links upwards. For example,
"Canadian French", code `fr-CA`, is an etymology-only language whose parent is the full language "French", code `fr`.
An example of an etymology-only language with another etymology-only parent is "Northumbrian Old English", code
`ang-nor`, which has "Anglian Old English", code `ang-ang` as its parent; this is an etymology-only language whose
parent is "Old English", code `ang`, which is a full language. (This is because Northumbrian Old English is considered
a variety of Anglian Old English.) Sometimes the parent is the "Undetermined" language, code `und`; this is the case,
for example, for "substrate" languages such as "Pre-Greek", code `qsb-grc`, and "the BMAC substrate", code `qsb-bma`.
It is important to distinguish language ''parents'' from language ''ancestors''. The parent-child relationship is one
of containment, i.e. if X is a child of Y, X is considered a variety of Y. On the other hand, the ancestor-descendant
relationship is one of descent in time. For example, "Classical Latin", code `la-cla`, and "Late Latin", code `la-lat`,
are both etymology-only languages with "Latin", code `la`, as their parents, because both of the former are varieties
of Latin. However, Late Latin does *NOT* have Classical Latin as its parent because Late Latin is *not* a variety of
Classical Latin; rather, it is a descendant. There is in fact a separate `ancestors` field that is used to express the
ancestor-descendant relationship, and Late Latin's ancestor is given as Classical Latin. It is also important to note
that sometimes an etymology-only language is actually the conceptual ancestor of its parent language. This happens,
for example, with "Old Italian" (code `roa-oit`), which is an etymology-only variant of full language "Italian" (code
`it`), and with "Old Latin" (code `itc-ola`), which is an etymology-only variant of Latin. In both cases, the full
language has the etymology-only variant listed as an ancestor. This allows a Latin term to inherit from Old Latin
using the {{tl|inh}} template (where in this template, "inheritance" refers to ancestral inheritance, i.e. inheritance
in time, rather than in the parent-child sense); likewise for Italian and Old Italian.
Full languages come in three subtypes:
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the
main namespace. There may also be reconstructed terms for the language, which are placed in the
{Reconstruction} namespace and must be prefixed with * to indicate a reconstruction. Most full languages
are natural (not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük,
among others) are also allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with
*. Languages such as Proto-Indo-European and Proto-Germanic are in this category.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in
the Appendix namespace, but they are not reconstructed and therefore should not have *
prefixed in links. Most constructed languages are of this subtype.
Both full languages and etymology-only languages have a {Language} object associated with them, which is fetched using
the {getByCode} function in [[Module:languages]] to convert a language code to a {Language} object. Depending on the
options supplied to this function, etymology-only languages may or may not be accepted, and family codes may be
accepted (returning a {Family} object as described in [[Module:families]]). There are also separate {getByCanonicalName}
functions in [[Module:languages]] and [[Module:etymology languages]] to convert a language's canonical name to a
{Language} object (depending on whether the canonical name refers to a full or etymology-only language).
===Textual representations===
Textual strings belonging to a given language come in several different ''text variants'':
# The ''input text'' is what the user supplies in wikitext, in the parameters to {{tl|m}}, {{tl|l}}, {{tl|ux}},
{{tl|t}}, {{tl|lang}} and the like.
# The ''corrected input text'' is the input text with some corrections and/or normalizations applied, such as
bad-character replacements for certain languages, like replacing `l` or `1` to [[palochka]] in some languages written
in Cyrillic. (FIXME: This currently goes under the name ''display text'' but that will be repurposed below. Also,
[[User:Surjection]] suggests renaming this to ''normalized input text'', but "normalized" is used in a different sense
in [[Module:usex]].)
# The ''display text'' is the text in the form as it will be displayed to the user. This is what appears in headwords,
in usexes, in displayed internal links, etc. This can include accent marks that are removed to form the stripped
display text (see below), as well as embedded bracketed links that are variously processed further. The display text
is generated from the corrected input text by applying language-specific transformations; for most languages, there
will be no such transformations. The general reason for having a difference between input and display text is to allow
for extra information in the input text that is not displayed to the user but is sent to the transliteration module.
Note that having different display and input text is only supported currently through special-casing but will be
generalized. Examples of transformations are: (1) Removing the {{cd|^}} that is used in certain East Asian (and
possibly other unicameral) languages to indicate capitalization of the transliteration (which is currently
special-cased); (2) for Korean, removing or otherwise processing hyphens (which is currently special-cased); (3) for
Arabic, removing a ''sukūn'' diacritic placed over a ''tāʔ marbūṭa'' (like this: ةْ) to indicate that the
''tāʔ marbūṭa'' is pronounced and transliterated as /t/ instead of being silent [NOTE, NOT IMPLEMENTED YET]; (4) for
Thai and Khmer, converting space-separated words to bracketed words and resolving respelling substitutions such as
`[กรีน/กฺรีน]`, which indicate how to transliterate given words [NOTE, NOT IMPLEMENTED YET except in language-specific
templates like {{tl|th-usex}}].
## The ''right-resolved display text'' is the result of removing brackets around one-part embedded links and resolving
two-part embedded links into their right-hand components (i.e. converting two-part links into the displayed form).
The process of right-resolution is what happens when you call {{cd|remove_links()}} in [[Module:links]] on some text.
When applied to the display text, it produces exactly what the user sees, without any link markup.
# The ''stripped display text'' is the result of applying diacritic-stripping to the display text.
## The ''left-resolved stripped display text'' [NEED BETTER NAME] is the result of applying left-resolution to the
stripped display text, i.e. similar to right-resolution but resolving two-part embedded links into their left-hand
components (i.e. the linked-to page). If the display text refers to a single page, the resulting of applying
diacritic stripping and left-resolution produces the ''logical pagename''.
# The ''physical pagename text'' is the result of converting the stripped display text into physical page links. If the
stripped display text contains embedded links, the left side of those links is converted into physical page links;
otherwise, the entire text is considered a pagename and converted in the same fashion. The conversion does three
things: (1) converts characters not allowed in pagenames into their "unsupported title" representation, e.g.
{{cd|Unsupported titles/`gt`}} in place of the logical name {{cd|>}}; (2) handles certain special-cased
unsupported-title logical pagenames, such as {{cd|Unsupported titles/Space}} in place of {{cd|[space]}} and
{{cd|Unsupported titles/Ancient Greek dish}} in place of a very long Greek name for a gourmet dish as found in
Aristophanes; (3) converts "mammoth" pagenames such as [[a]] into their appropriate split component, e.g.
[[a/languages A to L]].
# The ''source translit text'' is the text as supplied to the language-specific {{cd|transliterate()}} method. The form
of the source translit text may need to be language-specific, e.g Thai and Khmer will need the corrected input text,
whereas other languages may need to work off the display text. [FIXME: It's still unclear to me how embedded bracketed
links are handled in the existing code.] In general, embedded links need to be right-resolved (see above), but when
this happens is unclear to me [FIXME]. Some languages have a chop-up-and-paste-together scheme that sends parts of the
text through the transliterate mechanism, and for others (those listed with "cont" in {{cd|substitution}} in
[[Module:languages/data]]) they receive the full input text, but preprocessed in certain ways. (The wisdom of this is
still unclear to me.)
# The ''transliterated text'' (or ''transliteration'') is the result of transliterating the source translit text. Unlike
for all the other text variants except the transcribed text, it is always in the Latin script.
# The ''transcribed text'' (or ''transcription'') is the result of transcribing the source translit text, where
"transcription" here means a close approximation to the phonetic form of the language in languages (e.g. Akkadian,
Sumerian, Ancient Egyptian, maybe Tibetan) that have a wide difference between the written letters and spoken form.
Unlike for all the other text variants other than the transliterated text, it is always in the Latin script.
Currently, the transcribed text is always supplied manually be the user; there is no such thing as a
{{cd|transcribe()}} method on language objects.
# The ''sort key'' is the text used in sort keys for determining the placing of pages in categories they belong to. The
sort key is generated from the pagename or a specified ''sort base'' by lowercasing, doing language-specific
transformations and then uppercasing the result. If the sort base is supplied and is generated from input text, it
needs to be converted to display text, have embedded links removed through right-resolution and have
diacritic-stripping applied.
# There are other text variants that occur in usexes (specifically, there are normalized variants of several of the
above text variants), but we can skip them for now.
The following methods exist on {Language} objects to convert between different text variants:
# {correctInputText} (currently called {makeDisplayText}): This converts input text to corrected input text.
# {stripDiacritics}: This converts to stripped display text. [FIXME: This needs some rethinking. In particular,
{stripDiacritics} is sometimes called on input text, corrected input text or display text (in various paths inside of
[[Module:links]], and, in the case of input text, usually from other modules). We need to make sure we don't try to
convert input text to display text twice, but at the same time we need to support calling it directly on input text
since so many modules do this. This means we need to add a parameter indicating whether the passed-in text is input,
corrected input, or display text; if the former two, we call {correctInputText} ourselves.]
# {logicalToPhysical}: This converts logical pagenames to physical pagenames.
# {transliterate}: This appears to convert input text with embedded brackets removed into a transliteration.
[FIXME: This needs some rethinking. In particular, it calls {processDisplayText} on its input, which won't work
for Thai and Khmer, so we may need language-specific flags indicating whether to pass the input text directly to the
language transliterate method. In addition, I'm not sure how embedded links are handled in the existing translit code;
a lot of callers remove the links themselves before calling {transliterate()}, which I assume is wrong.]
# {makeSortKey}: This converts display text (?) to a sort key. [FIXME: Clarify this.]
]==]
local export = {}
local debug_track_module = "Module:debug/track"
local etymology_languages_data_module = "Module:etymology languages/data"
local families_module = "Module:families"
local headword_page_module = "Module:headword/page"
local json_module = "Module:JSON"
local language_like_module = "Module:language-like"
local languages_data_module = "Module:languages/data"
local languages_data_patterns_module = "Module:languages/data/patterns"
local links_data_module = "Module:links/data"
local load_module = "Module:load"
local scripts_module = "Module:scripts"
local scripts_data_module = "Module:scripts/data"
local string_encode_entities_module = "Module:string/encode entities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local wikimedia_languages_module = "Module:wikimedia languages"
local mw = mw
local string = string
local table = table
local char = string.char
local concat = table.concat
local find = string.find
local floor = math.floor
local get_by_code -- Defined below.
local get_data_module_name -- Defined below.
local get_extra_data_module_name -- Defined below.
local getmetatable = getmetatable
local gmatch = string.gmatch
local gsub = string.gsub
local insert = table.insert
local ipairs = ipairs
local is_known_language_tag = mw.language.isKnownLanguageTag
local make_object -- Defined below.
local match = string.match
local next = next
local pairs = pairs
local remove = table.remove
local require = require
local select = select
local setmetatable = setmetatable
local sub = string.sub
local type = type
local unstrip = mw.text.unstrip
-- Loaded as needed by findBestScript.
local Hans_chars
local Hant_chars
local function check_object(...)
check_object = require(utilities_module).check_object
return check_object(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
local function deep_copy(...)
deep_copy = require(table_module).deepCopy
return deep_copy(...)
end
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function get_L2_sort_key(...)
get_L2_sort_key = require(headword_page_module).get_L2_sort_key
return get_L2_sort_key(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function get_family(...)
get_family = require(families_module).getByCode
return get_family(...)
end
local function get_plaintext(...)
get_plaintext = require(utilities_module).get_plaintext
return get_plaintext(...)
end
local function get_wikimedia_lang(...)
get_wikimedia_lang = require(wikimedia_languages_module).getByCode
return get_wikimedia_lang(...)
end
local function keys_to_list(...)
keys_to_list = require(table_module).keysToList
return keys_to_list(...)
end
local function list_to_set(...)
list_to_set = require(table_module).listToSet
return list_to_set(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function make_family_object(...)
make_family_object = require(families_module).makeObject
return make_family_object(...)
end
local function pattern_escape(...)
pattern_escape = require(string_pattern_escape_module)
return pattern_escape(...)
end
local function replacement_escape(...)
replacement_escape = require(string_replacement_escape_module)
return replacement_escape(...)
end
local function safe_require(...)
safe_require = require(load_module).safe_require
return safe_require(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function to_json(...)
to_json = require(json_module).toJSON
return to_json(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ugsub(...)
ugsub = require(string_utilities_module).gsub
return ugsub(...)
end
local function ulen(...)
ulen = require(string_utilities_module).len
return ulen(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local function uupper(...)
uupper = require(string_utilities_module).upper
return uupper(...)
end
local function track(page)
debug_track("languages/" .. page)
return true
end
local function normalize_code(code)
return load_data(languages_data_module).aliases[code] or code
end
local function check_inputs(self, check, default, ...)
local n = select("#", ...)
if n == 0 then
return false
end
local ret = check(self, (...))
if ret ~= nil then
return ret
elseif n > 1 then
local inputs = {...}
for i = 2, n do
ret = check(self, inputs[i])
if ret ~= nil then
return ret
end
end
end
return default
end
local function make_link(self, target, display)
local prefix, main
if self:getFamilyCode() == "qfa-sub" then
prefix, main = display:match("^(the )(.*)")
if not prefix then
prefix, main = display:match("^(a )(.*)")
end
end
return (prefix or "") .. "[[" .. target .. "|" .. (main or display) .. "]]"
end
-- Convert risky characters to HTML entities, which minimizes interference once returned (e.g. for "sms:a", "<!-- -->" etc.).
local function escape_risky_characters(text)
-- Spacing characters in isolation generally need to be escaped in order to be properly processed by the MediaWiki
-- software.
if umatch(text, "^%s*$") then
return encode_entities(text, text)
end
return encode_entities(text, "!#%&*+/:;<=>?@[\\]_{|}")
end
-- Temporarily convert various formatting characters to PUA to prevent them from being disrupted by the substitution process.
local function doTempSubstitutions(text, subbedChars, keepCarets, noTrim)
-- Clone so that we don't insert any extra patterns into the table in package.loaded. For some reason, using require
-- seems to keep memory use down; probably because the table is always cloned.
local patterns = shallow_copy(require(languages_data_patterns_module))
if keepCarets then
insert(patterns, "((\\+)%^)")
insert(patterns, "((%^))")
end
-- Ensure any whitespace at the beginning and end is temp substituted, to prevent it from being accidentally
-- trimmed. We only want to trim any final spaces added during the substitution process (e.g. by a module), which
-- means we only do this during the first round of temp substitutions.
if not noTrim then
insert(patterns, "^([\128-\191\244]*(%s+))")
insert(patterns, "((%s+)[\128-\191\244]*)$")
end
-- Pre-substitution, of "[[" and "]]", which makes pattern matching more accurate.
text = gsub(text, "%f[%[]%[%[", "\1"):gsub("%f[%]]%]%]", "\2")
local i = #subbedChars
for _, pattern in ipairs(patterns) do
-- Patterns ending in \0 stand are for things like "[[" or "]]"), so the inserted PUA are treated as breaks
-- between terms by modules that scrape info from pages.
local term_divider
pattern = gsub(pattern, "%z$", function(divider)
term_divider = divider == "\0"
return ""
end)
text = gsub(text, pattern, function(...)
local m = {...}
local m1New = m[1]
for k = 2, #m do
local n = i + k - 1
subbedChars[n] = m[k]
local byte2 = floor(n / 4096) % 64 + (term_divider and 128 or 136)
local byte3 = floor(n / 64) % 64 + 128
local byte4 = n % 64 + 128
m1New = gsub(m1New, pattern_escape(m[k]), "\244" .. char(byte2) .. char(byte3) .. char(byte4), 1)
end
i = i + #m - 1
return m1New
end)
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text, subbedChars
end
-- Reinsert any formatting that was temporarily substituted.
local function undoTempSubstitutions(text, subbedChars)
for i = 1, #subbedChars do
local byte2 = floor(i / 4096) % 64 + 128
local byte3 = floor(i / 64) % 64 + 128
local byte4 = i % 64 + 128
text = gsub(text, "\244[" .. char(byte2) .. char(byte2+8) .. "]" .. char(byte3) .. char(byte4),
replacement_escape(subbedChars[i]))
end
text = gsub(text, "\1", "%[%["):gsub("\2", "%]%]")
return text
end
-- Check if the raw text is an unsupported title, and if so return that. Otherwise, remove HTML entities. We do the
-- pre-conversion to avoid loading the unsupported title list unnecessarily.
local function checkNoEntities(text)
local textNoEnc = decode_entities(text)
if textNoEnc ~= text and load_data(links_data_module).unsupported_titles[text] then
return text
else
return textNoEnc
end
end
-- If no script object is provided (or if it's invalid or None), get one.
local function checkScript(text, self, sc)
if not check_object("script", true, sc) or sc:getCode() == "None" then
return self:findBestScript(text)
end
return sc
end
local function normalize(text, sc)
text = sc:fixDiscouragedSequences(text)
return sc:toFixedNFD(text)
end
--[=[
Subfunction of iterateSectionSubstitutions(). Process an individual chunk of text according to the specifications in
`substitution_data`. The input parameters are all as in the documentation of iterateSectionSubstitutions() except for
`recursed`, which is set to true if we called ourselves recursively to process a script-specific setting or
script-wide fallback. Returns two values: the processed text and the actual substitution data used to do the
substitutions (same as the `actual_substitution_data` return value to iterateSectionSubstitutions()).
]=]
local function doSubstitutions(self, text, sc, substitution_data, data_field, function_name, recursed)
-- BE CAREFUL in this function because the value at any level can be `false`, which causes no processing to be done
-- and blocks any further fallback processing.
local actual_substitution_data = substitution_data
-- If there are language-specific substitutes given in the data module, use those.
if type(substitution_data) == "table" then
-- If a script is specified, run this function with the script-specific data before continuing.
local sc_code = sc:getCode()
local has_substitution_data = false
if substitution_data[sc_code] ~= nil then
has_substitution_data = true
if substitution_data[sc_code] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[sc_code], data_field,
function_name, true)
end
-- Hant, Hans and Hani are usually treated the same, so add a special case to avoid having to specify each one
-- separately.
elseif sc_code:match("^Han") and substitution_data.Hani ~= nil then
has_substitution_data = true
if substitution_data.Hani then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data.Hani, data_field,
function_name, true)
end
-- Substitution data with key 1 in the outer table may be given as a fallback.
elseif substitution_data[1] ~= nil then
has_substitution_data = true
if substitution_data[1] then
text, actual_substitution_data = doSubstitutions(self, text, sc, substitution_data[1], data_field,
function_name, true)
end
end
-- Iterate over all strings in the "from" subtable, and gsub with the corresponding string in "to". We work with
-- the NFD decomposed forms, as this simplifies many substitutions.
if substitution_data.from then
has_substitution_data = true
for i, from in ipairs(substitution_data.from) do
-- Normalize each loop, to ensure multi-stage substitutions work correctly.
text = sc:toFixedNFD(text)
text = ugsub(text, sc:toFixedNFD(from), substitution_data.to[i] or "")
end
end
if substitution_data.remove_diacritics then
has_substitution_data = true
text = sc:toFixedNFD(text)
-- Convert exceptions to PUA.
local remove_exceptions, substitutes = substitution_data.remove_exceptions
if remove_exceptions then
substitutes = {}
local i = 0
for _, exception in ipairs(remove_exceptions) do
exception = sc:toFixedNFD(exception)
text = ugsub(text, exception, function(m)
i = i + 1
local subst = u(0x80000 + i)
substitutes[subst] = m
return subst
end)
end
end
-- Strip diacritics.
text = ugsub(text, "[" .. substitution_data.remove_diacritics .. "]", "")
-- Convert exceptions back.
if remove_exceptions then
text = text:gsub("\242[\128-\191]*", substitutes)
end
end
if not has_substitution_data and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
elseif type(substitution_data) == "string" then
-- If there is a dedicated function module, use that.
local module = safe_require("Module:" .. substitution_data)
if module then
-- TODO: translit functions should take objects, not codes.
-- TODO: translit functions should be called with form NFD.
if function_name == "tr" then
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named 'tr'"):format(substitution_data))
end
text = module[function_name](text, self._code, sc:getCode())
elseif function_name == "stripDiacritics" then
-- FIXME, get rid of this arm after renaming makeEntryName -> stripDiacritics.
if module[function_name] then
text = module[function_name](sc:toFixedNFD(text), self, sc)
elseif module.makeEntryName then
text = module.makeEntryName(sc:toFixedNFD(text), self, sc)
else
error(("Internal error: Module [[%s]] has no function named 'stripDiacritics' or 'makeEntryName'"
):format(substitution_data))
end
else
if not module[function_name] then
error(("Internal error: Module [[%s]] has no function named '%s'"):format(
substitution_data, function_name))
end
text = module[function_name](sc:toFixedNFD(text), self, sc)
end
else
error("Substitution data '" .. substitution_data .. "' does not match an existing module.")
end
elseif substitution_data == nil and sc._data[data_field] then
-- If language-specific sort key (etc.) is nil, fall back to script-wide sort key (etc.).
text, actual_substitution_data = doSubstitutions(self, text, sc, sc._data[data_field], data_field,
function_name, true)
end
-- Don't normalize to NFC if this is the inner loop or if a module returned nil.
if recursed or not text then
return text, actual_substitution_data
end
-- Fix any discouraged sequences created during the substitution process, and normalize into the final form.
return sc:toFixedNFC(sc:fixDiscouragedSequences(text)), actual_substitution_data
end
--[=[
Split the text into sections, based on the presence of temporarily substituted formatting characters, then iterate over
each section to apply substitutions (e.g. transliteration or diacritic stripping). This avoids putting PUA (Private Use
Area) characters through language-specific modules, which may be unequipped for them. This function is passed the
following values:
* `self` (the Language object);
* `text` (the text to process);
* `sc` (the script of the text, which must be specified; callers should call checkScript() as needed to autodetect the
script of the text if not given explicitly by the user);
* `subbedChars` (an array of the same length as the text, indicating which characters have been substituted and by
what, or {nil} if no substitutions are to happen);
* `keepCarets` (DOCUMENT ME);
* `substitution_data` (the data indicating which substitutions to apply, taken directly from `data_field` in the
language's data structure in a submodule of [[Module:languages/data]]);
* `data_field` (the field from which `substitution_data` was fetched, such as {"sort_key"} or {"strip_diacritics"});
* `function_name` (the name of the function to call to do the substitution, in case `substitution_data` specifies a
module to do the substitution);
* `notrim` (don't trim whitespace at the edges of `text`; set when computing the sort key, because whitespace at the
beginning of a sort key is significant and causes the resulting page to be sorted at the beginning of the category
it's in).
Return three values:
# the processed text;
# the value of `subbedChars` that was passed in, possibly modified with additional character substitutions; will be
{nil} if {nil} was passed in;
# the actual substitution data that was used to apply substitutions to `text`; this may be different from the value
of `substitution_data` passed in if that value recursively specified script-specific substitutions or if no
substitution data could be found in the language-specific data (e.g. {nil} was passed in or a structure was passed
in that had no setting for the script given in `sc`), but a script-wide fallback value was set; currently it is
only used by {makeSortKey()}.
]=]
local function iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, substitution_data, data_field,
function_name, notrim)
local sections
-- See [[Module:languages/data]].
if not find(text, "\244") or load_data(languages_data_module).substitution[self._code] == "cont" then
sections = {text}
else
sections = split(text, "\244[\128-\143][\128-\191]*", true)
end
local actual_substitution_data
for _, section in ipairs(sections) do
-- Don't bother processing empty strings or whitespace (which may also not be handled well by dedicated
-- modules).
if gsub(section, "%s+", "") ~= "" then
local sub, this_actual_substitution_data = doSubstitutions(self, section, sc, substitution_data, data_field,
function_name)
actual_substitution_data = this_actual_substitution_data
-- Second round of temporary substitutions, in case any formatting was added by the main substitution
-- process. However, don't do this if the section contains formatting already (as it would have had to have
-- been escaped to reach this stage, and therefore should be given as raw text).
if sub and subbedChars then
local noSub
for _, pattern in ipairs(require(languages_data_patterns_module)) do
if match(section, pattern .. "%z?") then
noSub = true
end
end
if not noSub then
sub, subbedChars = doTempSubstitutions(sub, subbedChars, keepCarets, true)
end
end
if not sub then
text = sub
break
end
text = sub and gsub(text, pattern_escape(section), replacement_escape(sub), 1) or text
end
end
if not notrim then
-- Trim, unless there are only spacing characters, while ignoring any final formatting characters.
-- Do not trim sort keys because spaces at the beginning are significant.
text = text and text:gsub("^([\128-\191\244]*)%s+(%S)", "%1%2"):gsub("(%S)%s+([\128-\191\244]*)$", "%1%2") or
nil
end
return text, subbedChars, actual_substitution_data
end
-- Process carets (and any escapes). Default to simple removal, if no pattern/replacement is given.
local function processCarets(text, pattern, repl)
local rep
repeat
text, rep = gsub(text, "\\\\(\\*^)", "\3%1")
until rep == 0
return (text:gsub("\\^", "\4")
:gsub(pattern or "%^", repl or "")
:gsub("\3", "\\")
:gsub("\4", "^"))
end
local function hasUnescapedCarets(text)
return processCarets(text, "%^", "\1"):find("\1", 1, true) ~= nil
end
local function assertCaretCapitalizationAllowed(text, sc)
if sc:forbidsCaretCapitalization() and hasUnescapedCarets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
local function removeCarets(text, sc)
if text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
return processCarets(text)
end
end
return text
end
local Language = {}
--[==[
Return the language code of the language. Example: {fr"} for French.
]==]
function Language:getCode()
return self._code
end
--[==[
Return the canonical name of the language. This is the name used to represent that language on Wiktionary, and is
guaranteed to be unique to that language alone. Example: {"French"} for French.
]==]
function Language:getCanonicalName()
local name = self._name
if name == nil then
name = self._data[1]
self._name = name
end
return name
end
--[==[
Return the display form of the language. The display form of a language, family or script is the form it takes when
appearing as the <code><var>source</var></code> in categories such as <code>English terms derived from
<var>source</var></code> or <code>English given names from <var>source</var></code>, and is also the displayed text
in `##makeCategoryLink()` links. For full and etymology-only languages, this is the same as the canonical name, but
for families, it reads <code>"<var>name</var> languages"</code> (e.g. {"Indo-Iranian languages"}), and for scripts,
it reads <code>"<var>name</var> script"</code> (e.g. {"Arabic script"}).
]==]
function Language:getDisplayForm()
local form = self._displayForm
if form == nil then
form = self:getCanonicalName()
-- Add article and " substrate" to substrates that lack them.
if self:getFamilyCode() == "qfa-sub" then
if not (sub(form, 1, 4) == "the " or sub(form, 1, 2) == "a ") then
form = "a " .. form
end
if not match(form, " [Ss]ubstrate") then
form = form .. " substrate"
end
end
self._displayForm = form
end
return form
end
--[==[
Return the value which should be used in the HTML `lang=` attribute for tagged text in the language.
]==]
function Language:getHTMLAttribute(sc, region)
local code = self._code
if not find(code, "-", 1, true) then
return code .. "-" .. sc:getCode() .. (region and "-" .. region or "")
end
local parent = self:getParent()
region = region or match(code, "%f[%u][%u-]+%f[%U]")
if parent then
return parent:getHTMLAttribute(sc, region)
end
-- TODO: ISO family codes can also be used.
return "mis-" .. sc:getCode() .. (region and "-" .. region or "")
end
--[==[
Return a list of the aliases that the language is known by, excluding the canonical name. Aliases are synonyms for the
language in question. The names are not guaranteed to be unique, in that sometimes more than one language is known by
the same name. Example: { {"High German", "New High German", "Deutsch"}} for {{lnl|de}}.
]==]
function Language:getAliases()
self:loadInExtraData()
return require(language_like_module).getAliases(self)
end
--[==[
Return a list of the known subvarieties of a given language, excluding subvarieties that have been given explicit
etymology-only language codes. The names are not guaranteed to be unique, in that sometimes a given name refers to a
subvariety of more than one language. Example: { {"Southern Aymara", "Central Aymara"}} for {{lnl|ay}}. Note that the
returned value can have nested tables in it, when a subvariety goes by more than one name. Example:
{ {"North Azerbaijani", "South Azerbaijani", {"Afshar", "Afshari", "Afshar Azerbaijani", "Afchar"}, {"Qashqa'i", "Qashqai", "Kashkay"}, "Sonqor"}}
for {{lnl|az}}. Here, for example, Afshar, Afshari, Afshar Azerbaijani and Afchar all refer to the same subvariety,
whose preferred name is Afshar (the one listed first). To avoid a return value with nested tables in it, specify a
non-{nil} value for the `flatten` parameter; in that case, the return value would be
{ {"North Azerbaijani", "South Azerbaijani", "Afshar", "Afshari", "Afshar Azerbaijani", "Afchar", "Qashqa'i", "Qashqai", "Kashkay", "Sonqor"}}.
]==]
function Language:getVarieties(flatten)
self:loadInExtraData()
return require(language_like_module).getVarieties(self, flatten)
end
--[==[
Return a table of the "other names" that the language is known by, which are listed in the `other_names` field in the
language's extra-data module. It should be noted that the `other_names` field itself is deprecated, and entries listed
there should eventually be moved to either `aliases` or `varieties`, or removed if they refer to larger entities which
the language in question is actually a part of.
]==]
function Language:getOtherNames() -- To be eventually removed, once there are no more uses of the `other_names` field.
self:loadInExtraData()
return require(language_like_module).getOtherNames(self)
end
--[==[
Return a combined table of the canonical name, aliases, varieties and other names of a given language.
]==]
function Language:getAllNames()
self:loadInExtraData()
return require(language_like_module).getAllNames(self)
end
--[==[
Return a table of types as a set (with the types as keys). The possible types are
* {language}: This is a language, either full or etymology-only.
* {full}: This is a "full" (not etymology-only) language, i.e. the union of {regular}, {reconstructed} and
{appendix-constructed}. Note that the types {full} and {etymology-only} also exist for families, so if you want to
check specifically for a full language and you have an object that might be a family, you should use
{hasType("language", "full")} and not simply {hasType("full")}.
* {etymology-only}: This is an etymology-only (not full) language, whose parent is another etymology-only language or a
full language. Note that the types {full} and {etymology-only} also exist for families, so if you want to check
specifically for an etymology-only language and you have an object that might be a family, you should use
{hasType("language", "etymology-only")} and not simply {hasType("etymology-only")}.
* {regular}: This indicates a full language that is attested according to [[WT:CFI]] and therefore permitted in the main
namespace. There may also be reconstructed terms for the language, which are placed in the {Reconstruction}
namespace and must be prefixed with `*` to indicate a reconstruction. Most full languages are natural
(not constructed) languages, but a few constructed languages (e.g. Esperanto and Volapük, among others) are also
allowed in the mainspace and considered regular languages.
* {reconstructed}: This language is not attested according to [[WT:CFI]], and therefore is allowed only in the
{Reconstruction} namespace. All terms in this language are reconstructed, and must be prefixed with `*`. Languages
such as Proto-Indo-European and Proto-Germanic are in this category. '''Exception:''' Reconstructed languages can
have entries in the mainspace using the ''anti-asterisk'' feature. This requires that both the headword for the
mainspace term (as specified using {{para|head}}) and links to the term are prefixed with the anti-asterisk
indicator `!!`.
* {appendix-constructed}: This language is attested but does not meet the additional requirements set out for
constructed languages ([[WT:CFI#Constructed languages]]). Its entries must therefore be in the Appendix namespace,
but they are not reconstructed and therefore should not have * prefixed in links.
]==]
function Language:getTypes()
local types = self._types
if types == nil then
types = {language = true}
if self:getFullCode() == self._code then
types.full = true
else
types["etymology-only"] = true
end
for t in gmatch(self._data.type, "[^,]+") do
types[t] = true
end
self._types = types
end
return types
end
--[==[
Given a list of types as strings, return {true} if the language has all of them.
]==]
function Language:hasType(...)
Language.hasType = require(language_like_module).hasType
return self:hasType(...)
end
--[==[
Return a list containing `WikimediaLanguage` objects (see [[Module:wikimedia languages]]), which represent languages
and their codes as they are used in Wikimedia projects for interwiki linking and such. More than one object may be
returned, as a single Wiktionary language may correspond to multiple Wikimedia languages. For example, Wiktionary's
single code `sh` (Serbo-Croatian) maps to four Wikimedia codes: `sh` (Serbo-Croatian), `bs` (Bosnian), `hr` (Croatian)
and `sr` (Serbian). The code for the Wikimedia language is retrieved from the `wikimedia_codes` property in the data
modules. If that property is not present, the code of the current language is used. If none of the available codes is
actually a valid Wikimedia code, an empty list is returned.
]==]
function Language:getWikimediaLanguages()
local wm_langs = self._wikimediaLanguageObjects
if wm_langs == nil then
local codes = self:getWikimediaLanguageCodes()
wm_langs = {}
for i = 1, #codes do
wm_langs[i] = get_wikimedia_lang(codes[i])
end
self._wikimediaLanguageObjects = wm_langs
end
return wm_langs
end
function Language:getWikimediaLanguageCodes()
local wm_langs = self._wikimediaLanguageCodes
if wm_langs == nil then
wm_langs = self._data.wikimedia_codes
if wm_langs then
wm_langs = split(wm_langs, ",", true, true)
else
local code = self._code
if is_known_language_tag(code) then
wm_langs = {code}
else
-- Inherit, but only if no codes are specified in the data *and*
-- the language code isn't a valid Wikimedia language code.
local parent = self:getParent()
wm_langs = parent and parent:getWikimediaLanguageCodes() or {}
end
end
self._wikimediaLanguageCodes = wm_langs
end
return wm_langs
end
--[==[
Return the name of the Wikipedia article for the language. `project` specifies the language and project to retrieve
the article from, defaulting to {"enwiki"} for the English Wikipedia. Normally if specified it should be the project
code for a specific-language Wikipedia e.g. "zhwiki" for the Chinese Wikipedia, but it can be any project, including
non-Wikipedia ones. If the project is the English Wikipedia and the property {wikipedia_article} is present in the data
module it will be used first. In all other cases, a sitelink will be generated from {:getWikidataItem} (if set). The
resulting value (or lack of value) is cached so that subsequent calls are fast. If no value could be determined, and
`noCategoryFallback` is {false}, `##Language:getCategoryName` is used as fallback; otherwise, {nil} is returned. Note
that if `noCategoryFallback` is {nil} or omitted, it defaults to {false} if the project is the English Wikipedia,
otherwise to {true}. In other words, under normal circumstances, if the English Wikipedia article couldn't be retrieved,
the return value will fall back to a link to the language's category, but this won't normally happen for any other
project.
]==]
function Language:getWikipediaArticle(noCategoryFallback, project)
Language.getWikipediaArticle = require(language_like_module).getWikipediaArticle
return self:getWikipediaArticle(noCategoryFallback, project)
end
function Language:makeWikipediaLink()
return make_link(self, "w:" .. self:getWikipediaArticle(), self:getCanonicalName())
end
--[==[
Return the name of the Wikimedia Commons category page for the language.
]==]
function Language:getCommonsCategory()
Language.getCommonsCategory = require(language_like_module).getCommonsCategory
return self:getCommonsCategory()
end
--[==[
Return the Wikidata item ID for the language or {nil}. This corresponds to the the second field in the data modules.
]==]
function Language:getWikidataItem()
Language.getWikidataItem = require(language_like_module).getWikidataItem
return self:getWikidataItem()
end
--[==[
Return a list of `Script` objects for all scripts that the language is written in. See [[Module:scripts]].
]==]
function Language:getScripts()
local scripts = self._scriptObjects
if scripts == nil then
local codes = self:getScriptCodes()
if codes[1] == "All" then
scripts = load_data(scripts_data_module)
else
scripts = {}
for i = 1, #codes do
scripts[i] = get_script(codes[i])
end
end
self._scriptObjects = scripts
end
return scripts
end
--[==[
Return the list of script codes in the language's data file.
]==]
function Language:getScriptCodes()
local scripts = self._scriptCodes
if scripts == nil then
scripts = self._data[4]
if scripts then
local codes, n = {}, 0
for code in gmatch(scripts, "[^,]+") do
n = n + 1
-- Special handling of "Hants", which represents "Hani", "Hant" and "Hans" collectively.
if code == "Hants" then
codes[n] = "Hani"
codes[n + 1] = "Hant"
codes[n + 2] = "Hans"
n = n + 2
else
codes[n] = code
end
end
scripts = codes
else
scripts = {"None"}
end
self._scriptCodes = scripts
end
return scripts
end
--[==[
Given some text, iterate through the scripts of a given language trying to find the script that best matches the text.
Return a {Script} object representing the script. If no match is found at all, it returns the {None} script object.
]==]
function Language:findBestScript(text, forceDetect)
if not text or text == "" or text == "-" then
return get_script("None")
end
-- Differs from table returned by getScriptCodes, as Hants is not normalized into its constituents.
local codes = self._bestScriptCodes
if codes == nil then
codes = self._data[4]
codes = codes and split(codes, ",", true, true) or {"None"}
self._bestScriptCodes = codes
end
local first_sc = codes[1]
if first_sc == "All" then
return find_best_script_without_lang(text)
end
local codes_len = #codes
if not (forceDetect or first_sc == "Hants" or codes_len > 1) then
first_sc = get_script(first_sc)
local charset = first_sc.characters
return charset and umatch(text, "[" .. charset .. "]") and first_sc or get_script("None")
end
-- Remove all formatting characters.
text = get_plaintext(text)
-- Remove all spaces and any ASCII punctuation. Some non-ASCII punctuation is script-specific, so can't be removed.
text = ugsub(text, "[%s!\"#%%&'()*,%-./:;?@[\\%]_{}]+", "")
if #text == 0 then
return get_script("None")
end
-- Try to match every script against the text,
-- and return the one with the most matching characters.
local bestcount, bestscript, length = 0
for i = 1, codes_len do
local sc = codes[i]
-- Special case for "Hants", which is a special code that represents whichever of "Hant" or "Hans" best matches,
-- or "Hani" if they match equally. This avoids having to list all three. In addition, "Hants" will be treated
-- as the best match if there is at least one matching character, under the assumption that a Han script is
-- desirable in terms that contain a mix of Han and other scripts (not counting those which use Jpan or Kore).
if sc == "Hants" then
local Hani = get_script("Hani")
if not Hant_chars then
Hant_chars = load_data("Module:zh/data/ts")
Hans_chars = load_data("Module:zh/data/st")
end
local t, s, found = 0, 0
-- This is faster than using mw.ustring.gmatch directly.
for ch in gmatch((ugsub(text, "[" .. Hani.characters .. "]", "\255%0")), "\255(.[\128-\191]*)") do
found = true
if Hant_chars[ch] then
t = t + 1
if Hans_chars[ch] then
s = s + 1
end
elseif Hans_chars[ch] then
s = s + 1
else
t, s = t + 1, s + 1
end
end
if found then
if t == s then
return Hani
end
return get_script(t > s and "Hant" or "Hans")
end
else
sc = get_script(sc)
if not length then
length = ulen(text)
end
-- Count characters by removing everything in the script's charset and comparing to the original length.
local charset = sc.characters
local count = charset and length - ulen((ugsub(text, "[" .. charset .. "]+", ""))) or 0
if count >= length then
return sc
elseif count > bestcount then
bestcount = count
bestscript = sc
end
end
end
-- Return best matching script, or otherwise None.
return bestscript or get_script("None")
end
--[==[
Return a `Family` object for the language family that the language belongs to. See [[Module:families]].
]==]
function Language:getFamily()
local family = self._familyObject
if family == nil then
family = self:getFamilyCode()
-- If the value is nil, it's cached as false.
family = family and get_family(family) or false
self._familyObject = family
end
return family or nil
end
--[==[
Return the family code in the language's data file.
]==]
function Language:getFamilyCode()
local family = self._familyCode
if family == nil then
-- If the value is nil, it's cached as false.
family = self._data[3] or false
self._familyCode = family
end
return family or nil
end
function Language:getFamilyName()
local family = self._familyName
if family == nil then
family = self:getFamily()
-- If the value is nil, it's cached as false.
family = family and family:getCanonicalName() or false
self._familyName = family
end
return family or nil
end
do
local function check_family(self, family)
if type(family) == "table" then
family = family:getCode()
end
if self:getFamilyCode() == family then
return true
end
local self_family = self:getFamily()
if self_family:inFamily(family) then
return true
-- If the family isn't a real family (e.g. creoles) check any ancestors.
elseif self_family:inFamily("qfa-not") then
local ancestors = self:getAncestors()
for _, ancestor in ipairs(ancestors) do
if ancestor:inFamily(family) then
return true
end
end
end
end
--[==[
Check whether the language belongs to `family` (which can be a family code or object). A list of objects can be given in
place of `family`; in that case, return true if the language belongs to any of the specified families. Note that some
languages (in particular, certain creoles) can have multiple immediate ancestors potentially belonging to different
families; in that case, return true if the language belongs to any of the specified families.
]==]
function Language:inFamily(...)
if self:getFamilyCode() == nil then
return false
end
return check_inputs(self, check_family, false, ...)
end
end
function Language:getParent()
local parent = self._parentObject
if parent == nil then
parent = self:getParentCode()
-- If the value is nil, it's cached as false.
parent = parent and get_by_code(parent, nil, true, true) or false
self._parentObject = parent
end
return parent or nil
end
function Language:getParentCode()
local parent = self._parentCode
if parent == nil then
-- If the value is nil, it's cached as false.
parent = self._data.parent or false
self._parentCode = parent
end
return parent or nil
end
function Language:getParentName()
local parent = self._parentName
if parent == nil then
parent = self:getParent()
-- If the value is nil, it's cached as false.
parent = parent and parent:getCanonicalName() or false
self._parentName = parent
end
return parent or nil
end
function Language:getParentChain()
local chain = self._parentChain
if chain == nil then
chain = {}
local parent, n = self:getParent(), 0
while parent do
n = n + 1
chain[n] = parent
parent = parent:getParent()
end
self._parentChain = chain
end
return chain
end
--[==[
Return a list of the pseudo-families (if any) that a language belongs to. The returned value is a list of Family
objects. Pseudo-families are groupings of languages that are not clades but share some geographic, ethnic or other
characteristic (e.g. [[:Category:Papuan languages]], [[:Category:Jewish languages]]).
]==]
function Language:getPseudoFamilies()
self:loadInExtraData()
return require(language_like_module).getPseudoFamilies(self)
end
--[==[
Return a list of the pseudo-family codes (if any) that a language belongs to. The returned value is a list of strings
(family codes). See `##Language:getPseudoFamilies`.
]==]
function Language:getPseudoFamilyCodes()
local codes = {}
for _, family in ipairs(self:getPseudoFamilies()) do
insert(codes, family:getCode())
end
return codes
end
do
local function check_lang(self, lang)
for _, parent in ipairs(self:getParentChain()) do
if (type(lang) == "string" and lang or lang:getCode()) == parent:getCode() then
return true
end
end
end
function Language:hasParent(...)
return check_inputs(self, check_lang, false, ...)
end
end
--[==[
If the language is etymology-only, iterate through parents until a full language or family is found, and the
corresponding object is returned. If the language is a full language, return that language.
]==]
function Language:getFull()
local full = self._fullObject
if full == nil then
full = self:getFullCode()
full = full == self._code and self or get_by_code(full)
self._fullObject = full
end
return full
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and
the corresponding code is returned. If the language is a full language, return that language's code.
]==]
function Language:getFullCode()
return self._fullCode or self._code
end
--[==[
If the language is an etymology-only language, iterate through parents until a full language or family is found, and the
corresponding canonical name is returned. If the language is a full language, return that language's canonical name.
]==]
function Language:getFullName()
local full = self._fullName
if full == nil then
full = self:getFull():getCanonicalName()
self._fullName = full
end
return full
end
--[==[
Return a list of {Language} objects for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestors()
local ancestors = self._ancestorObjects
if ancestors == nil then
ancestors = {}
local ancestor_codes = self:getAncestorCodes()
if #ancestor_codes > 0 then
for _, ancestor in ipairs(ancestor_codes) do
insert(ancestors, get_by_code(ancestor, nil, true))
end
else
local fam = self:getFamily()
local protoLang = fam and fam:getProtoLanguage() or nil
-- For the cases where the current language is the proto-language
-- of its family, or an etymology-only language that is ancestral to that
-- proto-language, we need to step up a level higher right from the
-- start.
if protoLang and (
protoLang:getCode() == self._code or
(self:hasType("etymology-only") and protoLang:hasAncestor(self))
) then
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
while not protoLang and not (not fam or fam:getCode() == "qfa-not") do
fam = fam:getFamily()
protoLang = fam and fam:getProtoLanguage() or nil
end
insert(ancestors, protoLang)
end
self._ancestorObjects = ancestors
end
return ancestors
end
do
-- Avoid a language being its own ancestor via class inheritance. We only need to check for this if the language has
-- inherited an ancestor table from its parent, because we never want to drop ancestors that have been explicitly
-- set in the data. Recursively iterate over ancestors until we either find self or run out. If self is found,
-- return true.
local function check_ancestor(self, lang)
local codes = lang:getAncestorCodes()
if not codes then
return nil
end
for i = 1, #codes do
local code = codes[i]
if code == self._code then
return true
end
local anc = get_by_code(code, nil, true)
if check_ancestor(self, anc) then
return true
end
end
end
--[==[
Return a list of `Language` codes for all languages that this language is directly descended from. Generally this is
only a single language, but creoles, pidgins and mixed languages can have multiple ancestors.
]==]
function Language:getAncestorCodes()
if self._ancestorCodes then
return self._ancestorCodes
end
local data = self._data
local codes = data.ancestors
if codes == nil then
codes = {}
self._ancestorCodes = codes
return codes
end
codes = split(codes, ",", true, true)
self._ancestorCodes = codes
-- If there are no codes or the ancestors weren't inherited data, there's nothing left to check.
if #codes == 0 or self:getData(false, "raw").ancestors ~= nil then
return codes
end
local i = 1
while i <= #codes do
if check_ancestor(self, self) then
remove(codes, i)
else
i = i + 1
end
end
return codes
end
end
--[==[
Given a list of language objects or codes, return true if at least one of them is an ancestor. This includes any
etymology-only children of that ancestor. If the language's ancestor(s) are etymology-only languages, it will also
return true for those language parent(s) (e.g. if Vulgar Latin is the ancestor, it will also return true for its parent,
Latin). However, a parent is excluded from this if the ancestor is also ancestral to that parent (e.g. if Classical
Persian is the ancestor, Persian would return {false}, because Classical Persian is also ancestral to Persian).
]==]
function Language:hasAncestor(...)
local function iterateOverAncestorTree(node, func, parent_check)
local ancestors = node:getAncestors()
local ancestorsParents = {}
for _, ancestor in ipairs(ancestors) do
-- When checking the parents of the other language, and the ancestor is also a parent, skip to the next
-- ancestor, so that we exclude any etymology-only children of that parent that are not directly related
-- (see below).
local ret = (parent_check or not node:hasParent(ancestor)) and
func(ancestor) or iterateOverAncestorTree(ancestor, func, parent_check)
if ret then
return ret
end
end
-- Check the parents of any ancestors. We don't do this if checking the parents of the other language, so that
-- we exclude any etymology-only children of those parents that are not directly related (e.g. if the ancestor
-- is Vulgar Latin and we are checking New Latin, we want it to return false because they are on different
-- ancestral branches. As such, if we're already checking the parent of New Latin (Latin) we don't want to
-- compare it to the parent of the ancestor (Latin), as this would be a false positive; it should be one or the
-- other).
if not parent_check then
return nil
end
for _, ancestor in ipairs(ancestors) do
local ancestorParents = ancestor:getParentChain()
for _, ancestorParent in ipairs(ancestorParents) do
if ancestorParent:getCode() == self._code or ancestorParent:hasAncestor(ancestor) then
break
else
insert(ancestorsParents, ancestorParent)
end
end
end
for _, ancestorParent in ipairs(ancestorsParents) do
local ret = func(ancestorParent)
if ret then
return ret
end
end
end
local function do_iteration(otherlang, parent_check)
-- otherlang can't be self
if (type(otherlang) == "string" and otherlang or otherlang:getCode()) == self._code then
return false
end
repeat
if iterateOverAncestorTree(
self,
function(ancestor)
return ancestor:getCode() == (type(otherlang) == "string" and otherlang or otherlang:getCode())
end,
parent_check
) then
return true
elseif type(otherlang) == "string" then
otherlang = get_by_code(otherlang, nil, true)
end
otherlang = otherlang:getParent()
parent_check = false
until not otherlang
end
local parent_check = true
for _, otherlang in ipairs{...} do
local ret = do_iteration(otherlang, parent_check)
if ret then
return true
end
end
return false
end
do
local function construct_node(lang, memo)
local branch, ancestors = {lang = lang:getCode()}
memo[lang:getCode()] = branch
for _, ancestor in ipairs(lang:getAncestors()) do
if ancestors == nil then
ancestors = {}
end
insert(ancestors, memo[ancestor:getCode()] or construct_node(ancestor, memo))
end
branch.ancestors = ancestors
return branch
end
function Language:getAncestorChain()
local chain = self._ancestorChain
if chain == nil then
chain = construct_node(self, {})
self._ancestorChain = chain
end
return chain
end
end
function Language:getAncestorChainOld()
local chain = self._ancestorChain
if chain == nil then
chain = {}
local step = self
while true do
local ancestors = step:getAncestors()
step = #ancestors == 1 and ancestors[1] or nil
if not step then
break
end
insert(chain, step)
end
self._ancestorChain = chain
end
return chain
end
local function fetch_descendants(self, fmt)
local descendants, family = {}, self:getFamily()
-- Iterate over all three datasets.
for _, data in ipairs{
require("Module:languages/code to canonical name"),
require("Module:etymology languages/code to canonical name"),
require("Module:families/code to canonical name"),
} do
for code in pairs(data) do
local lang = get_by_code(code, nil, true, true)
if not lang then
error(("Internal error: code '%s' can't be fetched"):format(code))
end
-- Test for a descendant. Earlier tests weed out most candidates, while the more intensive tests are only used sparingly.
if (
code ~= self._code and -- Not self.
lang:inFamily(family) and -- In the same family.
(
family:getProtoLanguageCode() == self._code or -- Self is the protolanguage.
self:hasDescendant(lang) or -- Full hasDescendant check.
(lang:getFullCode() == self._code and not self:hasAncestor(lang)) -- Etymology-only child which isn't an ancestor.
)
) then
if fmt == "object" then
insert(descendants, lang)
elseif fmt == "code" then
insert(descendants, code)
elseif fmt == "name" then
insert(descendants, lang:getCanonicalName())
end
end
end
end
return descendants
end
function Language:getDescendants()
local descendants = self._descendantObjects
if descendants == nil then
descendants = fetch_descendants(self, "object")
self._descendantObjects = descendants
end
return descendants
end
function Language:getDescendantCodes()
local descendants = self._descendantCodes
if descendants == nil then
descendants = fetch_descendants(self, "code")
self._descendantCodes = descendants
end
return descendants
end
function Language:getDescendantNames()
local descendants = self._descendantNames
if descendants == nil then
descendants = fetch_descendants(self, "name")
self._descendantNames = descendants
end
return descendants
end
do
local function check_lang(self, lang)
if type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasAncestor(self) then
return true
end
end
function Language:hasDescendant(...)
return check_inputs(self, check_lang, false, ...)
end
end
local function fetch_children(self, fmt)
local m_etym_data = require(etymology_languages_data_module)
local self_code, children = self._code, {}
for code, lang in pairs(m_etym_data) do
local _lang = lang
repeat
local parent = _lang.parent
if parent == self_code then
if fmt == "object" then
insert(children, get_by_code(code, nil, true))
elseif fmt == "code" then
insert(children, code)
elseif fmt == "name" then
insert(children, lang[1])
end
break
end
_lang = m_etym_data[parent]
until not _lang
end
return children
end
function Language:getChildren()
local children = self._childObjects
if children == nil then
children = fetch_children(self, "object")
self._childObjects = children
end
return children
end
function Language:getChildrenCodes()
local children = self._childCodes
if children == nil then
children = fetch_children(self, "code")
self._childCodes = children
end
return children
end
function Language:getChildrenNames()
local children = self._childNames
if children == nil then
children = fetch_children(self, "name")
self._childNames = children
end
return children
end
function Language:hasChild(...)
local lang = ...
if not lang then
return false
elseif type(lang) == "string" then
lang = get_by_code(lang, nil, true)
end
if lang:hasParent(self) then
return true
end
return self:hasChild(select(2, ...))
end
--[==[
Return the name of the main category of that language. Example: {French language"} for French, whose category is at
[[:Category:French language]]. Unless optional argument `nocap` is given, the language name at the beginning of the
returned value will be capitalized. This capitalization is correct for category names, but not if the language name is
lowercase and the returned value of this function is used in the middle of a sentence.
]==]
function Language:getCategoryName(nocap)
local name = self._categoryName
if name == nil then
name = self:getCanonicalName()
-- If a substrate, omit any leading article.
if self:getFamilyCode() == "qfa-sub" then
name = name:gsub("^the ", ""):gsub("^a ", "")
end
-- Only add " language" if a full language.
if self:hasType("full") then
-- Unless the canonical name already ends with "language", "lect" or their derivatives, add " language".
if not (match(name, "භාෂාව$") or match(name, "[Ll]ect$")) then
name = name .. " භාෂාව"
end
end
self._categoryName = name
end
if nocap then
return name
end
return mw.getContentLanguage():ucfirst(name)
end
--[==[
Create a link to the category; the link text is the canonical name.
]==]
function Language:makeCategoryLink()
return make_link(self, ":Category:" .. self:getCategoryName(), self:getDisplayForm())
end
function Language:getStandardCharacters(sc)
local standard_chars = self._data.standard_chars
if type(standard_chars) ~= "table" then
return standard_chars
elseif sc and type(sc) ~= "string" then
check_object("script", nil, sc)
sc = sc:getCode()
end
if (not sc) or sc == "None" then
local scripts = {}
for _, script in pairs(standard_chars) do
insert(scripts, script)
end
return concat(scripts)
end
if standard_chars[sc] then
return standard_chars[sc] .. (standard_chars[1] or "")
end
end
--[==[
Strip diacritics from display text `text` (in a language-specific fashion), which is in the script `sc`. If `sc` is
omitted or {nil}, the script is autodetected. This also strips certain punctuation characters from the end and (in the
case of Spanish upside-down question mark and exclamation points) from the beginning; strips any whitespace at the
end of the text or between the text and final stripped punctuation characters; and applies some language-specific
Unicode normalizations to replace discouraged characters with their prescribed alternatives. Return the stripped text.
]==]
function Language:stripDiacritics(text, sc)
if (not text) or text == "" then
return text
end
sc = checkScript(text, self, sc)
text = normalize(text, sc)
-- FIXME, rename makeEntryName to stripDiacritics and get rid of second and third return values
-- everywhere
local _
text, _, _ = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.strip_diacritics or self._data.entry_name, "strip_diacritics", "stripDiacritics")
text = umatch(text, "^[¿¡]?(.-[^%s%p].-)%s*[؟?!;՛՜ ՞ ՟?!︖︕।॥။၊་།]?$") or text
return text
end
--[==[
Convert a ''logical'' pagename (the pagename as it appears to the user, after diacritics and punctuation have been
stripped) to a ''physical'' pagename (the pagename as it appears in the MediaWiki database). Reasons for a difference
between the two are (a) unsupported titles such as `[ ]` (with square brackets in them), `#` (pound/hash sign) and
`¯\_(ツ)_/¯` (with underscores), as well as overly long titles of various sorts; (b) "mammoth" pages that are split into
parts (e.g. `a`, which is split into physical pagenames `a/languages A to L` and `a/languages M to Z`). For almost all
purposes, you should work with logical and not physical pagenames. But there are certain use cases that require physical
pagenames, such as checking the existence of a page or retrieving a page's contents.
`pagename` is the logical pagename to be converted. `is_reconstructed_or_appendix` indicates whether the page is in the
`Reconstruction` or `Appendix` namespaces. If it is omitted or has the value {nil}, the pagename is checked for an
initial asterisk, and if found, the page is assumed to be a `Reconstruction` page. Setting a value of `false` or `true`
to `is_reconstructed_or_appendix` disables this check and allows for mainspace pagenames that begin with an asterisk.
]==]
function Language:logicalToPhysical(pagename, is_reconstructed_or_appendix)
-- FIXME: This probably shouldn't happen but it happens when makeEntryName() receives nil.
if pagename == nil then
track("nil-passed-to-logicalToPhysical")
return nil
end
local initial_asterisk
if is_reconstructed_or_appendix == nil then
local pagename_minus_initial_asterisk
initial_asterisk, pagename_minus_initial_asterisk = pagename:match("^(%*)(.*)$")
if pagename_minus_initial_asterisk then
is_reconstructed_or_appendix = true
pagename = pagename_minus_initial_asterisk
elseif self:hasType("appendix-constructed") then
is_reconstructed_or_appendix = true
end
end
if not is_reconstructed_or_appendix then
-- Check if the pagename is a listed unsupported title.
local unsupportedTitles = load_data(links_data_module).unsupported_titles
if unsupportedTitles[pagename] then
return "Unsupported titles/" .. unsupportedTitles[pagename]
end
end
-- Set `unsupported` as true if certain conditions are met.
local unsupported
-- Check if there's an unsupported character. \239\191\189 is the replacement character U+FFFD, which can't be typed
-- directly here due to an abuse filter. Unix-style dot-slash notation is also unsupported, as it is used for
-- relative paths in links, as are 3 or more consecutive tildes. Note: match is faster with magic
-- characters/charsets; find is faster with plaintext.
if (
match(pagename, "[#<>%[%]_{|}]") or
find(pagename, "\239\191\189") or
match(pagename, "%f[^%z/]%.%.?%f[%z/]") or
find(pagename, "~~~")
) then
unsupported = true
-- If it looks like an interwiki link.
elseif find(pagename, ":") then
local prefix = gsub(pagename, "^:*(.-):.*", ulower)
if (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
unsupported = true
end
end
-- Escape unsupported characters so they can be used in titles. ` is used as a delimiter for this, so a raw use of
-- it in an unsupported title is also escaped here to prevent interference; this is only done with unsupported
-- titles, though, so inclusion won't in itself mean a title is treated as unsupported (which is why it's excluded
-- from the earlier test).
if unsupported then
-- FIXME: This conversion needs to be different for reconstructed pages with unsupported characters. There
-- aren't any currently, but if there ever are, we need to fix this e.g. to put them in something like
-- Reconstruction:Proto-Indo-European/Unsupported titles/`lowbar``num`.
local unsupported_characters = load_data(links_data_module).unsupported_characters
pagename = pagename:gsub("[#<>%[%]_`{|}\239]\191?\189?", unsupported_characters)
:gsub("%f[^%z/]%.%.?%f[%z/]", function(m)
return (gsub(m, "%.", "`period`"))
end)
:gsub("~~~+", function(m)
return (gsub(m, "~", "`tilde`"))
end)
pagename = "Unsupported titles/" .. pagename
elseif not is_reconstructed_or_appendix then
-- Check if this is a mammoth page. If so, which subpage should we link to?
local m_links_data = load_data(links_data_module)
local mammoth_page_type = m_links_data.mammoth_pages[pagename]
if mammoth_page_type then
local canonical_name = self:getFullName()
if canonical_name ~= "Translingual" and canonical_name ~= "English" then
local this_subpage
local L2_sort_key = get_L2_sort_key(canonical_name)
for _, subpage_spec in ipairs(m_links_data.mammoth_page_subpage_types[mammoth_page_type]) do
-- unpack() fails utterly on data loaded using mw.loadData() even if offsets are given
local subpage, pattern = subpage_spec[1], subpage_spec[2]
if pattern == true or L2_sort_key:match(pattern) then
this_subpage = subpage
break
end
end
if not this_subpage then
error(("Internal error: Bad data in mammoth_page_subpage_pages in [[Module:links/data]] for mammoth page %s, type %s; last entry didn't have 'true' in it"):format(
pagename, mammoth_page_type))
end
pagename = pagename .. "/" .. this_subpage
end
end
end
return (initial_asterisk or "") .. pagename
end
--[==[
Strip the diacritics from a display pagename and convert the resulting logical pagename into a physical pagename.
This allows you, for example, to retrieve the contents of the page or check its existence. WARNING: This is deprecated
and will be going away. It is a simple composition of `##Language:stripDiacritics` and `##Language:logicalToPhysical`;
most callers only want the former, and if you need both, call them both yourself.
`text` and `sc` are as in `##Language:stripDiacritics`, and `is_reconstructed_or_appendix` is as in
`##Language:logicalToPhysical`.
]==]
function Language:makeEntryName(text, sc, is_reconstructed_or_appendix)
track("makeEntryName called")
return self:logicalToPhysical(self:stripDiacritics(text, sc), is_reconstructed_or_appendix)
end
--[==[
Generate term alternants (e.g. simplified versions of traditional Chinese terms) using a language-specific method, and
return them as a table. If the language provides no method for generating alternants, return a table containing only the
input term.
]==]
function Language:generateAlternants(text, sc)
local generate_alternants = self._data.generate_alternants
if generate_alternants == nil then
return {text}
end
sc = checkScript(text, self, sc)
return require("Module:" .. generate_alternants).generateAlternants(text, self, sc)
end
--[==[
Create a sort key for the given stripped text, following the rules appropriate for the language. This removes
diacritical marks from the stripped text if they are not considered significant for sorting, and may perform some other
changes. Any initial hyphen is also removed, and anything in parentheses is removed as well. The `sort_key` setting for
each language in the data modules defines the replacements made by this function, or it gives the name of the module
that takes the stripped text and returns a sortkey.
]==]
function Language:makeSortKey(text, sc)
if (not text) or text == "" then
return text
end
if match(text, "<[^<>]+>") then
track("track HTML tag")
end
-- Remove directionality/control characters, bold, italics, soft hyphens, strip markers and HTML tags.
-- FIXME: Partly duplicated with remove_formatting() in [[Module:links]].
text = ugsub(text, "[\194\173\216\156\226\128\142\226\128\143\226\128\170-\226\128\174\226\129\166-\226\129\175]", "")
text = text:gsub("('*)'''(.-'*)'''", "%1%2"):gsub("('*)''(.-'*)''", "%1%2")
text = gsub(unstrip(text), "<[^<>]+>", "")
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
-- Remove initial hyphens and * unless the term only consists of spacing + punctuation characters.
text = ugsub(text, "^([-]*)[-־ـ᠊*]+([-]*)(.*[^%s%p].*)", "%1%2%3")
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text = removeCarets(text, sc)
-- For languages with dotted dotless i, ensure that "İ" is sorted as "i", and "I" is sorted as "ı".
if self:hasDottedDotlessI() then
text = gsub(text, "I\204\135", "i") -- decomposed "İ"
:gsub("I", "ı")
text = sc:toFixedNFD(text)
end
-- Convert to lowercase, make the sortkey, then convert to uppercase. Where the language has dotted dotless i, it is
-- usually not necessary to convert "i" to "İ" and "ı" to "I" first, because "I" will always be interpreted as
-- conventional "I" (not dotless "İ") by any sorting algorithms, which will have been taken into account by the
-- sortkey substitutions themselves. However, if no sortkey substitutions have been specified, then conversion is
-- necessary so as to prevent "i" and "ı" both being sorted as "I".
--
-- An exception is made for scripts that (sometimes) sort by scraping page content, as that means they are sensitive
-- to changes in capitalization (as it changes the target page).
if not sc:sortByScraping() then
text = ulower(text)
end
local actual_substitution_data, _
-- Don't trim whitespace here because it's significant at the beginning of a sort key or sort base.
text, _, actual_substitution_data = iterateSectionSubstitutions(self, text, sc, nil, nil,
self._data.sort_key, "sort_key", "makeSortKey", "notrim")
if not sc:sortByScraping() then
if self:hasDottedDotlessI() and not actual_substitution_data then
text = text:gsub("ı", "I"):gsub("i", "İ")
text = sc:toFixedNFC(text)
end
text = uupper(text)
end
-- Remove parentheses, as long as they are either preceded or followed by something.
text = gsub(text, "(.)[()]+", "%1"):gsub("[()]+(.)", "%1")
text = escape_risky_characters(text)
return text
end
--[==[
Create the form used as as a basis for display text and transliteration. FIXME: Rename to correctInputText().
]==]
local function processDisplayText(text, self, sc, keepCarets, keepPrefixes)
local subbedChars = {}
text, subbedChars = doTempSubstitutions(text, subbedChars, keepCarets)
text = decode_uri(text, "PATH")
text = checkNoEntities(text)
sc = checkScript(text, self, sc)
text = normalize(text, sc)
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, keepCarets, self._data.display_text,
"display_text", "makeDisplayText")
text = removeCarets(text, sc)
-- Remove any interwiki link prefixes (unless they have been escaped or this has been disabled).
if find(text, ":") and not keepPrefixes then
local rep
repeat
text, rep = gsub(text, "\\\\(\\*:)", "\3%1")
until rep == 0
text = gsub(text, "\\:", "\4")
while true do
local prefix = gsub(text, "^(.-):.+", function(m1)
return (gsub(m1, "\244[\128-\191]*", ""))
end)
-- Check if the prefix is an interwiki, though ignore capitalised Wiktionary:, which is a namespace.
if not prefix or prefix == text or prefix == "Wiktionary"
or not (load_data("Module:data/interwikis")[ulower(prefix)] or prefix == "") then
break
end
text = gsub(text, "^(.-):(.*)", function(m1, m2)
local ret = {}
for subbedChar in gmatch(m1, "\244[\128-\191]*") do
insert(ret, subbedChar)
end
return concat(ret) .. m2
end)
end
text = gsub(text, "\3", "\\"):gsub("\4", ":")
end
return text, subbedChars
end
--[==[
Make the display text (i.e. what is displayed on the page).
]==]
function Language:makeDisplayText(text, sc, keepPrefixes)
if not text or text == "" then
return text
end
local subbedChars
text, subbedChars = processDisplayText(text, self, sc, nil, keepPrefixes)
text = escape_risky_characters(text)
return undoTempSubstitutions(text, subbedChars)
end
--[==[
Transliterate the text from the given script into Latin script (see [[Wiktionary:Transliteration and romanization]]).
The language must have the `translit` property for this to work; if it is not present, {nil} is returned.
The `sc` parameter is handled by the transliteration module, and how it is handled is specific to that module. Some
transliteration modules may tolerate {nil} as the script, others require it to be one of the possible scripts that the
module can transliterate, and will throw an error if it's not one of them. For this reason, the `sc` parameter should
always be provided when writing non-language-specific code.
The `module_override` parameter is used to override the default module that is used to provide the transliteration.
This is useful in cases where you need to demonstrate a particular module in use, but there is no default module yet,
or you want to demonstrate an alternative version of a transliteration module before making it official. It should not
be used in real modules or templates, only for testing. All uses of this parameter are tracked by
[[Wiktionary:Tracking/languages/module_override]].
'''Known bugs''':
* This function assumes {tr(s1) .. tr(s2) == tr(s1 .. s2)}. When this assertion fails, wikitext markups like
<nowiki>'''</nowiki> can cause wrong transliterations.
* HTML entities like `&apos;`, often used to escape wikitext markups, do not work.
]==]
function Language:transliterate(text, sc, module_override)
-- If there is no text, or the language doesn't have transliteration data and there's no override, return nil.
if not text or text == "" or text == "-" then
return text
end
-- If the script is not transliteratable (and no override is given), return nil.
sc = checkScript(text, self, sc)
if not (sc:isTransliterated() or module_override) then
-- temporary tracking to see if/when this gets triggered
track("non-transliterable")
track("non-transliterable/" .. self._code)
track("non-transliterable/" .. sc:getCode())
track("non-transliterable/" .. sc:getCode() .. "/" .. self._code)
return nil
end
-- Remove any strip markers.
text = unstrip(text)
-- Do not process the formatting into PUA characters for certain languages.
local processed = load_data(languages_data_module).substitution[self._code] ~= "none"
-- Get the display text with the keepCarets flag set.
local subbedChars
if processed then
text, subbedChars = processDisplayText(text, self, sc, true)
end
-- Transliterate (using the module override if applicable).
text, subbedChars = iterateSectionSubstitutions(self, text, sc, subbedChars, true, module_override or
self._data.translit, "translit", "tr")
if not text then
return nil
end
-- Incomplete transliterations return nil.
local charset = sc.characters
if charset and umatch(text, "[" .. charset .. "]") then
-- Remove any characters in Latin, which includes Latin characters also included in other scripts (as these are
-- false positives), as well as any PUA substitutions. Anything remaining should only be script code "None"
-- (e.g. numerals).
local check_text = ugsub(text, "[" .. get_script("Latn").characters .. "-]+", "")
-- Set none_is_last_resort_only flag, so that any non-None chars will cause a script other than "None" to be
-- returned.
if find_best_script_without_lang(check_text, true):getCode() ~= "None" then
return nil
end
end
if processed then
text = escape_risky_characters(text)
text = undoTempSubstitutions(text, subbedChars)
end
-- If allowed for this script, capitalize transliteration letters preceded by ^ and remove the caret.
if text and text:find("^", 1, true) then
assertCaretCapitalizationAllowed(text, sc)
if sc:hasCaretCapitalization() then
text = processCarets(text, "%^([\128-\191\244]*%*?)([^\128-\191\244][\128-\191]*)", function(m1, m2)
return m1 .. uupper(m2)
end)
end
end
-- Track module overrides.
if module_override ~= nil then
track("module_override")
end
return text
end
do
local function handle_language_spec(self, spec, sc)
local ret = self["_" .. spec]
if ret == nil then
ret = self._data[spec]
if type(ret) == "string" then
ret = list_to_set(split(ret, ",", true, true))
end
self["_" .. spec] = ret
end
if type(ret) == "table" then
ret = ret[sc:getCode()]
end
return not not ret
end
function Language:overrideManualTranslit(sc)
return handle_language_spec(self, "override_translit", sc)
end
function Language:link_tr(sc)
return handle_language_spec(self, "link_tr", sc)
end
end
--[==[
Return {true} if the language has a transliteration module, or {false} if it doesn't.
]==]
function Language:hasTranslit()
return not not self._data.translit
end
--[==[
Return {true} if the language uses the letters I/ı and İ/i, or {false} if it doesn't.]==]
function Language:hasDottedDotlessI()
return not not self._data.dotted_dotless_i
end
function Language:toJSON(opts)
local strip_diacritics, strip_diacritics_patterns, strip_diacritics_remove_diacritics = self._data.strip_diacritics
if strip_diacritics then
if strip_diacritics.from then
strip_diacritics_patterns = {}
for i, from in ipairs(strip_diacritics.from) do
insert(strip_diacritics_patterns, {from = from, to = strip_diacritics.to[i] or ""})
end
end
strip_diacritics_remove_diacritics = strip_diacritics.remove_diacritics
end
-- mainCode should only end up non-nil if dontCanonicalizeAliases is passed to make_object().
-- props should either contain zero-argument functions to compute the value, or the value itself.
local props = {
ancestors = function() return self:getAncestorCodes() end,
canonicalName = function() return self:getCanonicalName() end,
categoryName = function() return self:getCategoryName("nocap") end,
code = self._code,
mainCode = self._mainCode,
parent = function() return self:getParentCode() end,
full = function() return self:getFullCode() end,
stripDiacriticsPatterns = strip_diacritics_patterns,
stripDiacriticsRemoveDiacritics = strip_diacritics_remove_diacritics,
family = function() return self:getFamilyCode() end,
aliases = function() return self:getAliases() end,
varieties = function() return self:getVarieties() end,
otherNames = function() return self:getOtherNames() end,
pseudoFamilies = function() return self:getPseudoFamilyCodes() end,
scripts = function() return self:getScriptCodes() end,
type = function() return keys_to_list(self:getTypes()) end,
wikimediaLanguages = function() return self:getWikimediaLanguageCodes() end,
wikidataItem = function() return self:getWikidataItem() end,
wikipediaArticle = function() return self:getWikipediaArticle(true) end,
}
local ret = {}
for prop, val in pairs(props) do
if not opts.skip_fields or not opts.skip_fields[prop] then
if type(val) == "function" then
ret[prop] = val()
else
ret[prop] = val
end
end
end
-- Use `deep_copy` when returning a table, so that there are no editing restrictions imposed by `mw.loadData`.
return opts and opts.lua_table and deep_copy(ret) or to_json(ret, opts)
end
function export.getDataModuleName(code)
local letter = match(code, "^(%l)%l%l?$")
return "Module:" .. (
letter == nil and "languages/data/exceptional" or
#code == 2 and "languages/data/2" or
"languages/data/3/" .. letter
)
end
get_data_module_name = export.getDataModuleName
function export.getExtraDataModuleName(code)
return get_data_module_name(code) .. "/extra"
end
get_extra_data_module_name = export.getExtraDataModuleName
do
local function make_stack(data)
local key_types = {
[2] = "unique",
aliases = "unique",
other_names = "unique",
type = "append",
varieties = "unique",
wikipedia_article = "unique",
wikimedia_codes = "unique"
}
local function __index(self, k)
local stack, key_type = getmetatable(self), key_types[k]
-- Data that isn't inherited from the parent.
if key_type == "unique" then
local v = stack[stack[make_stack]][k]
if v == nil then
local layer = stack[0]
if layer then -- Could be false if there's no extra data.
v = layer[k]
end
end
return v
-- Data that is appended by each generation.
elseif key_type == "append" then
local parts, offset, n = {}, 0, stack[make_stack]
for i = 1, n do
local part = stack[i][k]
if part == nil then
offset = offset + 1
else
parts[i - offset] = part
end
end
return offset ~= n and concat(parts, ",") or nil
end
local n = stack[make_stack]
while true do
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
local v = layer[k]
if v ~= nil then
return v
end
n = n - 1
end
end
local function __newindex()
error("table is read-only")
end
local function __pairs(self)
-- Iterate down the stack, caching keys to avoid duplicate returns.
local stack, seen = getmetatable(self), {}
local n = stack[make_stack]
local iter, state, k, v = pairs(stack[n])
return function()
repeat
repeat
k = iter(state, k)
if k == nil then
n = n - 1
local layer = stack[n]
if not layer then -- Could be false if there's no extra data.
return nil
end
iter, state, k = pairs(layer)
end
until not (k == nil or seen[k])
-- Get the value via a lookup, as the one returned by the
-- iterator will be the raw value from the current layer,
-- which may not be the one __index will return for that
-- key. Also memoize the key in `seen` (even if the lookup
-- returns nil) so that it doesn't get looked up again.
-- TODO: store values in `self`, avoiding the need to create
-- the `seen` table. The iterator will need to iterate over
-- `self` with `next` first to find these on future loops.
v, seen[k] = self[k], true
until v ~= nil
return k, v
end
end
local __ipairs = require(table_module).indexIpairs
function make_stack(data)
local stack = {
data,
[make_stack] = 1, -- stores the length and acts as a sentinel to confirm a given metatable is a stack.
__index = __index,
__newindex = __newindex,
__pairs = __pairs,
__ipairs = __ipairs,
}
stack.__metatable = stack
return setmetatable({}, stack), stack
end
return make_stack(data)
end
local function get_stack(data)
local stack = getmetatable(data)
return stack and type(stack) == "table" and stack[make_stack] and stack or nil
end
--[==[
<span style="color: var(--wikt-palette-red,#BA0000)">This function is not for use in entries or other content pages.</span>
Return a blob of data about the language. The format of this blob is undocumented, and perhaps unstable; it's intended
for things like the module's own unit-tests, which are "close friends" with the module and will be kept up-to-date as
the format changes. If `extra` is set, any extra data in the relevant `/extra` module will be included. (Note that it
will be included anyway if it has already been loaded into the language object.) If `raw` is set, then the returned data
will not contain any data inherited from parent objects.
-- Do NOT use these methods!
-- All uses should be pre-approved on the talk page!
]==]
function Language:getData(extra, raw)
if extra then
self:loadInExtraData()
end
local data = self._data
-- If raw is not set, just return the data.
if not raw then
return data
end
local stack = get_stack(data)
-- If there isn't a stack or its length is 1, return the data. Extra data (if any) will be included, as it's
-- stored at key 0 and doesn't affect the reported length.
if stack == nil then
return data
end
local n = stack[make_stack]
if n == 1 then
return data
end
extra = stack[0]
-- If there isn't any extra data, return the top layer of the stack.
if extra == nil then
return stack[n]
end
-- If there is, return a new stack which has the top layer at key 1 and the extra data at key 0.
data, stack = make_stack(stack[n])
stack[0] = extra
return data
end
function Language:loadInExtraData()
-- Only full languages have extra data.
if not self:hasType("language", "full") then
return
end
local data = self._data
-- If there's no stack, create one.
local stack = get_stack(self._data)
if stack == nil then
data, stack = make_stack(data)
-- If already loaded, return.
elseif stack[0] ~= nil then
return
end
self._data = data
-- Load extra data from the relevant module and add it to the stack at key 0, so that the __index and __pairs
-- metamethods will pick it up, since they iterate down the stack until they run out of layers.
local code = self._code
local modulename = get_extra_data_module_name(code)
-- No data cached as false.
stack[0] = modulename and load_data(modulename)[code] or false
end
--[==[
Return the name of the module containing the language's data, e.g. [[Module:languages/data/3/k]] for three-letter codes
beginning with `k`.
]==]
function Language:getDataModuleName()
local name = self._dataModuleName
if name == nil then
name = self:hasType("etymology-only") and etymology_languages_data_module or
get_data_module_name(self._mainCode or self._code)
self._dataModuleName = name
end
return name
end
--[==[
Return the name of the module containing the language's extra data, e.g. [[Module:languages/data/3/k/extra]] for
three-letter codes beginning with `k`.
]==]
function Language:getExtraDataModuleName()
local name = self._extraDataModuleName
if name == nil then
name = not self:hasType("etymology-only") and get_extra_data_module_name(self._mainCode or self._code) or false
self._extraDataModuleName = name
end
return name or nil
end
function export.makeObject(code, data, dontCanonicalizeAliases)
local data_type = type(data)
if data_type ~= "table" then
error(("bad argument #2 to 'makeObject' (table expected, got %s)"):format(data_type))
end
-- Convert any aliases.
local input_code = code
code = normalize_code(code)
input_code = dontCanonicalizeAliases and input_code or code
local parent
if data.parent then
parent = get_by_code(data.parent, nil, true, true)
else
parent = Language
end
parent.__index = parent
local lang = {_code = input_code}
-- This can only happen if dontCanonicalizeAliases is passed to make_object().
if code ~= input_code then
lang._mainCode = code
end
local parent_data = parent._data
if parent_data == nil then
-- Full code is the same as the code.
lang._fullCode = parent._code or code
else
-- Copy full code.
lang._fullCode = parent._fullCode
local stack = get_stack(parent_data)
if stack == nil then
parent_data, stack = make_stack(parent_data)
end
-- Insert the input data as the new top layer of the stack.
local n = stack[make_stack] + 1
data, stack[n], stack[make_stack] = parent_data, data, n
end
lang._data = data
return setmetatable(lang, parent)
end
make_object = export.makeObject
end
--[==[
Find the language whose code matches the one provided. If it exists, return a `Language` object representing the
language. Otherwise, return {nil}, unless `paramForError` is given, in which case an error is generated. If
`paramForError` is {true}, a generic error message mentioning the bad code is generated; otherwise `paramForError`
should be a string or number specifying the parameter that the code came from, and this parameter will be mentioned
in the error message along with the bad code. If `allowEtymLang` is specified, etymology-only language codes are allowed
and looked up along with full language codes. If `allowFamily` is specified, language family codes are allowed and
looked up along with normal language codes.
]==]
function export.getByCode(code, paramForError, allowEtymLang, allowFamily)
-- [[ Track uses of paramForError, ultimately so it can be removed, as error-handling should be done by
-- [[Module:parameters]], not here. ]] -- I (Benwing) disagree; that is an idealistic goal unlikely to be achievable
-- realistically.
if paramForError ~= nil then
track("paramForError")
end
if type(code) ~= "string" then
local typ
if not code then
typ = "nil"
elseif check_object("language", true, code) then
typ = "a language object"
elseif check_object("family", true, code) then
typ = "a family object"
else
typ = "a " .. type(code)
end
error("The function getByCode expects a string as its first argument, but received " .. typ .. ".")
end
local m_data = load_data(languages_data_module)
if m_data.aliases[code] or m_data.track[code] then
track(code)
end
local norm_code = normalize_code(code)
-- Get the data, checking for etymology-only languages if allowEtymLang is set.
local data = load_data(get_data_module_name(norm_code))[norm_code] or
allowEtymLang and load_data(etymology_languages_data_module)[norm_code]
-- If no data was found and allowFamily is set, check the family data. If the main family data was found, make the
-- object with [[Module:families]] instead, as family objects have different methods. However, if it's an
-- etymology-only family, use make_object in this module (which handles object inheritance), and the
-- family-specific methods will be inherited from the parent object.
if data == nil and allowFamily then
data = load_data("Module:families/data")[norm_code]
if data ~= nil then
if data.parent == nil then
return make_family_object(norm_code, data)
elseif not allowEtymLang then
data = nil
end
end
end
local retval = code and data and make_object(code, data)
if not retval and paramForError then
require("Module:languages/errorGetBy").code(code, paramForError, allowEtymLang, allowFamily)
end
return retval
end
get_by_code = export.getByCode
--[==[
Find the language whose canonical name (the name used to represent that language on Wiktionary) or other name matches
the one provided. If it exists, return a `Language` object representing the language. Otherwise, return {nil}, unless
`paramForError` is given, in which case an error is generated. If `allowEtymLang` is specified, etymology-only language
codes are allowed and looked up along with full language codes. If `allowFamily` is specified, language family codes are
allowed and looked up along with normal language codes. The canonical name of languages should always be unique (it is
an error for two languages on Wiktionary to share the same canonical name), so this is guaranteed to give at most one
result. This function is powered by [[Module:languages/canonical names]], which contains a pre-generated mapping of
full-language canonical names to codes. It is generated by going through the [[:Category:Language data modules]] for
full languages. When `allowEtymLang` is specified for the above function, [[Module:etymology languages/canonical names]]
may also be used, and when `allowFamily` is specified for the above function, [[Module:families/canonical names]] may
also be used.
]==]
function export.getByCanonicalName(name, errorIfInvalid, allowEtymLang, allowFamily)
local byName = load_data("Module:languages/canonical names")
local code = byName and byName[name]
if not code and allowEtymLang then
byName = load_data("Module:etymology languages/canonical names")
code = byName and byName[name] or
byName[gsub(name, " [Ss]ubstrate$", "")] or
byName[gsub(name, "^a ", "")] or
byName[gsub(name, "^a ", ""):gsub(" [Ss]ubstrate$", "")] or
-- For etymology families like "ira-pro".
-- FIXME: This is not ideal, as it allows " languages" to be appended to any etymology-only language, too.
byName[match(name, "^(.*) භාෂා$")]
end
if not code and allowFamily then
byName = load_data("Module:families/canonical names")
code = byName[name] or byName[match(name, "^(.*) භාෂා$")]
end
local retval = code and get_by_code(code, errorIfInvalid, allowEtymLang, allowFamily)
if not retval and errorIfInvalid then
require("Module:languages/errorGetBy").canonicalName(name, allowEtymLang, allowFamily)
end
return retval
end
--[==[
Used by [[Module:languages/data/2]] (et al.) and [[Module:etymology languages/data]], [[Module:families/data]],
[[Module:scripts/data]] and [[Module:writing systems/data]] to finalize the data into the format that is actually returned.
]==]
function export.finalizeData(data, main_type, variety)
local fields = {"type"}
if main_type == "language" then
insert(fields, 4) -- script codes
insert(fields, "ancestors")
insert(fields, "link_tr")
insert(fields, "override_translit")
insert(fields, "wikimedia_codes")
elseif main_type == "script" then
insert(fields, 3) -- writing system codes
end -- Families and writing systems have no extra fields to process.
local fields_len = #fields
for _, entity in next, data do
if variety then
-- Move parent from 3 to "parent" and family from "family" to 3. These are different for the sake of
-- convenience, since very few varieties have the family specified, whereas all of them have a parent.
entity.parent, entity[3] = entity[3], entity.family
entity.family = nil
-- Give the type "regular" iff not a variety and no other types are assigned.
elseif not (entity.type or entity.parent) then
entity.type = "regular"
end
for i = 1, fields_len do
local key = fields[i]
local field = entity[key]
if field and type(field) == "string" then
entity[key] = gsub(field, "%s*,%s*", ",")
end
end
end
return data
end
--[==[
For backwards compatibility only; modules should require the error themselves.
]==]
function export.err(lang_code, param, code_desc, template_tag, not_real_lang)
return require("Module:languages/error")(lang_code, param, code_desc, template_tag, not_real_lang)
end
return export
10348awa5wg0ld0dg2osngg4iam5gja
Module:category tree/languages
828
7928
238814
234674
2026-10-17T15:10:28Z
en>Surjection
0
I don't think these images should be links
238814
Scribunto
text/plain
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["All languages"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|Rough world map of language families]]",
description = "Categories for every language on Wiktionary.",
additional = "Not all languages that Wiktionary recognises may have a category here yet. There are many that have " ..
"not yet received any attention from editors, mainly because not all Wiktionary users know about every single " ..
"language. See [[Wiktionary:List of languages]] for a full list.",
parents = {
"Fundamental",
},
}
raw_categories["All extinct languages"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "All languages", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["Languages by country"] = {
topright = "{{commonscat|Languages by continent}}",
description = "Categories that group languages by country.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "Category:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("Category:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wiktionary edition''']=], wikt_plural, [=[ written in ]=], canonicalName, [=[:
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "Category:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 300px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ language links'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|Wikipedia]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''English Wikipedia''' has an article on:
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wikimedia Commons''' has links to ]=], canonicalName, [=[-related content in sister projects:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|Entry]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wiktionary entry''' for the language's English name:
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("en"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|Resources]]
|| '''Wiktionary resources''' for editors contributing to ]=], canonicalName, [=[ entries:
<div style="padding: 5px 0">
* '''[[Wiktionary:]=], canonicalName, [=[ entry guidelines]]'''
* '''[[:Category:]=], canonicalName, [=[ reference templates|Reference templates]] ({{PAGESINCAT:]=], canonicalName, [=[ reference templates}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|Bibliography]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "Edit language data")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>Canonical name</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|Language code]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Language family]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:Category:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:Category:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:Category:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:Category:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:Category:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:Category:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:Category:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:Category:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>Ancestors</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[Wiktionary:Scripts|Scripts]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[Wiktionary:Scripts|Scripts]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>Wikidata</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" Language$") then
the_prefix = ""
else
the_prefix = "the "
end
local description = "This is the main category of " .. the_prefix .. "'''" .. nameWithLanguage .. "'''."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "across"
insert(location_links, location)
elseif location ~= "UNKNOWN" then
this_prep = "in"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(location))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("It is %s %s %s.\n\n"):format(
extinct and "an [[extinct language]] that was formerly spoken" or "spoken",
prep, location_link_text
)
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. "Information about " .. canonicalName .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Appendix: namespace. " ..
"All terms in this language may be available at [[Appendix:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "en"}
local ret = {{name = "All languages", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "Category:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "Category:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "Category:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "Category:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "Category:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "Category:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:Category:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "Category:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "Category:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "Category:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "Category:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "Category:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "Category:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "Category:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "Category:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " languages"
end
insert(ret, {name = "Category:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "Category:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = "Languages of " .. location
insert(ret, {name = "Category:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "Category:All extinct languages", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "Category:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"appendices", "entry maintenance", "lemmas", "names", "phrases", "rhymes", "symbols", "templates", "terms by etymology", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "terms derived from {{{langname}}}", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:All topics", sort = "all topics"})
insert(ret, {name = "Varieties of {{{langname}}}"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("[Ll]anguage$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) language$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^Languages of (.*)$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "Languages by country", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "Category:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("Category:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("Categories for languages of %s (including sublects)."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin languages", sort = {sort_base = "*" .. langname, lang = "en"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "en"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
1ghxkdr4eu8nrjgito6w3qxhk54bf0r
238815
238814
2026-11-12T07:27:33Z
Lee
19
[[:en:Module:category_tree/languages]] වෙතින් එක් සංශෝධනයක්
238814
Scribunto
text/plain
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["All languages"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|Rough world map of language families]]",
description = "Categories for every language on Wiktionary.",
additional = "Not all languages that Wiktionary recognises may have a category here yet. There are many that have " ..
"not yet received any attention from editors, mainly because not all Wiktionary users know about every single " ..
"language. See [[Wiktionary:List of languages]] for a full list.",
parents = {
"Fundamental",
},
}
raw_categories["All extinct languages"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "All languages", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["Languages by country"] = {
topright = "{{commonscat|Languages by continent}}",
description = "Categories that group languages by country.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "Category:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("Category:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wiktionary edition''']=], wikt_plural, [=[ written in ]=], canonicalName, [=[:
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "Category:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 300px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ language links'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|Wikipedia]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''English Wikipedia''' has an article on:
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wikimedia Commons''' has links to ]=], canonicalName, [=[-related content in sister projects:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|Entry]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''Wiktionary entry''' for the language's English name:
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("en"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|Resources]]
|| '''Wiktionary resources''' for editors contributing to ]=], canonicalName, [=[ entries:
<div style="padding: 5px 0">
* '''[[Wiktionary:]=], canonicalName, [=[ entry guidelines]]'''
* '''[[:Category:]=], canonicalName, [=[ reference templates|Reference templates]] ({{PAGESINCAT:]=], canonicalName, [=[ reference templates}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|Bibliography]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "Edit language data")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>Canonical name</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|Language code]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|Language family]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:Category:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:Category:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:Category:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:Category:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:Category:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:Category:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:Category:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:Category:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>Ancestors</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[Wiktionary:Scripts|Scripts]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[Wiktionary:Scripts|Scripts]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>Wikidata</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" Language$") then
the_prefix = ""
else
the_prefix = "the "
end
local description = "This is the main category of " .. the_prefix .. "'''" .. nameWithLanguage .. "'''."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "across"
insert(location_links, location)
elseif location ~= "UNKNOWN" then
this_prep = "in"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(location))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("It is %s %s %s.\n\n"):format(
extinct and "an [[extinct language]] that was formerly spoken" or "spoken",
prep, location_link_text
)
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. "Information about " .. canonicalName .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Appendix: namespace. " ..
"All terms in this language may be available at [[Appendix:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "en"}
local ret = {{name = "All languages", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "Category:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "Category:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "Category:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "Category:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "Category:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "Category:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:Category:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "Category:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "Category:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "Category:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "Category:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "Category:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "Category:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "Category:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "Category:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " languages"
end
insert(ret, {name = "Category:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "Category:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = "Languages of " .. location
insert(ret, {name = "Category:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "Category:All extinct languages", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "Category:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"appendices", "entry maintenance", "lemmas", "names", "phrases", "rhymes", "symbols", "templates", "terms by etymology", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "terms derived from {{{langname}}}", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:All topics", sort = "all topics"})
insert(ret, {name = "Varieties of {{{langname}}}"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("[Ll]anguage$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) language$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^Languages of (.*)$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "Languages by country", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "Category:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("Category:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("Categories for languages of %s (including sublects)."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin languages", sort = {sort_base = "*" .. langname, lang = "en"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "en"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
1ghxkdr4eu8nrjgito6w3qxhk54bf0r
238816
238815
2026-11-12T07:27:59Z
Lee
19
පැරණි සංස්කරණයකින් ගත් කොටස්...
238816
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා සියල්ල"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|භාෂා පවුල් දළ ලෝක සිතියම]]",
description = "මෙම ප්රවර්ගය තුළ වික්ෂනරිය තුළ ඇති භාෂා සියල්ල සඳහා ම වන ප්රවර්ග අඩංගු වෙයි.",
additional = "වික්ෂනරිය තුළ පිළිගැනීමක් සහිත භාෂා සියල්ල සඳහා ම තවම මෙහි ප්රවර්ගයක් නොපැවතීමට ඉඩ ඇත. සියලුම වික්ෂනරි පරිශීලකයින් සෑම " ..
"භාෂාවක් පිළිබඳව ම නොදන්නා හෙයින්, තවමත් සංස්කාරකවරුන්ගේ අවධානයට ලක් නොවූ බොහෝ භාෂා " ..
"පැවතීමට ඉඩ ඇත. සම්පූර්ණ ලැයිස්තුව සඳහා [[වික්ෂනරි:භාෂා ලැයිස්තුව]] වෙතට යොමු වන්න.",
parents = {
"මූලධර්ම",
},
}
raw_categories["නෂ්ට වූ භාෂා සියල්ල"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "All extinct languages", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "All languages", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["රට අනුව භාෂා"] = {
topright = "{{commonscat|Languages by continent}}",
description = "රට අනුව භාෂා සමූහනය සිදු කරන ප්රවර්ග.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "ප්රවර්ගය:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
local frame = mw.getCurrentFrame()
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | ]=], wikt_plural, [=[ ]=], canonicalName, [=[ භාෂා '''වික්ෂණරි සංස්කරණය''':
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "ප්රවර්ගය:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 320px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ භාෂා සබැඳි'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|විකිපීඩියා]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''සිංහල විකිපීඩියා ලිපිය''':
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | '''විකිමීඩියා කොමන්ස්''' තුළ ]=], canonicalName, [=[ හා සබැඳි අන්තර්ගතය:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|ප්රවේශය]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | මෙම භාෂාවේ සිංහල නාමය සඳහා වන ''වික්ෂණරි ප්රවේශය''':
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("si"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|සම්පත්]]
|| ]=], canonicalName, [=[ ප්රවේශ සඳහා දායකත්වය සපයන සංස්කාරකවරු සඳහා වන '''වික්ෂණරි සම්පත්''':
<div style="padding: 5px 0">
* '''[[වික්ෂනරි:]=], canonicalName, [=[ ප්රවේශ මාර්ගෝපදේශ]]'''
* '''[[:ප්රවර්ගය:]=], canonicalName, [=[ මූලාශ්ර සැකිලි|මූලාශ්ර සැකිලි]] ({{PAGESINCAT:]=], canonicalName, [=[ මූලාශ්ර සැකිලි}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|ග්රන්ථනාමාවලිය]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "භාෂා දත්ත සංස්කරණය")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>කැනොනිකල් නාමය</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|භාෂා කේතය]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|භාෂා පවුල]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:ප්රවර්ගය:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:ප්රවර්ගය:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:ප්රවර්ගය:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:ප්රවර්ගය:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:ප්රවර්ගය:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:ප්රවර්ගය:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:ප්රවර්ගය:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:ප්රවර්ගය:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>පූර්වජයෝ</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>විකි දත්ත</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" භාෂාව$") then
the_prefix = ""
else
-- the_prefix = "the "
-- දැනට අවශ්ය නොවේ
the_prefix = ""
end
local description = "මෙය " .. the_prefix .. "'''" .. nameWithLanguage .. "''' සඳහා වන ප්රධාන ප්රවර්ගය වේ."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "පුරා"
insert(location_links, m_sinhala.sinhala(location))
elseif location ~= "UNKNOWN" then
this_prep = "තුළ"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(m_sinhala.sinhala(location)))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("එය %s %s %s.\n\n"):format(
location_link_text,
prep,
extinct and "an [[extinct language]] that was formerly spoken" or "භාවිතා වන භාෂාවකි")
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. canonicalName .. " බස පිළිබඳ තොරතුරු" .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the උපග්රන්ථය: namespace. " ..
"All terms in this language may be available at [[උපග්රන්ථය:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "si"}
local ret = {{name = "භාෂා සියල්ල", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "ප්රවර්ගය:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "ප්රවර්ගය:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "ප්රවර්ගය:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "ප්රවර්ගය:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "ප්රවර්ගය:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "ප්රවර්ගය:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:ප්රවර්ගය:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "ප්රවර්ගය:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "ප්රවර්ගය:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "ප්රවර්ගය:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "ප්රවර්ගය:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " භාවිතාවන භාෂා"
end
insert(ret, {name = "ප්රවර්ගය:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "ප්රවර්ගය:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = location .. " තුළ භාවිතා වන භාෂා"
insert(ret, {name = "ප්රවර්ගය:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "ප්රවර්ගය:නෂ්ට වූ භාෂා සියල්ල", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "ප්රවර්ගය:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"උපග්රන්ථ", "ප්රවේශ නඩත්තුව", "පාඨ", "නාම", "වාක්ය ඛණ්ඩ", "rhymes", "සංකේත", "සැකිලි", "යෙදුම්, නිරුක්තිය අනුව", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "යෙදුම්, {{{langname}}} වෙතින් ව්යුත්පන්න", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:මාතෘකා සියල්ල", sort = "මාතෘකා සියල්ල"})
insert(ret, {name = "{{{langname}}} ප්රභේද"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("භාෂාව$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) භාෂාව$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^(.*) තුළ භාවිතා වන භාෂා$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "රට අනුව භාෂා", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "ප්රවර්ගය:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("ප්රවර්ගය:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("%s තුළ භාවිතා වන භාෂා (including sublects) සඳහා වන ප්රවර්ග."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin භාෂා", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
t29wd18afe3nmrx3vm5f0je5o44egg5
238817
238816
2026-11-12T07:33:20Z
Lee
19
"All extinct languages" සිට "නෂ්ට වූ භාෂා සියල්ල" වෙතට
238817
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා සියල්ල"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|භාෂා පවුල් දළ ලෝක සිතියම]]",
description = "මෙම ප්රවර්ගය තුළ වික්ෂනරිය තුළ ඇති භාෂා සියල්ල සඳහා ම වන ප්රවර්ග අඩංගු වෙයි.",
additional = "වික්ෂනරිය තුළ පිළිගැනීමක් සහිත භාෂා සියල්ල සඳහා ම තවම මෙහි ප්රවර්ගයක් නොපැවතීමට ඉඩ ඇත. සියලුම වික්ෂනරි පරිශීලකයින් සෑම " ..
"භාෂාවක් පිළිබඳව ම නොදන්නා හෙයින්, තවමත් සංස්කාරකවරුන්ගේ අවධානයට ලක් නොවූ බොහෝ භාෂා " ..
"පැවතීමට ඉඩ ඇත. සම්පූර්ණ ලැයිස්තුව සඳහා [[වික්ෂනරි:භාෂා ලැයිස්තුව]] වෙතට යොමු වන්න.",
parents = {
"මූලධර්ම",
},
}
raw_categories["නෂ්ට වූ භාෂා සියල්ල"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "All languages", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "All languages", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "All languages", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["රට අනුව භාෂා"] = {
topright = "{{commonscat|Languages by continent}}",
description = "රට අනුව භාෂා සමූහනය සිදු කරන ප්රවර්ග.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "ප්රවර්ගය:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
local frame = mw.getCurrentFrame()
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | ]=], wikt_plural, [=[ ]=], canonicalName, [=[ භාෂා '''වික්ෂණරි සංස්කරණය''':
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "ප්රවර්ගය:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 320px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ භාෂා සබැඳි'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|විකිපීඩියා]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''සිංහල විකිපීඩියා ලිපිය''':
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | '''විකිමීඩියා කොමන්ස්''' තුළ ]=], canonicalName, [=[ හා සබැඳි අන්තර්ගතය:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|ප්රවේශය]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | මෙම භාෂාවේ සිංහල නාමය සඳහා වන ''වික්ෂණරි ප්රවේශය''':
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("si"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|සම්පත්]]
|| ]=], canonicalName, [=[ ප්රවේශ සඳහා දායකත්වය සපයන සංස්කාරකවරු සඳහා වන '''වික්ෂණරි සම්පත්''':
<div style="padding: 5px 0">
* '''[[වික්ෂනරි:]=], canonicalName, [=[ ප්රවේශ මාර්ගෝපදේශ]]'''
* '''[[:ප්රවර්ගය:]=], canonicalName, [=[ මූලාශ්ර සැකිලි|මූලාශ්ර සැකිලි]] ({{PAGESINCAT:]=], canonicalName, [=[ මූලාශ්ර සැකිලි}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|ග්රන්ථනාමාවලිය]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "භාෂා දත්ත සංස්කරණය")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>කැනොනිකල් නාමය</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|භාෂා කේතය]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|භාෂා පවුල]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:ප්රවර්ගය:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:ප්රවර්ගය:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:ප්රවර්ගය:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:ප්රවර්ගය:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:ප්රවර්ගය:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:ප්රවර්ගය:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:ප්රවර්ගය:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:ප්රවර්ගය:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>පූර්වජයෝ</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>විකි දත්ත</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" භාෂාව$") then
the_prefix = ""
else
-- the_prefix = "the "
-- දැනට අවශ්ය නොවේ
the_prefix = ""
end
local description = "මෙය " .. the_prefix .. "'''" .. nameWithLanguage .. "''' සඳහා වන ප්රධාන ප්රවර්ගය වේ."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "පුරා"
insert(location_links, m_sinhala.sinhala(location))
elseif location ~= "UNKNOWN" then
this_prep = "තුළ"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(m_sinhala.sinhala(location)))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("එය %s %s %s.\n\n"):format(
location_link_text,
prep,
extinct and "an [[extinct language]] that was formerly spoken" or "භාවිතා වන භාෂාවකි")
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. canonicalName .. " බස පිළිබඳ තොරතුරු" .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the උපග්රන්ථය: namespace. " ..
"All terms in this language may be available at [[උපග්රන්ථය:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "si"}
local ret = {{name = "භාෂා සියල්ල", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "ප්රවර්ගය:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "ප්රවර්ගය:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "ප්රවර්ගය:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "ප්රවර්ගය:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "ප්රවර්ගය:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "ප්රවර්ගය:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:ප්රවර්ගය:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "ප්රවර්ගය:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "ප්රවර්ගය:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "ප්රවර්ගය:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "ප්රවර්ගය:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " භාවිතාවන භාෂා"
end
insert(ret, {name = "ප්රවර්ගය:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "ප්රවර්ගය:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = location .. " තුළ භාවිතා වන භාෂා"
insert(ret, {name = "ප්රවර්ගය:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "ප්රවර්ගය:නෂ්ට වූ භාෂා සියල්ල", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "ප්රවර්ගය:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"උපග්රන්ථ", "ප්රවේශ නඩත්තුව", "පාඨ", "නාම", "වාක්ය ඛණ්ඩ", "rhymes", "සංකේත", "සැකිලි", "යෙදුම්, නිරුක්තිය අනුව", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "යෙදුම්, {{{langname}}} වෙතින් ව්යුත්පන්න", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:මාතෘකා සියල්ල", sort = "මාතෘකා සියල්ල"})
insert(ret, {name = "{{{langname}}} ප්රභේද"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("භාෂාව$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) භාෂාව$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^(.*) තුළ භාවිතා වන භාෂා$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "රට අනුව භාෂා", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "ප්රවර්ගය:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("ප්රවර්ගය:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("%s තුළ භාවිතා වන භාෂා (including sublects) සඳහා වන ප්රවර්ග."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin භාෂා", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
10n4bhqovvuauf12w73kkwzi9hzf517
238818
238817
2026-11-12T07:35:11Z
Lee
19
"All languages" සිට "භාෂා සියල්ල" වෙතට
238818
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා සියල්ල"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|භාෂා පවුල් දළ ලෝක සිතියම]]",
description = "මෙම ප්රවර්ගය තුළ වික්ෂනරිය තුළ ඇති භාෂා සියල්ල සඳහා ම වන ප්රවර්ග අඩංගු වෙයි.",
additional = "වික්ෂනරිය තුළ පිළිගැනීමක් සහිත භාෂා සියල්ල සඳහා ම තවම මෙහි ප්රවර්ගයක් නොපැවතීමට ඉඩ ඇත. සියලුම වික්ෂනරි පරිශීලකයින් සෑම " ..
"භාෂාවක් පිළිබඳව ම නොදන්නා හෙයින්, තවමත් සංස්කාරකවරුන්ගේ අවධානයට ලක් නොවූ බොහෝ භාෂා " ..
"පැවතීමට ඉඩ ඇත. සම්පූර්ණ ලැයිස්තුව සඳහා [[වික්ෂනරි:භාෂා ලැයිස්තුව]] වෙතට යොමු වන්න.",
parents = {
"මූලධර්ම",
},
}
raw_categories["නෂ්ට වූ භාෂා සියල්ල"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "භාෂා සියල්ල", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["රට අනුව භාෂා"] = {
topright = "{{commonscat|Languages by continent}}",
description = "රට අනුව භාෂා සමූහනය සිදු කරන ප්රවර්ග.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "ප්රවර්ගය:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
local frame = mw.getCurrentFrame()
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | ]=], wikt_plural, [=[ ]=], canonicalName, [=[ භාෂා '''වික්ෂණරි සංස්කරණය''':
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "ප්රවර්ගය:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 320px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ භාෂා සබැඳි'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|විකිපීඩියා]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''සිංහල විකිපීඩියා ලිපිය''':
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | '''විකිමීඩියා කොමන්ස්''' තුළ ]=], canonicalName, [=[ හා සබැඳි අන්තර්ගතය:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|ප්රවේශය]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | මෙම භාෂාවේ සිංහල නාමය සඳහා වන ''වික්ෂණරි ප්රවේශය''':
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("si"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|සම්පත්]]
|| ]=], canonicalName, [=[ ප්රවේශ සඳහා දායකත්වය සපයන සංස්කාරකවරු සඳහා වන '''වික්ෂණරි සම්පත්''':
<div style="padding: 5px 0">
* '''[[වික්ෂනරි:]=], canonicalName, [=[ ප්රවේශ මාර්ගෝපදේශ]]'''
* '''[[:ප්රවර්ගය:]=], canonicalName, [=[ මූලාශ්ර සැකිලි|මූලාශ්ර සැකිලි]] ({{PAGESINCAT:]=], canonicalName, [=[ මූලාශ්ර සැකිලි}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|ග්රන්ථනාමාවලිය]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "භාෂා දත්ත සංස්කරණය")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>කැනොනිකල් නාමය</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|භාෂා කේතය]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|භාෂා පවුල]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:ප්රවර්ගය:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:ප්රවර්ගය:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:ප්රවර්ගය:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:ප්රවර්ගය:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:ප්රවර්ගය:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:ප්රවර්ගය:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:ප්රවර්ගය:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:ප්රවර්ගය:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>පූර්වජයෝ</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>විකි දත්ත</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" භාෂාව$") then
the_prefix = ""
else
-- the_prefix = "the "
-- දැනට අවශ්ය නොවේ
the_prefix = ""
end
local description = "මෙය " .. the_prefix .. "'''" .. nameWithLanguage .. "''' සඳහා වන ප්රධාන ප්රවර්ගය වේ."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "පුරා"
insert(location_links, m_sinhala.sinhala(location))
elseif location ~= "UNKNOWN" then
this_prep = "තුළ"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(m_sinhala.sinhala(location)))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("එය %s %s %s.\n\n"):format(
location_link_text,
prep,
extinct and "an [[extinct language]] that was formerly spoken" or "භාවිතා වන භාෂාවකි")
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. canonicalName .. " බස පිළිබඳ තොරතුරු" .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the උපග්රන්ථය: namespace. " ..
"All terms in this language may be available at [[උපග්රන්ථය:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "si"}
local ret = {{name = "භාෂා සියල්ල", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "ප්රවර්ගය:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "ප්රවර්ගය:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "ප්රවර්ගය:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "ප්රවර්ගය:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "ප්රවර්ගය:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "ප්රවර්ගය:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:ප්රවර්ගය:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "ප්රවර්ගය:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "ප්රවර්ගය:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "ප්රවර්ගය:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "ප්රවර්ගය:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " භාවිතාවන භාෂා"
end
insert(ret, {name = "ප්රවර්ගය:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "ප්රවර්ගය:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = location .. " තුළ භාවිතා වන භාෂා"
insert(ret, {name = "ප්රවර්ගය:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "ප්රවර්ගය:නෂ්ට වූ භාෂා සියල්ල", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "ප්රවර්ගය:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"උපග්රන්ථ", "ප්රවේශ නඩත්තුව", "පාඨ", "නාම", "වාක්ය ඛණ්ඩ", "rhymes", "සංකේත", "සැකිලි", "යෙදුම්, නිරුක්තිය අනුව", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "යෙදුම්, {{{langname}}} වෙතින් ව්යුත්පන්න", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:මාතෘකා සියල්ල", sort = "මාතෘකා සියල්ල"})
insert(ret, {name = "{{{langname}}} ප්රභේද"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("භාෂාව$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) භාෂාව$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^(.*) තුළ භාවිතා වන භාෂා$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "රට අනුව භාෂා", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "ප්රවර්ගය:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("ප්රවර්ගය:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("%s තුළ භාවිතා වන භාෂා (including sublects) සඳහා වන ප්රවර්ග."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin භාෂා", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
atzikuoya5wbhb7uzz141jgxf6t2oty
238819
238818
2026-11-12T07:38:14Z
Lee
19
[[:ප්රවර්ගය:Bactrian භාෂාව]], [[:ප්රවර්ගය:Afghanistan තුළ භාවිතා වන භාෂා]] සිට [[:ප්රවර්ගය:ඇෆ්ගනිස්ථානය තුළ භාවිතා වන භාෂා]] වෙතට යොමු කිරීම
238819
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local new_title = mw.title.new
local ucfirst = require("Module:string utilities").ucfirst
local split = require("Module:string utilities").split
local raw_categories = {}
local raw_handlers = {}
local m_languages = require("Module:languages")
local m_sc_getByCode = require("Module:scripts").getByCode
local m_table = require("Module:table")
local parse_utilities_module = "Module:parse utilities"
local concat = table.concat
local insert = table.insert
local reverse_ipairs = m_table.reverseIpairs
local serial_comma_join = m_table.serialCommaJoin
local size = m_table.size
local sorted_pairs = m_table.sortedPairs
local to_json = require("Module:JSON").toJSON
local Hang = m_sc_getByCode("Hang")
local Hani = m_sc_getByCode("Hani")
local Hira = m_sc_getByCode("Hira")
local Hrkt = m_sc_getByCode("Hrkt")
local Kana = m_sc_getByCode("Kana")
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/languages/PAGE]]
return require("Module:debug/track")("category tree/languages/" .. page)
end
-- This handles language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]]; categories like [[:Category:Languages of Indonesia]]; categories like
-- [[:Category:English-based creole or pidgin languages]]; and categories like
-- [[:Category:English-based constructed languages]].
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා සියල්ල"] = {
topright = "{{commonscat|Languages}}\n[[File:Languages world map-transparent background.svg|thumb|right|250px|භාෂා පවුල් දළ ලෝක සිතියම]]",
description = "මෙම ප්රවර්ගය තුළ වික්ෂනරිය තුළ ඇති භාෂා සියල්ල සඳහා ම වන ප්රවර්ග අඩංගු වෙයි.",
additional = "වික්ෂනරිය තුළ පිළිගැනීමක් සහිත භාෂා සියල්ල සඳහා ම තවම මෙහි ප්රවර්ගයක් නොපැවතීමට ඉඩ ඇත. සියලුම වික්ෂනරි පරිශීලකයින් සෑම " ..
"භාෂාවක් පිළිබඳව ම නොදන්නා හෙයින්, තවමත් සංස්කාරකවරුන්ගේ අවධානයට ලක් නොවූ බොහෝ භාෂා " ..
"පැවතීමට ඉඩ ඇත. සම්පූර්ණ ලැයිස්තුව සඳහා [[වික්ෂනරි:භාෂා ලැයිස්තුව]] වෙතට යොමු වන්න.",
parents = {
"මූලධර්ම",
},
}
raw_categories["නෂ්ට වූ භාෂා සියල්ල"] = {
description = "Categories for every [[extinct language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Extinct languages]], which is an umbrella category for the names of extinct languages in specific other languages (e.g. {{m+|de|Langobardisch}} for the ancient [[Lombardic]] language).",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Reconstructed languages"] = {
description = "Categories for every [[Wiktionary:Reconstructed terms|reconstructed language]] on Wiktionary, and appendices for proposed proto-language reconstructions that are considered promising but have not yet gained general acceptance.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Appendix-only terms"] = {
description = "Terms that do not pass the [[WT:CFI|criteria for inclusion]], but are noteworthy enough to be included in the Appendix.",
additional = "Examples are dictionary-only terms (terms found in dictionaries but not elsewhere, including but not limited to [[ghost word]]s) and certain noteworthy [[protologism]]s.",
parents = {"Appendices"},
}
raw_categories["Appendix-only constructed languages"] = {
description = "[[constructed language|Constructed languages]] that per the [[WT:CFI|criteria for inclusion]], may not be present in the main namespace, but may have entries in the {{cd|Appendix:}} namespace.",
additional = "For instance, all terms in Klingon may be available at [[Appendix:Klingon]].",
breadcrumb = "appendix-only",
parents = {
{name = "Constructed languages", sort = " "},
"Appendix-only terms",
},
}
raw_categories["Unattested languages"] = {
description = "Categories for languages of which there are no written records and which have not been reconstructed based on their descendants.",
additional = "Most of these are [[w:Stratum (linguistics)#Unattested substrata|unattested substrate languages]] that have been proposed as sources of vocabulary in certain languages.",
parents = {
{name = "නෂ්ට වූ භාෂා සියල්ල", sort = " "},
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Unwritten languages"] = {
description = "Categories for every [[unwritten]] [[language]] on Wiktionary.",
additional = "Do not confuse this category with [[:Category:Unspecified script languages]], which contains categories for languages that may be written but where the appropriate script has not yet been specified in the language data.",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages with automatic transliteration"] = {
preceding = "{{also|:Category:Terms with redundant transliterations by language|:Category:Terms with non-redundant manual transliterations by language}}",
description = "Categories for languages with automatic [[transliteration]], i.e. which have the name of a transliteration module listed in their [[:Category:Language data modules|language data table]].",
additional = [=[For example, for {{lnl|hi}}, {{lua|1=translit_module = "hi-translit"}}, referring to [[Module:hi-translit]]). The [[:Category:Transliteration modules|transliteration module]] converts the language's native script into a Latin-script version (a transliteration), which is then displayed in templates like {{tl|l}}, {{tl|m}} and {{tl|head}}.]=],
parents = {
{name = "භාෂා සියල්ල", sort = " "},
{name = "Transliteration modules", sort = " "},
}
}
raw_categories["රට අනුව භාෂා"] = {
topright = "{{commonscat|Languages by continent}}",
description = "රට අනුව භාෂා සමූහනය සිදු කරන ප්රවර්ග.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
{name = "භාෂා සියල්ල", sort = " "},
},
}
raw_categories["Languages not sorted into a location category"] = {
description = "Languages which do not specify (in their {{tl|auto cat}} call) the location(s) where they are spoken.",
additional = "This excludes constructed and reconstructed languages; as a result, all languages in this category explicitly specify their location as {{cd|UNKNOWN}}.",
parents = {
{name = "Requests"},
},
hidden = true,
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
-- Given a category (without the "ප්රවර්ගය:" prefix), look up the page
-- defining the category, find the call to {{auto cat}} (if any),
-- and return a table of its arguments. If the category page doesn't exist
-- or doesn't have an {{auto cat}} invocation, return nil.
-- FIXME: Duplicated in [[Module:category tree/lects]].
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
local frame = mw.getCurrentFrame()
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and
-- canonicalizes them.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
local function link_location(location)
local location_no_the = location:match("^the (.*)$")
local bare_location = location_no_the or location
local bare_location_parts = split(bare_location, ", ")
for i, part in ipairs(bare_location_parts) do
bare_location_parts[i] = ("[[%s]]"):format(part)
end
local location_link = concat(bare_location_parts, ", ")
if location_no_the then location_link = "the " .. location_link end
return location_link
end
local function linkbox(lang, setwiki, setwikt, setsister, entryname)
local wiktionarylinks = {}
local canonicalName = lang:getCanonicalName()
local wikimediaLanguages = lang:getWikimediaLanguages()
local wikipediaArticle = setwiki or lang:getWikipediaArticle(true)
setwiki = not wikipediaArticle and "-"
setsister = setsister and ucfirst(setsister) or nil
if setwikt then
track("setwikt")
if setwikt == "-" then track("setwikt/hyphen") end
end
if setwikt ~= "-" and wikimediaLanguages and wikimediaLanguages[1] then
for _, wikimedialang in ipairs(wikimediaLanguages) do
local check = new_title(wikimedialang:getCode() .. ":")
if check and check.isExternal then
insert(wiktionarylinks,
(
wikimedialang:getCanonicalName() ~= canonicalName
and "(''" .. wikimedialang:getCanonicalName() .. "'') "
or ""
) .. (
"'''[[:" .. wikimedialang:getCode()
.. ":|" .. wikimedialang:getCode()
.. ".wiktionary.org]]'''"
)
)
end
end
wiktionarylinks = concat(wiktionarylinks, "<br/>")
end
local wikt_plural = wikimediaLanguages[2] and "s" or ""
if #wiktionarylinks == 0 then
wiktionarylinks = "''None.''"
end
-- Avoid showing Wiktionary links section for reconstructed languages,
-- as they are ineligible for Wiktionary editions
local wiktionarylinks_chunk = concat{
[=[|-
| style="vertical-align: top; height: 35px; width: 40px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Wiktionary-logo-v2.svg|35px|none|link=|Wiktionary]]
|style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | ]=], wikt_plural, [=[ ]=], canonicalName, [=[ භාෂා '''වික්ෂණරි සංස්කරණය''':
<div style="padding: 5px 10px">]=], wiktionarylinks, [=[</div>
]=]}
if lang:hasType('reconstructed') then
wiktionarylinks_chunk = ''
end
if setsister then
track("setsister")
if setsister == "-" then
track("setsister/hyphen")
else
setsister = "ප්රවර්ගය:" .. setsister
end
else
setsister = lang:getCommonsCategory() or "-"
end
return concat{ -- FIXME: Bare wikicode
[=[<div class="wikitable" style="float: right; clear: right; margin: 0 0 0.5em 1em; width: 320px; padding: 5px;">
<div style="text-align: center; margin-bottom: 10px; margin-top: 5px">''']=], canonicalName, [=[ භාෂා සබැඳි'''</div>
{| style="font-size: 90%"
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | [[File:Wikipedia-logo.png|35px|none|link=|විකිපීඩියා]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | '''සිංහල විකිපීඩියා ලිපිය''':
<div style="padding: 5px 10px">]=], (setwiki == "-" and "''None.''" or "'''[[w:" .. wikipediaArticle .. "|" .. wikipediaArticle .. "]]'''"), [=[</div>
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Commons-logo.svg|35px|none|link=|Wikimedia Commons]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | '''විකිමීඩියා කොමන්ස්''' තුළ ]=], canonicalName, [=[ හා සබැඳි අන්තර්ගතය:
<div style="padding: 5px 10px">]=], (setsister == "-" and "''None.''" or "'''[[commons:" .. setsister .. "|" .. setsister .. "]]'''"), [=[</div>
]=], wiktionarylinks_chunk, [=[
|-
| style="vertical-align: top; height: 35px; border-bottom: 1px solid var(--wikt-palette-grey-4, lightgray);" | [[File:Codex icon articles color-placeholder (v2.6).svg|35px|none|link=|ප්රවේශය]]
| style="border-bottom: 1px solid var(--wikt-palette-grey-4,lightgray);" | මෙම භාෂාවේ සිංහල නාමය සඳහා වන ''වික්ෂණරි ප්රවේශය''':
<div style="padding: 5px 10px">''']=], require("Module:links").full_link({lang = m_languages.getByCode("si"), term = entryname or canonicalName}), [=['''</div>
|-
| style="vertical-align: top; height: 35px;" | [[File:Codex icon book color-placeholder (v2.6).svg|35px|none|link=|සම්පත්]]
|| ]=], canonicalName, [=[ ප්රවේශ සඳහා දායකත්වය සපයන සංස්කාරකවරු සඳහා වන '''වික්ෂණරි සම්පත්''':
<div style="padding: 5px 0">
* '''[[වික්ෂනරි:]=], canonicalName, [=[ ප්රවේශ මාර්ගෝපදේශ]]'''
* '''[[:ප්රවර්ගය:]=], canonicalName, [=[ මූලාශ්ර සැකිලි|මූලාශ්ර සැකිලි]] ({{PAGESINCAT:]=], canonicalName, [=[ මූලාශ්ර සැකිලි}})'''
* '''[[Appendix:]=], canonicalName, [=[ bibliography|ග්රන්ථනාමාවලිය]]'''
</div>
|}
</div>]=]
}
end
local function edit_link(title, text)
return '<span class="plainlinks">['
.. tostring(mw.uri.fullUrl(title, { action = "edit" }))
.. ' ' .. text .. ']</span>'
end
-- Should perhaps use wiki syntax.
local function infobox(lang)
local ret = {}
insert(ret, '<table class="wikitable language-category-info"')
local raw_data = lang:getData("extra")
if raw_data then
local replacements = {
[1] = "canonical-name",
[2] = "wikidata-item",
[3] = "family",
[4] = "scripts",
}
local function replacer(letter1, letter2)
return letter1:lower() .. "-" .. letter2:lower()
end
-- For each key in the language data modules, returns a descriptive
-- kebab-case version (containing ASCII lowercase words separated
-- by hyphens).
local function kebab_case(key)
key = replacements[key] or key
key = key:gsub("(%l)(%u)", replacer):gsub("(%l)_(%l)", replacer)
return key
end
local compress = {compress = true}
local function html_attribute_encode(str)
str = to_json(str, compress)
:gsub('"', """)
-- & in attributes is automatically escaped.
-- :gsub("&", "&")
:gsub("<", "<")
:gsub(">", ">")
return str
end
insert(ret, ' data-code="' .. lang:getCode() .. '"')
for k, v in sorted_pairs(raw_data) do
insert(ret, " data-" .. kebab_case(k)
.. '="'
.. html_attribute_encode(v)
.. '"')
end
end
insert(ret, '>\n')
insert(ret, '<tr class="language-category-data">\n<th colspan="2">'
.. edit_link(lang:getDataModuleName(), "භාෂා දත්ත සංස්කරණය")
.. "</th>\n</tr>\n")
insert(ret, "<tr>\n<th>කැනොනිකල් නාමය</th><td>" .. lang:getCanonicalName() .. "</td>\n</tr>\n")
local otherNames = lang:getOtherNames()
if otherNames then
local names = {}
for _, name in ipairs(otherNames) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Other names</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local aliases = lang:getAliases()
if aliases then
local names = {}
for _, name in ipairs(aliases) do
insert(names, "<li>" .. name .. "</li>")
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Aliases</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
local varieties = lang:getVarieties()
if varieties then
local names = {}
for _, name in ipairs(varieties) do
if type(name) == "string" then
insert(names, "<li>" .. name .. "</li>")
else
assert(type(name) == "table")
local first_var
local subvars = {}
for i, var in ipairs(name) do
if i == 1 then
first_var = var
else
insert(subvars, "<li>" .. var .. "</li>")
end
end
if #subvars > 0 then
insert(names, (
"<li><dl><dt>"
.. first_var .. "</dt>\n<dd><ul>"
.. concat(subvars, "\n")
.. "</ul></dd></dl></li>"
)
)
elseif first_var then
insert(names, "<li>" .. first_var .. "</li>")
end
end
end
if #names > 0 then
insert(ret, (
"<tr>\n<th>Varieties</th><td><ul>"
.. concat(names, "\n")
.. "</ul></td>\n</tr>\n"
)
)
end
end
insert(ret, (
"<tr>\n<th>[[Wiktionary:Languages|භාෂා කේතය]]</th><td><code>"
.. lang:getCode()
.. "</code></td>\n</tr>\n"
)
)
insert(ret, "<tr>\n<th>[[Wiktionary:Families|භාෂා පවුල]]</th>\n")
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
if not fam then
insert(ret, "<td>[[:ප්රවර්ගය:Unassigned languages|unassigned]]</td>")
elseif famCode == "qfa-dis" then
insert(ret, "<td>[[:ප්රවර්ගය:Languages of disputed affiliation|disputed affiliation]]</td>")
elseif famCode == "qfa-iso" then
insert(ret, "<td>[[:ප්රවර්ගය:Language isolates|language isolate]]</td>")
elseif famCode == "qfa-mix" then
insert(ret, "<td>[[:ප්රවර්ගය:Mixed languages|mixed language]]</td>")
elseif famCode == "qfa-unc" then
insert(ret, "<td>[[:ප්රවර්ගය:Unclassifiable languages|unclassifiable language]]</td>")
elseif famCode == "sgn" then
insert(ret, "<td>[[:ප්රවර්ගය:Sign languages|sign language]]</td>")
elseif famCode == "crp" then
insert(ret, "<td>[[:ප්රවර්ගය:Creole or pidgin languages|creole or pidgin]]</td>")
elseif famCode == "art" then
insert(ret, "<td>[[:ප්රවර්ගය:Constructed languages|constructed language]]</td>")
else
insert(ret, "<td>" .. fam:makeCategoryLink() .. "</td>")
end
insert(ret, "\n</tr>\n<tr>\n<th>පූර්වජයෝ</th>\n<td>")
local ancestors = lang:getAncestors()
if ancestors[2] then
local ancestorList = {}
for i, anc in ipairs(ancestors) do
ancestorList[i] = "<li>" .. anc:makeCategoryLink() .. "</li>"
end
insert(ret, "<ul>\n" .. concat(ancestorList, "\n") .. "</ul>")
else
local ancestorChain = lang:getAncestorChainOld()
if ancestorChain[1] then
local chain = {}
for _, anc in reverse_ipairs(ancestorChain) do
insert(chain, "<li>" .. anc:makeCategoryLink() .. "</li>")
end
insert(ret, "<ul>\n" .. concat(chain, "\n<ul>\n") .. ("</ul>"):rep(#chain))
else
insert(ret, "unknown")
end
end
insert(ret, "</td>\n</tr>\n")
local scripts = lang:getScripts()
if scripts[1] then
local script_text = {}
local function makeScriptLine(sc)
local code = sc:getCode()
local url = tostring(mw.uri.fullUrl('Special:Search', {
search = 'contentmodel:css insource:"' .. code
.. '" insource:/\\.' .. code .. '/',
ns8 = '1'
}))
local sc_catlink
if code == "Zxxx" then
sc_catlink = "[[:Category:Unwritten languages|unwritten]]"
else
sc_catlink = sc:makeCategoryLink(lang)
end
return sc_catlink
.. ' (<span class="plainlinks" title="Search for stylesheets referencing this script">[' .. url .. ' <code>' .. code .. '</code>]</span>)'
end
local function add_Hrkt(text)
insert(text, "<li>" .. makeScriptLine(Hrkt))
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hira) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Kana) .. "</li>")
insert(text, "</ul>")
insert(text, "</li>")
end
for _, sc in ipairs(scripts) do
local text = {}
local code = sc:getCode()
if code == "Hrkt" then
add_Hrkt(text)
else
insert(text, "<li>" .. makeScriptLine(sc))
if code == "Jpan" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
add_Hrkt(text)
insert(text, "</ul>")
elseif code == "Kore" then
insert(text, "<ul>")
insert(text, "<li>" .. makeScriptLine(Hang) .. "</li>")
insert(text, "<li>" .. makeScriptLine(Hani) .. "</li>")
insert(text, "</ul>")
end
insert(text, "</li>")
end
insert(script_text, concat(text, "\n"))
end
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td><ul>\n" .. concat(script_text, "\n") .. "</ul></td>\n</tr>\n")
else
insert(ret, "<tr>\n<th>[[වික්ෂනරි:අක්ෂර ක්රම|අක්ෂරක්රම]]</th>\n<td>not specified</td>\n</tr>\n")
end
local function add_module_info(raw_data, heading)
if raw_data then
local scripts = lang:getScriptCodes()
local module_info, add = {}, false
if type(raw_data) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data))
add = true
else
local raw_data_type = type(raw_data)
if raw_data_type == "table" and size(scripts) == 1 and type(raw_data[scripts[1]]) == "string" then
insert(module_info,
("[[Module:%s]]"):format(raw_data[scripts[1]]))
add = true
elseif raw_data_type == "table" then
insert(module_info, "<ul>")
for script, data in sorted_pairs(raw_data) do
if type(data) == "string" and m_sc_getByCode(script) then
insert(module_info, ("<li><code>%s</code>: [[Module:%s]]</li>"):format(script, data))
end
end
insert(module_info, "</ul>")
add = size(module_info) > 2
end
end
if add then
insert(ret, [=[
<tr>
<th>]=] .. heading .. [=[</th>
<td>]=] .. concat(module_info) .. [=[</td>
</tr>
]=])
end
end
end
add_module_info(raw_data.generate_alternants, "Alternant-generating<br>module")
add_module_info(raw_data.translit, "[[Wiktionary:Transliteration and romanization|Transliteration<br>module]]")
add_module_info(raw_data.display_text, "Display text<br>module")
add_module_info(raw_data.strip_diacritics, "Diacritic-stripping<br>module")
add_module_info(raw_data.sort_key, "[[sortkey|Sortkey]]<br>module")
local wikidataItem = lang:getWikidataItem()
if lang:getWikidataItem() and mw.wikibase then
local URL = mw.wikibase.getEntityUrl(wikidataItem)
local link
if URL then
link = '[[d:' .. wikidataItem .. '|' .. wikidataItem .. ']]'
else
link = '<span class="error">Invalid Wikidata item: <code>' .. wikidataItem .. '</code></span>'
end
insert(ret, "<tr><th>විකි දත්ත</th><td>" .. link .. "</td></tr>")
end
insert(ret, "</table>")
return concat(ret)
end
local function NavFrame_for_family_tree(content, title)
return '<div class="NavFrame"><div class="NavHead">'
.. (title or '{{{title}}}') .. '</div>'
.. '<div class="NavContent" style="text-align: left; font-size: calc(1em / 0.95); padding: 0.3em">'
.. content
.. '</div></div>'
end
local function get_description_topright_additional(lang, locations, extinct, setwiki, setwikt, setsister, entryname)
local nameWithLanguage = lang:getCategoryName("nocap")
if lang:getCode() == "und" then
local description =
"This is the main category of the '''" .. nameWithLanguage .. "''', represented in Wiktionary by the [[Wiktionary:Languages|code]] '''" .. lang:getCode() .. "'''. " ..
"This language contains terms in historical writing, whose meaning has not yet been determined by scholars."
return description, nil, nil
end
local canonicalName = lang:getCanonicalName()
local topright = linkbox(lang, setwiki, setwikt, setsister, entryname)
local the_prefix
if canonicalName:find(" භාෂාව$") then
the_prefix = ""
else
-- the_prefix = "the "
-- දැනට අවශ්ය නොවේ
the_prefix = ""
end
local description = "මෙය " .. the_prefix .. "'''" .. nameWithLanguage .. "''' සඳහා වන ප්රධාන ප්රවර්ගය වේ."
local location_links = {}
local prep
local saw_embedded_comma = false
for _, location in ipairs(locations) do
local this_prep
if location == "the world" then
this_prep = "පුරා"
insert(location_links, m_sinhala.sinhala(location))
elseif location ~= "UNKNOWN" then
this_prep = "තුළ"
if location:find(",") then
saw_embedded_comma = true
end
insert(location_links, link_location(m_sinhala.sinhala(location)))
end
if this_prep then
if prep and this_prep ~= prep then
error("Can't handle location 'the world' along with another location (clashing prepositions)")
end
prep = this_prep
end
end
local location_desc
if #location_links > 0 then
local location_link_text
if saw_embedded_comma and #location_links >= 3 then
location_link_text = mw.text.listToText(location_links, "; ", "; and ")
else
location_link_text = serial_comma_join(location_links)
end
location_desc = ("එය %s %s %s.\n\n"):format(
location_link_text,
prep,
extinct and "an [[extinct language]] that was formerly spoken" or "භාවිතා වන භාෂාවකි")
elseif extinct then
location_desc = "It is an [[extinct language]].\n\n"
else
location_desc = ""
end
local add = location_desc .. canonicalName .. " බස පිළිබඳ තොරතුරු" .. ":\n\n" .. infobox(lang)
if lang:hasType("reconstructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a reconstructed language. Its words and roots are not directly attested in any written works, but have been reconstructed through the ''comparative method'', " ..
"which finds regular similarities between languages that cannot be explained by coincidence or word-borrowing, and extrapolates ancient forms from these similarities.\n\n" ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the Reconstruction: namespace."
elseif lang:hasType("appendix-constructed") then
add = add .. "\n\n" ..
ucfirst(canonicalName) .. " is a constructed language that is only in sporadic use. " ..
"According to our [[Wiktionary:Criteria for inclusion|criteria for inclusion]], terms in " .. canonicalName ..
" should '''not''' be present in entries in the main namespace, but may be added to the උපග්රන්ථය: namespace. " ..
"All terms in this language may be available at [[උපග්රන්ථය:" .. ucfirst(canonicalName) .. "]]."
end
local entry_guidelines_page = "Wiktionary:" .. canonicalName .. " entry guidelines"
local entry_guidelines = new_title(entry_guidelines_page)
if entry_guidelines.exists then
add = add .. "\n\n" ..
"Please see '''[[" .. entry_guidelines_page .. "]]''' for information and special considerations for creating " .. nameWithLanguage .. " entries."
end
local ok, tree_of_descendants = pcall(
require("Module:family tree").render,
lang:getCode(), {
families = "show",
varieties = "show",
pair = "family-first",
must_have_descendants = true,
})
if ok then
if tree_of_descendants then
add = add .. NavFrame_for_family_tree(
tree_of_descendants,
"Family tree")
else
add = add .. "\n\n" .. ucfirst(lang:getCanonicalName())
.. " has no descendants or varieties listed in Wiktionary's language data modules."
end
else
mw.log("error while generating tree: " .. tostring(tree_of_descendants))
end
return description, topright, add
end
local function get_parents(lang, locations, extinct)
local canonicalName = lang:getCanonicalName()
local sortkey = {sort_base = canonicalName, lang = "si"}
local ret = {{name = "භාෂා සියල්ල", sort = sortkey}}
local fam = lang:getFamily()
local famCode = fam and fam:getCode()
-- FIXME: Some of the following categories should be added to this module.
if not fam then
insert(ret, {name = "ප්රවර්ගය:Unassigned languages", sort = sortkey})
elseif famCode == "qfa-dis" then
insert(ret, {name = "ප්රවර්ගය:Languages of disputed affiliation", sort = sortkey})
elseif famCode == "qfa-iso" then
insert(ret, {name = "ප්රවර්ගය:Language isolates", sort = sortkey})
elseif famCode == "qfa-mix" then
insert(ret, {name = "ප්රවර්ගය:Mixed languages", sort = sortkey})
elseif famCode == "qfa-unc" then
insert(ret, {name = "ප්රවර්ගය:Unclassifiable languages", sort = sortkey})
elseif famCode == "crp" then
insert(ret, {name = "ප්රවර්ගය:Creole or pidgin languages", sort = sortkey})
for _, anc in ipairs(lang:getAncestors()) do
-- Avoid Haitian Creole being categorised in [[:ප්රවර්ගය:Haitian Creole-based creole or pidgin languages]], as one of its ancestors is an etymology-only variety of it.
-- Use that ancestor's ancestors instead.
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based creole or pidgin languages", sort = sortkey})
end
end
elseif famCode == "art" then
if lang:hasType("appendix-constructed") then
insert(ret, {name = "ප්රවර්ගය:Appendix-only constructed languages", sort = sortkey})
else
insert(ret, {name = "ප්රවර්ගය:Constructed languages", sort = sortkey})
end
for _, anc in ipairs(lang:getAncestors()) do
if anc:getFullCode() == lang:getCode() then
for _, anc_extra in ipairs(anc:getAncestors()) do
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc_extra:getFullName()) .. "-based constructed languages", sort = sortkey})
end
else
insert(ret, {name = "ප්රවර්ගය:" .. ucfirst(anc:getFullName()) .. "-based constructed languages", sort = sortkey})
end
end
else
insert(ret, {name = "ප්රවර්ගය:" .. fam:getCategoryName(), sort = sortkey})
if lang:hasType("reconstructed") then
insert(ret, {
name = "ප්රවර්ගය:Reconstructed languages",
sort = {sort_base = canonicalName:gsub("^Proto%-", ""), lang = "en"}
})
end
end
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
insert(ret, {name = "Category:" .. pseudofam:getCategoryName(), sort = sortkey})
end
local function add_sc_cat(sc)
local catname
if sc:getCode() == "Zxxx" then
catname = "Unwritten languages"
else
catname = sc:getCategoryName(false, lang) .. " භාවිතාවන භාෂා"
end
insert(ret, {name = "ප්රවර්ගය:" .. catname, sort = sortkey})
end
local function add_Hrkt()
add_sc_cat(Hrkt)
add_sc_cat(Hira)
add_sc_cat(Kana)
end
for _, sc in ipairs(lang:getScripts()) do
if sc:getCode() == "Hrkt" then
add_Hrkt()
else
add_sc_cat(sc)
if sc:getCode() == "Jpan" then
add_sc_cat(Hani)
add_Hrkt()
elseif sc:getCode() == "Kore" then
add_sc_cat(Hang)
add_sc_cat(Hani)
end
end
end
if lang:hasTranslit() then
insert(ret, {name = "ප්රවර්ගය:Languages with automatic transliteration", sort = sortkey})
end
local function insert_location_language_cat(location)
local cat = m_sinhala.sinhala(location) .. " තුළ භාවිතා වන භාෂා"
insert(ret, {name = "ප්රවර්ගය:" .. cat, sort = sortkey})
local auto_cat_args = scrape_category_for_auto_cat_args(cat)
local location_parent = auto_cat_args and auto_cat_args.parent
if location_parent then
local split_parents = require(parse_utilities_module).split_on_comma(location_parent)
for _, parent in ipairs(split_parents) do
parent = parent:match("^(.-):.*$") or parent
insert_location_language_cat(parent)
end
end
end
local saw_location = false
for _, location in ipairs(locations) do
if location ~= "UNKNOWN" then
saw_location = true
insert_location_language_cat(location)
end
end
if extinct then
insert(ret, {name = "ප්රවර්ගය:නෂ්ට වූ භාෂා සියල්ල", sort = sortkey})
end
if not saw_location and not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
-- Constructed and reconstructed languages don't need a location specified and often won't have one,
-- so don't put them in this maintenance category.
insert(ret, {name = "ප්රවර්ගය:Languages not sorted into a location category", sort = sortkey})
end
return ret
end
local function get_children()
local ret = {}
-- FIXME: We should work on the children mechanism so it isn't necessary to manually specify these.
for _, label in ipairs({"උපග්රන්ථ", "ප්රවේශ නඩත්තුව", "පාඨ", "නාම", "වාක්ය ඛණ්ඩ", "rhymes", "සංකේත", "සැකිලි", "යෙදුම්, නිරුක්තිය අනුව", "terms by usage"}) do
insert(ret, {name = label, is_label = true})
end
insert(ret, {name = "යෙදුම්, {{{langname}}} වෙතින් ව්යුත්පන්න", is_label = true, lang = false})
insert(ret, {name = "{{{langcode}}}:මාතෘකා සියල්ල", sort = "මාතෘකා සියල්ල"})
insert(ret, {name = "{{{langname}}} ප්රභේද"})
insert(ret, {name = "Requests concerning {{{langname}}}"})
insert(ret, {name = "Rhymes:{{{langname}}}", description = "Lists of {{{langname}}} words by their rhymes."})
insert(ret, {name = "User {{{langcode}}}", description = "Wiktionary users categorized by fluency levels in {{{langdisp}}}."})
return ret
end
-- Handle language categories of the form e.g. [[:Category:French language]] and
-- [[:Category:British Sign Language]].
insert(raw_handlers, function(data)
local category = data.category
if not (category:find("භාෂාව$") or category:find("[Ll]ect$")) then
return nil
end
local lang = m_languages.getByCanonicalName(category)
if not lang then
local langname = category:match("^(.*) භාෂාව$")
if langname then
lang = m_languages.getByCanonicalName(langname)
end
if not lang then
return nil
end
end
local args = require("Module:parameters").process(data.args, {
[1] = {list = true},
["setwiki"] = true,
["setwikt"] = true,
["setsister"] = true,
["entryname"] = true,
["extinct"] = {type = "boolean"},
})
-- If called from inside, don't require any arguments, as they can't be known
-- in general and aren't needed just to generate the first parent (used for
-- breadcrumbs).
if #args[1] == 0 and not data.called_from_inside then
-- At least one location must be specified unless the language is constructed (e.g. Esperanto) or reconstructed (e.g. Proto-Indo-European).
local fam = lang:getFamily()
if not (lang:hasType("reconstructed") or (fam and fam:getCode() == "art")) then
error("At least one location (param 1=) must be specified for language '" .. lang:getCanonicalName() .. "' (code '" .. lang:getCode() .. "'). " ..
"Use the value UNKNOWN if the language's location is truly unknown.")
end
end
local description, topright, additional = "", "", ""
-- If called from inside the category tree system, it's called when generating
-- parents or children, and we don't need to generate the description or additional
-- text (which is very expensive in terms of memory because it calls [[Module:family tree]],
-- which calls [[Module:languages/data/all]]).
if not data.called_from_inside then
description, topright, additional = get_description_topright_additional(
lang, args[1], args.extinct, args.setwiki, args.setwikt, args.setsister, args.entryname
)
end
return {
canonical_name = lang:getCategoryName(),
description = description,
lang = lang:getCode(),
topright = topright,
additional = additional,
breadcrumb = lang:getCanonicalName(),
parents = get_parents(lang, args[1], args.extinct),
extra_children = get_children(lang),
umbrella = false,
can_be_empty = true,
}, true
end)
-- Handle categories such as [[:Category:Languages of Indonesia]].
insert(raw_handlers, function(data)
local location = data.category:match("^(.*) තුළ භාවිතා වන භාෂා$")
if location then
local args = require("Module:parameters").process(data.args, {
["flagfile"] = true,
["commonscat"] = true,
["wp"] = true,
["basename"] = true,
["parent"] = true,
["locationcat"] = true,
["locationlink"] = true,
})
local topright
local basename = args.basename or location:gsub(", .*", "")
if args.flagfile ~= "-" then
local flagfile_arg = args.flagfile or ("Flag of %s.svg"):format(basename)
local files = require(parse_utilities_module).split_on_comma(flagfile_arg)
local topright_parts = {}
for _, file in ipairs(files) do
local flagfile = "File:" .. file
local flagfile_page = new_title(flagfile)
if flagfile_page and flagfile_page.file.exists then
insert(topright_parts, ("[[%s|right|100px|border]]"):format(flagfile))
elseif args.flagfile then
error(("Explicit flagfile '%s' doesn't exist"):format(flagfile))
end
end
topright = concat(topright_parts)
end
if args.wp then
local wp = require("Module:yesno")(args.wp, "+")
if wp == "+" or wp == true then
wp = data.category
end
if wp then
local wp_topright = ("{{wikipedia|%s}}"):format(wp)
if topright then
topright = topright .. wp_topright
else
topright = wp_topright
end
end
end
if args.commonscat then
local commonscat = require("Module:yesno")(args.commonscat, "+")
if commonscat == "+" or commonscat == true then
commonscat = data.category
end
if commonscat then
local commons_topright = ("{{commonscat|%s}}"):format(commonscat)
if topright then
topright = topright .. commons_topright
else
topright = commons_topright
end
end
end
local bare_location = location:match("^the (.*)$") or location
local location_link = args.locationlink or link_location(location)
local bare_basename = basename:match("^the (.*)$") or basename
local parents = {}
if args.parent then
local explicit_parents = require(parse_utilities_module).split_on_comma(args.parent)
for i, parent in ipairs(explicit_parents) do
local actual_parent, sort_key = parent:match("^(.-):(.*)$")
if actual_parent then
parent = actual_parent
sort_key = sort_key:gsub("%+", bare_location)
else
sort_key = " " .. bare_location
end
insert(parents, {name = "Languages of " .. parent, sort = sort_key})
end
else
insert(parents, {name = "රට අනුව භාෂා", sort = {sort_base = bare_location, lang = "en"}})
end
if args.locationcat then
local explicit_location_cats = require(parse_utilities_module).split_on_comma(args.locationcat)
for i, locationcat in ipairs(explicit_location_cats) do
insert(parents, {name = "ප්රවර්ගය:" .. locationcat, sort = " Languages"})
end
else
local location_cat = ("ප්රවර්ගය:%s"):format(bare_location)
local location_page = new_title(location_cat)
if location_page and location_page.exists then
insert(parents, {name = location_cat, sort = "Languages"})
end
end
local description = ("%s තුළ භාවිතා වන භාෂා (including sublects) සඳහා වන ප්රවර්ග."):format(location_link)
return {
topright = topright,
description = description,
parents = parents,
breadcrumb = bare_basename,
additional = "{{{umbrella_msg}}}",
}, true
end
end)
-- Handle categories such as [[:Category:English-based creole or pidgin languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based creole or pidgin languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Languages which developed as a [[creole]] or [[pidgin]] from " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Creole or pidgin භාෂා", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
-- Handle categories such as [[:Category:English-based constructed languages]].
insert(raw_handlers, function(data)
local langname = data.category:match("(.*)%-based constructed languages$")
if langname then
local lang = m_languages.getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Constructed languages which are based on " .. lang:makeCategoryLink() .. ".",
parents = {{name = "Constructed languages", sort = {sort_base = "*" .. langname, lang = "si"}}},
breadcrumb = lang:getCanonicalName() .. "-based",
}
end
end
end)
return {
RAW_CATEGORIES = raw_categories,
RAW_HANDLERS = raw_handlers
}
0tbg5oy7rvti7slcweqsnszbxck7amm
Module:links/templates
828
7932
238836
227026
2026-09-17T06:05:07Z
en>Benwing2
0
show_qualifiers -> show_decorations
238836
Scribunto
text/plain
-- Prevent substitution.
if mw.isSubsting() then
return require("Module:unsubst")
end
local export = {}
local links_module = "Module:links"
local process_params = require("Module:parameters").process
local remove = table.remove
local upper = require("Module:string utilities").upper
--[=[
Modules used:
[[Module:links]]
[[Module:languages]]
[[Module:scripts]]
[[Module:parameters]]
[[Module:debug]]
]=]
do
local function get_args(frame)
-- `compat` is a compatibility mode for {{term}}.
-- If given a nonempty value, the function uses lang= to specify the
-- language, and all the positional parameters shift one number lower.
local iargs = frame.args
iargs.compat = iargs.compat and iargs.compat ~= ""
iargs.langname = iargs.langname and iargs.langname ~= ""
iargs.notself = iargs.notself and iargs.notself ~= ""
local alias_of_4 = {alias_of = 4}
local boolean = {type = "boolean"}
local params = {
[1] = {required = true, type = "language", default = "und"},
[2] = true,
[3] = true,
[4] = true,
g = {list = true, type = "genders", flatten = true},
gloss = alias_of_4,
id = true,
lit = true,
ng = true,
pos = true,
sc = {type = "script"},
t = alias_of_4,
tr = true,
ts = true,
q = {type = "qualifier"},
qq = {type = "qualifier"},
l = {type = "labels"},
ll = {type = "labels"},
ref = {type = "references"},
["accel-form"] = true,
["accel-translit"] = true,
["accel-lemma"] = true,
["accel-lemma-translit"] = true,
["accel-gender"] = true,
["accel-nostore"] = boolean,
}
if iargs.compat then
params.lang = {type = "language", default = "und"}
remove(params, 1)
alias_of_4.alias_of = 3
end
if iargs.langname then
params.w = boolean
end
return process_params(frame:getParent().args, params), iargs
end
-- Used in [[Template:l]] and [[Template:m]].
function export.l_term_t(frame)
local args, iargs = get_args(frame)
local compat = iargs.compat
local lang = args[compat and "lang" or 1]
-- Tracking for und.
if not compat and lang:getCode() == "und" then
require("Module:debug").track("link/und")
end
local term = args[(compat and 1 or 2)]
local alt = args[(compat and 2 or 3)]
term = term ~= "" and term or nil
if not term and not alt and iargs.demo then
term = iargs.demo
end
local langname = iargs.langname and (
args.w and lang:makeWikipediaLink() or
lang:getCanonicalName()
) or nil
if langname and term == "-" then
return langname
end
-- Forward the information to full_link
return (langname and langname .. " " or "") .. require(links_module).full_link(
{
lang = lang,
sc = args.sc,
track_sc = true,
term = term,
alt = alt,
gloss = args[4],
id = args.id,
tr = args.tr,
ts = args.ts,
genders = args.g,
pos = args.pos,
ng = args.ng,
lit = args.lit,
q = args.q,
qq = args.qq,
l = args.l,
ll = args.ll,
refs = args.ref,
show_decorations = true,
accel = args["accel-form"] and {
form = args["accel-form"],
translit = args["accel-translit"],
lemma = args["accel-lemma"],
lemma_translit = args["accel-lemma-translit"],
gender = args["accel-gender"],
nostore = args["accel-nostore"],
} or nil
},
iargs.face,
not iargs.notself
)
end
-- Used in [[Template:link-annotations]].
function export.l_annotations_t(frame)
local args, iargs = get_args(frame)
-- Forward the information to format_link_annotations
return require(links_module).format_link_annotations(
{
lang = args[1],
tr = { args.tr },
ts = { args.ts },
genders = args.g,
pos = args.pos,
ng = args.ng,
lit = args.lit
},
iargs.face
)
end
end
-- Used in [[Template:ll]].
do
local function get_args(frame)
return process_params(frame:getParent().args, {
[1] = {required = true, type = "language", default = "und"},
[2] = {allow_empty = true},
[3] = true,
id = true,
sc = {type = "script"},
})
end
function export.ll(frame)
local args = get_args(frame)
local lang = args[1]
local sc = args.sc
local term = args[2]
term = term ~= "" and term or nil
return require(links_module).language_link{
lang = lang,
sc = sc,
term = term,
alt = args[3],
id = args.id
} or "<small>[Term?]</small>" ..
require("Module:utilities").format_categories(
{lang:getFullName() .. " term requests"},
lang, "-", nil, nil, sc
)
end
end
function export.def_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true, default = ""},
})
local face = frame.args.face
local ret = require("Module:script utilities").tag_definition(require(links_module).embedded_language_links{
term = args[1],
lang = require("Module:languages").getByCode("en"),
sc = require("Module:scripts").getByCode("Latn")
}, face)
if face == "non-gloss" then
return ret
end
return '<span class="mention-gloss-paren">(</span>' .. ret .. '<span class="mention-gloss-paren">)</span>'
end
function export.linkify_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true, default = ""},
})
args[1] = mw.text.trim(args[1])
if args[1] == "" or args[1]:find("[[", nil, true) then
return args[1]
end
return "[[" .. args[1] .. "]]"
end
function export.cap_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true},
[2] = true,
lang = {type = "language", default = "en"},
})
local term = args[1]
return require(links_module).full_link{
lang = args.lang,
term = term,
alt = term:gsub("^.[\128-\191]*", upper) .. (args[2] or "")
}
end
function export.section_link_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {},
})
return require(links_module).section_link(args[1])
end
return export
notqdjaat0bxru1ch2nr8ozilppfmpp
238837
238836
2026-11-12T08:59:48Z
Lee
19
[[:en:Module:links/templates]] වෙතින් එක් සංශෝධනයක්
238836
Scribunto
text/plain
-- Prevent substitution.
if mw.isSubsting() then
return require("Module:unsubst")
end
local export = {}
local links_module = "Module:links"
local process_params = require("Module:parameters").process
local remove = table.remove
local upper = require("Module:string utilities").upper
--[=[
Modules used:
[[Module:links]]
[[Module:languages]]
[[Module:scripts]]
[[Module:parameters]]
[[Module:debug]]
]=]
do
local function get_args(frame)
-- `compat` is a compatibility mode for {{term}}.
-- If given a nonempty value, the function uses lang= to specify the
-- language, and all the positional parameters shift one number lower.
local iargs = frame.args
iargs.compat = iargs.compat and iargs.compat ~= ""
iargs.langname = iargs.langname and iargs.langname ~= ""
iargs.notself = iargs.notself and iargs.notself ~= ""
local alias_of_4 = {alias_of = 4}
local boolean = {type = "boolean"}
local params = {
[1] = {required = true, type = "language", default = "und"},
[2] = true,
[3] = true,
[4] = true,
g = {list = true, type = "genders", flatten = true},
gloss = alias_of_4,
id = true,
lit = true,
ng = true,
pos = true,
sc = {type = "script"},
t = alias_of_4,
tr = true,
ts = true,
q = {type = "qualifier"},
qq = {type = "qualifier"},
l = {type = "labels"},
ll = {type = "labels"},
ref = {type = "references"},
["accel-form"] = true,
["accel-translit"] = true,
["accel-lemma"] = true,
["accel-lemma-translit"] = true,
["accel-gender"] = true,
["accel-nostore"] = boolean,
}
if iargs.compat then
params.lang = {type = "language", default = "und"}
remove(params, 1)
alias_of_4.alias_of = 3
end
if iargs.langname then
params.w = boolean
end
return process_params(frame:getParent().args, params), iargs
end
-- Used in [[Template:l]] and [[Template:m]].
function export.l_term_t(frame)
local args, iargs = get_args(frame)
local compat = iargs.compat
local lang = args[compat and "lang" or 1]
-- Tracking for und.
if not compat and lang:getCode() == "und" then
require("Module:debug").track("link/und")
end
local term = args[(compat and 1 or 2)]
local alt = args[(compat and 2 or 3)]
term = term ~= "" and term or nil
if not term and not alt and iargs.demo then
term = iargs.demo
end
local langname = iargs.langname and (
args.w and lang:makeWikipediaLink() or
lang:getCanonicalName()
) or nil
if langname and term == "-" then
return langname
end
-- Forward the information to full_link
return (langname and langname .. " " or "") .. require(links_module).full_link(
{
lang = lang,
sc = args.sc,
track_sc = true,
term = term,
alt = alt,
gloss = args[4],
id = args.id,
tr = args.tr,
ts = args.ts,
genders = args.g,
pos = args.pos,
ng = args.ng,
lit = args.lit,
q = args.q,
qq = args.qq,
l = args.l,
ll = args.ll,
refs = args.ref,
show_decorations = true,
accel = args["accel-form"] and {
form = args["accel-form"],
translit = args["accel-translit"],
lemma = args["accel-lemma"],
lemma_translit = args["accel-lemma-translit"],
gender = args["accel-gender"],
nostore = args["accel-nostore"],
} or nil
},
iargs.face,
not iargs.notself
)
end
-- Used in [[Template:link-annotations]].
function export.l_annotations_t(frame)
local args, iargs = get_args(frame)
-- Forward the information to format_link_annotations
return require(links_module).format_link_annotations(
{
lang = args[1],
tr = { args.tr },
ts = { args.ts },
genders = args.g,
pos = args.pos,
ng = args.ng,
lit = args.lit
},
iargs.face
)
end
end
-- Used in [[Template:ll]].
do
local function get_args(frame)
return process_params(frame:getParent().args, {
[1] = {required = true, type = "language", default = "und"},
[2] = {allow_empty = true},
[3] = true,
id = true,
sc = {type = "script"},
})
end
function export.ll(frame)
local args = get_args(frame)
local lang = args[1]
local sc = args.sc
local term = args[2]
term = term ~= "" and term or nil
return require(links_module).language_link{
lang = lang,
sc = sc,
term = term,
alt = args[3],
id = args.id
} or "<small>[Term?]</small>" ..
require("Module:utilities").format_categories(
{lang:getFullName() .. " term requests"},
lang, "-", nil, nil, sc
)
end
end
function export.def_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true, default = ""},
})
local face = frame.args.face
local ret = require("Module:script utilities").tag_definition(require(links_module).embedded_language_links{
term = args[1],
lang = require("Module:languages").getByCode("en"),
sc = require("Module:scripts").getByCode("Latn")
}, face)
if face == "non-gloss" then
return ret
end
return '<span class="mention-gloss-paren">(</span>' .. ret .. '<span class="mention-gloss-paren">)</span>'
end
function export.linkify_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true, default = ""},
})
args[1] = mw.text.trim(args[1])
if args[1] == "" or args[1]:find("[[", nil, true) then
return args[1]
end
return "[[" .. args[1] .. "]]"
end
function export.cap_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {required = true},
[2] = true,
lang = {type = "language", default = "en"},
})
local term = args[1]
return require(links_module).full_link{
lang = args.lang,
term = term,
alt = term:gsub("^.[\128-\191]*", upper) .. (args[2] or "")
}
end
function export.section_link_t(frame)
local args = process_params(frame:getParent().args, {
[1] = {},
})
return require(links_module).section_link(args[1])
end
return export
notqdjaat0bxru1ch2nr8ozilppfmpp
Module:links/data
828
7936
238834
227028
2026-08-18T09:35:53Z
en>This, that and the other
0
mammothise [[i]]
238834
Scribunto
text/plain
local data = {}
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local u = require("Module:string utilities").char
data.phonetic_extraction = {
["th"] = "Module:th",
["km"] = "Module:km",
}
data.ignored_prefixes = {
["cat"] = true,
["category"] = true,
["file"] = true,
["image"] = true
}
-- Scheme for using unsupported characters in titles.
data.unsupported_characters = {
["#"] = "`num`",
["%"] = "`percnt`", -- only escaped in percent encoding
["&"] = "`amp`", -- only escaped in HTML entities
["."] = "`period`", -- only escaped in dot-slash notation
["<"] = "`lt`",
[">"] = "`gt`",
["["] = "`lsqb`",
["]"] = "`rsqb`",
["_"] = "`lowbar`",
["`"] = "`grave`", -- used to enclose unsupported characters in the scheme, so a raw use in an unsupported title must be escaped to prevent interference
["{"] = "`lcub`",
["|"] = "`vert`",
["}"] = "`rcub`",
["~"] = "`tilde`", -- only escaped when 3 or more are consecutive
["\239\191\189"] = "`repl`" -- replacement character U+FFFD, which can't be typed directly here due to an abuse filter
}
-- Manually specified unsupported titles. Only put titles here if there is a different reason why they are unsupported, and not just because they contain one of the unsupported characters above.
data.unsupported_titles = {
[" "] = "Space",
["&"] = "`amp`amp;",
["λοπαδοτεμαχοσελαχογαλεοκρανιολειψανοδριμυποτριμματοσιλφιοκαραβομελιτοκατακεχυμενοκιχλεπικοσσυφοφαττοπεριστεραλεκτρυονοπτοκεφαλλιοκιγκλοπελειολαγῳοσιραιοβαφητραγανοπτερύγων"] = "Ancient Greek dish",
["กรุงเทพมหานคร อมรรัตนโกสินทร์ มหินทรายุธยา มหาดิลกภพ นพรัตนราชธานีบูรีรมย์ อุดมราชนิเวศน์มหาสถาน อมรพิมานอวตารสถิต สักกะทัตติยวิษณุกรรมประสิทธิ์"] = "Thai name of Bangkok",
[u(0x1680)] = "Ogham space",
[u(0x3000)] = "Ideographic space"
}
-- Mammoth pages contain only Translingual and English entries, if present. The remaining L2s are placed on subpages.
-- The same subpage titles are used across all mammoth pages for the convenience of bot and script operators.
-- Assuming that most mammoth pages will be Latin-script terms, the subpage groupings are determined by dividing the
-- list of Latin-script languages known to Wiktionary into two (three, ...) roughly equal alphabetic divisions. This is
-- easily done by looking at Petscan's output:
-- https://petscan.wmcloud.org/?sortby=title&language=en&ns%5B14%5D=1&categories=Latin+script+languages&project=wiktionary&doit=
-- This data structure contains types of splits, each of which is a list of names of splits and Lua patterns applied to
-- the decomposed L2 name (with apostrophes and double quotes removed and certain other transformations applied; see
-- get_L2_sort_key() in [[Module:headword/page]]), or "true" for the final catch-all subpage (which includes anything
-- not beginning with a Latin letter after the transformations are applied; this includes e.g. ǃKung but not 'Are'are,
-- which sorts with A, and not Àhàn, which likewise sorts with A). The patterns must be suitable for use with plain
-- string functions, not their mw.ustring equivalents.
data.mammoth_page_subpage_types = {
twos = {
{"languages A to L", "^[A-L]"},
{"languages M to Z", true},
},
threes = {
{"languages A to I", "^[A-I]"},
{"languages J to Q", "^[J-Q]"},
{"languages R to Z", true},
},
CJK = {
{"languages A to C", "^[A-C]"}, -- Translingual and Chinese on one page
{"languages D to Z", true}, -- all the remainder (mostly Japanese, Korean, Vietnamese) on the other
},
}
-- "Mammoth pages" are pages whose entries cannot be housed on a single page because of MediaWiki limits. The key is
-- the page and the value is the subpage type, as defined above in `mammoth_page_subpage_types`.
data.mammoth_pages = {
["a"] = "twos", -- FIXME: change to threes
["i"] = "twos",
["mammoth page test"] = "twos", -- required for testing purposes - please leave here
}
return data
9n45na7udwk645td2vxc6cwry17hnx5
238835
238834
2026-11-12T08:58:15Z
Lee
19
[[:en:Module:links/data]] වෙතින් එක් සංශෝධනයක්
238834
Scribunto
text/plain
local data = {}
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local u = require("Module:string utilities").char
data.phonetic_extraction = {
["th"] = "Module:th",
["km"] = "Module:km",
}
data.ignored_prefixes = {
["cat"] = true,
["category"] = true,
["file"] = true,
["image"] = true
}
-- Scheme for using unsupported characters in titles.
data.unsupported_characters = {
["#"] = "`num`",
["%"] = "`percnt`", -- only escaped in percent encoding
["&"] = "`amp`", -- only escaped in HTML entities
["."] = "`period`", -- only escaped in dot-slash notation
["<"] = "`lt`",
[">"] = "`gt`",
["["] = "`lsqb`",
["]"] = "`rsqb`",
["_"] = "`lowbar`",
["`"] = "`grave`", -- used to enclose unsupported characters in the scheme, so a raw use in an unsupported title must be escaped to prevent interference
["{"] = "`lcub`",
["|"] = "`vert`",
["}"] = "`rcub`",
["~"] = "`tilde`", -- only escaped when 3 or more are consecutive
["\239\191\189"] = "`repl`" -- replacement character U+FFFD, which can't be typed directly here due to an abuse filter
}
-- Manually specified unsupported titles. Only put titles here if there is a different reason why they are unsupported, and not just because they contain one of the unsupported characters above.
data.unsupported_titles = {
[" "] = "Space",
["&"] = "`amp`amp;",
["λοπαδοτεμαχοσελαχογαλεοκρανιολειψανοδριμυποτριμματοσιλφιοκαραβομελιτοκατακεχυμενοκιχλεπικοσσυφοφαττοπεριστεραλεκτρυονοπτοκεφαλλιοκιγκλοπελειολαγῳοσιραιοβαφητραγανοπτερύγων"] = "Ancient Greek dish",
["กรุงเทพมหานคร อมรรัตนโกสินทร์ มหินทรายุธยา มหาดิลกภพ นพรัตนราชธานีบูรีรมย์ อุดมราชนิเวศน์มหาสถาน อมรพิมานอวตารสถิต สักกะทัตติยวิษณุกรรมประสิทธิ์"] = "Thai name of Bangkok",
[u(0x1680)] = "Ogham space",
[u(0x3000)] = "Ideographic space"
}
-- Mammoth pages contain only Translingual and English entries, if present. The remaining L2s are placed on subpages.
-- The same subpage titles are used across all mammoth pages for the convenience of bot and script operators.
-- Assuming that most mammoth pages will be Latin-script terms, the subpage groupings are determined by dividing the
-- list of Latin-script languages known to Wiktionary into two (three, ...) roughly equal alphabetic divisions. This is
-- easily done by looking at Petscan's output:
-- https://petscan.wmcloud.org/?sortby=title&language=en&ns%5B14%5D=1&categories=Latin+script+languages&project=wiktionary&doit=
-- This data structure contains types of splits, each of which is a list of names of splits and Lua patterns applied to
-- the decomposed L2 name (with apostrophes and double quotes removed and certain other transformations applied; see
-- get_L2_sort_key() in [[Module:headword/page]]), or "true" for the final catch-all subpage (which includes anything
-- not beginning with a Latin letter after the transformations are applied; this includes e.g. ǃKung but not 'Are'are,
-- which sorts with A, and not Àhàn, which likewise sorts with A). The patterns must be suitable for use with plain
-- string functions, not their mw.ustring equivalents.
data.mammoth_page_subpage_types = {
twos = {
{"languages A to L", "^[A-L]"},
{"languages M to Z", true},
},
threes = {
{"languages A to I", "^[A-I]"},
{"languages J to Q", "^[J-Q]"},
{"languages R to Z", true},
},
CJK = {
{"languages A to C", "^[A-C]"}, -- Translingual and Chinese on one page
{"languages D to Z", true}, -- all the remainder (mostly Japanese, Korean, Vietnamese) on the other
},
}
-- "Mammoth pages" are pages whose entries cannot be housed on a single page because of MediaWiki limits. The key is
-- the page and the value is the subpage type, as defined above in `mammoth_page_subpage_types`.
data.mammoth_pages = {
["a"] = "twos", -- FIXME: change to threes
["i"] = "twos",
["mammoth page test"] = "twos", -- required for testing purposes - please leave here
}
return data
9n45na7udwk645td2vxc6cwry17hnx5
Module:links
828
7940
238801
229336
2026-10-07T16:44:24Z
en>Benwing2
0
[[User:J3133]] check for asterisks before initial hyphens when setting nowrap
238801
Scribunto
text/plain
local export = {}
--[=[
[[Unsupported titles]], pages with high memory usage,
extraction modules and part-of-speech names are listed
at [[Module:links/data]].
Other modules used:
[[Module:script utilities]]
[[Module:scripts]]
[[Module:languages]] and its submodules
[[Module:gender and number]]
[[Module:debug/track]]
]=]
local anchors_module = "Module:anchors"
local debug_track_module = "Module:debug/track"
local decorations_module = "Module:decorations"
local form_of_module = "Module:form of"
local gender_and_number_module = "Module:gender and number"
local languages_module = "Module:languages"
local load_module = "Module:load"
local memoize_module = "Module:memoize"
local pages_module = "Module:pages"
local roots_module = "Module:roots"
local scripts_module = "Module:scripts"
local script_utilities_module = "Module:script utilities"
local string_encode_entities_module = "Module:string/encode entities"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local concat = table.concat
local find = string.find
local get_current_title = mw.title.getCurrentTitle
local insert = table.insert
local ipairs = ipairs
local match = string.match
local new_title = mw.title.new
local pairs = pairs
local remove = table.remove
local sub = string.sub
local toNFC = mw.ustring.toNFC
local tostring = tostring
local type = type
local unstrip = mw.text.unstrip
local NAMESPACE = get_current_title().nsText
local function anchor_encode(...)
anchor_encode = require(memoize_module)(mw.uri.anchorEncode, true)
return anchor_encode(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
-- Can't yet replace, as the [[Module:string utilities]] version no longer has automatic double-encoding prevention, which requires changes here to account for.
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function extend(...)
extend = require(table_module).extend
return extend(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_genders(...)
format_genders = require(gender_and_number_module).format_genders
return format_genders(...)
end
local function format_decorations(...)
format_decorations = require(decorations_module).format_decorations
return format_decorations(...)
end
local function get_current_L2(...)
get_current_L2 = require(pages_module).get_current_L2
return get_current_L2(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function language_anchor(...)
language_anchor = require(anchors_module).language_anchor
return language_anchor(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function request_script(...)
request_script = require(script_utilities_module).request_script
return request_script(...)
end
local function get_root_link_page(...)
get_root_link_page = require(roots_module).get_link_page
return get_root_link_page(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function trim(...)
trim = require(string_utilities_module).trim
return trim(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local m_headword_data
local function get_headword_data()
m_headword_data = load_data("Module:headword/data")
return m_headword_data
end
local function track(page, code)
local tracking_page = "links/" .. page
debug_track(tracking_page)
if code then
debug_track(tracking_page .. "/" .. code)
end
end
local function field_non_empty(list, field)
if not list then
return nil
end
if type(list) ~= "table" then
error(("Internal error: Wrong type for `termobj.%s`=%s, should be %s\"table\""):format(
field, mw.dumpObject(list), field == "q" or field == "qq" and "\"string\" or " or ""))
end
return list[1]
end
--[=[
Add any decorations (left or right regular or accent qualifiers, labels or references) to an item. `text` is the
item's text (to which to add the decorations) and `itemobj` is the object specifying the item's decorations, which
should optionally contain:
* left regular qualifiers in `q` (an array of strings or a single string); an empty array will be ignored;
* right regular qualifiers in `qq` (an array of strings or a single string); an empty array will be ignored;
* left accent qualifiers in `a` (an array of strings); an empty array will be ignored;
* right accent qualifiers in `aa` (an array of strings); an empty array will be ignored;
* left labels in `l` (an array of strings); an empty array will be ignored;
* right labels in `ll` (an array of strings); an empty array will be ignored;
* references in `refs`, an array either of strings (formatted reference text) or objects containing fields `text`
(formatted reference text) and optionally `name` and/or `group`; an empty array will be ignored.
`lang` is a language object and is required if any accent qualifiers or labels are given.
]=]
local function add_text_decorations(text, itemobj, lang)
local q = itemobj.q
if type(q) == "string" then
q = { q }
end
local qq = itemobj.qq
if type(qq) == "string" then
qq = { qq }
end
if field_non_empty(q, "q") or field_non_empty(qq, "qq") or field_non_empty(itemobj.a, "a") or
field_non_empty(itemobj.aa, "aa") or field_non_empty(itemobj.l, "l") or field_non_empty(itemobj.ll, "ll") or
field_non_empty(itemobj.refs, "refs") then
text = format_decorations {
lang = lang,
text = text,
q = q,
qq = qq,
a = itemobj.a,
aa = itemobj.aa,
l = itemobj.l,
ll = itemobj.ll,
refs = itemobj.refs,
}
end
return text
end
local function selective_trim(...)
-- Unconditionally trimmed charset.
local always_trim =
"\194\128-\194\159" .. -- U+0080-009F (C1 control characters)
"\194\173" .. -- U+00AD (soft hyphen)
"\226\128\170-\226\128\174" .. -- U+202A-202E (directionality formatting characters)
"\226\129\166-\226\129\169" -- U+2066-2069 (directionality formatting characters)
-- Standard trimmed charset.
local standard_trim = "%s" .. -- (default whitespace charset)
"\226\128\139-\226\128\141" .. -- U+200B-200D (zero-width spaces)
always_trim
-- If there are non-whitespace characters, trim all characters in `standard_trim`.
-- Otherwise, only trim the characters in `always_trim`.
selective_trim = function(text)
if text == "" then
return text
end
local trimmed = trim(text, standard_trim)
if trimmed ~= "" then
return trimmed
end
return trim(text, always_trim)
end
return selective_trim(...)
end
local function escape(text, str)
local rep
repeat
text, rep = text:gsub("\\\\(\\*" .. str .. ")", "\5%1")
until rep == 0
return (text:gsub("\\" .. str, "\6"))
end
local function unescape(text, str)
return (text
:gsub("\5", "\\")
:gsub("\6", str))
end
local function has_unescaped_carets(text)
return escape(text, "^"):find("^", 1, true) ~= nil
end
local function assert_caret_capitalization_allowed(text, sc)
if sc:forbidsCaretCapitalization() and has_unescaped_carets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove bold, italics, soft hyphens, strip markers and HTML tags.
local function remove_formatting(str)
str = str
:gsub("('*)'''(.-'*)'''", "%1%2")
:gsub("('*)''(.-'*)''", "%1%2")
:gsub("", "")
return (unstrip(str)
:gsub("<[^<>]+>", ""))
end
--[==[
Split `text` on double slashes (taking account of escaping backslashes). Return a list of split items.
]==]
function export.split_on_slashes(text)
if text:find("\\", nil, true) then
track("escaped", "split_on_slashes")
end
text = split(escape(text, "//"), "//", true) or {}
for i, v in ipairs(text) do
text[i] = unescape(v, "//")
if v == "" then
text[i] = false
end
end
return text
end
--[==[
If `text` is a wikilink (i.e. in the form `<nowiki>[[foo]]</nowiki>` or `<nowiki>[[foo|bar]]</nowiki>`), return the link
target and display text. If the wikilink is single-part, the display text will be the same as the link target. If the
text is not in wikilink form, return {nil} for both link target and display text.
]==]
function export.get_wikilink_parts(text)
-- TODO: replace `allow_bad_target` with `allow_unsupported`, with support for links to unsupported titles, including escape sequences.
if ( -- Filters out anything but "[[...]]" with no intermediate "[[" or "]]".
not match(text, "^()%[%[") or -- Faster than sub(text, 1, 2) ~= "[[".
find(text, "[[", 3, true) or
find(text, "]]", 3, true) ~= #text - 1
) then
return nil, nil
end
local pipe = find(text, "|", 3, true)
local title, display
if pipe then
title, display = sub(text, 3, pipe - 1), sub(text, pipe + 1, -3)
else
title = sub(text, 3, -3)
display = title
end
return title, display
end
-- Does the work of export.get_fragment, but can be called directly to avoid unnecessary checks for embedded links.
local function get_fragment(text)
text = escape(text, "#")
-- Replace numeric character references with the corresponding character (' → '),
-- as they contain #, which causes the numeric character reference to be
-- misparsed (wa'a → wa'a → pagename wa&, fragment 39;a).
text = decode_entities(text)
local target, fragment = text:match("^(.-)#(.+)$")
target = target or text
target = unescape(target, "#")
fragment = fragment and unescape(fragment, "#") or nil
return target, fragment
end
--[==[
Given a link target possibly containing a fragment (i.e. a pound sign and following anchor), return two values, the
actual target (minus the fragment) and the fragment, or {nil} if there is no fragment.
]==]
function export.get_fragment(text)
if text:find("\\", nil, true) then
track("escaped", "get_fragment")
end
-- If there are no embedded links, process input.
local open = find(text, "[[", nil, true)
if not open then
return get_fragment(text)
end
local close = find(text, "]]", open + 2, true)
if not close then
return get_fragment(text)
-- If there is one, but it's redundant (i.e. encloses everything with no pipe), remove and process.
elseif open == 1 and close == #text - 1 and not find(text, "|", 3, true) then
return get_fragment(sub(text, 3, -3))
end
-- Otherwise, return the input.
return text, nil
end
--[==[
Given a link target as passed to `full_link()`, get the actual page that the target refers to. This removes
bold, italics, strip markets and HTML; calls `makeEntryName()` for the language in question; converts targets
beginning with `*` to the Reconstruction namespace; and converts appendix-constructed languages to the Appendix
namespace. Returns up to three values:
# the actual page to link to, or {nil} to not link to anything;
# how the target should be displayed as, if the user didn't explicitly specify any display text; generally the
same as the original target, but minus any anti-asterisk !!;
# the value `true` if the target had a backslash-escaped * in it (FIXME: explain this more clearly).
FIXME: This should not be calling deprecated `makeEntryName()` and should always return the same number of values.
]==]
function export.get_link_page_with_auto_display(target, lang, sc, plain)
local orig_target = target
if not target then
return nil
elseif target:find("\\", nil, true) then
track("escaped", "get_link_page")
end
target = remove_formatting(target)
if target:sub(1, 1) == ":" then
track("initial colon")
-- FIXME, the auto_display (second return value) should probably remove the colon
return target:sub(2), orig_target
end
local prefix = target:match("^(.-):")
-- Convert any escaped colons
target = target:gsub("\\:", ":")
if prefix then
-- If this is an a link to another namespace or an interwiki link, ensure there's an initial colon and then
-- return what we have (so that it works as a conventional link, and doesn't do anything weird like add the term
-- to a category.)
prefix = ulower(trim(prefix))
if prefix ~= "" and (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
return target, orig_target
end
end
-- Check if the term is reconstructed and remove any asterisk. Also check for anti-asterisk (!!).
-- Otherwise, handle the escapes.
local reconstructed, escaped, anti_asterisk
if not plain then
target, reconstructed = target:gsub("^%*(.)", "%1")
if reconstructed == 0 then
target, anti_asterisk = target:gsub("^!!(.)", "%1")
if anti_asterisk == 1 then
-- Remove !! from original. FIXME! We do it this way because the call to remove_formatting() above
-- may cause non-initial !! to be interpreted as anti-asterisks. We should surely move the
-- remove_formatting() call later.
orig_target = orig_target:gsub("^!!", "")
end
end
end
target, escaped = target:gsub("^(\\-)\\%*", "%1*")
if not (sc and sc:getCode() ~= "None") then
sc = lang:findBestScript(target)
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
if target:match("%^") then
assert_caret_capitalization_allowed(target, sc)
if sc:hasCaretCapitalization() then
target = escape(target, "^")
:gsub("%^", "")
target = unescape(target, "^")
end
end
-- Get the entry name for the language.
target = lang:makeEntryName(target, sc, reconstructed == 1 or lang:hasType("appendix-constructed"))
-- If the link contains unexpanded template parameters, then don't create a link.
if target:match("{{{.-}}}") then
-- FIXME: Should we return the original target as the default display value (second return value)?
return nil
end
-- Link to appendix for reconstructed terms and terms in appendix-only languages. Plain links interpret *
-- literally, however.
if reconstructed == 1 then
if lang:getFullCode() == "und" then
-- Return the original target as default display value. If we don't do this, we wrongly get
-- [Term?] displayed instead.
return nil, orig_target
end
target = "Reconstruction:" .. lang:getFullName() .. "/" .. target
-- Reconstructed languages and substrates require an initial *.
elseif anti_asterisk ~= 1 and (lang:hasType("reconstructed") or lang:getFamilyCode() == "qfa-sub") then
error(("The specified language %s is unattested, while the term '%s' does not begin with '*' to indicate that it is reconstructed.")
:
format(lang:getCanonicalName(), orig_target))
elseif lang:hasType("appendix-constructed") then
target = "Appendix:" .. lang:getFullName() .. "/" .. target
else
target = target
end
return target, orig_target, escaped > 0
end
function export.get_link_page(target, lang, sc, plain)
local target, auto_display, escaped = export.get_link_page_with_auto_display(target, lang, sc, plain)
return target, escaped
end
-- Make a link from a given link's parts.
local function make_link(link, lang, sc, id, isolated, cats, no_alt_ast, plain)
-- Convert percent encoding to plaintext.
link.target = link.target and decode_uri(link.target, "PATH")
link.fragment = link.fragment and decode_uri(link.fragment, "PATH")
-- Find fragments (if one isn't already set).
-- Prevents {{l|en|word#Etymology 2|word}} from linking to [[word#Etymology 2#English]].
-- # can be escaped as \#.
if link.target and link.fragment == nil then
link.target, link.fragment = get_fragment(link.target)
end
-- Process the target
local auto_display, escaped
link.target, auto_display, escaped = export.get_link_page_with_auto_display(link.target, lang, sc, plain)
-- Create a default display form.
-- If the target is "" then it's a link like [[#English]], which refers to the current page.
if auto_display == "" then
auto_display = (m_headword_data or get_headword_data()).pagename
end
-- If the display is the target and the reconstruction * has been escaped, remove the escaping backslash.
if escaped then
auto_display = auto_display:gsub("\\([^\\]*%*)", "%1", 1)
end
-- Process the display form.
if link.display then
local orig_display = link.display
link.display = lang:makeDisplayText(link.display, sc, true)
if cats then
auto_display = lang:makeDisplayText(auto_display, sc)
-- If the alt text is the same as what would have been automatically generated, then the alt parameter is
-- redundant (e.g. {{l|en|foo|foo}}, {{l|en|w:foo|foo}}, but not {{l|en|w:foo|w:foo}}). If they're
-- different, but the alt text could have been entered as the term parameter without it affecting the target
-- page, then the target parameter is redundant (e.g. {{l|ru|фу|фу́}}). If `no_alt_ast` is true, use pcall
-- to catch the error which will be thrown if this is a reconstructed lang and the alt text doesn't have *.
if link.display == auto_display then
insert(cats, lang:getFullName() .. " links with redundant alt parameters")
else
local ok, check
if no_alt_ast then
ok, check = pcall(export.get_link_page, orig_display, lang, sc, plain)
else
ok = true
check = export.get_link_page(orig_display, lang, sc, plain)
end
if ok and link.target == check then
insert(cats, lang:getFullName() .. " links with redundant target parameters")
end
end
end
else
link.display = lang:makeDisplayText(auto_display, sc)
end
if not link.target then
return link.display
end
-- If the target is the same as the current page, there is no sense id
-- and either the language code is "und" or the current L2 is the current
-- language then return a "self-link" like the software does.
if link.target == get_current_title().prefixedText then
local fragment, current_L2 = link.fragment, get_current_L2()
if (
fragment and fragment == current_L2 or
not (id or fragment) and (lang:getFullCode() == "und" or lang:getFullName() == current_L2)
) then
return tostring(mw.html.create("strong")
:addClass("selflink")
:wikitext(link.display))
end
end
-- Add fragment. Do not add a section link to "Undetermined", as such sections do not exist and are invalid.
-- TabbedLanguages handles links without a section by linking to the "last visited" section, but adding
-- "Undetermined" would break that feature. For localized prefixes that make syntax error, please use the
-- format: ["xyz"] = true.
local prefix = link.target:match("^:*([^:]+):")
prefix = prefix and ulower(prefix)
if prefix ~= "category" and not (prefix and load_data("Module:data/interwikis")[prefix]) then
if (link.fragment or link.target:sub(-1) == "#") and not plain then
track("fragment", lang:getFullCode())
if cats then
insert(cats, lang:getFullName() .. " links with manual fragments")
end
end
if not link.fragment then
if id then
link.fragment = lang:getFullCode() == "und" and anchor_encode(id) or language_anchor(lang, id)
elseif lang:getFullCode() ~= "und" and not (link.target:match("^Appendix:") or link.target:match("^Reconstruction:")) then
link.fragment = anchor_encode(lang:getFullName())
end
end
end
-- Put inward-facing square brackets around a link to isolated spacing character(s).
if isolated and link.display[1] and not umatch(decode_entities(link.display), "%S") then
link.display = "]" .. link.display .. "["
end
link.target = link.target:gsub("^(:?)(.*)", function(m1, m2)
return m1 .. encode_entities(m2, "#%&+/:<=>@[\\]_{|}")
end)
link.fragment = link.fragment and encode_entities(remove_formatting(link.fragment), "#%&+/:<=>@[\\]_{|}")
return "[[" ..
link.target:gsub("^[^:]", ":%0") .. (link.fragment and "#" .. link.fragment or "") .. "|" .. link.display .. "]]"
end
-- Split a link into its parts.
local function parse_link(linktext)
local link = { target = linktext }
local target = link.target
link.target, link.display = target:match("^(..-)|(.+)$")
if not link.target then
link.target = target
link.display = target
end
-- There's no point in processing these, as they aren't real links.
local target_lower = link.target:lower()
for _, false_positive in ipairs({ "category", "cat", "file", "image" }) do
if target_lower:match("^" .. false_positive .. ":") then
return nil
end
end
link.display = decode_entities(link.display)
link.target, link.fragment = get_fragment(link.target)
-- So that make_link does not look for a fragment again.
if not link.fragment then
link.fragment = false
end
return link
end
local function check_params_ignored_when_embedded(alt, lang, id, cats)
if alt then
track("alt-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored alt parameters")
end
end
if id then
track("id-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored id parameters")
end
end
end
-- Find embedded links and ensure they link to the correct section.
local function process_embedded_links(text, alt, lang, sc, id, cats, no_alt_ast, plain)
-- Process the non-linked text.
text = lang:makeDisplayText(text, sc, true)
-- If the text begins with * and another character, then act as if each link begins with *. However, don't do this if the * is contained within a link at the start. E.g. `|*[[foo]]` would set all_reconstructed to true, while `|[[*foo]]` would not.
local all_reconstructed = false
if not plain then
-- anchor_encode removes links etc.
if anchor_encode(text):sub(1, 1) == "*" then
all_reconstructed = true
end
-- Otherwise, handle any escapes.
text = text:gsub("^(\\-)\\%*", "%1*")
end
check_params_ignored_when_embedded(alt, lang, id, cats)
local function process_link(space1, linktext, space2)
local capture = "[[" .. linktext .. "]]"
local link = parse_link(linktext)
-- Return unprocessed false positives untouched (e.g. categories).
if not link then
return capture
end
if all_reconstructed then
if link.target:find("^!!") then
-- Check for anti-asterisk !! at the beginning of a target, indicating that a reconstructed term
-- wants a part of the term to link to a non-reconstructed term, e.g. Old English
-- {{ang-noun|m|head=*[[!!Crist|Cristes]] [[!!mæsseǣfen]]}}.
link.target = link.target:sub(3)
-- Also remove !! from the display, which may have been copied from the target (as in mæsseǣfen in
-- the example above).
link.display = link.display:gsub("^!!", "")
elseif not link.target:match("^%*") then
link.target = "*" .. link.target
end
end
linktext = make_link(link, lang, sc, id, false, nil, no_alt_ast, plain)
:gsub("^%[%[", "\3")
:gsub("%]%]$", "\4")
return space1 .. linktext .. space2
end
-- Use chars 1 and 2 as temporary substitutions, so that we can use charsets. These are converted to chars 3 and 4 by process_link, which means we can convert any remaining chars 1 and 2 back to square brackets (i.e. those not part of a link).
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- If the script uses ^ to capitalize transliterations, make sure that any carets preceding links are on the inside, so that they get processed with the following text.
if text:find("^", nil, true) then
assert_caret_capitalization_allowed(text, sc)
if sc:hasCaretCapitalization() then
text = escape(text, "^")
:gsub("%^\1", "\1%^")
text = unescape(text, "^")
end
end
text = text:gsub("\1(%s*)([^\1\2]-)(%s*)\2", process_link)
-- Remove the extra * at the beginning of a language link if it's immediately followed by a link whose display begins with * too.
if all_reconstructed then
text = text:gsub("^%*\3([^|\1-\4]+)|%*", "\3%1|*")
end
return (text
:gsub("[\1\3]", "[[")
:gsub("[\2\4]", "]]")
)
end
local function simple_link(term, fragment, alt, lang, sc, id, cats, no_alt_ast, suppress_redundant_wikilink_cat)
local plain
if lang == nil then
lang, plain = get_lang("und"), true
end
-- Get the link target and display text. If the term is the empty string, treat the input as a link to the current page.
if term == "" then
term = get_current_title().prefixedText
elseif term then
local new_term, new_alt = export.get_wikilink_parts(term)
if new_term then
check_params_ignored_when_embedded(alt, lang, id, cats)
-- [[|foo]] links are treated as plaintext "[[|foo]]".
-- FIXME: Pipes should be handled via a proper escape sequence, as they can occur in unsupported titles.
if new_term == "" then
term, alt = nil, term
else
local title = new_title(new_term)
if title then
local ns = title.namespace
-- File: and Category: links should be returned as-is.
if ns == 6 or ns == 14 then
return term
end
end
term, alt = new_term, new_alt
if cats then
if not (suppress_redundant_wikilink_cat and suppress_redundant_wikilink_cat(term, alt)) then
insert(cats, lang:getFullName() .. " links with redundant wikilinks")
end
end
end
end
end
if alt then
alt = selective_trim(alt)
if alt == "" then
alt = nil
end
end
-- If there's nothing to process, return nil.
if not (term or alt) then
return nil
end
-- If there is no script, get one.
if not sc then
sc = lang:findBestScript(alt or term)
end
-- Embedded wikilinks need to be processed individually.
if term then
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, alt, lang, sc, id, cats, no_alt_ast, plain)
end
term = selective_trim(term)
end
-- If not, make a link using the parameters.
return make_link({
target = term,
display = alt,
fragment = fragment
}, lang, sc, id, true, cats, no_alt_ast, plain)
end
--[==[
Create a basic link to the given term. It links to the language section (such as `==English==`), but it does not add
language and script wrappers, so any code that uses this function should call `[[Module:script utilities#tag_text]]`
to add such wrappers itself at some point. The first argument, `data`, may contain the following items, a subset of the
items used in the `data` argument of `##full_link`. If any other items are included, they are ignored.
{ {
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
no_alt_ast = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
cats = nil or {}, -- NOTE: If given, will be side-effected to return categories to add the page to.
} }
Specifically:
* `term`: Term to turn into a link. This is generally the name of a page, possibly with extra diacritics added (e.g.
length marks in Latin or Old English terms, accents in Russian terms, vowel diacritics in Arabic terms, etc.), which
are stripped to determine the actual pagename. The term can contain wikilinks already embedded in it. These are
processed individually just like a single link would be. The `alt` argument is ignored in this case.
* `alt`: The alternative display for the link, if different from the linked page. If this is {nil}, the `term` argument
is used instead (much like regular wikilinks). If `term` contains wikilinks in it, this argument is ignored and has no
effect. (Links in which the alt is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/alt-ignored}}.)
* `lang` ('''required'''): The [[Module:languages#Language objects|language object]] for the term being linked. The link
or links in `term` will normally have their fragment set to point to the canonical name (see
{{tl|language data documentation}}) of `lang` (or, if it is an etymology-only language, to the canonical name of its
L2 parent). (However, if `id` is defined, the fragment will point to a language-specific sense ID corresponding to
this field, which in turn will be overridden by `fragment` if specified.)
* `sc`: The [[Module:scripts#Script objects|script object]] for the term being linked. This rarely needs to be specified
because it is autodetected based on `term` or `alt`, and the detection is usually correct. It is used to determine
how to convert the term into a pagename, possibly by stripping certain diacritics from the term's text.
* `fragment`: If specified, overrides the fragment in the generated link (i.e. the portion after `#`, which determines
where on the page to go to when the link is clicked). If not specified, the fragment is generated from `id` (if given)
or otherwise from `lang`.
* `id`: Sense ID string. If this argument is defined, the link will point to a language-specific sense ID
({{ll|en|identifier|id=HTML}}) created by the template {{temp|senseid}}. The fragment for a sense ID consists of the
language's canonical name, a hyphen (`-`), and the string that was supplied as the `id` argument. This is useful when
a term has more than one sense in a language. If the `term` argument contains wikilinks, this argument is ignored.
(Links in which the sense ID is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/id-ignored}}.)
* `no_alt_ast`: This is the same as `no_alt_ast` in `##full_link()`. See that function for more information.
* `suppress_redundant_wikilink_cat`: This is the same as `suppress_redundant_wikilink_cat` in `##full_link()`. See
that function for more information.
* `cats`: This should be either {nil} or an empty list. In the latter case, tracking categories will be added to the
list when appropriate. The caller can choose to add the page to those categories (as is done by ##full_link()`).
The following special options are processed for each link (both simple terms and with embedded wikilinks):
* The target page name will be processed by stripping certain diacritics (as mentioned above) and converting the
resulting ''logical'' pagename to a ''physical'' pagename (which will be different from the logical pagename in the
case of pages with unsupported characters in them and certain overly large pages, such as [[a]], that are split into
parts).
* If the term starts with `*`, then it is considered a reconstructed term, and a link to the `Reconstruction:` namespace
will be created. If the text contains embedded wikilinks, then `*` is automatically applied to each one individually,
while preserving the displayed form of each link as it was given. This allows linking to phrases containing multiple
reconstructed terms, while only showing the `*` once at the beginning.
* If the text starts with `:`, then the link is treated as "raw" and the above steps are skipped. This can be used in
rare cases where the page name begins with `*` or if diacritics should not be stripped. For example:
** {{tl|l|en|*nix}} links to the nonexistent page [[Reconstruction:English/nix]] (`*` is interpreted as a
reconstruction), but {{tl|l|en|:*nix}} links to [[*nix]].
** {{tl|l|sl|Franche-Comté}} links to the nonexistent page [[Franche-Comte]] (`é` is converted to `e` by the
diacritic-stripping process), but {{tl|l|sl|:Franche-Comté}} links to [[Franche-Comté]].
]==]
function export.language_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function language_link must be a table. See [[Module:links/documentation]] for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "language_link")
end
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
return simple_link(
data.term,
data.fragment,
data.alt,
lang,
data.sc,
data.id,
cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
function export.plain_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function plain_link must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "plain_link")
end
return simple_link(
data.term,
data.fragment,
data.alt,
nil,
data.sc,
data.id,
data.cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
--[==[Replace any links with links to the correct section, but don't link the whole text if no embedded links are found. Returns the display text form.]==]
function export.embedded_language_links(data)
if type(data) ~= "table" then
error(
"The first argument to the function embedded_language_links must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "embedded_language_links")
end
local term, lang, sc = data.term, data.lang, data.sc
-- If we don't have a script, get one.
if not sc then
sc = lang:findBestScript(term)
end
-- Do we have embedded wikilinks? If so, they need to be processed individually.
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, data.alt, lang, sc, data.id, data.cats, data.no_alt_ast)
end
-- If not, return the display text.
term = selective_trim(term)
-- FIXME: Double-escape any percent-signs, because we don't want to treat non-linked text as having percent-encoded
-- characters. This is a hack: percent-decoding should come out of [[Module:languages]] and only dealt with in this
-- module, as it's specific to links.
term = term:gsub("%%", "%%25")
return lang:makeDisplayText(term, sc, true)
end
function export.mark(text, item_type, face, lang)
local tag = { "", "" }
if item_type == "gloss" then
tag = { '<span class="mention-gloss-double-quote">“</span><span class="mention-gloss">',
'</span><span class="mention-gloss-double-quote">”</span>' }
if type(text) == "string" and text:match("^''[^'].*''$") then
-- Temporary tracking for mention glosses that are entirely italicized or bolded, which is probably
-- wrong. (Note that this will also find bolded mention glosses since they use triple apostrophes.)
track("italicized-mention-gloss", lang and lang:getFullCode() or nil)
end
elseif item_type == "tr" then
if face == "term" then
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr mention-tr Latn">',
'</span>' }
else
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr Latn">', '</span>' }
end
elseif item_type == "ts" then
-- \226\129\160 = word joiner (zero-width non-breaking space) U+2060
tag = { '<span class="ts mention-ts Latn">/\226\129\160', '\226\129\160/</span>' }
elseif item_type == "pos" then
tag = { '<span class="ann-pos">', '</span>' }
elseif item_type == "non-gloss" then
tag = { '<span class="ann-non-gloss">', '</span>' }
elseif item_type == "annotations" then
tag = { '<span class="mention-gloss-paren annotation-paren">(</span>',
'<span class="mention-gloss-paren annotation-paren">)</span>' }
elseif item_type == "infl" then
tag = { '<span class="ann-infl">', '</span>' }
end
if type(text) == "string" then
return tag[1] .. text .. tag[2]
else
return ""
end
end
--[=[
Implementation of `format_transliteration` and `format_transcription`. The implementation is identical except that the
field containing the transliteration or transcription may vary and is specified in `field`, and the way a given
transliteration or transcription is tagged may vary and is controlled by `tag_fn`, which is passed three parameters:
`text` (the transliteration or transcription), `lang` (the language passed in) and `face` (the face passed in).
On input, `item` is the transliteration or transcription or list of such objects; `field` is either {"tr"} or {"ts"};
`tag_fn` is a function of three parameters to tag the item, as described above; `lang` is the language object of the
term whose transliteration or transcription is specified; and `face` is a string indicating how to display the item
(generally only the strings {"term"} and {"default"} are recognized).
]=]
local function format_transliteration_or_transcription(item, field, tag_fn, lang, item_face)
if type(item) == "string" then
return tag_fn(item, lang, item_face)
end
local formatted_items = {}
for _, itemobj in ipairs(item) do
local tagged_item = tag_fn(itemobj[field], lang, item_face)
tagged_item = add_text_decorations(tagged_item, item, lang)
insert(formatted_items, tagged_item)
end
if formatted_items[2] then
-- FIXME: This should be customizable.
return concat(formatted_items, " <i>or</i> ")
else
return formatted_items[1]
end
end
--[==[
Format a transliteration string or list of transliteration objects. `tr` contains the transliteration(s), which for
forward compatibility reasons can only be either a single transliteration string or a list of transliteration objects
(each of which has a `tr` field holding the transliteration and optional fields `q`, `qq`, `l`, `ll` and/or `refs`).
This correctly handles multiple transliterations as well as decorations (qualifiers, labels or references) attached to
transliterations.
]==]
function export.format_transliteration(tr, lang, face)
return format_transliteration_or_transcription(tr, "tr", tag_translit, lang, face)
end
local function tag_transcription(ts, _lang, _face)
return export.mark(ts, "ts")
end
--[==[
Format a transcription string or list of transcription objects. `ts` contains the transcription(s), which for forward
compatibility reasons can only be either a single transcription string or a list of transcription objects (each of which
has a `ts` field holding the transcription and optional decoration fields `q`, `qq`, `l`, `ll` and/or `refs`). This
correctly handles multiple transcriptions as well as decorations (qualifiers, labels or references) attached to
transcriptions.
]==]
function export.format_transcription(ts, lang, face)
return format_transliteration_or_transcription(ts, "ts", tag_transcription, lang, face)
end
local pos_tags
--[==[
Format the annotations that are displayed with a link created by `full_link()`. Annotations are the extra bits of
information that are displayed following the linked term, and include things such as gender, transliteration, gloss,
etc. The first argument is a table with some or all of the following keys (all are optional):
* `interwiki`: An interwiki link. This is used for links in translation tables to the corresponding term in another
Wiktionary. If specified, it should be a fully formatted link and is inserted as-is at the beginning of the output.
See the `interwiki()` function in [[Module:translations]].
* `genders`: Table containing a list of gender specifications in the style of [[Module:gender and number]]. If
specified, these are formatted using `format_genders()` in [[Module:gender and number]] and the result inserted at
the beginning of the output, following any interwiki link and (in all cases) directly after a no-break space.
* `tr`: Transliteration or transliterations. Currently, this is always a one-item list. It is a list because of
potential support for per-alternant transliterations due to the multiple alternants (separated by `//`) that can be
specified in `term` or `alt`. The item in the list can be either a string or a list of transliteration objects (see
`format_transliteration()`).
* `ts`: Transcription or transcriptions. Like `tr`, this is currently always a one-item list, with the item being either
a single string or a list of transcription objects, as described in `format_transcription()`.
* `gloss`: Gloss that translates the term in the link.
* `pos`: Part of speech of the linked term. If the given argument matches one of the aliases in `pos_aliases` in
[[Module:headword/data]], or consists of a part of speech or alias followed by `f` (for a non-lemma form), expand it
appropriately. Otherwise, just show the given text as it is.
With `root`, the term links to the page where [[Module:roots]] keeps the language's roots, for languages that keep
them outside the main namespace (`Appendix:Arabic roots/…`).
* `infl`: A list of tags, each a string. Multiple tag sets may be encoded in this list by separating them with an
element consisting of a semicolon. If there are multiple tag sets, they are formatted individually and separated
by a semicolon + space.
* `ng`: Arbitrary non-gloss descriptive text for the link. This should be used in preference to putting descriptive text
in `gloss` or `pos`.
* `lit`: Literal meaning of the term, if the usual meaning is figurative or idiomatic.
* `postprocess_annotations`: A function to postprocess the annotations, after they have been formatted (see below).
The `interwiki` and `genders` properties are formatted specially, and `postprocess_annotations` is a callback function
rather than an item to display; all others are formatted (each in their own way), separated by commas and placed inside
of parentheses (except that if both transliteration and transcription are present, they are separated by a space). The
order of the annotations is `tr`+`ts`, `gloss`, `pos`, `infl`, `ng` and `lit`. The `postprocess_annotations` function,
if supplied, is passed a single object, a table with two keys `data` (the `data` object passed into
`format_link_annotations()`) and `annotations` (the formatted annotations, prior to being concatenated). It should
side-effect the `annotations` list, e.g. by inserting more annotations. (It is used to handle nested inflections in
[[Module:headword]]. FIXME: It should probably be generalized so that it can return the final formatted string, to allow
for e.g. changing the way the annotations are formatted.)
* The second argument is a string controlling the "face" that the terms are displayed in. Currently it only affects
transliteration and transcription and only when the value {"term"} is passed in, in which case those annotations are
displayed italicized.
]==]
function export.format_link_annotations(data, face)
local output = {}
-- Interwiki link
if data.interwiki then
insert(output, data.interwiki)
end
-- Genders
if type(data.genders) ~= "table" then
data.genders = { data.genders }
end
if data.genders and data.genders[1] then
local genders, gender_cats = format_genders(data.genders, data.lang)
insert(output, " " .. genders)
if gender_cats then
local cats = data.cats
if cats then
extend(cats, gender_cats)
end
end
end
local annotations = {}
-- Transliteration and transcription
local tr = data.tr and data.tr[1] or nil
local ts = data.ts and data.ts[1] or nil
if tr or ts then
local item_face
if face == "term" then
item_face = face
else
item_face = "default"
end
local formatted_tr = tr and export.format_transliteration(tr, data.lang, item_face) or nil
local formatted_ts = ts and export.format_transcription(ts, data.lang, item_face) or nil
if formatted_tr and formatted_ts then
insert(annotations, {text = formatted_tr .. " " .. formatted_ts})
else
insert(annotations, {text = formatted_tr or formatted_ts})
end
end
-- Gloss/translation
if data.gloss then
insert(annotations, {text = export.mark(data.gloss, "gloss")})
end
-- Part of speech
if data.pos then
-- debug category for pos= containing transcriptions
if data.pos:match("/[^><]-/") then
data.pos = data.pos .. "[[Category:links likely containing transcriptions in pos]]"
end
-- Canonicalize part of speech aliases as well as non-lemma aliases like 'nf' or 'nounf' for "noun form".
pos_tags = pos_tags or (m_headword_data or get_headword_data()).pos_aliases
local pos = pos_tags[data.pos]
if not pos and data.pos:find("f$") then
local pos_form = data.pos:sub(1, -2)
-- We only expand something ending in 'f' if the result is a recognized non-lemma POS.
pos_form = (pos_tags[pos_form] or pos_form) .. " form"
if (m_headword_data or get_headword_data()).nonlemmas[pos_form .. "s"] then
pos = pos_form
end
end
insert(annotations, {text = export.mark(pos or data.pos, "pos")})
end
-- Inflection data
if data.infl then
local m_form_of = require(form_of_module)
-- Split tag sets manually, since tagged_inflections creates a numbered list, and we do not want that.
local infl_outputs = {}
local tag_sets = m_form_of.split_tag_set(data.infl)
for _, tag_set in ipairs(tag_sets) do
table.insert(infl_outputs,
m_form_of.tagged_inflections({ tags = tag_set, lang = data.lang, nocat = true, nolink = true, nowrap = true }))
end
insert(annotations, {text = export.mark(table.concat(infl_outputs, "; "), "infl")})
end
-- Non-gloss text
if data.ng then
local separator
local ng = data.ng
if ng:find("^[;:]") then
separator = ""
elseif ng:find("^_") then
ng = ng:sub(2)
separator = " "
end
insert(annotations, {text = export.mark(ng, "non-gloss"), separator = separator})
end
-- Literal/sum-of-parts meaning
if data.lit then
insert(annotations, {text = "literally " .. export.mark(data.lit, "gloss")})
end
-- Provide a hook to insert additional annotations such as nested inflections.
if data.postprocess_annotations then
data.postprocess_annotations {
data = data,
annotations = annotations
}
end
if annotations[1] then
local annparts = {}
for i, annotation in ipairs(annotations) do
local separator = annotation.separator
if not separator then
if i == 1 then
separator = ""
else
separator = ", "
end
end
insert(annparts, separator)
insert(annparts, annotation.text)
end
insert(output, " ")
insert(output, export.mark(concat(annparts), "annotations"))
end
return concat(output)
end
-- Encode certain characters to avoid various delimiter-related issues at various stages. We need to encode < and >
-- because they end up forming part of CSS class names inside of <span ...> and will interfere with finding the end
-- of the HTML tag. I first tried converting them to URL encoding, i.e. %3C and %3E; they then appear in the URL as
-- %253C and %253E, which get mapped back to %3C and %3E when passed to [[Module:accel]]. But mapping them to <
-- and > somehow works magically without any further work; they appear in the URL as < and >, and get passed to
-- [[Module:accel]] as < and >. I have no idea who along the chain of calls is doing the encoding and decoding. If
-- someone knows, please modify this comment appropriately!
local accel_char_map
local function get_accel_char_map()
accel_char_map = {
["%"] = ".",
[" "] = "_",
["_"] = u(0xFFF0),
["<"] = "<",
[">"] = ">",
}
return accel_char_map
end
local function encode_accel_param_chars(param)
return (param:gsub("[%% <>_]", accel_char_map or get_accel_char_map()))
end
local function encode_accel_param(prefix, param)
if not param then
return ""
end
if type(param) == "table" then
local filled_params = {}
-- There may be gaps in the sequence, especially for translit params.
local maxindex = 0
for k in pairs(param) do
if type(k) == "number" and k > maxindex then
maxindex = k
end
end
for i = 1, maxindex do
filled_params[i] = param[i] or ""
end
-- [[Module:accel]] splits these up again.
param = concat(filled_params, "*~!")
end
-- This is decoded again by [[WT:ACCEL]].
return prefix .. encode_accel_param_chars(param)
end
local function insert_if_not_blank(list, item)
if item == "" then
return
end
insert(list, item)
end
local function get_css_classes(lang, tr, accel, nowrap)
if not accel and not nowrap then
return ""
end
local classes = {}
if accel then
insert(classes, "form-of lang-" .. lang:getFullCode())
local form = accel.form
if form then
insert(classes, encode_accel_param_chars(form) .. "-form-of")
end
insert_if_not_blank(classes, encode_accel_param("gender-", accel.gender))
insert_if_not_blank(classes, encode_accel_param("pos-", accel.pos))
insert_if_not_blank(classes, encode_accel_param("transliteration-", accel.translit or (tr ~= "-" and tr or nil)))
insert_if_not_blank(classes, encode_accel_param("target-", accel.target))
insert_if_not_blank(classes, encode_accel_param("origin-", accel.lemma))
insert_if_not_blank(classes, encode_accel_param("origin_transliteration-", accel.lemma_translit))
if accel.no_store then
insert(classes, "form-of-nostore")
end
end
if nowrap then
insert(classes, nowrap)
end
return concat(classes, " ")
end
--[==[
Creates a full link, with annotations (see `##format_link_annotations`), in the style of {{tl|l}} or {{tl|m}}.
The first argument, `data`, must be a table. It contains the various elements that can be supplied as parameters to
{{tl|l}} or {{tl|m}}:
{ {
-- Basic link-related fields
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
accel = {accelerated_creation_tags},
-- Link annotation fields
interwiki = "interwiki_link",
genders = {"gender1", "gender2", ...} or {{spec = "gender1", q = {"left qualifier", ...}, qq = {"right qualifier"}, ...}, ...},
tr = "transliteration" or "-" or {{tr = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
ts = "transcription" or {{ts = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
gloss = "gloss",
pos = "part_of_speech_tag",
infl = {"infl1_tag1", "infl1_tag2", ..., ";", "infl2_tag1", "infl2_tag2", ...},
ng = "non-gloss text",
lit = "literal_translation",
postprocess_annotations = function({data = full_link_data, annotations = {"annotation1", "annotation2", ...}}) -> nil,
-- Other transliteration-related fields
respect_link_tr = boolean,
never_call_transliteration_module = boolean,
suppress_tr = boolean,
-- Decoration fields
q = { "left_qualifier1", "left_qualifier2", ...} or "left_qualifier",
qq = { "right_qualifier1", "right_qualifier2", ...} or "right_qualifier",
l = { "left_label1", "left_label2", ...},
ll = { "right_label1", "right_label2", ...},
a = { "left_accent_qualifier1", "left_accent_qualifier2", ...},
aa = { "right_accent_qualifier1", "right_accent_qualifier2", ...},
refs = { "formatted_ref1", "formatted_ref2", ...} or { {text = "text", name = "name", group = "group"}, ... },
pretext = "text_at_beginning",
posttext = "text_at_end",
show_decorations = boolean,
-- Fields controlling tracking categories
track_sc = boolean,
no_nonstandard_sc_cat = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
-- Miscellaneous fields
no_alt_ast = boolean,
no_generate_alternants = boolean,
} }
Any one of the items in the `data` table (except for `lang`) may be {nil}. If none of `term`, `alt` and `tr` is present,
a term request will be shown. Thus, calling {full_link{ term = term, lang = lang, sc = sc }}, where `term` is the page
to link to (which may have diacritics that will be stripped and/or embedded bracketed links) and `lang` is a
[[Module:languages#Language objects|language object]] from [[Module:languages]], will give a plain link similar to the
one produced by the template {{tl|l}}, and calling {full_link( { term = term, lang = lang, sc = sc }, "term" )} will
give a link similar to the one produced by the template {{tl|m}}.
The function will:
* Try to determine the script, based on the characters found in the `term` or `alt` argument, if the script was not
given. If a script is given and `track_sc` is {true}, it will check whether the input script is the same as the one
which would have been automatically generated and add the category ` ``lang`` terms with redundant script codes` if
yes, or ` ``lang`` terms with non-redundant manual script codes` if no. This should be used when the input script
object is directly determined by a template's `sc` parameter.
* Call `simple_link()` on the `term` or `alt` forms, to remove diacritics in the page name, process any embedded
wikilinks and create links to Reconstruction or Appendix pages when necessary. (`simple_link()` is almost exactly the
same as `##language_link()`; the latter is a simple wrapper around the former that adds a bit of extra tracking.)
* Call `[[Module:script utilities#tag_text]]` to add the appropriate language and script tags to the term and
italicize terms written in the Latin script if necessary. Accelerated creation tags, as used by [[WT:ACCEL]], are
included.
* Generate a transliteration, based on the `alt` or `term` arguments, if the script is not Latin, no transliteration was
provided in `tr` and the combination of the term's language and script support automatic transliteration. The
transliteration itself will be linked if both `.respect_link_tr` is specified and the language of the term has the
`link_tr` property set for the script of the term; but not otherwise.
* Add the annotations (transliteration, gender, gloss, etc.) after the link.
* If `no_alt_ast` is specified, then the `alt` text does not need to contain an asterisk if the language is
reconstructed. This should only be used by modules which really need to allow links to reconstructions that don't
display asterisks (e.g. number boxes).
* If `suppress_redundant_wikilink_cat` is specified, it should be a function that indicates whether to suppress the
generation of the ` ``lang`` links with redundant wikilinks` tracking category. It is passed two arguments, the `term`
and `alt` parameters. Normally, this tracking category is added whenever the `term` argument consists entirely of a
one-part or two-part embedded link, which is considered "redundant" in that the link can be rewritten into separate
`term` and `alt` arguments without any embedded links. For certain wrapping templates, however, otherwise "redundant"
embedded links are necessary to prevent interpretation of certain characters as delimiters. For example, {{tl|col}}
and related templates use `~` as a separator, as well as `,` when not followed by a space. In these templates,
embedded links are required to correctly link to terms containing those delimiters, such as [[Micros~1]] and
[[1,6-Cleves acid]], but will incorrectly trigger the addition of the tracking category unless the appropriate
`suppress_redundant_wikilink_cat` function is given.
* If `pretext` or `posttext` is specified, this is text to (respectively) prepend or append to the output, directly
before processing decorations (qualifiers, labels and references). This can be used to add arbitrary extra text inside
of the decorations.
* If `show_decorations` is specified, then decorations specified in `data` (i.e. left and right qualifiers, accent
qualifiers, labels and references) will be displayed, otherwise they will be ignored. (This is because a fair amount
of code stores decorations in these fields and displays them itself, rather than expecting {full_link()} to display
them.)
* ]==]
function export.full_link(data, face, allow_self_link, show_qualifiers)
if type(data) ~= "table" then
error("The first argument to the function full_link must be a table. "
.. "See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "full_link")
end
if show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-17, remove after 2026-10-17 or so.
error("Can't pass fourth parameter `show_qualifiers` any more. Set `show_decorations = true` on data.")
end
if data.show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-18, remove after 2026-10-18 or so.
error("Can't set field `show_qualifiers`; use `show_decorations`")
end
if data.no_generate_forms then
-- FIXME: Eventually remove the error code. Added 2026-09-14, remove after 2026-10-14 or so.
error("Can't set field `no_generate_forms`; use `no_generate_alternants`")
end
-- Prevent data from being destructively modified.
data = shallow_copy(data)
data.cats = {}
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
-- With pos=root, link to the page where Module:roots keeps the language's roots (Appendix:Arabic roots/…) and
-- display the root as given.
if data.pos == "root" and type(data.term) == "string" and not data.term:find(":", nil, true) then
local root_page = get_root_link_page(lang, data.term)
if root_page then
data.alt = data.alt or data.term
data.term = root_page
end
end
local terms = { true }
-- Generate multiple alternants if applicable.
for _, param in ipairs { "term", "alt" } do
if type(data[param]) == "string" and data[param]:find("//", nil, true) then
data[param] = export.split_on_slashes(data[param])
elseif type(data[param]) == "string" and not (type(data.term) == "string" and data.term:find("//", nil, true)) then
if not data.no_generate_alternants then
data[param] = lang:generateAlternants(data[param])
else
data[param] = { data[param] }
end
else
data[param] = {}
end
end
for _, param in ipairs { "sc", "tr", "ts" } do
data[param] = { data[param] }
end
for _, param in ipairs { "term", "alt", "sc", "tr", "ts" } do
for i in pairs(data[param]) do
terms[i] = true
end
end
-- Create the link
local outparts = {}
local id, no_alt_ast, suppress_redundant_wikilink_cat, accel, never_call_transliteration_module =
data.id, data.no_alt_ast, data.suppress_redundant_wikilink_cat, data.accel,
data.never_call_transliteration_module
local link_tr = data.respect_link_tr and lang:link_tr(data.sc[1])
for i in ipairs(terms) do
local link
-- Is there any text to show?
if (data.term[i] or data.alt[i]) then
-- Try to detect the script if it was not provided
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
local best = lang:findBestScript(display_term)
-- no_nonstandard_sc_cat is intended for use in [[Module:interproject]]
if (
not data.no_nonstandard_sc_cat and
best:getCode() == "None" and
find_best_script_without_lang(display_term):getCode() ~= "None"
) then
insert(cats, lang:getFullName() .. " terms in nonstandard scripts")
end
if not data.sc[i] then
data.sc[i] = best
-- Track uses of sc parameter.
elseif data.track_sc then
if data.sc[i]:getCode() == best:getCode() then
insert(cats, lang:getFullName() .. " terms with redundant script codes")
else
insert(cats, lang:getFullName() .. " terms with non-redundant manual script codes")
end
end
-- If using a discouraged character sequence, add to maintenance category
if data.sc[i]:hasNormalizationFixes() == true then
if (data.term[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.term[i])) ~= toNFC(data.term[i])) or (data.alt[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.alt[i])) ~= toNFC(data.alt[i])) then
insert(cats, "Pages using discouraged character sequences")
end
end
link = simple_link(
data.term[i],
data.fragment,
data.alt[i],
lang,
data.sc[i],
id,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
end
-- simple_link can return nil, so check if a link has been generated.
if link then
-- Add "nowrap" class to prefixes in order to prevent wrapping after the hyphen
local nowrap
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
-- FIXME, use hyphens from [[Module:affix]]
if display_term and (display_term:find("^%*?%-") or display_term:find("^%*?־")) then -- Hebrew maqqef
nowrap = "nowrap"
end
-- Forcibly disable acceleration in the presence of embedded links, because it doesn't work correctly;
-- if one of the embedded terms doesn't exist, the acceleration code will try to make a form-of for the
-- embedded term pointing to the original headword (which is wrong).
if link:find(".%[%[") or link:find("%]%].") then
accel = nil
end
link = tag_text(link, lang, data.sc[i], face, get_css_classes(lang, data.tr[i], accel, nowrap))
else
--[[ No term to show.
Is there at least a transliteration we can work from? ]]
link = request_script(lang, data.sc[i])
-- No link to show, and no transliteration either. Show a term request (unless it's a substrate, as they rarely take terms).
if (link == "" or (not data.tr[i]) or data.tr[i] == "-") and lang:getFamilyCode() ~= "qfa-sub" then
-- If there are multiple terms, break the loop instead.
if i > 1 then
remove(outparts)
break
elseif NAMESPACE ~= "Template" then
insert(cats, lang:getFullName() .. " term requests")
end
link = "<small>[Term?]</small>"
end
end
insert(outparts, link)
if i < #terms then insert(outparts, "<span class=\"Zsym mention\" style=\"font-size:100%;\"> / </span>") end
end
-- When suppress_tr is true, do not show or generate any transliteration
if data.suppress_tr then
data.tr[1] = nil
else
-- TODO: Currently only handles the first transliteration, pending consensus on how to handle multiple translits for multiple forms, as this is not always desirable (e.g. traditional/simplified Chinese).
if data.tr[1] == "" or data.tr[1] == "-" then
data.tr[1] = nil
else
local phonetic_extraction = load_data("Module:links/data").phonetic_extraction
phonetic_extraction = phonetic_extraction[lang:getCode()] or phonetic_extraction[lang:getFullCode()]
if phonetic_extraction then
data.tr[1] = data.tr[1] or
require(phonetic_extraction).getTranslit(export.remove_links(data.alt[1] or data.term[1]))
elseif (data.term[1] or data.alt[1]) and data.sc[1]:isTransliterated() then
-- Track whenever there is manual translit. The categories below like 'terms with redundant transliterations'
-- aren't sufficient because they only work with reference to automatic translit and won't operate at all in
-- languages without any automatic translit, like Persian and Hebrew.
if data.tr[1] then
local full_code = lang:getFullCode()
track("manual-tr", full_code)
end
if not never_call_transliteration_module then
-- Try to generate a transliteration.
local text = data.alt[1] or data.term[1]
if not link_tr then
text = export.remove_links(text, true)
end
local automated_tr = lang:transliterate(text, data.sc[1])
if automated_tr then
local manual_tr = data.tr[1]
if manual_tr then
if export.remove_links(manual_tr) == export.remove_links(automated_tr) then
insert(cats, lang:getFullName() .. " terms with redundant transliterations")
else
-- Prevents Arabic root categories from flooding the tracking categories.
if NAMESPACE ~= "Category" then
insert(cats,
lang:getFullName() .. " terms with non-redundant manual transliterations")
end
end
end
if not manual_tr or lang:overrideManualTranslit(data.sc[1]) then
data.tr[1] = automated_tr
end
end
end
end
end
end
-- Link to the transliteration entry for languages that require this
if data.tr[1] and link_tr and not data.tr[1]:match("%[%[(.-)%]%]") then
data.tr[1] = simple_link(
data.tr[1],
nil,
nil,
lang,
get_script("Latn"),
nil,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
elseif data.tr[1] and not link_tr then
-- Remove the pseudo-HTML tags added by remove_links.
data.tr[1] = data.tr[1]:gsub("</?link>", "")
end
if data.tr[1] and not umatch(data.tr[1], "[^%s%p]") then data.tr[1] = nil end
insert(outparts, export.format_link_annotations(data, face))
if data.pretext then
insert(outparts, 1, data.pretext)
end
if data.posttext then
insert(outparts, data.posttext)
end
local categories = cats[1] and format_categories(cats, lang, "-", nil, nil, data.sc) or ""
local output = concat(outparts)
if data.show_decorations then
output = add_text_decorations(output, data, lang)
end
return output .. categories
end
--[==[
Strip links by replacing all wikilinks with their displayed text, and remove any categories. This function can be
invoked either from a template or from another module. Specifically, this function deletes category links, the targets
of piped links, and any double square brackets involved in links (other than file links, which are untouched). If `tag`
is set, then any links removed will be given pseudo-HTML tags, which allow the substitution functions in
[[Module:languages]] to properly subdivide the text in order to reduce the chance of substitution failures in modules
which scrape pages like [[Module:zh-translit]]. (FIXME: This is quite hacky. We probably want this to be integrated
into [[Module:languages]], but we can't do that until we know that nothing is pushing pipe linked transliterations
through it for languages which don't have link_tr set.)
* `<nowiki>[[page|displayed text]]</nowiki>` → `displayed text`
* `<nowiki>[[page and displayed text]]</nowiki>` → `page and displayed text`
* `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` → ''(nothing)''
]==]
function export.remove_links(text, tag)
if type(text) == "table" then
text = text.args[1]
end
if not text or text == "" then
return ""
end
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- Parse internal links for the display text.
text = text:gsub("(\1)([^\1\2]-)(\2)",
function(c1, c2, c3)
-- Don't remove files.
for _, false_positive in ipairs({ "file", "image" }) do
if c2:lower():match("^" .. false_positive .. ":") then return c1 .. c2 .. c3 end
end
-- Remove categories completely.
for _, false_positive in ipairs({ "category", "cat" }) do
if c2:lower():match("^" .. false_positive .. ":") then return "" end
end
-- In piped links, remove all text before the pipe, unless it's the final character (i.e. the pipe trick), in which case just remove the pipe.
c2 = c2:match("^[^|]*|(.+)") or c2:match("([^|]+)|$") or c2
if tag then
return "<link>" .. c2 .. "</link>"
else
return c2
end
end)
text = text
:gsub("\1", "[[")
:gsub("\2", "]]")
return text
end
function export.section_link(link)
if type(link) ~= "string" then
error("The first argument to section_link was a " .. type(link) .. ", but it should be a string.")
elseif link:find("\\", nil, true) then
track("escaped", "section_link")
end
local target, section = get_fragment((link:gsub("_", " ")))
if not section then
error("No \"#\" delineating a section name")
end
return simple_link(
target,
section,
target .. " § " .. section
)
end
return export
fxgo1kcyu74nkoxulrdg2jwx4cxaiyy
238802
238801
2026-11-12T06:10:10Z
Lee
19
[[:en:Module:links]] වෙතින් එක් සංශෝධනයක්
238801
Scribunto
text/plain
local export = {}
--[=[
[[Unsupported titles]], pages with high memory usage,
extraction modules and part-of-speech names are listed
at [[Module:links/data]].
Other modules used:
[[Module:script utilities]]
[[Module:scripts]]
[[Module:languages]] and its submodules
[[Module:gender and number]]
[[Module:debug/track]]
]=]
local anchors_module = "Module:anchors"
local debug_track_module = "Module:debug/track"
local decorations_module = "Module:decorations"
local form_of_module = "Module:form of"
local gender_and_number_module = "Module:gender and number"
local languages_module = "Module:languages"
local load_module = "Module:load"
local memoize_module = "Module:memoize"
local pages_module = "Module:pages"
local roots_module = "Module:roots"
local scripts_module = "Module:scripts"
local script_utilities_module = "Module:script utilities"
local string_encode_entities_module = "Module:string/encode entities"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local concat = table.concat
local find = string.find
local get_current_title = mw.title.getCurrentTitle
local insert = table.insert
local ipairs = ipairs
local match = string.match
local new_title = mw.title.new
local pairs = pairs
local remove = table.remove
local sub = string.sub
local toNFC = mw.ustring.toNFC
local tostring = tostring
local type = type
local unstrip = mw.text.unstrip
local NAMESPACE = get_current_title().nsText
local function anchor_encode(...)
anchor_encode = require(memoize_module)(mw.uri.anchorEncode, true)
return anchor_encode(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
-- Can't yet replace, as the [[Module:string utilities]] version no longer has automatic double-encoding prevention, which requires changes here to account for.
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function extend(...)
extend = require(table_module).extend
return extend(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_genders(...)
format_genders = require(gender_and_number_module).format_genders
return format_genders(...)
end
local function format_decorations(...)
format_decorations = require(decorations_module).format_decorations
return format_decorations(...)
end
local function get_current_L2(...)
get_current_L2 = require(pages_module).get_current_L2
return get_current_L2(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function language_anchor(...)
language_anchor = require(anchors_module).language_anchor
return language_anchor(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function request_script(...)
request_script = require(script_utilities_module).request_script
return request_script(...)
end
local function get_root_link_page(...)
get_root_link_page = require(roots_module).get_link_page
return get_root_link_page(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function trim(...)
trim = require(string_utilities_module).trim
return trim(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local m_headword_data
local function get_headword_data()
m_headword_data = load_data("Module:headword/data")
return m_headword_data
end
local function track(page, code)
local tracking_page = "links/" .. page
debug_track(tracking_page)
if code then
debug_track(tracking_page .. "/" .. code)
end
end
local function field_non_empty(list, field)
if not list then
return nil
end
if type(list) ~= "table" then
error(("Internal error: Wrong type for `termobj.%s`=%s, should be %s\"table\""):format(
field, mw.dumpObject(list), field == "q" or field == "qq" and "\"string\" or " or ""))
end
return list[1]
end
--[=[
Add any decorations (left or right regular or accent qualifiers, labels or references) to an item. `text` is the
item's text (to which to add the decorations) and `itemobj` is the object specifying the item's decorations, which
should optionally contain:
* left regular qualifiers in `q` (an array of strings or a single string); an empty array will be ignored;
* right regular qualifiers in `qq` (an array of strings or a single string); an empty array will be ignored;
* left accent qualifiers in `a` (an array of strings); an empty array will be ignored;
* right accent qualifiers in `aa` (an array of strings); an empty array will be ignored;
* left labels in `l` (an array of strings); an empty array will be ignored;
* right labels in `ll` (an array of strings); an empty array will be ignored;
* references in `refs`, an array either of strings (formatted reference text) or objects containing fields `text`
(formatted reference text) and optionally `name` and/or `group`; an empty array will be ignored.
`lang` is a language object and is required if any accent qualifiers or labels are given.
]=]
local function add_text_decorations(text, itemobj, lang)
local q = itemobj.q
if type(q) == "string" then
q = { q }
end
local qq = itemobj.qq
if type(qq) == "string" then
qq = { qq }
end
if field_non_empty(q, "q") or field_non_empty(qq, "qq") or field_non_empty(itemobj.a, "a") or
field_non_empty(itemobj.aa, "aa") or field_non_empty(itemobj.l, "l") or field_non_empty(itemobj.ll, "ll") or
field_non_empty(itemobj.refs, "refs") then
text = format_decorations {
lang = lang,
text = text,
q = q,
qq = qq,
a = itemobj.a,
aa = itemobj.aa,
l = itemobj.l,
ll = itemobj.ll,
refs = itemobj.refs,
}
end
return text
end
local function selective_trim(...)
-- Unconditionally trimmed charset.
local always_trim =
"\194\128-\194\159" .. -- U+0080-009F (C1 control characters)
"\194\173" .. -- U+00AD (soft hyphen)
"\226\128\170-\226\128\174" .. -- U+202A-202E (directionality formatting characters)
"\226\129\166-\226\129\169" -- U+2066-2069 (directionality formatting characters)
-- Standard trimmed charset.
local standard_trim = "%s" .. -- (default whitespace charset)
"\226\128\139-\226\128\141" .. -- U+200B-200D (zero-width spaces)
always_trim
-- If there are non-whitespace characters, trim all characters in `standard_trim`.
-- Otherwise, only trim the characters in `always_trim`.
selective_trim = function(text)
if text == "" then
return text
end
local trimmed = trim(text, standard_trim)
if trimmed ~= "" then
return trimmed
end
return trim(text, always_trim)
end
return selective_trim(...)
end
local function escape(text, str)
local rep
repeat
text, rep = text:gsub("\\\\(\\*" .. str .. ")", "\5%1")
until rep == 0
return (text:gsub("\\" .. str, "\6"))
end
local function unescape(text, str)
return (text
:gsub("\5", "\\")
:gsub("\6", str))
end
local function has_unescaped_carets(text)
return escape(text, "^"):find("^", 1, true) ~= nil
end
local function assert_caret_capitalization_allowed(text, sc)
if sc:forbidsCaretCapitalization() and has_unescaped_carets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove bold, italics, soft hyphens, strip markers and HTML tags.
local function remove_formatting(str)
str = str
:gsub("('*)'''(.-'*)'''", "%1%2")
:gsub("('*)''(.-'*)''", "%1%2")
:gsub("", "")
return (unstrip(str)
:gsub("<[^<>]+>", ""))
end
--[==[
Split `text` on double slashes (taking account of escaping backslashes). Return a list of split items.
]==]
function export.split_on_slashes(text)
if text:find("\\", nil, true) then
track("escaped", "split_on_slashes")
end
text = split(escape(text, "//"), "//", true) or {}
for i, v in ipairs(text) do
text[i] = unescape(v, "//")
if v == "" then
text[i] = false
end
end
return text
end
--[==[
If `text` is a wikilink (i.e. in the form `<nowiki>[[foo]]</nowiki>` or `<nowiki>[[foo|bar]]</nowiki>`), return the link
target and display text. If the wikilink is single-part, the display text will be the same as the link target. If the
text is not in wikilink form, return {nil} for both link target and display text.
]==]
function export.get_wikilink_parts(text)
-- TODO: replace `allow_bad_target` with `allow_unsupported`, with support for links to unsupported titles, including escape sequences.
if ( -- Filters out anything but "[[...]]" with no intermediate "[[" or "]]".
not match(text, "^()%[%[") or -- Faster than sub(text, 1, 2) ~= "[[".
find(text, "[[", 3, true) or
find(text, "]]", 3, true) ~= #text - 1
) then
return nil, nil
end
local pipe = find(text, "|", 3, true)
local title, display
if pipe then
title, display = sub(text, 3, pipe - 1), sub(text, pipe + 1, -3)
else
title = sub(text, 3, -3)
display = title
end
return title, display
end
-- Does the work of export.get_fragment, but can be called directly to avoid unnecessary checks for embedded links.
local function get_fragment(text)
text = escape(text, "#")
-- Replace numeric character references with the corresponding character (' → '),
-- as they contain #, which causes the numeric character reference to be
-- misparsed (wa'a → wa'a → pagename wa&, fragment 39;a).
text = decode_entities(text)
local target, fragment = text:match("^(.-)#(.+)$")
target = target or text
target = unescape(target, "#")
fragment = fragment and unescape(fragment, "#") or nil
return target, fragment
end
--[==[
Given a link target possibly containing a fragment (i.e. a pound sign and following anchor), return two values, the
actual target (minus the fragment) and the fragment, or {nil} if there is no fragment.
]==]
function export.get_fragment(text)
if text:find("\\", nil, true) then
track("escaped", "get_fragment")
end
-- If there are no embedded links, process input.
local open = find(text, "[[", nil, true)
if not open then
return get_fragment(text)
end
local close = find(text, "]]", open + 2, true)
if not close then
return get_fragment(text)
-- If there is one, but it's redundant (i.e. encloses everything with no pipe), remove and process.
elseif open == 1 and close == #text - 1 and not find(text, "|", 3, true) then
return get_fragment(sub(text, 3, -3))
end
-- Otherwise, return the input.
return text, nil
end
--[==[
Given a link target as passed to `full_link()`, get the actual page that the target refers to. This removes
bold, italics, strip markets and HTML; calls `makeEntryName()` for the language in question; converts targets
beginning with `*` to the Reconstruction namespace; and converts appendix-constructed languages to the Appendix
namespace. Returns up to three values:
# the actual page to link to, or {nil} to not link to anything;
# how the target should be displayed as, if the user didn't explicitly specify any display text; generally the
same as the original target, but minus any anti-asterisk !!;
# the value `true` if the target had a backslash-escaped * in it (FIXME: explain this more clearly).
FIXME: This should not be calling deprecated `makeEntryName()` and should always return the same number of values.
]==]
function export.get_link_page_with_auto_display(target, lang, sc, plain)
local orig_target = target
if not target then
return nil
elseif target:find("\\", nil, true) then
track("escaped", "get_link_page")
end
target = remove_formatting(target)
if target:sub(1, 1) == ":" then
track("initial colon")
-- FIXME, the auto_display (second return value) should probably remove the colon
return target:sub(2), orig_target
end
local prefix = target:match("^(.-):")
-- Convert any escaped colons
target = target:gsub("\\:", ":")
if prefix then
-- If this is an a link to another namespace or an interwiki link, ensure there's an initial colon and then
-- return what we have (so that it works as a conventional link, and doesn't do anything weird like add the term
-- to a category.)
prefix = ulower(trim(prefix))
if prefix ~= "" and (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
return target, orig_target
end
end
-- Check if the term is reconstructed and remove any asterisk. Also check for anti-asterisk (!!).
-- Otherwise, handle the escapes.
local reconstructed, escaped, anti_asterisk
if not plain then
target, reconstructed = target:gsub("^%*(.)", "%1")
if reconstructed == 0 then
target, anti_asterisk = target:gsub("^!!(.)", "%1")
if anti_asterisk == 1 then
-- Remove !! from original. FIXME! We do it this way because the call to remove_formatting() above
-- may cause non-initial !! to be interpreted as anti-asterisks. We should surely move the
-- remove_formatting() call later.
orig_target = orig_target:gsub("^!!", "")
end
end
end
target, escaped = target:gsub("^(\\-)\\%*", "%1*")
if not (sc and sc:getCode() ~= "None") then
sc = lang:findBestScript(target)
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
if target:match("%^") then
assert_caret_capitalization_allowed(target, sc)
if sc:hasCaretCapitalization() then
target = escape(target, "^")
:gsub("%^", "")
target = unescape(target, "^")
end
end
-- Get the entry name for the language.
target = lang:makeEntryName(target, sc, reconstructed == 1 or lang:hasType("appendix-constructed"))
-- If the link contains unexpanded template parameters, then don't create a link.
if target:match("{{{.-}}}") then
-- FIXME: Should we return the original target as the default display value (second return value)?
return nil
end
-- Link to appendix for reconstructed terms and terms in appendix-only languages. Plain links interpret *
-- literally, however.
if reconstructed == 1 then
if lang:getFullCode() == "und" then
-- Return the original target as default display value. If we don't do this, we wrongly get
-- [Term?] displayed instead.
return nil, orig_target
end
target = "Reconstruction:" .. lang:getFullName() .. "/" .. target
-- Reconstructed languages and substrates require an initial *.
elseif anti_asterisk ~= 1 and (lang:hasType("reconstructed") or lang:getFamilyCode() == "qfa-sub") then
error(("The specified language %s is unattested, while the term '%s' does not begin with '*' to indicate that it is reconstructed.")
:
format(lang:getCanonicalName(), orig_target))
elseif lang:hasType("appendix-constructed") then
target = "Appendix:" .. lang:getFullName() .. "/" .. target
else
target = target
end
return target, orig_target, escaped > 0
end
function export.get_link_page(target, lang, sc, plain)
local target, auto_display, escaped = export.get_link_page_with_auto_display(target, lang, sc, plain)
return target, escaped
end
-- Make a link from a given link's parts.
local function make_link(link, lang, sc, id, isolated, cats, no_alt_ast, plain)
-- Convert percent encoding to plaintext.
link.target = link.target and decode_uri(link.target, "PATH")
link.fragment = link.fragment and decode_uri(link.fragment, "PATH")
-- Find fragments (if one isn't already set).
-- Prevents {{l|en|word#Etymology 2|word}} from linking to [[word#Etymology 2#English]].
-- # can be escaped as \#.
if link.target and link.fragment == nil then
link.target, link.fragment = get_fragment(link.target)
end
-- Process the target
local auto_display, escaped
link.target, auto_display, escaped = export.get_link_page_with_auto_display(link.target, lang, sc, plain)
-- Create a default display form.
-- If the target is "" then it's a link like [[#English]], which refers to the current page.
if auto_display == "" then
auto_display = (m_headword_data or get_headword_data()).pagename
end
-- If the display is the target and the reconstruction * has been escaped, remove the escaping backslash.
if escaped then
auto_display = auto_display:gsub("\\([^\\]*%*)", "%1", 1)
end
-- Process the display form.
if link.display then
local orig_display = link.display
link.display = lang:makeDisplayText(link.display, sc, true)
if cats then
auto_display = lang:makeDisplayText(auto_display, sc)
-- If the alt text is the same as what would have been automatically generated, then the alt parameter is
-- redundant (e.g. {{l|en|foo|foo}}, {{l|en|w:foo|foo}}, but not {{l|en|w:foo|w:foo}}). If they're
-- different, but the alt text could have been entered as the term parameter without it affecting the target
-- page, then the target parameter is redundant (e.g. {{l|ru|фу|фу́}}). If `no_alt_ast` is true, use pcall
-- to catch the error which will be thrown if this is a reconstructed lang and the alt text doesn't have *.
if link.display == auto_display then
insert(cats, lang:getFullName() .. " links with redundant alt parameters")
else
local ok, check
if no_alt_ast then
ok, check = pcall(export.get_link_page, orig_display, lang, sc, plain)
else
ok = true
check = export.get_link_page(orig_display, lang, sc, plain)
end
if ok and link.target == check then
insert(cats, lang:getFullName() .. " links with redundant target parameters")
end
end
end
else
link.display = lang:makeDisplayText(auto_display, sc)
end
if not link.target then
return link.display
end
-- If the target is the same as the current page, there is no sense id
-- and either the language code is "und" or the current L2 is the current
-- language then return a "self-link" like the software does.
if link.target == get_current_title().prefixedText then
local fragment, current_L2 = link.fragment, get_current_L2()
if (
fragment and fragment == current_L2 or
not (id or fragment) and (lang:getFullCode() == "und" or lang:getFullName() == current_L2)
) then
return tostring(mw.html.create("strong")
:addClass("selflink")
:wikitext(link.display))
end
end
-- Add fragment. Do not add a section link to "Undetermined", as such sections do not exist and are invalid.
-- TabbedLanguages handles links without a section by linking to the "last visited" section, but adding
-- "Undetermined" would break that feature. For localized prefixes that make syntax error, please use the
-- format: ["xyz"] = true.
local prefix = link.target:match("^:*([^:]+):")
prefix = prefix and ulower(prefix)
if prefix ~= "category" and not (prefix and load_data("Module:data/interwikis")[prefix]) then
if (link.fragment or link.target:sub(-1) == "#") and not plain then
track("fragment", lang:getFullCode())
if cats then
insert(cats, lang:getFullName() .. " links with manual fragments")
end
end
if not link.fragment then
if id then
link.fragment = lang:getFullCode() == "und" and anchor_encode(id) or language_anchor(lang, id)
elseif lang:getFullCode() ~= "und" and not (link.target:match("^Appendix:") or link.target:match("^Reconstruction:")) then
link.fragment = anchor_encode(lang:getFullName())
end
end
end
-- Put inward-facing square brackets around a link to isolated spacing character(s).
if isolated and link.display[1] and not umatch(decode_entities(link.display), "%S") then
link.display = "]" .. link.display .. "["
end
link.target = link.target:gsub("^(:?)(.*)", function(m1, m2)
return m1 .. encode_entities(m2, "#%&+/:<=>@[\\]_{|}")
end)
link.fragment = link.fragment and encode_entities(remove_formatting(link.fragment), "#%&+/:<=>@[\\]_{|}")
return "[[" ..
link.target:gsub("^[^:]", ":%0") .. (link.fragment and "#" .. link.fragment or "") .. "|" .. link.display .. "]]"
end
-- Split a link into its parts.
local function parse_link(linktext)
local link = { target = linktext }
local target = link.target
link.target, link.display = target:match("^(..-)|(.+)$")
if not link.target then
link.target = target
link.display = target
end
-- There's no point in processing these, as they aren't real links.
local target_lower = link.target:lower()
for _, false_positive in ipairs({ "category", "cat", "file", "image" }) do
if target_lower:match("^" .. false_positive .. ":") then
return nil
end
end
link.display = decode_entities(link.display)
link.target, link.fragment = get_fragment(link.target)
-- So that make_link does not look for a fragment again.
if not link.fragment then
link.fragment = false
end
return link
end
local function check_params_ignored_when_embedded(alt, lang, id, cats)
if alt then
track("alt-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored alt parameters")
end
end
if id then
track("id-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored id parameters")
end
end
end
-- Find embedded links and ensure they link to the correct section.
local function process_embedded_links(text, alt, lang, sc, id, cats, no_alt_ast, plain)
-- Process the non-linked text.
text = lang:makeDisplayText(text, sc, true)
-- If the text begins with * and another character, then act as if each link begins with *. However, don't do this if the * is contained within a link at the start. E.g. `|*[[foo]]` would set all_reconstructed to true, while `|[[*foo]]` would not.
local all_reconstructed = false
if not plain then
-- anchor_encode removes links etc.
if anchor_encode(text):sub(1, 1) == "*" then
all_reconstructed = true
end
-- Otherwise, handle any escapes.
text = text:gsub("^(\\-)\\%*", "%1*")
end
check_params_ignored_when_embedded(alt, lang, id, cats)
local function process_link(space1, linktext, space2)
local capture = "[[" .. linktext .. "]]"
local link = parse_link(linktext)
-- Return unprocessed false positives untouched (e.g. categories).
if not link then
return capture
end
if all_reconstructed then
if link.target:find("^!!") then
-- Check for anti-asterisk !! at the beginning of a target, indicating that a reconstructed term
-- wants a part of the term to link to a non-reconstructed term, e.g. Old English
-- {{ang-noun|m|head=*[[!!Crist|Cristes]] [[!!mæsseǣfen]]}}.
link.target = link.target:sub(3)
-- Also remove !! from the display, which may have been copied from the target (as in mæsseǣfen in
-- the example above).
link.display = link.display:gsub("^!!", "")
elseif not link.target:match("^%*") then
link.target = "*" .. link.target
end
end
linktext = make_link(link, lang, sc, id, false, nil, no_alt_ast, plain)
:gsub("^%[%[", "\3")
:gsub("%]%]$", "\4")
return space1 .. linktext .. space2
end
-- Use chars 1 and 2 as temporary substitutions, so that we can use charsets. These are converted to chars 3 and 4 by process_link, which means we can convert any remaining chars 1 and 2 back to square brackets (i.e. those not part of a link).
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- If the script uses ^ to capitalize transliterations, make sure that any carets preceding links are on the inside, so that they get processed with the following text.
if text:find("^", nil, true) then
assert_caret_capitalization_allowed(text, sc)
if sc:hasCaretCapitalization() then
text = escape(text, "^")
:gsub("%^\1", "\1%^")
text = unescape(text, "^")
end
end
text = text:gsub("\1(%s*)([^\1\2]-)(%s*)\2", process_link)
-- Remove the extra * at the beginning of a language link if it's immediately followed by a link whose display begins with * too.
if all_reconstructed then
text = text:gsub("^%*\3([^|\1-\4]+)|%*", "\3%1|*")
end
return (text
:gsub("[\1\3]", "[[")
:gsub("[\2\4]", "]]")
)
end
local function simple_link(term, fragment, alt, lang, sc, id, cats, no_alt_ast, suppress_redundant_wikilink_cat)
local plain
if lang == nil then
lang, plain = get_lang("und"), true
end
-- Get the link target and display text. If the term is the empty string, treat the input as a link to the current page.
if term == "" then
term = get_current_title().prefixedText
elseif term then
local new_term, new_alt = export.get_wikilink_parts(term)
if new_term then
check_params_ignored_when_embedded(alt, lang, id, cats)
-- [[|foo]] links are treated as plaintext "[[|foo]]".
-- FIXME: Pipes should be handled via a proper escape sequence, as they can occur in unsupported titles.
if new_term == "" then
term, alt = nil, term
else
local title = new_title(new_term)
if title then
local ns = title.namespace
-- File: and Category: links should be returned as-is.
if ns == 6 or ns == 14 then
return term
end
end
term, alt = new_term, new_alt
if cats then
if not (suppress_redundant_wikilink_cat and suppress_redundant_wikilink_cat(term, alt)) then
insert(cats, lang:getFullName() .. " links with redundant wikilinks")
end
end
end
end
end
if alt then
alt = selective_trim(alt)
if alt == "" then
alt = nil
end
end
-- If there's nothing to process, return nil.
if not (term or alt) then
return nil
end
-- If there is no script, get one.
if not sc then
sc = lang:findBestScript(alt or term)
end
-- Embedded wikilinks need to be processed individually.
if term then
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, alt, lang, sc, id, cats, no_alt_ast, plain)
end
term = selective_trim(term)
end
-- If not, make a link using the parameters.
return make_link({
target = term,
display = alt,
fragment = fragment
}, lang, sc, id, true, cats, no_alt_ast, plain)
end
--[==[
Create a basic link to the given term. It links to the language section (such as `==English==`), but it does not add
language and script wrappers, so any code that uses this function should call `[[Module:script utilities#tag_text]]`
to add such wrappers itself at some point. The first argument, `data`, may contain the following items, a subset of the
items used in the `data` argument of `##full_link`. If any other items are included, they are ignored.
{ {
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
no_alt_ast = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
cats = nil or {}, -- NOTE: If given, will be side-effected to return categories to add the page to.
} }
Specifically:
* `term`: Term to turn into a link. This is generally the name of a page, possibly with extra diacritics added (e.g.
length marks in Latin or Old English terms, accents in Russian terms, vowel diacritics in Arabic terms, etc.), which
are stripped to determine the actual pagename. The term can contain wikilinks already embedded in it. These are
processed individually just like a single link would be. The `alt` argument is ignored in this case.
* `alt`: The alternative display for the link, if different from the linked page. If this is {nil}, the `term` argument
is used instead (much like regular wikilinks). If `term` contains wikilinks in it, this argument is ignored and has no
effect. (Links in which the alt is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/alt-ignored}}.)
* `lang` ('''required'''): The [[Module:languages#Language objects|language object]] for the term being linked. The link
or links in `term` will normally have their fragment set to point to the canonical name (see
{{tl|language data documentation}}) of `lang` (or, if it is an etymology-only language, to the canonical name of its
L2 parent). (However, if `id` is defined, the fragment will point to a language-specific sense ID corresponding to
this field, which in turn will be overridden by `fragment` if specified.)
* `sc`: The [[Module:scripts#Script objects|script object]] for the term being linked. This rarely needs to be specified
because it is autodetected based on `term` or `alt`, and the detection is usually correct. It is used to determine
how to convert the term into a pagename, possibly by stripping certain diacritics from the term's text.
* `fragment`: If specified, overrides the fragment in the generated link (i.e. the portion after `#`, which determines
where on the page to go to when the link is clicked). If not specified, the fragment is generated from `id` (if given)
or otherwise from `lang`.
* `id`: Sense ID string. If this argument is defined, the link will point to a language-specific sense ID
({{ll|en|identifier|id=HTML}}) created by the template {{temp|senseid}}. The fragment for a sense ID consists of the
language's canonical name, a hyphen (`-`), and the string that was supplied as the `id` argument. This is useful when
a term has more than one sense in a language. If the `term` argument contains wikilinks, this argument is ignored.
(Links in which the sense ID is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/id-ignored}}.)
* `no_alt_ast`: This is the same as `no_alt_ast` in `##full_link()`. See that function for more information.
* `suppress_redundant_wikilink_cat`: This is the same as `suppress_redundant_wikilink_cat` in `##full_link()`. See
that function for more information.
* `cats`: This should be either {nil} or an empty list. In the latter case, tracking categories will be added to the
list when appropriate. The caller can choose to add the page to those categories (as is done by ##full_link()`).
The following special options are processed for each link (both simple terms and with embedded wikilinks):
* The target page name will be processed by stripping certain diacritics (as mentioned above) and converting the
resulting ''logical'' pagename to a ''physical'' pagename (which will be different from the logical pagename in the
case of pages with unsupported characters in them and certain overly large pages, such as [[a]], that are split into
parts).
* If the term starts with `*`, then it is considered a reconstructed term, and a link to the `Reconstruction:` namespace
will be created. If the text contains embedded wikilinks, then `*` is automatically applied to each one individually,
while preserving the displayed form of each link as it was given. This allows linking to phrases containing multiple
reconstructed terms, while only showing the `*` once at the beginning.
* If the text starts with `:`, then the link is treated as "raw" and the above steps are skipped. This can be used in
rare cases where the page name begins with `*` or if diacritics should not be stripped. For example:
** {{tl|l|en|*nix}} links to the nonexistent page [[Reconstruction:English/nix]] (`*` is interpreted as a
reconstruction), but {{tl|l|en|:*nix}} links to [[*nix]].
** {{tl|l|sl|Franche-Comté}} links to the nonexistent page [[Franche-Comte]] (`é` is converted to `e` by the
diacritic-stripping process), but {{tl|l|sl|:Franche-Comté}} links to [[Franche-Comté]].
]==]
function export.language_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function language_link must be a table. See [[Module:links/documentation]] for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "language_link")
end
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
return simple_link(
data.term,
data.fragment,
data.alt,
lang,
data.sc,
data.id,
cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
function export.plain_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function plain_link must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "plain_link")
end
return simple_link(
data.term,
data.fragment,
data.alt,
nil,
data.sc,
data.id,
data.cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
--[==[Replace any links with links to the correct section, but don't link the whole text if no embedded links are found. Returns the display text form.]==]
function export.embedded_language_links(data)
if type(data) ~= "table" then
error(
"The first argument to the function embedded_language_links must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "embedded_language_links")
end
local term, lang, sc = data.term, data.lang, data.sc
-- If we don't have a script, get one.
if not sc then
sc = lang:findBestScript(term)
end
-- Do we have embedded wikilinks? If so, they need to be processed individually.
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, data.alt, lang, sc, data.id, data.cats, data.no_alt_ast)
end
-- If not, return the display text.
term = selective_trim(term)
-- FIXME: Double-escape any percent-signs, because we don't want to treat non-linked text as having percent-encoded
-- characters. This is a hack: percent-decoding should come out of [[Module:languages]] and only dealt with in this
-- module, as it's specific to links.
term = term:gsub("%%", "%%25")
return lang:makeDisplayText(term, sc, true)
end
function export.mark(text, item_type, face, lang)
local tag = { "", "" }
if item_type == "gloss" then
tag = { '<span class="mention-gloss-double-quote">“</span><span class="mention-gloss">',
'</span><span class="mention-gloss-double-quote">”</span>' }
if type(text) == "string" and text:match("^''[^'].*''$") then
-- Temporary tracking for mention glosses that are entirely italicized or bolded, which is probably
-- wrong. (Note that this will also find bolded mention glosses since they use triple apostrophes.)
track("italicized-mention-gloss", lang and lang:getFullCode() or nil)
end
elseif item_type == "tr" then
if face == "term" then
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr mention-tr Latn">',
'</span>' }
else
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr Latn">', '</span>' }
end
elseif item_type == "ts" then
-- \226\129\160 = word joiner (zero-width non-breaking space) U+2060
tag = { '<span class="ts mention-ts Latn">/\226\129\160', '\226\129\160/</span>' }
elseif item_type == "pos" then
tag = { '<span class="ann-pos">', '</span>' }
elseif item_type == "non-gloss" then
tag = { '<span class="ann-non-gloss">', '</span>' }
elseif item_type == "annotations" then
tag = { '<span class="mention-gloss-paren annotation-paren">(</span>',
'<span class="mention-gloss-paren annotation-paren">)</span>' }
elseif item_type == "infl" then
tag = { '<span class="ann-infl">', '</span>' }
end
if type(text) == "string" then
return tag[1] .. text .. tag[2]
else
return ""
end
end
--[=[
Implementation of `format_transliteration` and `format_transcription`. The implementation is identical except that the
field containing the transliteration or transcription may vary and is specified in `field`, and the way a given
transliteration or transcription is tagged may vary and is controlled by `tag_fn`, which is passed three parameters:
`text` (the transliteration or transcription), `lang` (the language passed in) and `face` (the face passed in).
On input, `item` is the transliteration or transcription or list of such objects; `field` is either {"tr"} or {"ts"};
`tag_fn` is a function of three parameters to tag the item, as described above; `lang` is the language object of the
term whose transliteration or transcription is specified; and `face` is a string indicating how to display the item
(generally only the strings {"term"} and {"default"} are recognized).
]=]
local function format_transliteration_or_transcription(item, field, tag_fn, lang, item_face)
if type(item) == "string" then
return tag_fn(item, lang, item_face)
end
local formatted_items = {}
for _, itemobj in ipairs(item) do
local tagged_item = tag_fn(itemobj[field], lang, item_face)
tagged_item = add_text_decorations(tagged_item, item, lang)
insert(formatted_items, tagged_item)
end
if formatted_items[2] then
-- FIXME: This should be customizable.
return concat(formatted_items, " <i>or</i> ")
else
return formatted_items[1]
end
end
--[==[
Format a transliteration string or list of transliteration objects. `tr` contains the transliteration(s), which for
forward compatibility reasons can only be either a single transliteration string or a list of transliteration objects
(each of which has a `tr` field holding the transliteration and optional fields `q`, `qq`, `l`, `ll` and/or `refs`).
This correctly handles multiple transliterations as well as decorations (qualifiers, labels or references) attached to
transliterations.
]==]
function export.format_transliteration(tr, lang, face)
return format_transliteration_or_transcription(tr, "tr", tag_translit, lang, face)
end
local function tag_transcription(ts, _lang, _face)
return export.mark(ts, "ts")
end
--[==[
Format a transcription string or list of transcription objects. `ts` contains the transcription(s), which for forward
compatibility reasons can only be either a single transcription string or a list of transcription objects (each of which
has a `ts` field holding the transcription and optional decoration fields `q`, `qq`, `l`, `ll` and/or `refs`). This
correctly handles multiple transcriptions as well as decorations (qualifiers, labels or references) attached to
transcriptions.
]==]
function export.format_transcription(ts, lang, face)
return format_transliteration_or_transcription(ts, "ts", tag_transcription, lang, face)
end
local pos_tags
--[==[
Format the annotations that are displayed with a link created by `full_link()`. Annotations are the extra bits of
information that are displayed following the linked term, and include things such as gender, transliteration, gloss,
etc. The first argument is a table with some or all of the following keys (all are optional):
* `interwiki`: An interwiki link. This is used for links in translation tables to the corresponding term in another
Wiktionary. If specified, it should be a fully formatted link and is inserted as-is at the beginning of the output.
See the `interwiki()` function in [[Module:translations]].
* `genders`: Table containing a list of gender specifications in the style of [[Module:gender and number]]. If
specified, these are formatted using `format_genders()` in [[Module:gender and number]] and the result inserted at
the beginning of the output, following any interwiki link and (in all cases) directly after a no-break space.
* `tr`: Transliteration or transliterations. Currently, this is always a one-item list. It is a list because of
potential support for per-alternant transliterations due to the multiple alternants (separated by `//`) that can be
specified in `term` or `alt`. The item in the list can be either a string or a list of transliteration objects (see
`format_transliteration()`).
* `ts`: Transcription or transcriptions. Like `tr`, this is currently always a one-item list, with the item being either
a single string or a list of transcription objects, as described in `format_transcription()`.
* `gloss`: Gloss that translates the term in the link.
* `pos`: Part of speech of the linked term. If the given argument matches one of the aliases in `pos_aliases` in
[[Module:headword/data]], or consists of a part of speech or alias followed by `f` (for a non-lemma form), expand it
appropriately. Otherwise, just show the given text as it is.
With `root`, the term links to the page where [[Module:roots]] keeps the language's roots, for languages that keep
them outside the main namespace (`Appendix:Arabic roots/…`).
* `infl`: A list of tags, each a string. Multiple tag sets may be encoded in this list by separating them with an
element consisting of a semicolon. If there are multiple tag sets, they are formatted individually and separated
by a semicolon + space.
* `ng`: Arbitrary non-gloss descriptive text for the link. This should be used in preference to putting descriptive text
in `gloss` or `pos`.
* `lit`: Literal meaning of the term, if the usual meaning is figurative or idiomatic.
* `postprocess_annotations`: A function to postprocess the annotations, after they have been formatted (see below).
The `interwiki` and `genders` properties are formatted specially, and `postprocess_annotations` is a callback function
rather than an item to display; all others are formatted (each in their own way), separated by commas and placed inside
of parentheses (except that if both transliteration and transcription are present, they are separated by a space). The
order of the annotations is `tr`+`ts`, `gloss`, `pos`, `infl`, `ng` and `lit`. The `postprocess_annotations` function,
if supplied, is passed a single object, a table with two keys `data` (the `data` object passed into
`format_link_annotations()`) and `annotations` (the formatted annotations, prior to being concatenated). It should
side-effect the `annotations` list, e.g. by inserting more annotations. (It is used to handle nested inflections in
[[Module:headword]]. FIXME: It should probably be generalized so that it can return the final formatted string, to allow
for e.g. changing the way the annotations are formatted.)
* The second argument is a string controlling the "face" that the terms are displayed in. Currently it only affects
transliteration and transcription and only when the value {"term"} is passed in, in which case those annotations are
displayed italicized.
]==]
function export.format_link_annotations(data, face)
local output = {}
-- Interwiki link
if data.interwiki then
insert(output, data.interwiki)
end
-- Genders
if type(data.genders) ~= "table" then
data.genders = { data.genders }
end
if data.genders and data.genders[1] then
local genders, gender_cats = format_genders(data.genders, data.lang)
insert(output, " " .. genders)
if gender_cats then
local cats = data.cats
if cats then
extend(cats, gender_cats)
end
end
end
local annotations = {}
-- Transliteration and transcription
local tr = data.tr and data.tr[1] or nil
local ts = data.ts and data.ts[1] or nil
if tr or ts then
local item_face
if face == "term" then
item_face = face
else
item_face = "default"
end
local formatted_tr = tr and export.format_transliteration(tr, data.lang, item_face) or nil
local formatted_ts = ts and export.format_transcription(ts, data.lang, item_face) or nil
if formatted_tr and formatted_ts then
insert(annotations, {text = formatted_tr .. " " .. formatted_ts})
else
insert(annotations, {text = formatted_tr or formatted_ts})
end
end
-- Gloss/translation
if data.gloss then
insert(annotations, {text = export.mark(data.gloss, "gloss")})
end
-- Part of speech
if data.pos then
-- debug category for pos= containing transcriptions
if data.pos:match("/[^><]-/") then
data.pos = data.pos .. "[[Category:links likely containing transcriptions in pos]]"
end
-- Canonicalize part of speech aliases as well as non-lemma aliases like 'nf' or 'nounf' for "noun form".
pos_tags = pos_tags or (m_headword_data or get_headword_data()).pos_aliases
local pos = pos_tags[data.pos]
if not pos and data.pos:find("f$") then
local pos_form = data.pos:sub(1, -2)
-- We only expand something ending in 'f' if the result is a recognized non-lemma POS.
pos_form = (pos_tags[pos_form] or pos_form) .. " form"
if (m_headword_data or get_headword_data()).nonlemmas[pos_form .. "s"] then
pos = pos_form
end
end
insert(annotations, {text = export.mark(pos or data.pos, "pos")})
end
-- Inflection data
if data.infl then
local m_form_of = require(form_of_module)
-- Split tag sets manually, since tagged_inflections creates a numbered list, and we do not want that.
local infl_outputs = {}
local tag_sets = m_form_of.split_tag_set(data.infl)
for _, tag_set in ipairs(tag_sets) do
table.insert(infl_outputs,
m_form_of.tagged_inflections({ tags = tag_set, lang = data.lang, nocat = true, nolink = true, nowrap = true }))
end
insert(annotations, {text = export.mark(table.concat(infl_outputs, "; "), "infl")})
end
-- Non-gloss text
if data.ng then
local separator
local ng = data.ng
if ng:find("^[;:]") then
separator = ""
elseif ng:find("^_") then
ng = ng:sub(2)
separator = " "
end
insert(annotations, {text = export.mark(ng, "non-gloss"), separator = separator})
end
-- Literal/sum-of-parts meaning
if data.lit then
insert(annotations, {text = "literally " .. export.mark(data.lit, "gloss")})
end
-- Provide a hook to insert additional annotations such as nested inflections.
if data.postprocess_annotations then
data.postprocess_annotations {
data = data,
annotations = annotations
}
end
if annotations[1] then
local annparts = {}
for i, annotation in ipairs(annotations) do
local separator = annotation.separator
if not separator then
if i == 1 then
separator = ""
else
separator = ", "
end
end
insert(annparts, separator)
insert(annparts, annotation.text)
end
insert(output, " ")
insert(output, export.mark(concat(annparts), "annotations"))
end
return concat(output)
end
-- Encode certain characters to avoid various delimiter-related issues at various stages. We need to encode < and >
-- because they end up forming part of CSS class names inside of <span ...> and will interfere with finding the end
-- of the HTML tag. I first tried converting them to URL encoding, i.e. %3C and %3E; they then appear in the URL as
-- %253C and %253E, which get mapped back to %3C and %3E when passed to [[Module:accel]]. But mapping them to <
-- and > somehow works magically without any further work; they appear in the URL as < and >, and get passed to
-- [[Module:accel]] as < and >. I have no idea who along the chain of calls is doing the encoding and decoding. If
-- someone knows, please modify this comment appropriately!
local accel_char_map
local function get_accel_char_map()
accel_char_map = {
["%"] = ".",
[" "] = "_",
["_"] = u(0xFFF0),
["<"] = "<",
[">"] = ">",
}
return accel_char_map
end
local function encode_accel_param_chars(param)
return (param:gsub("[%% <>_]", accel_char_map or get_accel_char_map()))
end
local function encode_accel_param(prefix, param)
if not param then
return ""
end
if type(param) == "table" then
local filled_params = {}
-- There may be gaps in the sequence, especially for translit params.
local maxindex = 0
for k in pairs(param) do
if type(k) == "number" and k > maxindex then
maxindex = k
end
end
for i = 1, maxindex do
filled_params[i] = param[i] or ""
end
-- [[Module:accel]] splits these up again.
param = concat(filled_params, "*~!")
end
-- This is decoded again by [[WT:ACCEL]].
return prefix .. encode_accel_param_chars(param)
end
local function insert_if_not_blank(list, item)
if item == "" then
return
end
insert(list, item)
end
local function get_css_classes(lang, tr, accel, nowrap)
if not accel and not nowrap then
return ""
end
local classes = {}
if accel then
insert(classes, "form-of lang-" .. lang:getFullCode())
local form = accel.form
if form then
insert(classes, encode_accel_param_chars(form) .. "-form-of")
end
insert_if_not_blank(classes, encode_accel_param("gender-", accel.gender))
insert_if_not_blank(classes, encode_accel_param("pos-", accel.pos))
insert_if_not_blank(classes, encode_accel_param("transliteration-", accel.translit or (tr ~= "-" and tr or nil)))
insert_if_not_blank(classes, encode_accel_param("target-", accel.target))
insert_if_not_blank(classes, encode_accel_param("origin-", accel.lemma))
insert_if_not_blank(classes, encode_accel_param("origin_transliteration-", accel.lemma_translit))
if accel.no_store then
insert(classes, "form-of-nostore")
end
end
if nowrap then
insert(classes, nowrap)
end
return concat(classes, " ")
end
--[==[
Creates a full link, with annotations (see `##format_link_annotations`), in the style of {{tl|l}} or {{tl|m}}.
The first argument, `data`, must be a table. It contains the various elements that can be supplied as parameters to
{{tl|l}} or {{tl|m}}:
{ {
-- Basic link-related fields
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
accel = {accelerated_creation_tags},
-- Link annotation fields
interwiki = "interwiki_link",
genders = {"gender1", "gender2", ...} or {{spec = "gender1", q = {"left qualifier", ...}, qq = {"right qualifier"}, ...}, ...},
tr = "transliteration" or "-" or {{tr = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
ts = "transcription" or {{ts = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
gloss = "gloss",
pos = "part_of_speech_tag",
infl = {"infl1_tag1", "infl1_tag2", ..., ";", "infl2_tag1", "infl2_tag2", ...},
ng = "non-gloss text",
lit = "literal_translation",
postprocess_annotations = function({data = full_link_data, annotations = {"annotation1", "annotation2", ...}}) -> nil,
-- Other transliteration-related fields
respect_link_tr = boolean,
never_call_transliteration_module = boolean,
suppress_tr = boolean,
-- Decoration fields
q = { "left_qualifier1", "left_qualifier2", ...} or "left_qualifier",
qq = { "right_qualifier1", "right_qualifier2", ...} or "right_qualifier",
l = { "left_label1", "left_label2", ...},
ll = { "right_label1", "right_label2", ...},
a = { "left_accent_qualifier1", "left_accent_qualifier2", ...},
aa = { "right_accent_qualifier1", "right_accent_qualifier2", ...},
refs = { "formatted_ref1", "formatted_ref2", ...} or { {text = "text", name = "name", group = "group"}, ... },
pretext = "text_at_beginning",
posttext = "text_at_end",
show_decorations = boolean,
-- Fields controlling tracking categories
track_sc = boolean,
no_nonstandard_sc_cat = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
-- Miscellaneous fields
no_alt_ast = boolean,
no_generate_alternants = boolean,
} }
Any one of the items in the `data` table (except for `lang`) may be {nil}. If none of `term`, `alt` and `tr` is present,
a term request will be shown. Thus, calling {full_link{ term = term, lang = lang, sc = sc }}, where `term` is the page
to link to (which may have diacritics that will be stripped and/or embedded bracketed links) and `lang` is a
[[Module:languages#Language objects|language object]] from [[Module:languages]], will give a plain link similar to the
one produced by the template {{tl|l}}, and calling {full_link( { term = term, lang = lang, sc = sc }, "term" )} will
give a link similar to the one produced by the template {{tl|m}}.
The function will:
* Try to determine the script, based on the characters found in the `term` or `alt` argument, if the script was not
given. If a script is given and `track_sc` is {true}, it will check whether the input script is the same as the one
which would have been automatically generated and add the category ` ``lang`` terms with redundant script codes` if
yes, or ` ``lang`` terms with non-redundant manual script codes` if no. This should be used when the input script
object is directly determined by a template's `sc` parameter.
* Call `simple_link()` on the `term` or `alt` forms, to remove diacritics in the page name, process any embedded
wikilinks and create links to Reconstruction or Appendix pages when necessary. (`simple_link()` is almost exactly the
same as `##language_link()`; the latter is a simple wrapper around the former that adds a bit of extra tracking.)
* Call `[[Module:script utilities#tag_text]]` to add the appropriate language and script tags to the term and
italicize terms written in the Latin script if necessary. Accelerated creation tags, as used by [[WT:ACCEL]], are
included.
* Generate a transliteration, based on the `alt` or `term` arguments, if the script is not Latin, no transliteration was
provided in `tr` and the combination of the term's language and script support automatic transliteration. The
transliteration itself will be linked if both `.respect_link_tr` is specified and the language of the term has the
`link_tr` property set for the script of the term; but not otherwise.
* Add the annotations (transliteration, gender, gloss, etc.) after the link.
* If `no_alt_ast` is specified, then the `alt` text does not need to contain an asterisk if the language is
reconstructed. This should only be used by modules which really need to allow links to reconstructions that don't
display asterisks (e.g. number boxes).
* If `suppress_redundant_wikilink_cat` is specified, it should be a function that indicates whether to suppress the
generation of the ` ``lang`` links with redundant wikilinks` tracking category. It is passed two arguments, the `term`
and `alt` parameters. Normally, this tracking category is added whenever the `term` argument consists entirely of a
one-part or two-part embedded link, which is considered "redundant" in that the link can be rewritten into separate
`term` and `alt` arguments without any embedded links. For certain wrapping templates, however, otherwise "redundant"
embedded links are necessary to prevent interpretation of certain characters as delimiters. For example, {{tl|col}}
and related templates use `~` as a separator, as well as `,` when not followed by a space. In these templates,
embedded links are required to correctly link to terms containing those delimiters, such as [[Micros~1]] and
[[1,6-Cleves acid]], but will incorrectly trigger the addition of the tracking category unless the appropriate
`suppress_redundant_wikilink_cat` function is given.
* If `pretext` or `posttext` is specified, this is text to (respectively) prepend or append to the output, directly
before processing decorations (qualifiers, labels and references). This can be used to add arbitrary extra text inside
of the decorations.
* If `show_decorations` is specified, then decorations specified in `data` (i.e. left and right qualifiers, accent
qualifiers, labels and references) will be displayed, otherwise they will be ignored. (This is because a fair amount
of code stores decorations in these fields and displays them itself, rather than expecting {full_link()} to display
them.)
* ]==]
function export.full_link(data, face, allow_self_link, show_qualifiers)
if type(data) ~= "table" then
error("The first argument to the function full_link must be a table. "
.. "See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "full_link")
end
if show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-17, remove after 2026-10-17 or so.
error("Can't pass fourth parameter `show_qualifiers` any more. Set `show_decorations = true` on data.")
end
if data.show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-18, remove after 2026-10-18 or so.
error("Can't set field `show_qualifiers`; use `show_decorations`")
end
if data.no_generate_forms then
-- FIXME: Eventually remove the error code. Added 2026-09-14, remove after 2026-10-14 or so.
error("Can't set field `no_generate_forms`; use `no_generate_alternants`")
end
-- Prevent data from being destructively modified.
data = shallow_copy(data)
data.cats = {}
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
-- With pos=root, link to the page where Module:roots keeps the language's roots (Appendix:Arabic roots/…) and
-- display the root as given.
if data.pos == "root" and type(data.term) == "string" and not data.term:find(":", nil, true) then
local root_page = get_root_link_page(lang, data.term)
if root_page then
data.alt = data.alt or data.term
data.term = root_page
end
end
local terms = { true }
-- Generate multiple alternants if applicable.
for _, param in ipairs { "term", "alt" } do
if type(data[param]) == "string" and data[param]:find("//", nil, true) then
data[param] = export.split_on_slashes(data[param])
elseif type(data[param]) == "string" and not (type(data.term) == "string" and data.term:find("//", nil, true)) then
if not data.no_generate_alternants then
data[param] = lang:generateAlternants(data[param])
else
data[param] = { data[param] }
end
else
data[param] = {}
end
end
for _, param in ipairs { "sc", "tr", "ts" } do
data[param] = { data[param] }
end
for _, param in ipairs { "term", "alt", "sc", "tr", "ts" } do
for i in pairs(data[param]) do
terms[i] = true
end
end
-- Create the link
local outparts = {}
local id, no_alt_ast, suppress_redundant_wikilink_cat, accel, never_call_transliteration_module =
data.id, data.no_alt_ast, data.suppress_redundant_wikilink_cat, data.accel,
data.never_call_transliteration_module
local link_tr = data.respect_link_tr and lang:link_tr(data.sc[1])
for i in ipairs(terms) do
local link
-- Is there any text to show?
if (data.term[i] or data.alt[i]) then
-- Try to detect the script if it was not provided
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
local best = lang:findBestScript(display_term)
-- no_nonstandard_sc_cat is intended for use in [[Module:interproject]]
if (
not data.no_nonstandard_sc_cat and
best:getCode() == "None" and
find_best_script_without_lang(display_term):getCode() ~= "None"
) then
insert(cats, lang:getFullName() .. " terms in nonstandard scripts")
end
if not data.sc[i] then
data.sc[i] = best
-- Track uses of sc parameter.
elseif data.track_sc then
if data.sc[i]:getCode() == best:getCode() then
insert(cats, lang:getFullName() .. " terms with redundant script codes")
else
insert(cats, lang:getFullName() .. " terms with non-redundant manual script codes")
end
end
-- If using a discouraged character sequence, add to maintenance category
if data.sc[i]:hasNormalizationFixes() == true then
if (data.term[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.term[i])) ~= toNFC(data.term[i])) or (data.alt[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.alt[i])) ~= toNFC(data.alt[i])) then
insert(cats, "Pages using discouraged character sequences")
end
end
link = simple_link(
data.term[i],
data.fragment,
data.alt[i],
lang,
data.sc[i],
id,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
end
-- simple_link can return nil, so check if a link has been generated.
if link then
-- Add "nowrap" class to prefixes in order to prevent wrapping after the hyphen
local nowrap
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
-- FIXME, use hyphens from [[Module:affix]]
if display_term and (display_term:find("^%*?%-") or display_term:find("^%*?־")) then -- Hebrew maqqef
nowrap = "nowrap"
end
-- Forcibly disable acceleration in the presence of embedded links, because it doesn't work correctly;
-- if one of the embedded terms doesn't exist, the acceleration code will try to make a form-of for the
-- embedded term pointing to the original headword (which is wrong).
if link:find(".%[%[") or link:find("%]%].") then
accel = nil
end
link = tag_text(link, lang, data.sc[i], face, get_css_classes(lang, data.tr[i], accel, nowrap))
else
--[[ No term to show.
Is there at least a transliteration we can work from? ]]
link = request_script(lang, data.sc[i])
-- No link to show, and no transliteration either. Show a term request (unless it's a substrate, as they rarely take terms).
if (link == "" or (not data.tr[i]) or data.tr[i] == "-") and lang:getFamilyCode() ~= "qfa-sub" then
-- If there are multiple terms, break the loop instead.
if i > 1 then
remove(outparts)
break
elseif NAMESPACE ~= "Template" then
insert(cats, lang:getFullName() .. " term requests")
end
link = "<small>[Term?]</small>"
end
end
insert(outparts, link)
if i < #terms then insert(outparts, "<span class=\"Zsym mention\" style=\"font-size:100%;\"> / </span>") end
end
-- When suppress_tr is true, do not show or generate any transliteration
if data.suppress_tr then
data.tr[1] = nil
else
-- TODO: Currently only handles the first transliteration, pending consensus on how to handle multiple translits for multiple forms, as this is not always desirable (e.g. traditional/simplified Chinese).
if data.tr[1] == "" or data.tr[1] == "-" then
data.tr[1] = nil
else
local phonetic_extraction = load_data("Module:links/data").phonetic_extraction
phonetic_extraction = phonetic_extraction[lang:getCode()] or phonetic_extraction[lang:getFullCode()]
if phonetic_extraction then
data.tr[1] = data.tr[1] or
require(phonetic_extraction).getTranslit(export.remove_links(data.alt[1] or data.term[1]))
elseif (data.term[1] or data.alt[1]) and data.sc[1]:isTransliterated() then
-- Track whenever there is manual translit. The categories below like 'terms with redundant transliterations'
-- aren't sufficient because they only work with reference to automatic translit and won't operate at all in
-- languages without any automatic translit, like Persian and Hebrew.
if data.tr[1] then
local full_code = lang:getFullCode()
track("manual-tr", full_code)
end
if not never_call_transliteration_module then
-- Try to generate a transliteration.
local text = data.alt[1] or data.term[1]
if not link_tr then
text = export.remove_links(text, true)
end
local automated_tr = lang:transliterate(text, data.sc[1])
if automated_tr then
local manual_tr = data.tr[1]
if manual_tr then
if export.remove_links(manual_tr) == export.remove_links(automated_tr) then
insert(cats, lang:getFullName() .. " terms with redundant transliterations")
else
-- Prevents Arabic root categories from flooding the tracking categories.
if NAMESPACE ~= "Category" then
insert(cats,
lang:getFullName() .. " terms with non-redundant manual transliterations")
end
end
end
if not manual_tr or lang:overrideManualTranslit(data.sc[1]) then
data.tr[1] = automated_tr
end
end
end
end
end
end
-- Link to the transliteration entry for languages that require this
if data.tr[1] and link_tr and not data.tr[1]:match("%[%[(.-)%]%]") then
data.tr[1] = simple_link(
data.tr[1],
nil,
nil,
lang,
get_script("Latn"),
nil,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
elseif data.tr[1] and not link_tr then
-- Remove the pseudo-HTML tags added by remove_links.
data.tr[1] = data.tr[1]:gsub("</?link>", "")
end
if data.tr[1] and not umatch(data.tr[1], "[^%s%p]") then data.tr[1] = nil end
insert(outparts, export.format_link_annotations(data, face))
if data.pretext then
insert(outparts, 1, data.pretext)
end
if data.posttext then
insert(outparts, data.posttext)
end
local categories = cats[1] and format_categories(cats, lang, "-", nil, nil, data.sc) or ""
local output = concat(outparts)
if data.show_decorations then
output = add_text_decorations(output, data, lang)
end
return output .. categories
end
--[==[
Strip links by replacing all wikilinks with their displayed text, and remove any categories. This function can be
invoked either from a template or from another module. Specifically, this function deletes category links, the targets
of piped links, and any double square brackets involved in links (other than file links, which are untouched). If `tag`
is set, then any links removed will be given pseudo-HTML tags, which allow the substitution functions in
[[Module:languages]] to properly subdivide the text in order to reduce the chance of substitution failures in modules
which scrape pages like [[Module:zh-translit]]. (FIXME: This is quite hacky. We probably want this to be integrated
into [[Module:languages]], but we can't do that until we know that nothing is pushing pipe linked transliterations
through it for languages which don't have link_tr set.)
* `<nowiki>[[page|displayed text]]</nowiki>` → `displayed text`
* `<nowiki>[[page and displayed text]]</nowiki>` → `page and displayed text`
* `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` → ''(nothing)''
]==]
function export.remove_links(text, tag)
if type(text) == "table" then
text = text.args[1]
end
if not text or text == "" then
return ""
end
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- Parse internal links for the display text.
text = text:gsub("(\1)([^\1\2]-)(\2)",
function(c1, c2, c3)
-- Don't remove files.
for _, false_positive in ipairs({ "file", "image" }) do
if c2:lower():match("^" .. false_positive .. ":") then return c1 .. c2 .. c3 end
end
-- Remove categories completely.
for _, false_positive in ipairs({ "category", "cat" }) do
if c2:lower():match("^" .. false_positive .. ":") then return "" end
end
-- In piped links, remove all text before the pipe, unless it's the final character (i.e. the pipe trick), in which case just remove the pipe.
c2 = c2:match("^[^|]*|(.+)") or c2:match("([^|]+)|$") or c2
if tag then
return "<link>" .. c2 .. "</link>"
else
return c2
end
end)
text = text
:gsub("\1", "[[")
:gsub("\2", "]]")
return text
end
function export.section_link(link)
if type(link) ~= "string" then
error("The first argument to section_link was a " .. type(link) .. ", but it should be a string.")
elseif link:find("\\", nil, true) then
track("escaped", "section_link")
end
local target, section = get_fragment((link:gsub("_", " ")))
if not section then
error("No \"#\" delineating a section name")
end
return simple_link(
target,
section,
target .. " § " .. section
)
end
return export
fxgo1kcyu74nkoxulrdg2jwx4cxaiyy
238803
238802
2026-11-12T06:10:45Z
Lee
19
පැරණි සංස්කරණයකින් ගත් කොටස්...
238803
Scribunto
text/plain
local export = {}
--[=[
[[Unsupported titles]], pages with high memory usage,
extraction modules and part-of-speech names are listed
at [[Module:links/data]].
Other modules used:
[[Module:script utilities]]
[[Module:scripts]]
[[Module:languages]] and its submodules
[[Module:gender and number]]
[[Module:debug/track]]
]=]
local anchors_module = "Module:anchors"
local debug_track_module = "Module:debug/track"
local decorations_module = "Module:decorations"
local form_of_module = "Module:form of"
local gender_and_number_module = "Module:gender and number"
local languages_module = "Module:languages"
local load_module = "Module:load"
local memoize_module = "Module:memoize"
local pages_module = "Module:pages"
local roots_module = "Module:roots"
local scripts_module = "Module:scripts"
local script_utilities_module = "Module:script utilities"
local string_encode_entities_module = "Module:string/encode entities"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"
local concat = table.concat
local find = string.find
local get_current_title = mw.title.getCurrentTitle
local insert = table.insert
local ipairs = ipairs
local match = string.match
local new_title = mw.title.new
local pairs = pairs
local remove = table.remove
local sub = string.sub
local toNFC = mw.ustring.toNFC
local tostring = tostring
local type = type
local unstrip = mw.text.unstrip
local NAMESPACE = get_current_title().nsText
local function anchor_encode(...)
anchor_encode = require(memoize_module)(mw.uri.anchorEncode, true)
return anchor_encode(...)
end
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function decode_uri(...)
decode_uri = require(string_utilities_module).decode_uri
return decode_uri(...)
end
-- Can't yet replace, as the [[Module:string utilities]] version no longer has automatic double-encoding prevention, which requires changes here to account for.
local function encode_entities(...)
encode_entities = require(string_encode_entities_module)
return encode_entities(...)
end
local function extend(...)
extend = require(table_module).extend
return extend(...)
end
local function find_best_script_without_lang(...)
find_best_script_without_lang = require(scripts_module).findBestScriptWithoutLang
return find_best_script_without_lang(...)
end
local function format_categories(...)
format_categories = require(utilities_module).format_categories
return format_categories(...)
end
local function format_genders(...)
format_genders = require(gender_and_number_module).format_genders
return format_genders(...)
end
local function format_decorations(...)
format_decorations = require(decorations_module).format_decorations
return format_decorations(...)
end
local function get_current_L2(...)
get_current_L2 = require(pages_module).get_current_L2
return get_current_L2(...)
end
local function get_lang(...)
get_lang = require(languages_module).getByCode
return get_lang(...)
end
local function get_script(...)
get_script = require(scripts_module).getByCode
return get_script(...)
end
local function language_anchor(...)
language_anchor = require(anchors_module).language_anchor
return language_anchor(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function request_script(...)
request_script = require(script_utilities_module).request_script
return request_script(...)
end
local function get_root_link_page(...)
get_root_link_page = require(roots_module).get_link_page
return get_root_link_page(...)
end
local function shallow_copy(...)
shallow_copy = require(table_module).shallowCopy
return shallow_copy(...)
end
local function split(...)
split = require(string_utilities_module).split
return split(...)
end
local function tag_text(...)
tag_text = require(script_utilities_module).tag_text
return tag_text(...)
end
local function tag_translit(...)
tag_translit = require(script_utilities_module).tag_translit
return tag_translit(...)
end
local function trim(...)
trim = require(string_utilities_module).trim
return trim(...)
end
local function u(...)
u = require(string_utilities_module).char
return u(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function umatch(...)
umatch = require(string_utilities_module).match
return umatch(...)
end
local m_headword_data
local function get_headword_data()
m_headword_data = load_data("Module:headword/data")
return m_headword_data
end
local function track(page, code)
local tracking_page = "links/" .. page
debug_track(tracking_page)
if code then
debug_track(tracking_page .. "/" .. code)
end
end
local function field_non_empty(list, field)
if not list then
return nil
end
if type(list) ~= "table" then
error(("Internal error: Wrong type for `termobj.%s`=%s, should be %s\"table\""):format(
field, mw.dumpObject(list), field == "q" or field == "qq" and "\"string\" or " or ""))
end
return list[1]
end
--[=[
Add any decorations (left or right regular or accent qualifiers, labels or references) to an item. `text` is the
item's text (to which to add the decorations) and `itemobj` is the object specifying the item's decorations, which
should optionally contain:
* left regular qualifiers in `q` (an array of strings or a single string); an empty array will be ignored;
* right regular qualifiers in `qq` (an array of strings or a single string); an empty array will be ignored;
* left accent qualifiers in `a` (an array of strings); an empty array will be ignored;
* right accent qualifiers in `aa` (an array of strings); an empty array will be ignored;
* left labels in `l` (an array of strings); an empty array will be ignored;
* right labels in `ll` (an array of strings); an empty array will be ignored;
* references in `refs`, an array either of strings (formatted reference text) or objects containing fields `text`
(formatted reference text) and optionally `name` and/or `group`; an empty array will be ignored.
`lang` is a language object and is required if any accent qualifiers or labels are given.
]=]
local function add_text_decorations(text, itemobj, lang)
local q = itemobj.q
if type(q) == "string" then
q = { q }
end
local qq = itemobj.qq
if type(qq) == "string" then
qq = { qq }
end
if field_non_empty(q, "q") or field_non_empty(qq, "qq") or field_non_empty(itemobj.a, "a") or
field_non_empty(itemobj.aa, "aa") or field_non_empty(itemobj.l, "l") or field_non_empty(itemobj.ll, "ll") or
field_non_empty(itemobj.refs, "refs") then
text = format_decorations {
lang = lang,
text = text,
q = q,
qq = qq,
a = itemobj.a,
aa = itemobj.aa,
l = itemobj.l,
ll = itemobj.ll,
refs = itemobj.refs,
}
end
return text
end
local function selective_trim(...)
-- Unconditionally trimmed charset.
local always_trim =
"\194\128-\194\159" .. -- U+0080-009F (C1 control characters)
"\194\173" .. -- U+00AD (soft hyphen)
"\226\128\170-\226\128\174" .. -- U+202A-202E (directionality formatting characters)
"\226\129\166-\226\129\169" -- U+2066-2069 (directionality formatting characters)
-- Standard trimmed charset.
local standard_trim = "%s" .. -- (default whitespace charset)
"\226\128\139-\226\128\141" .. -- U+200B-200D (zero-width spaces)
always_trim
-- If there are non-whitespace characters, trim all characters in `standard_trim`.
-- Otherwise, only trim the characters in `always_trim`.
selective_trim = function(text)
if text == "" then
return text
end
local trimmed = trim(text, standard_trim)
if trimmed ~= "" then
return trimmed
end
return trim(text, always_trim)
end
return selective_trim(...)
end
local function escape(text, str)
local rep
repeat
text, rep = text:gsub("\\\\(\\*" .. str .. ")", "\5%1")
until rep == 0
return (text:gsub("\\" .. str, "\6"))
end
local function unescape(text, str)
return (text
:gsub("\5", "\\")
:gsub("\6", str))
end
local function has_unescaped_carets(text)
return escape(text, "^"):find("^", 1, true) ~= nil
end
local function assert_caret_capitalization_allowed(text, sc)
if sc:forbidsCaretCapitalization() and has_unescaped_carets(text) then
error(("Caret (^) cannot be used to capitalize transliterations for the %s script "
.. "(see caret_capitalization in [[Module:scripts/data]]).")
:format(sc:getCanonicalName()), 2)
end
end
-- Remove bold, italics, soft hyphens, strip markers and HTML tags.
local function remove_formatting(str)
str = str
:gsub("('*)'''(.-'*)'''", "%1%2")
:gsub("('*)''(.-'*)''", "%1%2")
:gsub("", "")
return (unstrip(str)
:gsub("<[^<>]+>", ""))
end
--[==[
Split `text` on double slashes (taking account of escaping backslashes). Return a list of split items.
]==]
function export.split_on_slashes(text)
if text:find("\\", nil, true) then
track("escaped", "split_on_slashes")
end
text = split(escape(text, "//"), "//", true) or {}
for i, v in ipairs(text) do
text[i] = unescape(v, "//")
if v == "" then
text[i] = false
end
end
return text
end
--[==[
If `text` is a wikilink (i.e. in the form `<nowiki>[[foo]]</nowiki>` or `<nowiki>[[foo|bar]]</nowiki>`), return the link
target and display text. If the wikilink is single-part, the display text will be the same as the link target. If the
text is not in wikilink form, return {nil} for both link target and display text.
]==]
function export.get_wikilink_parts(text)
-- TODO: replace `allow_bad_target` with `allow_unsupported`, with support for links to unsupported titles, including escape sequences.
if ( -- Filters out anything but "[[...]]" with no intermediate "[[" or "]]".
not match(text, "^()%[%[") or -- Faster than sub(text, 1, 2) ~= "[[".
find(text, "[[", 3, true) or
find(text, "]]", 3, true) ~= #text - 1
) then
return nil, nil
end
local pipe = find(text, "|", 3, true)
local title, display
if pipe then
title, display = sub(text, 3, pipe - 1), sub(text, pipe + 1, -3)
else
title = sub(text, 3, -3)
display = title
end
return title, display
end
-- Does the work of export.get_fragment, but can be called directly to avoid unnecessary checks for embedded links.
local function get_fragment(text)
text = escape(text, "#")
-- Replace numeric character references with the corresponding character (' → '),
-- as they contain #, which causes the numeric character reference to be
-- misparsed (wa'a → wa'a → pagename wa&, fragment 39;a).
text = decode_entities(text)
local target, fragment = text:match("^(.-)#(.+)$")
target = target or text
target = unescape(target, "#")
fragment = fragment and unescape(fragment, "#") or nil
return target, fragment
end
--[==[
Given a link target possibly containing a fragment (i.e. a pound sign and following anchor), return two values, the
actual target (minus the fragment) and the fragment, or {nil} if there is no fragment.
]==]
function export.get_fragment(text)
if text:find("\\", nil, true) then
track("escaped", "get_fragment")
end
-- If there are no embedded links, process input.
local open = find(text, "[[", nil, true)
if not open then
return get_fragment(text)
end
local close = find(text, "]]", open + 2, true)
if not close then
return get_fragment(text)
-- If there is one, but it's redundant (i.e. encloses everything with no pipe), remove and process.
elseif open == 1 and close == #text - 1 and not find(text, "|", 3, true) then
return get_fragment(sub(text, 3, -3))
end
-- Otherwise, return the input.
return text, nil
end
--[==[
Given a link target as passed to `full_link()`, get the actual page that the target refers to. This removes
bold, italics, strip markets and HTML; calls `makeEntryName()` for the language in question; converts targets
beginning with `*` to the Reconstruction namespace; and converts appendix-constructed languages to the Appendix
namespace. Returns up to three values:
# the actual page to link to, or {nil} to not link to anything;
# how the target should be displayed as, if the user didn't explicitly specify any display text; generally the
same as the original target, but minus any anti-asterisk !!;
# the value `true` if the target had a backslash-escaped * in it (FIXME: explain this more clearly).
FIXME: This should not be calling deprecated `makeEntryName()` and should always return the same number of values.
]==]
function export.get_link_page_with_auto_display(target, lang, sc, plain)
local orig_target = target
if not target then
return nil
elseif target:find("\\", nil, true) then
track("escaped", "get_link_page")
end
target = remove_formatting(target)
if target:sub(1, 1) == ":" then
track("initial colon")
-- FIXME, the auto_display (second return value) should probably remove the colon
return target:sub(2), orig_target
end
local prefix = target:match("^(.-):")
-- Convert any escaped colons
target = target:gsub("\\:", ":")
if prefix then
-- If this is an a link to another namespace or an interwiki link, ensure there's an initial colon and then
-- return what we have (so that it works as a conventional link, and doesn't do anything weird like add the term
-- to a category.)
prefix = ulower(trim(prefix))
if prefix ~= "" and (
load_data("Module:data/namespaces")[prefix] or
load_data("Module:data/interwikis")[prefix]
) then
return target, orig_target
end
end
-- Check if the term is reconstructed and remove any asterisk. Also check for anti-asterisk (!!).
-- Otherwise, handle the escapes.
local reconstructed, escaped, anti_asterisk
if not plain then
target, reconstructed = target:gsub("^%*(.)", "%1")
if reconstructed == 0 then
target, anti_asterisk = target:gsub("^!!(.)", "%1")
if anti_asterisk == 1 then
-- Remove !! from original. FIXME! We do it this way because the call to remove_formatting() above
-- may cause non-initial !! to be interpreted as anti-asterisks. We should surely move the
-- remove_formatting() call later.
orig_target = orig_target:gsub("^!!", "")
end
end
end
target, escaped = target:gsub("^(\\-)\\%*", "%1*")
if not (sc and sc:getCode() ~= "None") then
sc = lang:findBestScript(target)
end
-- Remove carets if they are used to capitalize parts of transliterations (unless they have been escaped).
if target:match("%^") then
assert_caret_capitalization_allowed(target, sc)
if sc:hasCaretCapitalization() then
target = escape(target, "^")
:gsub("%^", "")
target = unescape(target, "^")
end
end
-- Get the entry name for the language.
target = lang:makeEntryName(target, sc, reconstructed == 1 or lang:hasType("appendix-constructed"))
-- If the link contains unexpanded template parameters, then don't create a link.
if target:match("{{{.-}}}") then
-- FIXME: Should we return the original target as the default display value (second return value)?
return nil
end
-- Link to appendix for reconstructed terms and terms in appendix-only languages. Plain links interpret *
-- literally, however.
if reconstructed == 1 then
if lang:getFullCode() == "und" then
-- Return the original target as default display value. If we don't do this, we wrongly get
-- [Term?] displayed instead.
return nil, orig_target
end
target = "Reconstruction:" .. lang:getFullName() .. "/" .. target
-- Reconstructed languages and substrates require an initial *.
elseif anti_asterisk ~= 1 and (lang:hasType("reconstructed") or lang:getFamilyCode() == "qfa-sub") then
error(("The specified language %s is unattested, while the term '%s' does not begin with '*' to indicate that it is reconstructed.")
:
format(lang:getCanonicalName(), orig_target))
elseif lang:hasType("appendix-constructed") then
target = "Appendix:" .. lang:getFullName() .. "/" .. target
else
target = target
end
return target, orig_target, escaped > 0
end
function export.get_link_page(target, lang, sc, plain)
local target, auto_display, escaped = export.get_link_page_with_auto_display(target, lang, sc, plain)
return target, escaped
end
-- Make a link from a given link's parts.
local function make_link(link, lang, sc, id, isolated, cats, no_alt_ast, plain)
-- Convert percent encoding to plaintext.
link.target = link.target and decode_uri(link.target, "PATH")
link.fragment = link.fragment and decode_uri(link.fragment, "PATH")
-- Find fragments (if one isn't already set).
-- Prevents {{l|en|word#Etymology 2|word}} from linking to [[word#Etymology 2#English]].
-- # can be escaped as \#.
if link.target and link.fragment == nil then
link.target, link.fragment = get_fragment(link.target)
end
-- Process the target
local auto_display, escaped
link.target, auto_display, escaped = export.get_link_page_with_auto_display(link.target, lang, sc, plain)
-- Create a default display form.
-- If the target is "" then it's a link like [[#English]], which refers to the current page.
if auto_display == "" then
auto_display = (m_headword_data or get_headword_data()).pagename
end
-- If the display is the target and the reconstruction * has been escaped, remove the escaping backslash.
if escaped then
auto_display = auto_display:gsub("\\([^\\]*%*)", "%1", 1)
end
-- Process the display form.
if link.display then
local orig_display = link.display
link.display = lang:makeDisplayText(link.display, sc, true)
if cats then
auto_display = lang:makeDisplayText(auto_display, sc)
-- If the alt text is the same as what would have been automatically generated, then the alt parameter is
-- redundant (e.g. {{l|en|foo|foo}}, {{l|en|w:foo|foo}}, but not {{l|en|w:foo|w:foo}}). If they're
-- different, but the alt text could have been entered as the term parameter without it affecting the target
-- page, then the target parameter is redundant (e.g. {{l|ru|фу|фу́}}). If `no_alt_ast` is true, use pcall
-- to catch the error which will be thrown if this is a reconstructed lang and the alt text doesn't have *.
if link.display == auto_display then
insert(cats, lang:getFullName() .. " links with redundant alt parameters")
else
local ok, check
if no_alt_ast then
ok, check = pcall(export.get_link_page, orig_display, lang, sc, plain)
else
ok = true
check = export.get_link_page(orig_display, lang, sc, plain)
end
if ok and link.target == check then
insert(cats, lang:getFullName() .. " links with redundant target parameters")
end
end
end
else
link.display = lang:makeDisplayText(auto_display, sc)
end
if not link.target then
return link.display
end
-- If the target is the same as the current page, there is no sense id
-- and either the language code is "und" or the current L2 is the current
-- language then return a "self-link" like the software does.
if link.target == get_current_title().prefixedText then
local fragment, current_L2 = link.fragment, get_current_L2()
if (
fragment and fragment == current_L2 or
not (id or fragment) and (lang:getFullCode() == "und" or lang:getFullName() == current_L2)
) then
return tostring(mw.html.create("strong")
:addClass("selflink")
:wikitext(link.display))
end
end
-- Add fragment. Do not add a section link to "Undetermined", as such sections do not exist and are invalid.
-- TabbedLanguages handles links without a section by linking to the "last visited" section, but adding
-- "Undetermined" would break that feature. For localized prefixes that make syntax error, please use the
-- format: ["xyz"] = true.
local prefix = link.target:match("^:*([^:]+):")
prefix = prefix and ulower(prefix)
if prefix ~= "category" and not (prefix and load_data("Module:data/interwikis")[prefix]) then
if (link.fragment or link.target:sub(-1) == "#") and not plain then
track("fragment", lang:getFullCode())
if cats then
insert(cats, lang:getFullName() .. " links with manual fragments")
end
end
if not link.fragment then
if id then
link.fragment = lang:getFullCode() == "und" and anchor_encode(id) or language_anchor(lang, id)
elseif lang:getFullCode() ~= "und" and not (link.target:match("^Appendix:") or link.target:match("^Reconstruction:")) then
link.fragment = anchor_encode(lang:getFullName())
end
end
end
-- Put inward-facing square brackets around a link to isolated spacing character(s).
if isolated and link.display[1] and not umatch(decode_entities(link.display), "%S") then
link.display = "]" .. link.display .. "["
end
link.target = link.target:gsub("^(:?)(.*)", function(m1, m2)
return m1 .. encode_entities(m2, "#%&+/:<=>@[\\]_{|}")
end)
link.fragment = link.fragment and encode_entities(remove_formatting(link.fragment), "#%&+/:<=>@[\\]_{|}")
return "[[" ..
link.target:gsub("^[^:]", ":%0") .. (link.fragment and "#" .. link.fragment or "") .. "|" .. link.display .. "]]"
end
-- Split a link into its parts.
local function parse_link(linktext)
local link = { target = linktext }
local target = link.target
link.target, link.display = target:match("^(..-)|(.+)$")
if not link.target then
link.target = target
link.display = target
end
-- There's no point in processing these, as they aren't real links.
local target_lower = link.target:lower()
for _, false_positive in ipairs({ "category", "cat", "file", "image" }) do
if target_lower:match("^" .. false_positive .. ":") then
return nil
end
end
link.display = decode_entities(link.display)
link.target, link.fragment = get_fragment(link.target)
-- So that make_link does not look for a fragment again.
if not link.fragment then
link.fragment = false
end
return link
end
local function check_params_ignored_when_embedded(alt, lang, id, cats)
if alt then
track("alt-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored alt parameters")
end
end
if id then
track("id-ignored")
if cats then
insert(cats, lang:getFullName() .. " links with ignored id parameters")
end
end
end
-- Find embedded links and ensure they link to the correct section.
local function process_embedded_links(text, alt, lang, sc, id, cats, no_alt_ast, plain)
-- Process the non-linked text.
text = lang:makeDisplayText(text, sc, true)
-- If the text begins with * and another character, then act as if each link begins with *. However, don't do this if the * is contained within a link at the start. E.g. `|*[[foo]]` would set all_reconstructed to true, while `|[[*foo]]` would not.
local all_reconstructed = false
if not plain then
-- anchor_encode removes links etc.
if anchor_encode(text):sub(1, 1) == "*" then
all_reconstructed = true
end
-- Otherwise, handle any escapes.
text = text:gsub("^(\\-)\\%*", "%1*")
end
check_params_ignored_when_embedded(alt, lang, id, cats)
local function process_link(space1, linktext, space2)
local capture = "[[" .. linktext .. "]]"
local link = parse_link(linktext)
-- Return unprocessed false positives untouched (e.g. categories).
if not link then
return capture
end
if all_reconstructed then
if link.target:find("^!!") then
-- Check for anti-asterisk !! at the beginning of a target, indicating that a reconstructed term
-- wants a part of the term to link to a non-reconstructed term, e.g. Old English
-- {{ang-noun|m|head=*[[!!Crist|Cristes]] [[!!mæsseǣfen]]}}.
link.target = link.target:sub(3)
-- Also remove !! from the display, which may have been copied from the target (as in mæsseǣfen in
-- the example above).
link.display = link.display:gsub("^!!", "")
elseif not link.target:match("^%*") then
link.target = "*" .. link.target
end
end
linktext = make_link(link, lang, sc, id, false, nil, no_alt_ast, plain)
:gsub("^%[%[", "\3")
:gsub("%]%]$", "\4")
return space1 .. linktext .. space2
end
-- Use chars 1 and 2 as temporary substitutions, so that we can use charsets. These are converted to chars 3 and 4 by process_link, which means we can convert any remaining chars 1 and 2 back to square brackets (i.e. those not part of a link).
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- If the script uses ^ to capitalize transliterations, make sure that any carets preceding links are on the inside, so that they get processed with the following text.
if text:find("^", nil, true) then
assert_caret_capitalization_allowed(text, sc)
if sc:hasCaretCapitalization() then
text = escape(text, "^")
:gsub("%^\1", "\1%^")
text = unescape(text, "^")
end
end
text = text:gsub("\1(%s*)([^\1\2]-)(%s*)\2", process_link)
-- Remove the extra * at the beginning of a language link if it's immediately followed by a link whose display begins with * too.
if all_reconstructed then
text = text:gsub("^%*\3([^|\1-\4]+)|%*", "\3%1|*")
end
return (text
:gsub("[\1\3]", "[[")
:gsub("[\2\4]", "]]")
)
end
local function simple_link(term, fragment, alt, lang, sc, id, cats, no_alt_ast, suppress_redundant_wikilink_cat)
local plain
if lang == nil then
lang, plain = get_lang("und"), true
end
-- Get the link target and display text. If the term is the empty string, treat the input as a link to the current page.
if term == "" then
term = get_current_title().prefixedText
elseif term then
local new_term, new_alt = export.get_wikilink_parts(term)
if new_term then
check_params_ignored_when_embedded(alt, lang, id, cats)
-- [[|foo]] links are treated as plaintext "[[|foo]]".
-- FIXME: Pipes should be handled via a proper escape sequence, as they can occur in unsupported titles.
if new_term == "" then
term, alt = nil, term
else
local title = new_title(new_term)
if title then
local ns = title.namespace
-- File: and Category: links should be returned as-is.
if ns == 6 or ns == 14 then
return term
end
end
term, alt = new_term, new_alt
if cats then
if not (suppress_redundant_wikilink_cat and suppress_redundant_wikilink_cat(term, alt)) then
insert(cats, lang:getFullName() .. " සබැඳි, අනු පිටපත් කළ විකි සබැඳි සහිත")
end
end
end
end
end
if alt then
alt = selective_trim(alt)
if alt == "" then
alt = nil
end
end
-- If there's nothing to process, return nil.
if not (term or alt) then
return nil
end
-- If there is no script, get one.
if not sc then
sc = lang:findBestScript(alt or term)
end
-- Embedded wikilinks need to be processed individually.
if term then
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, alt, lang, sc, id, cats, no_alt_ast, plain)
end
term = selective_trim(term)
end
-- If not, make a link using the parameters.
return make_link({
target = term,
display = alt,
fragment = fragment
}, lang, sc, id, true, cats, no_alt_ast, plain)
end
--[==[
Create a basic link to the given term. It links to the language section (such as `==English==`), but it does not add
language and script wrappers, so any code that uses this function should call `[[Module:script utilities#tag_text]]`
to add such wrappers itself at some point. The first argument, `data`, may contain the following items, a subset of the
items used in the `data` argument of `##full_link`. If any other items are included, they are ignored.
{ {
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
no_alt_ast = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
cats = nil or {}, -- NOTE: If given, will be side-effected to return categories to add the page to.
} }
Specifically:
* `term`: Term to turn into a link. This is generally the name of a page, possibly with extra diacritics added (e.g.
length marks in Latin or Old English terms, accents in Russian terms, vowel diacritics in Arabic terms, etc.), which
are stripped to determine the actual pagename. The term can contain wikilinks already embedded in it. These are
processed individually just like a single link would be. The `alt` argument is ignored in this case.
* `alt`: The alternative display for the link, if different from the linked page. If this is {nil}, the `term` argument
is used instead (much like regular wikilinks). If `term` contains wikilinks in it, this argument is ignored and has no
effect. (Links in which the alt is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/alt-ignored}}.)
* `lang` ('''required'''): The [[Module:languages#Language objects|language object]] for the term being linked. The link
or links in `term` will normally have their fragment set to point to the canonical name (see
{{tl|language data documentation}}) of `lang` (or, if it is an etymology-only language, to the canonical name of its
L2 parent). (However, if `id` is defined, the fragment will point to a language-specific sense ID corresponding to
this field, which in turn will be overridden by `fragment` if specified.)
* `sc`: The [[Module:scripts#Script objects|script object]] for the term being linked. This rarely needs to be specified
because it is autodetected based on `term` or `alt`, and the detection is usually correct. It is used to determine
how to convert the term into a pagename, possibly by stripping certain diacritics from the term's text.
* `fragment`: If specified, overrides the fragment in the generated link (i.e. the portion after `#`, which determines
where on the page to go to when the link is clicked). If not specified, the fragment is generated from `id` (if given)
or otherwise from `lang`.
* `id`: Sense ID string. If this argument is defined, the link will point to a language-specific sense ID
({{ll|en|identifier|id=HTML}}) created by the template {{temp|senseid}}. The fragment for a sense ID consists of the
language's canonical name, a hyphen (`-`), and the string that was supplied as the `id` argument. This is useful when
a term has more than one sense in a language. If the `term` argument contains wikilinks, this argument is ignored.
(Links in which the sense ID is ignored are tracked with the tracking template
{{whatlinkshere|tracking=links/id-ignored}}.)
* `no_alt_ast`: This is the same as `no_alt_ast` in `##full_link()`. See that function for more information.
* `suppress_redundant_wikilink_cat`: This is the same as `suppress_redundant_wikilink_cat` in `##full_link()`. See
that function for more information.
* `cats`: This should be either {nil} or an empty list. In the latter case, tracking categories will be added to the
list when appropriate. The caller can choose to add the page to those categories (as is done by ##full_link()`).
The following special options are processed for each link (both simple terms and with embedded wikilinks):
* The target page name will be processed by stripping certain diacritics (as mentioned above) and converting the
resulting ''logical'' pagename to a ''physical'' pagename (which will be different from the logical pagename in the
case of pages with unsupported characters in them and certain overly large pages, such as [[a]], that are split into
parts).
* If the term starts with `*`, then it is considered a reconstructed term, and a link to the `Reconstruction:` namespace
will be created. If the text contains embedded wikilinks, then `*` is automatically applied to each one individually,
while preserving the displayed form of each link as it was given. This allows linking to phrases containing multiple
reconstructed terms, while only showing the `*` once at the beginning.
* If the text starts with `:`, then the link is treated as "raw" and the above steps are skipped. This can be used in
rare cases where the page name begins with `*` or if diacritics should not be stripped. For example:
** {{tl|l|en|*nix}} links to the nonexistent page [[Reconstruction:English/nix]] (`*` is interpreted as a
reconstruction), but {{tl|l|en|:*nix}} links to [[*nix]].
** {{tl|l|sl|Franche-Comté}} links to the nonexistent page [[Franche-Comte]] (`é` is converted to `e` by the
diacritic-stripping process), but {{tl|l|sl|:Franche-Comté}} links to [[Franche-Comté]].
]==]
function export.language_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function language_link must be a table. See [[Module:links/documentation]] for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "language_link")
end
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
return simple_link(
data.term,
data.fragment,
data.alt,
lang,
data.sc,
data.id,
cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
function export.plain_link(data)
if type(data) ~= "table" then
error(
"The first argument to the function plain_link must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "plain_link")
end
return simple_link(
data.term,
data.fragment,
data.alt,
nil,
data.sc,
data.id,
data.cats,
data.no_alt_ast,
data.suppress_redundant_wikilink_cat
)
end
--[==[Replace any links with links to the correct section, but don't link the whole text if no embedded links are found. Returns the display text form.]==]
function export.embedded_language_links(data)
if type(data) ~= "table" then
error(
"The first argument to the function embedded_language_links must be a table. See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "embedded_language_links")
end
local term, lang, sc = data.term, data.lang, data.sc
-- If we don't have a script, get one.
if not sc then
sc = lang:findBestScript(term)
end
-- Do we have embedded wikilinks? If so, they need to be processed individually.
local open = find(term, "[[", nil, true)
if open and find(term, "]]", open + 2, true) then
return process_embedded_links(term, data.alt, lang, sc, data.id, data.cats, data.no_alt_ast)
end
-- If not, return the display text.
term = selective_trim(term)
-- FIXME: Double-escape any percent-signs, because we don't want to treat non-linked text as having percent-encoded
-- characters. This is a hack: percent-decoding should come out of [[Module:languages]] and only dealt with in this
-- module, as it's specific to links.
term = term:gsub("%%", "%%25")
return lang:makeDisplayText(term, sc, true)
end
function export.mark(text, item_type, face, lang)
local tag = { "", "" }
if item_type == "gloss" then
tag = { '<span class="mention-gloss-double-quote">“</span><span class="mention-gloss">',
'</span><span class="mention-gloss-double-quote">”</span>' }
if type(text) == "string" and text:match("^''[^'].*''$") then
-- Temporary tracking for mention glosses that are entirely italicized or bolded, which is probably
-- wrong. (Note that this will also find bolded mention glosses since they use triple apostrophes.)
track("italicized-mention-gloss", lang and lang:getFullCode() or nil)
end
elseif item_type == "tr" then
if face == "term" then
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr mention-tr Latn">',
'</span>' }
else
tag = { '<span lang="' .. lang:getFullCode() .. '" class="tr Latn">', '</span>' }
end
elseif item_type == "ts" then
-- \226\129\160 = word joiner (zero-width non-breaking space) U+2060
tag = { '<span class="ts mention-ts Latn">/\226\129\160', '\226\129\160/</span>' }
elseif item_type == "pos" then
tag = { '<span class="ann-pos">', '</span>' }
elseif item_type == "non-gloss" then
tag = { '<span class="ann-non-gloss">', '</span>' }
elseif item_type == "annotations" then
tag = { '<span class="mention-gloss-paren annotation-paren">(</span>',
'<span class="mention-gloss-paren annotation-paren">)</span>' }
elseif item_type == "infl" then
tag = { '<span class="ann-infl">', '</span>' }
end
if type(text) == "string" then
return tag[1] .. text .. tag[2]
else
return ""
end
end
--[=[
Implementation of `format_transliteration` and `format_transcription`. The implementation is identical except that the
field containing the transliteration or transcription may vary and is specified in `field`, and the way a given
transliteration or transcription is tagged may vary and is controlled by `tag_fn`, which is passed three parameters:
`text` (the transliteration or transcription), `lang` (the language passed in) and `face` (the face passed in).
On input, `item` is the transliteration or transcription or list of such objects; `field` is either {"tr"} or {"ts"};
`tag_fn` is a function of three parameters to tag the item, as described above; `lang` is the language object of the
term whose transliteration or transcription is specified; and `face` is a string indicating how to display the item
(generally only the strings {"term"} and {"default"} are recognized).
]=]
local function format_transliteration_or_transcription(item, field, tag_fn, lang, item_face)
if type(item) == "string" then
return tag_fn(item, lang, item_face)
end
local formatted_items = {}
for _, itemobj in ipairs(item) do
local tagged_item = tag_fn(itemobj[field], lang, item_face)
tagged_item = add_text_decorations(tagged_item, item, lang)
insert(formatted_items, tagged_item)
end
if formatted_items[2] then
-- FIXME: This should be customizable.
return concat(formatted_items, " <i>or</i> ")
else
return formatted_items[1]
end
end
--[==[
Format a transliteration string or list of transliteration objects. `tr` contains the transliteration(s), which for
forward compatibility reasons can only be either a single transliteration string or a list of transliteration objects
(each of which has a `tr` field holding the transliteration and optional fields `q`, `qq`, `l`, `ll` and/or `refs`).
This correctly handles multiple transliterations as well as decorations (qualifiers, labels or references) attached to
transliterations.
]==]
function export.format_transliteration(tr, lang, face)
return format_transliteration_or_transcription(tr, "tr", tag_translit, lang, face)
end
local function tag_transcription(ts, _lang, _face)
return export.mark(ts, "ts")
end
--[==[
Format a transcription string or list of transcription objects. `ts` contains the transcription(s), which for forward
compatibility reasons can only be either a single transcription string or a list of transcription objects (each of which
has a `ts` field holding the transcription and optional decoration fields `q`, `qq`, `l`, `ll` and/or `refs`). This
correctly handles multiple transcriptions as well as decorations (qualifiers, labels or references) attached to
transcriptions.
]==]
function export.format_transcription(ts, lang, face)
return format_transliteration_or_transcription(ts, "ts", tag_transcription, lang, face)
end
local pos_tags
--[==[
Format the annotations that are displayed with a link created by `full_link()`. Annotations are the extra bits of
information that are displayed following the linked term, and include things such as gender, transliteration, gloss,
etc. The first argument is a table with some or all of the following keys (all are optional):
* `interwiki`: An interwiki link. This is used for links in translation tables to the corresponding term in another
Wiktionary. If specified, it should be a fully formatted link and is inserted as-is at the beginning of the output.
See the `interwiki()` function in [[Module:translations]].
* `genders`: Table containing a list of gender specifications in the style of [[Module:gender and number]]. If
specified, these are formatted using `format_genders()` in [[Module:gender and number]] and the result inserted at
the beginning of the output, following any interwiki link and (in all cases) directly after a no-break space.
* `tr`: Transliteration or transliterations. Currently, this is always a one-item list. It is a list because of
potential support for per-alternant transliterations due to the multiple alternants (separated by `//`) that can be
specified in `term` or `alt`. The item in the list can be either a string or a list of transliteration objects (see
`format_transliteration()`).
* `ts`: Transcription or transcriptions. Like `tr`, this is currently always a one-item list, with the item being either
a single string or a list of transcription objects, as described in `format_transcription()`.
* `gloss`: Gloss that translates the term in the link.
* `pos`: Part of speech of the linked term. If the given argument matches one of the aliases in `pos_aliases` in
[[Module:headword/data]], or consists of a part of speech or alias followed by `f` (for a non-lemma form), expand it
appropriately. Otherwise, just show the given text as it is.
With `root`, the term links to the page where [[Module:roots]] keeps the language's roots, for languages that keep
them outside the main namespace (`Appendix:Arabic roots/…`).
* `infl`: A list of tags, each a string. Multiple tag sets may be encoded in this list by separating them with an
element consisting of a semicolon. If there are multiple tag sets, they are formatted individually and separated
by a semicolon + space.
* `ng`: Arbitrary non-gloss descriptive text for the link. This should be used in preference to putting descriptive text
in `gloss` or `pos`.
* `lit`: Literal meaning of the term, if the usual meaning is figurative or idiomatic.
* `postprocess_annotations`: A function to postprocess the annotations, after they have been formatted (see below).
The `interwiki` and `genders` properties are formatted specially, and `postprocess_annotations` is a callback function
rather than an item to display; all others are formatted (each in their own way), separated by commas and placed inside
of parentheses (except that if both transliteration and transcription are present, they are separated by a space). The
order of the annotations is `tr`+`ts`, `gloss`, `pos`, `infl`, `ng` and `lit`. The `postprocess_annotations` function,
if supplied, is passed a single object, a table with two keys `data` (the `data` object passed into
`format_link_annotations()`) and `annotations` (the formatted annotations, prior to being concatenated). It should
side-effect the `annotations` list, e.g. by inserting more annotations. (It is used to handle nested inflections in
[[Module:headword]]. FIXME: It should probably be generalized so that it can return the final formatted string, to allow
for e.g. changing the way the annotations are formatted.)
* The second argument is a string controlling the "face" that the terms are displayed in. Currently it only affects
transliteration and transcription and only when the value {"term"} is passed in, in which case those annotations are
displayed italicized.
]==]
function export.format_link_annotations(data, face)
local output = {}
-- Interwiki link
if data.interwiki then
insert(output, data.interwiki)
end
-- Genders
if type(data.genders) ~= "table" then
data.genders = { data.genders }
end
if data.genders and data.genders[1] then
local genders, gender_cats = format_genders(data.genders, data.lang)
insert(output, " " .. genders)
if gender_cats then
local cats = data.cats
if cats then
extend(cats, gender_cats)
end
end
end
local annotations = {}
-- Transliteration and transcription
local tr = data.tr and data.tr[1] or nil
local ts = data.ts and data.ts[1] or nil
if tr or ts then
local item_face
if face == "term" then
item_face = face
else
item_face = "default"
end
local formatted_tr = tr and export.format_transliteration(tr, data.lang, item_face) or nil
local formatted_ts = ts and export.format_transcription(ts, data.lang, item_face) or nil
if formatted_tr and formatted_ts then
insert(annotations, {text = formatted_tr .. " " .. formatted_ts})
else
insert(annotations, {text = formatted_tr or formatted_ts})
end
end
-- Gloss/translation
if data.gloss then
insert(annotations, {text = export.mark(data.gloss, "gloss")})
end
-- Part of speech
if data.pos then
-- debug category for pos= containing transcriptions
if data.pos:match("/[^><]-/") then
data.pos = data.pos .. "[[Category:links likely containing transcriptions in pos]]"
end
-- Canonicalize part of speech aliases as well as non-lemma aliases like 'nf' or 'nounf' for "noun form".
pos_tags = pos_tags or (m_headword_data or get_headword_data()).pos_aliases
local pos = pos_tags[data.pos]
if not pos and data.pos:find("f$") then
local pos_form = data.pos:sub(1, -2)
-- We only expand something ending in 'f' if the result is a recognized non-lemma POS.
pos_form = (pos_tags[pos_form] or pos_form) .. " form"
if (m_headword_data or get_headword_data()).nonlemmas[pos_form .. "s"] then
pos = pos_form
end
end
insert(annotations, {text = export.mark(pos or data.pos, "pos")})
end
-- Inflection data
if data.infl then
local m_form_of = require(form_of_module)
-- Split tag sets manually, since tagged_inflections creates a numbered list, and we do not want that.
local infl_outputs = {}
local tag_sets = m_form_of.split_tag_set(data.infl)
for _, tag_set in ipairs(tag_sets) do
table.insert(infl_outputs,
m_form_of.tagged_inflections({ tags = tag_set, lang = data.lang, nocat = true, nolink = true, nowrap = true }))
end
insert(annotations, {text = export.mark(table.concat(infl_outputs, "; "), "infl")})
end
-- Non-gloss text
if data.ng then
local separator
local ng = data.ng
if ng:find("^[;:]") then
separator = ""
elseif ng:find("^_") then
ng = ng:sub(2)
separator = " "
end
insert(annotations, {text = export.mark(ng, "non-gloss"), separator = separator})
end
-- Literal/sum-of-parts meaning
if data.lit then
insert(annotations, {text = "literally " .. export.mark(data.lit, "gloss")})
end
-- Provide a hook to insert additional annotations such as nested inflections.
if data.postprocess_annotations then
data.postprocess_annotations {
data = data,
annotations = annotations
}
end
if annotations[1] then
local annparts = {}
for i, annotation in ipairs(annotations) do
local separator = annotation.separator
if not separator then
if i == 1 then
separator = ""
else
separator = ", "
end
end
insert(annparts, separator)
insert(annparts, annotation.text)
end
insert(output, " ")
insert(output, export.mark(concat(annparts), "annotations"))
end
return concat(output)
end
-- Encode certain characters to avoid various delimiter-related issues at various stages. We need to encode < and >
-- because they end up forming part of CSS class names inside of <span ...> and will interfere with finding the end
-- of the HTML tag. I first tried converting them to URL encoding, i.e. %3C and %3E; they then appear in the URL as
-- %253C and %253E, which get mapped back to %3C and %3E when passed to [[Module:accel]]. But mapping them to <
-- and > somehow works magically without any further work; they appear in the URL as < and >, and get passed to
-- [[Module:accel]] as < and >. I have no idea who along the chain of calls is doing the encoding and decoding. If
-- someone knows, please modify this comment appropriately!
local accel_char_map
local function get_accel_char_map()
accel_char_map = {
["%"] = ".",
[" "] = "_",
["_"] = u(0xFFF0),
["<"] = "<",
[">"] = ">",
}
return accel_char_map
end
local function encode_accel_param_chars(param)
return (param:gsub("[%% <>_]", accel_char_map or get_accel_char_map()))
end
local function encode_accel_param(prefix, param)
if not param then
return ""
end
if type(param) == "table" then
local filled_params = {}
-- There may be gaps in the sequence, especially for translit params.
local maxindex = 0
for k in pairs(param) do
if type(k) == "number" and k > maxindex then
maxindex = k
end
end
for i = 1, maxindex do
filled_params[i] = param[i] or ""
end
-- [[Module:accel]] splits these up again.
param = concat(filled_params, "*~!")
end
-- This is decoded again by [[WT:ACCEL]].
return prefix .. encode_accel_param_chars(param)
end
local function insert_if_not_blank(list, item)
if item == "" then
return
end
insert(list, item)
end
local function get_css_classes(lang, tr, accel, nowrap)
if not accel and not nowrap then
return ""
end
local classes = {}
if accel then
insert(classes, "form-of lang-" .. lang:getFullCode())
local form = accel.form
if form then
insert(classes, encode_accel_param_chars(form) .. "-form-of")
end
insert_if_not_blank(classes, encode_accel_param("gender-", accel.gender))
insert_if_not_blank(classes, encode_accel_param("pos-", accel.pos))
insert_if_not_blank(classes, encode_accel_param("transliteration-", accel.translit or (tr ~= "-" and tr or nil)))
insert_if_not_blank(classes, encode_accel_param("target-", accel.target))
insert_if_not_blank(classes, encode_accel_param("origin-", accel.lemma))
insert_if_not_blank(classes, encode_accel_param("origin_transliteration-", accel.lemma_translit))
if accel.no_store then
insert(classes, "form-of-nostore")
end
end
if nowrap then
insert(classes, nowrap)
end
return concat(classes, " ")
end
--[==[
Creates a full link, with annotations (see `##format_link_annotations`), in the style of {{tl|l}} or {{tl|m}}.
The first argument, `data`, must be a table. It contains the various elements that can be supplied as parameters to
{{tl|l}} or {{tl|m}}:
{ {
-- Basic link-related fields
term = "entry_to_link_to",
alt = "link_text_or_displayed_text",
lang = language_object,
sc = script_object,
fragment = "link_fragment",
id = "sense_id",
accel = {accelerated_creation_tags},
-- Link annotation fields
interwiki = "interwiki_link",
genders = {"gender1", "gender2", ...} or {{spec = "gender1", q = {"left qualifier", ...}, qq = {"right qualifier"}, ...}, ...},
tr = "transliteration" or "-" or {{tr = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
ts = "transcription" or {{ts = "transliteration", q = {"left_qualifier", ...}, qq = {"right_qualifier", ...}, ..., genders = {gender_spec, ...}}, ...},
gloss = "gloss",
pos = "part_of_speech_tag",
infl = {"infl1_tag1", "infl1_tag2", ..., ";", "infl2_tag1", "infl2_tag2", ...},
ng = "non-gloss text",
lit = "literal_translation",
postprocess_annotations = function({data = full_link_data, annotations = {"annotation1", "annotation2", ...}}) -> nil,
-- Other transliteration-related fields
respect_link_tr = boolean,
never_call_transliteration_module = boolean,
suppress_tr = boolean,
-- Decoration fields
q = { "left_qualifier1", "left_qualifier2", ...} or "left_qualifier",
qq = { "right_qualifier1", "right_qualifier2", ...} or "right_qualifier",
l = { "left_label1", "left_label2", ...},
ll = { "right_label1", "right_label2", ...},
a = { "left_accent_qualifier1", "left_accent_qualifier2", ...},
aa = { "right_accent_qualifier1", "right_accent_qualifier2", ...},
refs = { "formatted_ref1", "formatted_ref2", ...} or { {text = "text", name = "name", group = "group"}, ... },
pretext = "text_at_beginning",
posttext = "text_at_end",
show_decorations = boolean,
-- Fields controlling tracking categories
track_sc = boolean,
no_nonstandard_sc_cat = boolean,
suppress_redundant_wikilink_cat = function(term, alt) -> boolean,
-- Miscellaneous fields
no_alt_ast = boolean,
no_generate_alternants = boolean,
} }
Any one of the items in the `data` table (except for `lang`) may be {nil}. If none of `term`, `alt` and `tr` is present,
a term request will be shown. Thus, calling {full_link{ term = term, lang = lang, sc = sc }}, where `term` is the page
to link to (which may have diacritics that will be stripped and/or embedded bracketed links) and `lang` is a
[[Module:languages#Language objects|language object]] from [[Module:languages]], will give a plain link similar to the
one produced by the template {{tl|l}}, and calling {full_link( { term = term, lang = lang, sc = sc }, "term" )} will
give a link similar to the one produced by the template {{tl|m}}.
The function will:
* Try to determine the script, based on the characters found in the `term` or `alt` argument, if the script was not
given. If a script is given and `track_sc` is {true}, it will check whether the input script is the same as the one
which would have been automatically generated and add the category ` ``lang`` terms with redundant script codes` if
yes, or ` ``lang`` terms with non-redundant manual script codes` if no. This should be used when the input script
object is directly determined by a template's `sc` parameter.
* Call `simple_link()` on the `term` or `alt` forms, to remove diacritics in the page name, process any embedded
wikilinks and create links to Reconstruction or Appendix pages when necessary. (`simple_link()` is almost exactly the
same as `##language_link()`; the latter is a simple wrapper around the former that adds a bit of extra tracking.)
* Call `[[Module:script utilities#tag_text]]` to add the appropriate language and script tags to the term and
italicize terms written in the Latin script if necessary. Accelerated creation tags, as used by [[WT:ACCEL]], are
included.
* Generate a transliteration, based on the `alt` or `term` arguments, if the script is not Latin, no transliteration was
provided in `tr` and the combination of the term's language and script support automatic transliteration. The
transliteration itself will be linked if both `.respect_link_tr` is specified and the language of the term has the
`link_tr` property set for the script of the term; but not otherwise.
* Add the annotations (transliteration, gender, gloss, etc.) after the link.
* If `no_alt_ast` is specified, then the `alt` text does not need to contain an asterisk if the language is
reconstructed. This should only be used by modules which really need to allow links to reconstructions that don't
display asterisks (e.g. number boxes).
* If `suppress_redundant_wikilink_cat` is specified, it should be a function that indicates whether to suppress the
generation of the ` ``lang`` links with redundant wikilinks` tracking category. It is passed two arguments, the `term`
and `alt` parameters. Normally, this tracking category is added whenever the `term` argument consists entirely of a
one-part or two-part embedded link, which is considered "redundant" in that the link can be rewritten into separate
`term` and `alt` arguments without any embedded links. For certain wrapping templates, however, otherwise "redundant"
embedded links are necessary to prevent interpretation of certain characters as delimiters. For example, {{tl|col}}
and related templates use `~` as a separator, as well as `,` when not followed by a space. In these templates,
embedded links are required to correctly link to terms containing those delimiters, such as [[Micros~1]] and
[[1,6-Cleves acid]], but will incorrectly trigger the addition of the tracking category unless the appropriate
`suppress_redundant_wikilink_cat` function is given.
* If `pretext` or `posttext` is specified, this is text to (respectively) prepend or append to the output, directly
before processing decorations (qualifiers, labels and references). This can be used to add arbitrary extra text inside
of the decorations.
* If `show_decorations` is specified, then decorations specified in `data` (i.e. left and right qualifiers, accent
qualifiers, labels and references) will be displayed, otherwise they will be ignored. (This is because a fair amount
of code stores decorations in these fields and displays them itself, rather than expecting {full_link()} to display
them.)
* ]==]
function export.full_link(data, face, allow_self_link, show_qualifiers)
if type(data) ~= "table" then
error("The first argument to the function full_link must be a table. "
.. "See Module:links/documentation for more information.")
elseif data.term and data.term:find("\\", nil, true) or data.alt and data.alt:find("\\", nil, true) then
track("escaped", "full_link")
end
if show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-17, remove after 2026-10-17 or so.
error("Can't pass fourth parameter `show_qualifiers` any more. Set `show_decorations = true` on data.")
end
if data.show_qualifiers then
-- FIXME: Eventually remove the error code. Added 2026-09-18, remove after 2026-10-18 or so.
error("Can't set field `show_qualifiers`; use `show_decorations`")
end
if data.no_generate_forms then
-- FIXME: Eventually remove the error code. Added 2026-09-14, remove after 2026-10-14 or so.
error("Can't set field `no_generate_forms`; use `no_generate_alternants`")
end
-- Prevent data from being destructively modified.
data = shallow_copy(data)
data.cats = {}
-- Categorize links to "und".
local lang, cats = data.lang, data.cats
if cats and lang:getCode() == "und" then
insert(cats, "Undetermined language links")
end
-- With pos=root, link to the page where Module:roots keeps the language's roots (Appendix:Arabic roots/…) and
-- display the root as given.
if data.pos == "root" and type(data.term) == "string" and not data.term:find(":", nil, true) then
local root_page = get_root_link_page(lang, data.term)
if root_page then
data.alt = data.alt or data.term
data.term = root_page
end
end
local terms = { true }
-- Generate multiple alternants if applicable.
for _, param in ipairs { "term", "alt" } do
if type(data[param]) == "string" and data[param]:find("//", nil, true) then
data[param] = export.split_on_slashes(data[param])
elseif type(data[param]) == "string" and not (type(data.term) == "string" and data.term:find("//", nil, true)) then
if not data.no_generate_alternants then
data[param] = lang:generateAlternants(data[param])
else
data[param] = { data[param] }
end
else
data[param] = {}
end
end
for _, param in ipairs { "sc", "tr", "ts" } do
data[param] = { data[param] }
end
for _, param in ipairs { "term", "alt", "sc", "tr", "ts" } do
for i in pairs(data[param]) do
terms[i] = true
end
end
-- Create the link
local outparts = {}
local id, no_alt_ast, suppress_redundant_wikilink_cat, accel, never_call_transliteration_module =
data.id, data.no_alt_ast, data.suppress_redundant_wikilink_cat, data.accel,
data.never_call_transliteration_module
local link_tr = data.respect_link_tr and lang:link_tr(data.sc[1])
for i in ipairs(terms) do
local link
-- Is there any text to show?
if (data.term[i] or data.alt[i]) then
-- Try to detect the script if it was not provided
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
local best = lang:findBestScript(display_term)
-- no_nonstandard_sc_cat is intended for use in [[Module:interproject]]
if (
not data.no_nonstandard_sc_cat and
best:getCode() == "None" and
find_best_script_without_lang(display_term):getCode() ~= "None"
) then
insert(cats, lang:getFullName() .. " terms in nonstandard scripts")
end
if not data.sc[i] then
data.sc[i] = best
-- Track uses of sc parameter.
elseif data.track_sc then
if data.sc[i]:getCode() == best:getCode() then
insert(cats, lang:getFullName() .. " terms with redundant script codes")
else
insert(cats, lang:getFullName() .. " terms with non-redundant manual script codes")
end
end
-- If using a discouraged character sequence, add to maintenance category
if data.sc[i]:hasNormalizationFixes() == true then
if (data.term[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.term[i])) ~= toNFC(data.term[i])) or (data.alt[i] and data.sc[i]:fixDiscouragedSequences(toNFC(data.alt[i])) ~= toNFC(data.alt[i])) then
insert(cats, "Pages using discouraged character sequences")
end
end
link = simple_link(
data.term[i],
data.fragment,
data.alt[i],
lang,
data.sc[i],
id,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
end
-- simple_link can return nil, so check if a link has been generated.
if link then
-- Add "nowrap" class to prefixes in order to prevent wrapping after the hyphen
local nowrap
-- FIXME: alt is ignored if term contains embedded links, so the following isn't quite right.
local display_term = data.alt[i] or data.term[i]
-- FIXME, use hyphens from [[Module:affix]]
if display_term and (display_term:find("^%*?%-") or display_term:find("^%*?־")) then -- Hebrew maqqef
nowrap = "nowrap"
end
-- Forcibly disable acceleration in the presence of embedded links, because it doesn't work correctly;
-- if one of the embedded terms doesn't exist, the acceleration code will try to make a form-of for the
-- embedded term pointing to the original headword (which is wrong).
if link:find(".%[%[") or link:find("%]%].") then
accel = nil
end
link = tag_text(link, lang, data.sc[i], face, get_css_classes(lang, data.tr[i], accel, nowrap))
else
--[[ No term to show.
Is there at least a transliteration we can work from? ]]
link = request_script(lang, data.sc[i])
-- No link to show, and no transliteration either. Show a term request (unless it's a substrate, as they rarely take terms).
if (link == "" or (not data.tr[i]) or data.tr[i] == "-") and lang:getFamilyCode() ~= "qfa-sub" then
-- If there are multiple terms, break the loop instead.
if i > 1 then
remove(outparts)
break
elseif NAMESPACE ~= "Template" then
insert(cats, lang:getFullName() .. " term requests")
end
link = "<small>[Term?]</small>"
end
end
insert(outparts, link)
if i < #terms then insert(outparts, "<span class=\"Zsym mention\" style=\"font-size:100%;\"> / </span>") end
end
-- When suppress_tr is true, do not show or generate any transliteration
if data.suppress_tr then
data.tr[1] = nil
else
-- TODO: Currently only handles the first transliteration, pending consensus on how to handle multiple translits for multiple forms, as this is not always desirable (e.g. traditional/simplified Chinese).
if data.tr[1] == "" or data.tr[1] == "-" then
data.tr[1] = nil
else
local phonetic_extraction = load_data("Module:links/data").phonetic_extraction
phonetic_extraction = phonetic_extraction[lang:getCode()] or phonetic_extraction[lang:getFullCode()]
if phonetic_extraction then
data.tr[1] = data.tr[1] or
require(phonetic_extraction).getTranslit(export.remove_links(data.alt[1] or data.term[1]))
elseif (data.term[1] or data.alt[1]) and data.sc[1]:isTransliterated() then
-- Track whenever there is manual translit. The categories below like 'terms with redundant transliterations'
-- aren't sufficient because they only work with reference to automatic translit and won't operate at all in
-- languages without any automatic translit, like Persian and Hebrew.
if data.tr[1] then
local full_code = lang:getFullCode()
track("manual-tr", full_code)
end
if not never_call_transliteration_module then
-- Try to generate a transliteration.
local text = data.alt[1] or data.term[1]
if not link_tr then
text = export.remove_links(text, true)
end
local automated_tr = lang:transliterate(text, data.sc[1])
if automated_tr then
local manual_tr = data.tr[1]
if manual_tr then
if export.remove_links(manual_tr) == export.remove_links(automated_tr) then
insert(cats, lang:getFullName() .. " terms with redundant transliterations")
else
-- Prevents Arabic root categories from flooding the tracking categories.
if NAMESPACE ~= "Category" then
insert(cats,
lang:getFullName() .. " terms with non-redundant manual transliterations")
end
end
end
if not manual_tr or lang:overrideManualTranslit(data.sc[1]) then
data.tr[1] = automated_tr
end
end
end
end
end
end
-- Link to the transliteration entry for languages that require this
if data.tr[1] and link_tr and not data.tr[1]:match("%[%[(.-)%]%]") then
data.tr[1] = simple_link(
data.tr[1],
nil,
nil,
lang,
get_script("Latn"),
nil,
cats,
no_alt_ast,
suppress_redundant_wikilink_cat
)
elseif data.tr[1] and not link_tr then
-- Remove the pseudo-HTML tags added by remove_links.
data.tr[1] = data.tr[1]:gsub("</?link>", "")
end
if data.tr[1] and not umatch(data.tr[1], "[^%s%p]") then data.tr[1] = nil end
insert(outparts, export.format_link_annotations(data, face))
if data.pretext then
insert(outparts, 1, data.pretext)
end
if data.posttext then
insert(outparts, data.posttext)
end
local categories = cats[1] and format_categories(cats, lang, "-", nil, nil, data.sc) or ""
local output = concat(outparts)
if data.show_decorations then
output = add_text_decorations(output, data, lang)
end
return output .. categories
end
--[==[
Strip links by replacing all wikilinks with their displayed text, and remove any categories. This function can be
invoked either from a template or from another module. Specifically, this function deletes category links, the targets
of piped links, and any double square brackets involved in links (other than file links, which are untouched). If `tag`
is set, then any links removed will be given pseudo-HTML tags, which allow the substitution functions in
[[Module:languages]] to properly subdivide the text in order to reduce the chance of substitution failures in modules
which scrape pages like [[Module:zh-translit]]. (FIXME: This is quite hacky. We probably want this to be integrated
into [[Module:languages]], but we can't do that until we know that nothing is pushing pipe linked transliterations
through it for languages which don't have link_tr set.)
* `<nowiki>[[page|displayed text]]</nowiki>` → `displayed text`
* `<nowiki>[[page and displayed text]]</nowiki>` → `page and displayed text`
* `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` → ''(nothing)''
]==]
function export.remove_links(text, tag)
if type(text) == "table" then
text = text.args[1]
end
if not text or text == "" then
return ""
end
text = text
:gsub("%[%[", "\1")
:gsub("%]%]", "\2")
-- Parse internal links for the display text.
text = text:gsub("(\1)([^\1\2]-)(\2)",
function(c1, c2, c3)
-- Don't remove files.
for _, false_positive in ipairs({ "file", "image" }) do
if c2:lower():match("^" .. false_positive .. ":") then return c1 .. c2 .. c3 end
end
-- Remove categories completely.
for _, false_positive in ipairs({ "category", "cat" }) do
if c2:lower():match("^" .. false_positive .. ":") then return "" end
end
-- In piped links, remove all text before the pipe, unless it's the final character (i.e. the pipe trick), in which case just remove the pipe.
c2 = c2:match("^[^|]*|(.+)") or c2:match("([^|]+)|$") or c2
if tag then
return "<link>" .. c2 .. "</link>"
else
return c2
end
end)
text = text
:gsub("\1", "[[")
:gsub("\2", "]]")
return text
end
function export.section_link(link)
if type(link) ~= "string" then
error("The first argument to section_link was a " .. type(link) .. ", but it should be a string.")
elseif link:find("\\", nil, true) then
track("escaped", "section_link")
end
local target, section = get_fragment((link:gsub("_", " ")))
if not section then
error("No \"#\" delineating a section name")
end
return simple_link(
target,
section,
target .. " § " .. section
)
end
return export
gj50c5jsor3lwg1b7u6atthjjzbutsp
Module:character info
828
8916
238751
230149
2026-10-18T05:51:21Z
en>J3133
0
Added “image_emoji” (used in [[Module:character info#L-94|line 94]]: “image_emoji = args.image_emoji or m_unicode.lookup_image_emoji(codepoint)”) to “params” per [[Template talk:character info#Incorrect skin-invert-image for |Template talk:character info § Incorrect skin-invert-image for ]], where it was noted as missing.
238751
Scribunto
text/plain
local export = {}
local m_str_utils = require("Module:string utilities")
local ucp = m_str_utils.codepoint
local decode_entities = m_str_utils.decode_entities
local encode_entities = m_str_utils.encode_entities
local floor = math.floor
local gcodepoint = m_str_utils.gcodepoint
local toNFD = mw.ustring.toNFD
local u = m_str_utils.char
local ulen = m_str_utils.len
local m_unicode = require("Module:Unicode data")
local char_to_script = require("Module:scripts").charToScript
local languages_module = "Module:languages"
local utilities_module = "Module:utilities"
local insert = table.insert
local concat = table.concat
local dingbat_scripts = {
["Zsym"] = true;
["Zmth"] = true;
["Zyyy"] = true;
}
local function page_exists(title)
local ok, title_obj = pcall(mw.title.new, title)
if ok and title_obj then
local ok2, content = pcall(function() return title_obj:getContent() end)
return ok2 and not not content
else
return false
end
end
function export.exotic_symbol_warning(frame)
local title = mw.title.getCurrentTitle()
if title:getContent() then
return ""
end
local pagename = mw.loadData("Module:headword/data").pagename
if ulen(pagename) ~= 1 then
return ""
end
local codepoint = ucp(pagename)
local script_code = char_to_script(codepoint)
if dingbat_scripts[script_code] then
return frame:expandTemplate { title = "editnotice-exotic symbols" }
end
return ""
end
local function get_codepoint(codepoint, param_name)
codepoint = tonumber(codepoint) or decode_entities(codepoint)
if type(codepoint) == "string" and ulen(codepoint) == 1 then
codepoint = ucp(codepoint)
elseif type(codepoint) ~= "number" then
error("Unrecognised string given for the " .. param_name .. " parameter")
end
return codepoint
end
function export._show(args, parent_title)
local codepoint = args.codepoint
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local title = mw.title.getCurrentTitle()
local namespace = title.nsText
local categories = {}
if codepoint then
codepoint = get_codepoint(codepoint, "codepoint")
else
if not args.pagename and title.fullText == parent_title then
-- On template page itself
codepoint = 0xfffd
elseif ulen(pagename) == 1 then
codepoint = ucp(pagename)
else
error("Page title is not a single Unicode character")
end
end
local image, image_emoji
if args.image == "-" then
image = nil
image_emoji = nil
else
image = args.image or m_unicode.lookup_image(codepoint)
image_emoji = args.image_emoji or m_unicode.lookup_image_emoji(codepoint)
end
local table_markup = {}
local function ins(txt)
insert(table_markup, txt)
end
-- "display: table !important" overrides MediaWiki style rules for narrow screens
-- that collapse the table to a ridiculously narrow width
ins(
'{| class="wikitable floatright character-info" style="display: table !important;width:25em;"\n')
if image or image_emoji then
local category = {cat = "Character boxes with images", sort_key = "*" .. string.format("%010d", codepoint)}
if image and not image:match("\127") then -- <hiero> tags generate these; pass them through
if image:match("^%[?%[?[Ff]ile:") or image:match("^%[?%[?[Ii]mage:") then
image = image:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image = "[[File:" .. image .. "|120x140px|class=skin-invert-image]]"
insert(categories, category)
end
if image_emoji then
if image then
ins('|-\n! Text style !! Emoji style\n')
end
if image_emoji:match("^%[?%[?[Ff]ile:") or image_emoji:match("^%[?%[?[Ii]mage:") then
image_emoji = image_emoji:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image_emoji = "[[File:" .. image_emoji .. "|120x140px]]"
if not image then
-- FIXME: Yuck this code.
insert(categories, category)
end
if image then
ins(
('|-\n| style="text-align: center; width: 50%s;" | %s || style="text-align: center; width: 50%s;" | %s\n'):format(
'%', image, '%', image_emoji
)
)
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
image_emoji
)
)
end
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s<br/>%s\n'):format(
image, args.caption or ""
)
)
end
end
local show_different_styles_if_no_emoji_image = false
-- https://en.wikipedia.org/wiki/List_of_emojis
-- Basic Latin (see https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)#Variants)
if codepoint == 35 or codepoint == 42 or (codepoint > 47 and codepoint < 58)
-- Latin-1 Supplement
or codepoint == 169 or codepoint == 174
-- General Punctuation
or codepoint == 8252 or codepoint == 8265
-- Letterlike Symbols
or codepoint == 8482 or codepoint == 8505
-- Arrows
or (codepoint > 8595 and codepoint < 8602) or codepoint == 8617 or codepoint == 8618
-- Miscellaneous Technical
or codepoint == 8986 or codepoint == 8987 or codepoint == 9000 or codepoint == 9167 or (codepoint > 9192 and codepoint < 9204) or (codepoint > 9207 and codepoint < 9211)
-- Enclosed Alphanumerics
or codepoint == 9410
-- Geometric Shapes
or codepoint == 9642 or codepoint == 9643 or codepoint == 9654 or codepoint == 9664 or (codepoint > 9722 and codepoint < 9727)
-- Miscellaneous Symbols
or (codepoint > 9727 and codepoint < 9733) or codepoint == 9742 or codepoint == 9745 or codepoint == 9748 or codepoint == 9749 or codepoint == 9752 or codepoint == 9757 or codepoint == 9760 or codepoint == 9762 or codepoint == 9763 or codepoint == 9766 or codepoint == 9770 or codepoint == 9774 or codepoint == 9775 or (codepoint > 9783 and codepoint < 9787) or codepoint == 9792 or codepoint == 9794 or (codepoint > 9799 and codepoint < 9812) or codepoint == 9823 or codepoint == 9824 or codepoint == 9827 or codepoint == 9829 or codepoint == 9830 or codepoint == 9832 or codepoint == 9851 or codepoint == 9854 or codepoint == 9855 or (codepoint > 9873 and codepoint < 9880) or codepoint == 9881 or codepoint == 9883 or codepoint == 9884 or codepoint == 9888 or codepoint == 9889 or codepoint == 9895 or codepoint == 9898 or codepoint == 9899 or codepoint == 9904 or codepoint == 9905 or codepoint == 9917 or codepoint == 9918 or codepoint == 9924 or codepoint == 9925 or codepoint == 9928 or codepoint == 9934 or codepoint == 9935 or codepoint == 9937 or codepoint == 9939 or codepoint == 9940 or codepoint == 9961 or codepoint == 9962 or (codepoint > 9967 and codepoint < 9974) or (codepoint > 9974 and codepoint < 9979) or codepoint == 9981
-- Dingbats
or codepoint == 9986 or codepoint == 9989 or (codepoint > 9991 and codepoint < 9998) or codepoint == 9999 or codepoint == 10002 or codepoint == 10004 or codepoint == 10006 or codepoint == 10013 or codepoint == 10017 or codepoint == 10024 or codepoint == 10035 or codepoint == 10036 or codepoint == 10052 or codepoint == 10055 or codepoint == 10060 or codepoint == 10062 or (codepoint > 10066 and codepoint < 10070) or codepoint == 10071 or codepoint == 10083 or codepoint == 10084 or (codepoint > 10132 and codepoint < 10136) or codepoint == 10145 or codepoint == 10160 or codepoint == 10175
-- Supplemental Arrows-B
or codepoint == 10548 or codepoint == 10549
-- Miscellaneous Symbols and Arrows
or (codepoint > 11012 and codepoint < 11016) or codepoint == 11035 or codepoint == 11036 or codepoint == 11088 or codepoint == 11093
-- CJK Symbols and Punctuation
or codepoint == 12336 or codepoint == 12349
-- Enclosed CJK Letters and Months
or codepoint == 12951 or codepoint == 12953
-- Mahjong Tiles
or codepoint == 126980
-- Playing Cards
or codepoint == 127183
-- Enclosed Alphanumeric Supplement
or codepoint == 127344 or codepoint == 127345 or codepoint == 127358 or codepoint == 127359 or codepoint == 127374 or (codepoint > 127376 and codepoint < 127387)
-- Enclosed Ideographic Supplement
or codepoint == 127489 or codepoint == 127490 or codepoint == 127514 or codepoint == 127535 or (codepoint > 127537 and codepoint < 127547) or codepoint == 127568 or codepoint == 127569
-- Miscellaneous Symbols and Pictographs
or (codepoint > 127743 and codepoint < 127778) or (codepoint > 127779 and codepoint < 127892) or codepoint == 127894 or codepoint == 127895 or (codepoint > 127896 and codepoint < 127900) or (codepoint > 127901 and codepoint < 127985) or (codepoint > 127986 and codepoint < 127990) or (codepoint > 127990 and codepoint < 128254) or (codepoint > 128254 and codepoint < 128318) or (codepoint > 128328 and codepoint < 128335) or (codepoint > 128335 and codepoint < 128360) or codepoint == 128367 or codepoint == 128368 or (codepoint > 128370 and codepoint < 128379) or codepoint == 128391 or (codepoint > 128393 and codepoint < 128398) or codepoint == 128400 or codepoint == 128405 or codepoint == 128406 or codepoint == 128420 or codepoint == 128421 or codepoint == 128424 or codepoint == 128433 or codepoint == 128434 or codepoint == 128444 or (codepoint > 128449 and codepoint < 128453) or (codepoint > 128464 and codepoint < 128468) or (codepoint > 128475 and codepoint < 128479) or codepoint == 128481 or codepoint == 128483 or codepoint == 128488 or codepoint == 128495 or codepoint == 128499 or (codepoint > 128505 and codepoint < 128512)
-- Emoticons
or (codepoint > 128511 and codepoint < 128592)
-- Transport and Map Symbols
or (codepoint > 128639 and codepoint < 128710) or (codepoint > 128714 and codepoint < 128723) or (codepoint > 128724 and codepoint < 128732) or (codepoint > 128731 and codepoint < 128742) or codepoint == 128745 or codepoint == 128747 or codepoint == 128748 or codepoint == 128752 or (codepoint > 128754 and codepoint < 128765)
-- Geometric Shapes Extended
or (codepoint > 128991 and codepoint < 129004) or codepoint == 129008
-- Supplemental Symbols and Pictographs
or (codepoint > 129291 and codepoint < 129339) or (codepoint > 129339 and codepoint < 129350) or (codepoint > 129350 and codepoint < 129536)
-- Symbols and Pictographs Extended-A
or (codepoint > 129647 and codepoint < 129661) or (codepoint > 129663 and codepoint < 129673) or (codepoint > 129679 and codepoint < 129726) or (codepoint > 129726 and codepoint < 129734) or (codepoint > 129741 and codepoint < 129756) or (codepoint > 129759 and codepoint < 129769) or (codepoint > 129775 and codepoint < 129785)
then
show_different_styles_if_no_emoji_image = true
end
if show_different_styles_if_no_emoji_image and not (image and image_emoji) then
ins('|-\n! Text style !! Emoji style\n')
end
if show_different_styles_if_no_emoji_image or image_emoji or m_unicode.lookup_image_emoji(codepoint) then
ins(
('|- style="font-size: 250%; text-align: center; background: rgba(128,128,128,0.15);"\n| style="padding: 0;" | ' .. u(codepoint) .. '︎ || style="padding: 0;" | ' .. u(codepoint) .. '️\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&#xFE0E;⟩ and emoji style with ⟨&#xFE0F;⟩.\n')
)
end
if args.caption and (image_emoji or (not image and not image_emoji)) then
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
args.caption
)
)
end
local sc = args.sc or require("Module:scripts").getByCode(char_to_script(codepoint))
-- FIXME? This fetches the default name for scripts with multiple lang-specific names.
-- Should we fetch all names?
-- Formerly the sort key included the codepoint, but if we have two Unicode chars sharing the same page
-- (e.g. for [[א]], regular alef U+05D0 and wide alef U+FB21 share the same page), with two calls to
-- {{character info}}, the sort key of the later-specified one seems to take priority, which often
-- results in weird ordering. Just specifying a space will cause MediaWiki's secondary sorting algorithm
-- to sort by codepoint of the page. If that doesn't work for some reason, explicitly specify the page's
-- codepoint rather than the codepoint in 1=.
insert(categories, {cat = sc:getCategoryName() .. " characters", sort = " "})
local block_name = encode_entities(args.block or m_unicode.lookup_block(codepoint))
local function present_codepoint(cp, np, script, combining, name, printable, cptitle)
local display
local link_target
if combining == nil then
combining = m_unicode.is_combining(cp)
end
if printable == nil then
printable = m_unicode.is_printable(cp)
end
local char = u(cp)
if cptitle == "self" or page_exists(char) then
link_target = char
elseif cptitle ~= "-" then
link_target = m_unicode.get_entry_title(cp)
end
if printable then
display = ('<span class="character-sample-secondary %s">%s&#x%04X;</span>'):format(
script and script:getCode() or char_to_script(cp),
combining and "◌" or "", cp
)
end
local arrow_and_maybe_char
if np then
arrow_and_maybe_char = (display or "") .. " →"
else
arrow_and_maybe_char = "← " .. (display or "")
end
local text = ('<span title="%s">%s<br><small>[U+%04X]</small></span>')
:format(encode_entities(name or m_unicode.lookup_name(cp)),
arrow_and_maybe_char, cp)
if link_target then
return ("[[" .. link_target .. "|" .. text .. "]]")
else
return text
end
end
local function get_next(cp, step)
-- Skip past noncharacters and reserved characters (Cn), private-use
-- characters (Co), surrogates (Cs), and control characters (Cc), all
-- of which have a label beginning in "<" rather than a proper name.
if step < 0 and 0 < cp or step > 0 and cp < 0x10FFFF then
repeat
cp = cp + step
until m_unicode.lookup_name(cp):sub(1, 1) ~= "<"
or not (0 < cp and cp < 0x10FFFF)
end
return cp
end
local previous_codepoint =
args.previous_codepoint and get_codepoint(args.previous_codepoint, "previous_codepoint")
or get_next(codepoint, -1)
local next_codepoint =
args.next_codepoint and get_codepoint(args.next_codepoint, "next_codepoint")
or get_next(codepoint, 1)
local combining = args.combining
if combining == nil then
combining = m_unicode.is_combining(codepoint)
end
if combining then
insert(categories, "Combining characters")
end
ins('|-\n| style="width: 70px;" colspan="2" | ' ..
"<table>" ..
"<tr>" ..
"<td>" ..
('<span class="character-sample-primary %s">%s&#%u;</span>')
:format(sc:getCode(), combining and "◌" or "", codepoint) ..
"</td>" ..
"<td>" ..
(" [https://util.unicode.org/UnicodeJsps/character.jsp?a=%.4X U+%.4X]"):format(codepoint, codepoint) ..
", [[w:List of XML and HTML character entity references|&#" .. codepoint .. ";]]\n" ..
'<div class="character-sample-name">' ..
encode_entities(args.name or m_unicode.lookup_name(codepoint)) ..
"</div>")
local function parse_aliases()
local result = {}
local aliases
if args.aliases == "-" then
aliases = nil
else
aliases = mw.loadData("Module:Unicode data/aliases")[codepoint]
end
if aliases then
local classif = {}
for i, alias in ipairs(aliases) do
if not classif[alias[1]] then
classif[alias[1]] = {}
end
insert(classif[alias[1]], encode_entities(alias[2]))
end
if classif.correction then
for i, name in ipairs(classif.correction) do
insert(categories, "Character boxes with corrected names")
insert(result, ("Corrected: %s"):format(name))
end
end
if classif.alternate then
for i, name in ipairs(classif.alternate) do
insert(categories, "Character boxes with alternative names")
insert(result, ("Alternative: %s"):format(name))
end
end
if classif.abbreviation then
insert(categories, "Character boxes with abbreviations")
insert(result, ("Abbreviation: %s"):format(concat(classif.abbreviation, ", ")))
end
local parsed_result = concat(result, ", ")
return "<div>(" .. parsed_result .. ")</div>"
end
return ""
end
ins(parse_aliases())
ins("</td></tr></table>")
local rows = {}
local function insert_row(row_title, row_contents)
insert(rows, ('<tr><td style="text-align: left">%s:</td><td>%s</td></tr>'):format(row_title, row_contents))
end
local result = nil
if block_name == "Hangul Syllables" then
local initial_to_letter = { [0] =
0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142,
0x3143, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local vowel_to_letter = { [0] =
0x314F, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156,
0x3157, 0x3158, 0x3159, 0x315A, 0x315B, 0x315C, 0x315D, 0x315E,
0x315F, 0x3160, 0x3161, 0x3162, 0x3163,
}
local final_to_letter = {
0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3139,
0x313A, 0x313B, 0x313C, 0x313D, 0x313E, 0x313F, 0x3140, 0x3141,
0x3142, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local index = codepoint - 0xAC00
local li, vi, ti = floor(index / 588), floor((index % 588) / 28), index % 28
result = ((ti ~= 0) and
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]] + [[&#%u;]]</big>' or
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]]</big>'):format(
initial_to_letter[li],
vowel_to_letter[vi],
final_to_letter[ti]
)
else
local nfd = toNFD(u(codepoint))
if ulen(nfd) ~= 1 then
local compo = {}
for nfdcp in gcodepoint(nfd) do
local dotted_circle = (m_unicode.is_combining(nfdcp) and "◌" or "")
local link_target = m_unicode.get_entry_title(nfdcp)
if not link_target or not page_exists(link_target) then
link_target = nil
end
local script = char_to_script(nfdcp)
local character_text =
link_target and ('[[%s|<span class="%s">%s&#%u;</span> [U+%04X]]]')
:format(link_target, script, dotted_circle, nfdcp, nfdcp)
or ('<span class="%s">%s&#%u;</span> [U+%04X]')
:format(script, dotted_circle, nfdcp, nfdcp)
insert(compo, '<span class="character-sample-secondary">' .. character_text .. "</span> ")
end
result = concat(compo, " + ")
end
end
if result then
insert_row("Composition", result)
insert(categories, "Character boxes with compositions")
end
-- [[ Egyptian Hieroglyphs
if args.gardiner then
insert_row("Gardiner number", (
"[http://vincent.euverte.free.fr/Rosette/Rosette_410.php?Hiero=%s&Lang=E %s]\n"):format(
args.gardiner, args.gardiner
))
end
if args.mdc then
insert_row("Manuel de Codage", args.mdc)
end
if args.egpz then
insert_row("EGPZ 1.0", args.egpz)
end
if args.gardiner or args.mdc or args.egpz then
insert(categories, "Character boxes with additional information for Egyptian Hieroglyphs")
end
-- ]]
if rows[1] then
ins(('<table style="margin: 0 auto;">%s</table>'):format(concat(rows, "")))
end
local previous_unassigned_first = previous_codepoint + 1
local previous_unassigned_last = codepoint - 1
local next_unassigned_first = codepoint + 1
local next_unassigned_last = next_codepoint - 1
local left_unassigned_text
local right_unassigned_text
if previous_codepoint == 0 then
previous_unassigned_first = 0
end
if previous_unassigned_first <= previous_unassigned_last or next_unassigned_first <= next_unassigned_last then
if previous_unassigned_first < previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(previous_unassigned_first, previous_unassigned_last)
elseif previous_unassigned_first == previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X]"):format(previous_unassigned_first)
end
if next_unassigned_first < next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(next_unassigned_first, next_unassigned_last)
elseif next_unassigned_first == next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X]"):format(next_unassigned_first)
end
end
local unassigneds_row =
mw.html.create("table"):css("width", "100%"):css("font-size", "80%"):css("white-space", "nowrap")
:tag("tr")
:tag("td"):css("width", "50%"):css("text-align", "left"):wikitext(left_unassigned_text or ""):done()
:tag("td"):css("width", "50%"):css("text-align", "right"):wikitext(right_unassigned_text or ""):done()
:allDone()
ins(tostring(unassigneds_row) .."\n")
local previous_codepoint_text = ""
local next_codepoint_text = ("%s\n")
:format(present_codepoint(next_codepoint, true,
args.next_codepoint_sc, args.next_codepoint_combining,
args.next_codepoint_name, args.next_codepoint_printable,
args.next_codepoint_title))
if previous_codepoint > 0 then
previous_codepoint_text = ("%s\n")
:format(present_codepoint(previous_codepoint, false,
args.previous_codepoint_sc, args.previous_codepoint_combining,
args.previous_codepoint_name, args.previous_codepoint_printable,
args.previous_codepoint_title))
end
local block_name_text = ("[[Appendix:Unicode/%s|%s]]")
:format(block_name, block_name)
if namespace == "" then
block_name_text = block_name_text .. ("[[Category:%s block|*%010d]]\n")
:format(block_name, codepoint)
else
block_name_text = block_name_text .. "\n"
end
local last_row =
mw.html.create("table"):css("width", "100%"):css("text-align", "center")
:tag("tr")
:tag("td"):css("width", "20%"):wikitext(previous_codepoint_text):done()
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(left_unassigned_text and "'''...'''" or ""):attr("title", left_unassigned_text or ""):done():done()
:tag("td"):css("width", "60%"):css("font-size", "110%"):css("font-weight", "bold"):wikitext(block_name_text)
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(right_unassigned_text and "'''...'''" or ""):attr("title", right_unassigned_text or ""):done():done()
:tag("td"):css("width", "20%"):wikitext(next_codepoint_text):done()
:allDone()
ins(tostring(last_row) .."\n")
ins("|}")
if not args.nocat then
ins(
require(utilities_module).format_categories(categories, require(languages_module).getByCode("mul")))
end
ins(require("Module:TemplateStyles")("Template:character info/style.css"))
return concat(table_markup)
end
function export.show(frame)
local params = {
[1] = {alias_of = "codepoint"},
["codepoint"] = {},
["previous_codepoint"] = {},
["next_codepoint"] = {},
["name"] = {},
["previous_codepoint_name"] = {},
["next_codepoint_name"] = {},
["combining"] = {type = "boolean"},
["previous_codepoint_combining"] = {type = "boolean"},
["next_codepoint_combining"] = {type = "boolean"},
["printable"] = {type = "boolean"},
["previous_codepoint_printable"] = {type = "boolean"},
["next_codepoint_printable"] = {type = "boolean"},
["previous_codepoint_title"] = {},
["next_codepoint_title"] = {},
["sc"] = {type = "script"},
["next_codepoint_sc"] = {type = "script"},
["previous_codepoint_sc"] = {type = "script"},
["caption"] = {},
["aliases"] = {},
["image"] = {},
["image_emoji"] = {},
["block"] = {},
["gardiner"] = {},
["mdc"] = {},
["egpz"] = {},
["nocat"] = {type = "boolean"},
["pagename"] = {}, -- for testing etc.
}
local parent_frame = frame:getParent()
local args = require("Module:parameters").process(parent_frame.args, params)
return export._show(args, parent_frame:getTitle())
end
return export
si0zujnybey3d7w8d3gjjgfkyd7jxc4
238752
238751
2026-11-11T12:24:26Z
Lee
19
[[:en:Module:character_info]] වෙතින් එක් සංශෝධනයක්
238751
Scribunto
text/plain
local export = {}
local m_str_utils = require("Module:string utilities")
local ucp = m_str_utils.codepoint
local decode_entities = m_str_utils.decode_entities
local encode_entities = m_str_utils.encode_entities
local floor = math.floor
local gcodepoint = m_str_utils.gcodepoint
local toNFD = mw.ustring.toNFD
local u = m_str_utils.char
local ulen = m_str_utils.len
local m_unicode = require("Module:Unicode data")
local char_to_script = require("Module:scripts").charToScript
local languages_module = "Module:languages"
local utilities_module = "Module:utilities"
local insert = table.insert
local concat = table.concat
local dingbat_scripts = {
["Zsym"] = true;
["Zmth"] = true;
["Zyyy"] = true;
}
local function page_exists(title)
local ok, title_obj = pcall(mw.title.new, title)
if ok and title_obj then
local ok2, content = pcall(function() return title_obj:getContent() end)
return ok2 and not not content
else
return false
end
end
function export.exotic_symbol_warning(frame)
local title = mw.title.getCurrentTitle()
if title:getContent() then
return ""
end
local pagename = mw.loadData("Module:headword/data").pagename
if ulen(pagename) ~= 1 then
return ""
end
local codepoint = ucp(pagename)
local script_code = char_to_script(codepoint)
if dingbat_scripts[script_code] then
return frame:expandTemplate { title = "editnotice-exotic symbols" }
end
return ""
end
local function get_codepoint(codepoint, param_name)
codepoint = tonumber(codepoint) or decode_entities(codepoint)
if type(codepoint) == "string" and ulen(codepoint) == 1 then
codepoint = ucp(codepoint)
elseif type(codepoint) ~= "number" then
error("Unrecognised string given for the " .. param_name .. " parameter")
end
return codepoint
end
function export._show(args, parent_title)
local codepoint = args.codepoint
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local title = mw.title.getCurrentTitle()
local namespace = title.nsText
local categories = {}
if codepoint then
codepoint = get_codepoint(codepoint, "codepoint")
else
if not args.pagename and title.fullText == parent_title then
-- On template page itself
codepoint = 0xfffd
elseif ulen(pagename) == 1 then
codepoint = ucp(pagename)
else
error("Page title is not a single Unicode character")
end
end
local image, image_emoji
if args.image == "-" then
image = nil
image_emoji = nil
else
image = args.image or m_unicode.lookup_image(codepoint)
image_emoji = args.image_emoji or m_unicode.lookup_image_emoji(codepoint)
end
local table_markup = {}
local function ins(txt)
insert(table_markup, txt)
end
-- "display: table !important" overrides MediaWiki style rules for narrow screens
-- that collapse the table to a ridiculously narrow width
ins(
'{| class="wikitable floatright character-info" style="display: table !important;width:25em;"\n')
if image or image_emoji then
local category = {cat = "Character boxes with images", sort_key = "*" .. string.format("%010d", codepoint)}
if image and not image:match("\127") then -- <hiero> tags generate these; pass them through
if image:match("^%[?%[?[Ff]ile:") or image:match("^%[?%[?[Ii]mage:") then
image = image:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image = "[[File:" .. image .. "|120x140px|class=skin-invert-image]]"
insert(categories, category)
end
if image_emoji then
if image then
ins('|-\n! Text style !! Emoji style\n')
end
if image_emoji:match("^%[?%[?[Ff]ile:") or image_emoji:match("^%[?%[?[Ii]mage:") then
image_emoji = image_emoji:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image_emoji = "[[File:" .. image_emoji .. "|120x140px]]"
if not image then
-- FIXME: Yuck this code.
insert(categories, category)
end
if image then
ins(
('|-\n| style="text-align: center; width: 50%s;" | %s || style="text-align: center; width: 50%s;" | %s\n'):format(
'%', image, '%', image_emoji
)
)
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
image_emoji
)
)
end
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s<br/>%s\n'):format(
image, args.caption or ""
)
)
end
end
local show_different_styles_if_no_emoji_image = false
-- https://en.wikipedia.org/wiki/List_of_emojis
-- Basic Latin (see https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)#Variants)
if codepoint == 35 or codepoint == 42 or (codepoint > 47 and codepoint < 58)
-- Latin-1 Supplement
or codepoint == 169 or codepoint == 174
-- General Punctuation
or codepoint == 8252 or codepoint == 8265
-- Letterlike Symbols
or codepoint == 8482 or codepoint == 8505
-- Arrows
or (codepoint > 8595 and codepoint < 8602) or codepoint == 8617 or codepoint == 8618
-- Miscellaneous Technical
or codepoint == 8986 or codepoint == 8987 or codepoint == 9000 or codepoint == 9167 or (codepoint > 9192 and codepoint < 9204) or (codepoint > 9207 and codepoint < 9211)
-- Enclosed Alphanumerics
or codepoint == 9410
-- Geometric Shapes
or codepoint == 9642 or codepoint == 9643 or codepoint == 9654 or codepoint == 9664 or (codepoint > 9722 and codepoint < 9727)
-- Miscellaneous Symbols
or (codepoint > 9727 and codepoint < 9733) or codepoint == 9742 or codepoint == 9745 or codepoint == 9748 or codepoint == 9749 or codepoint == 9752 or codepoint == 9757 or codepoint == 9760 or codepoint == 9762 or codepoint == 9763 or codepoint == 9766 or codepoint == 9770 or codepoint == 9774 or codepoint == 9775 or (codepoint > 9783 and codepoint < 9787) or codepoint == 9792 or codepoint == 9794 or (codepoint > 9799 and codepoint < 9812) or codepoint == 9823 or codepoint == 9824 or codepoint == 9827 or codepoint == 9829 or codepoint == 9830 or codepoint == 9832 or codepoint == 9851 or codepoint == 9854 or codepoint == 9855 or (codepoint > 9873 and codepoint < 9880) or codepoint == 9881 or codepoint == 9883 or codepoint == 9884 or codepoint == 9888 or codepoint == 9889 or codepoint == 9895 or codepoint == 9898 or codepoint == 9899 or codepoint == 9904 or codepoint == 9905 or codepoint == 9917 or codepoint == 9918 or codepoint == 9924 or codepoint == 9925 or codepoint == 9928 or codepoint == 9934 or codepoint == 9935 or codepoint == 9937 or codepoint == 9939 or codepoint == 9940 or codepoint == 9961 or codepoint == 9962 or (codepoint > 9967 and codepoint < 9974) or (codepoint > 9974 and codepoint < 9979) or codepoint == 9981
-- Dingbats
or codepoint == 9986 or codepoint == 9989 or (codepoint > 9991 and codepoint < 9998) or codepoint == 9999 or codepoint == 10002 or codepoint == 10004 or codepoint == 10006 or codepoint == 10013 or codepoint == 10017 or codepoint == 10024 or codepoint == 10035 or codepoint == 10036 or codepoint == 10052 or codepoint == 10055 or codepoint == 10060 or codepoint == 10062 or (codepoint > 10066 and codepoint < 10070) or codepoint == 10071 or codepoint == 10083 or codepoint == 10084 or (codepoint > 10132 and codepoint < 10136) or codepoint == 10145 or codepoint == 10160 or codepoint == 10175
-- Supplemental Arrows-B
or codepoint == 10548 or codepoint == 10549
-- Miscellaneous Symbols and Arrows
or (codepoint > 11012 and codepoint < 11016) or codepoint == 11035 or codepoint == 11036 or codepoint == 11088 or codepoint == 11093
-- CJK Symbols and Punctuation
or codepoint == 12336 or codepoint == 12349
-- Enclosed CJK Letters and Months
or codepoint == 12951 or codepoint == 12953
-- Mahjong Tiles
or codepoint == 126980
-- Playing Cards
or codepoint == 127183
-- Enclosed Alphanumeric Supplement
or codepoint == 127344 or codepoint == 127345 or codepoint == 127358 or codepoint == 127359 or codepoint == 127374 or (codepoint > 127376 and codepoint < 127387)
-- Enclosed Ideographic Supplement
or codepoint == 127489 or codepoint == 127490 or codepoint == 127514 or codepoint == 127535 or (codepoint > 127537 and codepoint < 127547) or codepoint == 127568 or codepoint == 127569
-- Miscellaneous Symbols and Pictographs
or (codepoint > 127743 and codepoint < 127778) or (codepoint > 127779 and codepoint < 127892) or codepoint == 127894 or codepoint == 127895 or (codepoint > 127896 and codepoint < 127900) or (codepoint > 127901 and codepoint < 127985) or (codepoint > 127986 and codepoint < 127990) or (codepoint > 127990 and codepoint < 128254) or (codepoint > 128254 and codepoint < 128318) or (codepoint > 128328 and codepoint < 128335) or (codepoint > 128335 and codepoint < 128360) or codepoint == 128367 or codepoint == 128368 or (codepoint > 128370 and codepoint < 128379) or codepoint == 128391 or (codepoint > 128393 and codepoint < 128398) or codepoint == 128400 or codepoint == 128405 or codepoint == 128406 or codepoint == 128420 or codepoint == 128421 or codepoint == 128424 or codepoint == 128433 or codepoint == 128434 or codepoint == 128444 or (codepoint > 128449 and codepoint < 128453) or (codepoint > 128464 and codepoint < 128468) or (codepoint > 128475 and codepoint < 128479) or codepoint == 128481 or codepoint == 128483 or codepoint == 128488 or codepoint == 128495 or codepoint == 128499 or (codepoint > 128505 and codepoint < 128512)
-- Emoticons
or (codepoint > 128511 and codepoint < 128592)
-- Transport and Map Symbols
or (codepoint > 128639 and codepoint < 128710) or (codepoint > 128714 and codepoint < 128723) or (codepoint > 128724 and codepoint < 128732) or (codepoint > 128731 and codepoint < 128742) or codepoint == 128745 or codepoint == 128747 or codepoint == 128748 or codepoint == 128752 or (codepoint > 128754 and codepoint < 128765)
-- Geometric Shapes Extended
or (codepoint > 128991 and codepoint < 129004) or codepoint == 129008
-- Supplemental Symbols and Pictographs
or (codepoint > 129291 and codepoint < 129339) or (codepoint > 129339 and codepoint < 129350) or (codepoint > 129350 and codepoint < 129536)
-- Symbols and Pictographs Extended-A
or (codepoint > 129647 and codepoint < 129661) or (codepoint > 129663 and codepoint < 129673) or (codepoint > 129679 and codepoint < 129726) or (codepoint > 129726 and codepoint < 129734) or (codepoint > 129741 and codepoint < 129756) or (codepoint > 129759 and codepoint < 129769) or (codepoint > 129775 and codepoint < 129785)
then
show_different_styles_if_no_emoji_image = true
end
if show_different_styles_if_no_emoji_image and not (image and image_emoji) then
ins('|-\n! Text style !! Emoji style\n')
end
if show_different_styles_if_no_emoji_image or image_emoji or m_unicode.lookup_image_emoji(codepoint) then
ins(
('|- style="font-size: 250%; text-align: center; background: rgba(128,128,128,0.15);"\n| style="padding: 0;" | ' .. u(codepoint) .. '︎ || style="padding: 0;" | ' .. u(codepoint) .. '️\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&#xFE0E;⟩ and emoji style with ⟨&#xFE0F;⟩.\n')
)
end
if args.caption and (image_emoji or (not image and not image_emoji)) then
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
args.caption
)
)
end
local sc = args.sc or require("Module:scripts").getByCode(char_to_script(codepoint))
-- FIXME? This fetches the default name for scripts with multiple lang-specific names.
-- Should we fetch all names?
-- Formerly the sort key included the codepoint, but if we have two Unicode chars sharing the same page
-- (e.g. for [[א]], regular alef U+05D0 and wide alef U+FB21 share the same page), with two calls to
-- {{character info}}, the sort key of the later-specified one seems to take priority, which often
-- results in weird ordering. Just specifying a space will cause MediaWiki's secondary sorting algorithm
-- to sort by codepoint of the page. If that doesn't work for some reason, explicitly specify the page's
-- codepoint rather than the codepoint in 1=.
insert(categories, {cat = sc:getCategoryName() .. " characters", sort = " "})
local block_name = encode_entities(args.block or m_unicode.lookup_block(codepoint))
local function present_codepoint(cp, np, script, combining, name, printable, cptitle)
local display
local link_target
if combining == nil then
combining = m_unicode.is_combining(cp)
end
if printable == nil then
printable = m_unicode.is_printable(cp)
end
local char = u(cp)
if cptitle == "self" or page_exists(char) then
link_target = char
elseif cptitle ~= "-" then
link_target = m_unicode.get_entry_title(cp)
end
if printable then
display = ('<span class="character-sample-secondary %s">%s&#x%04X;</span>'):format(
script and script:getCode() or char_to_script(cp),
combining and "◌" or "", cp
)
end
local arrow_and_maybe_char
if np then
arrow_and_maybe_char = (display or "") .. " →"
else
arrow_and_maybe_char = "← " .. (display or "")
end
local text = ('<span title="%s">%s<br><small>[U+%04X]</small></span>')
:format(encode_entities(name or m_unicode.lookup_name(cp)),
arrow_and_maybe_char, cp)
if link_target then
return ("[[" .. link_target .. "|" .. text .. "]]")
else
return text
end
end
local function get_next(cp, step)
-- Skip past noncharacters and reserved characters (Cn), private-use
-- characters (Co), surrogates (Cs), and control characters (Cc), all
-- of which have a label beginning in "<" rather than a proper name.
if step < 0 and 0 < cp or step > 0 and cp < 0x10FFFF then
repeat
cp = cp + step
until m_unicode.lookup_name(cp):sub(1, 1) ~= "<"
or not (0 < cp and cp < 0x10FFFF)
end
return cp
end
local previous_codepoint =
args.previous_codepoint and get_codepoint(args.previous_codepoint, "previous_codepoint")
or get_next(codepoint, -1)
local next_codepoint =
args.next_codepoint and get_codepoint(args.next_codepoint, "next_codepoint")
or get_next(codepoint, 1)
local combining = args.combining
if combining == nil then
combining = m_unicode.is_combining(codepoint)
end
if combining then
insert(categories, "Combining characters")
end
ins('|-\n| style="width: 70px;" colspan="2" | ' ..
"<table>" ..
"<tr>" ..
"<td>" ..
('<span class="character-sample-primary %s">%s&#%u;</span>')
:format(sc:getCode(), combining and "◌" or "", codepoint) ..
"</td>" ..
"<td>" ..
(" [https://util.unicode.org/UnicodeJsps/character.jsp?a=%.4X U+%.4X]"):format(codepoint, codepoint) ..
", [[w:List of XML and HTML character entity references|&#" .. codepoint .. ";]]\n" ..
'<div class="character-sample-name">' ..
encode_entities(args.name or m_unicode.lookup_name(codepoint)) ..
"</div>")
local function parse_aliases()
local result = {}
local aliases
if args.aliases == "-" then
aliases = nil
else
aliases = mw.loadData("Module:Unicode data/aliases")[codepoint]
end
if aliases then
local classif = {}
for i, alias in ipairs(aliases) do
if not classif[alias[1]] then
classif[alias[1]] = {}
end
insert(classif[alias[1]], encode_entities(alias[2]))
end
if classif.correction then
for i, name in ipairs(classif.correction) do
insert(categories, "Character boxes with corrected names")
insert(result, ("Corrected: %s"):format(name))
end
end
if classif.alternate then
for i, name in ipairs(classif.alternate) do
insert(categories, "Character boxes with alternative names")
insert(result, ("Alternative: %s"):format(name))
end
end
if classif.abbreviation then
insert(categories, "Character boxes with abbreviations")
insert(result, ("Abbreviation: %s"):format(concat(classif.abbreviation, ", ")))
end
local parsed_result = concat(result, ", ")
return "<div>(" .. parsed_result .. ")</div>"
end
return ""
end
ins(parse_aliases())
ins("</td></tr></table>")
local rows = {}
local function insert_row(row_title, row_contents)
insert(rows, ('<tr><td style="text-align: left">%s:</td><td>%s</td></tr>'):format(row_title, row_contents))
end
local result = nil
if block_name == "Hangul Syllables" then
local initial_to_letter = { [0] =
0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142,
0x3143, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local vowel_to_letter = { [0] =
0x314F, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156,
0x3157, 0x3158, 0x3159, 0x315A, 0x315B, 0x315C, 0x315D, 0x315E,
0x315F, 0x3160, 0x3161, 0x3162, 0x3163,
}
local final_to_letter = {
0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3139,
0x313A, 0x313B, 0x313C, 0x313D, 0x313E, 0x313F, 0x3140, 0x3141,
0x3142, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local index = codepoint - 0xAC00
local li, vi, ti = floor(index / 588), floor((index % 588) / 28), index % 28
result = ((ti ~= 0) and
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]] + [[&#%u;]]</big>' or
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]]</big>'):format(
initial_to_letter[li],
vowel_to_letter[vi],
final_to_letter[ti]
)
else
local nfd = toNFD(u(codepoint))
if ulen(nfd) ~= 1 then
local compo = {}
for nfdcp in gcodepoint(nfd) do
local dotted_circle = (m_unicode.is_combining(nfdcp) and "◌" or "")
local link_target = m_unicode.get_entry_title(nfdcp)
if not link_target or not page_exists(link_target) then
link_target = nil
end
local script = char_to_script(nfdcp)
local character_text =
link_target and ('[[%s|<span class="%s">%s&#%u;</span> [U+%04X]]]')
:format(link_target, script, dotted_circle, nfdcp, nfdcp)
or ('<span class="%s">%s&#%u;</span> [U+%04X]')
:format(script, dotted_circle, nfdcp, nfdcp)
insert(compo, '<span class="character-sample-secondary">' .. character_text .. "</span> ")
end
result = concat(compo, " + ")
end
end
if result then
insert_row("Composition", result)
insert(categories, "Character boxes with compositions")
end
-- [[ Egyptian Hieroglyphs
if args.gardiner then
insert_row("Gardiner number", (
"[http://vincent.euverte.free.fr/Rosette/Rosette_410.php?Hiero=%s&Lang=E %s]\n"):format(
args.gardiner, args.gardiner
))
end
if args.mdc then
insert_row("Manuel de Codage", args.mdc)
end
if args.egpz then
insert_row("EGPZ 1.0", args.egpz)
end
if args.gardiner or args.mdc or args.egpz then
insert(categories, "Character boxes with additional information for Egyptian Hieroglyphs")
end
-- ]]
if rows[1] then
ins(('<table style="margin: 0 auto;">%s</table>'):format(concat(rows, "")))
end
local previous_unassigned_first = previous_codepoint + 1
local previous_unassigned_last = codepoint - 1
local next_unassigned_first = codepoint + 1
local next_unassigned_last = next_codepoint - 1
local left_unassigned_text
local right_unassigned_text
if previous_codepoint == 0 then
previous_unassigned_first = 0
end
if previous_unassigned_first <= previous_unassigned_last or next_unassigned_first <= next_unassigned_last then
if previous_unassigned_first < previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(previous_unassigned_first, previous_unassigned_last)
elseif previous_unassigned_first == previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X]"):format(previous_unassigned_first)
end
if next_unassigned_first < next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(next_unassigned_first, next_unassigned_last)
elseif next_unassigned_first == next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X]"):format(next_unassigned_first)
end
end
local unassigneds_row =
mw.html.create("table"):css("width", "100%"):css("font-size", "80%"):css("white-space", "nowrap")
:tag("tr")
:tag("td"):css("width", "50%"):css("text-align", "left"):wikitext(left_unassigned_text or ""):done()
:tag("td"):css("width", "50%"):css("text-align", "right"):wikitext(right_unassigned_text or ""):done()
:allDone()
ins(tostring(unassigneds_row) .."\n")
local previous_codepoint_text = ""
local next_codepoint_text = ("%s\n")
:format(present_codepoint(next_codepoint, true,
args.next_codepoint_sc, args.next_codepoint_combining,
args.next_codepoint_name, args.next_codepoint_printable,
args.next_codepoint_title))
if previous_codepoint > 0 then
previous_codepoint_text = ("%s\n")
:format(present_codepoint(previous_codepoint, false,
args.previous_codepoint_sc, args.previous_codepoint_combining,
args.previous_codepoint_name, args.previous_codepoint_printable,
args.previous_codepoint_title))
end
local block_name_text = ("[[Appendix:Unicode/%s|%s]]")
:format(block_name, block_name)
if namespace == "" then
block_name_text = block_name_text .. ("[[Category:%s block|*%010d]]\n")
:format(block_name, codepoint)
else
block_name_text = block_name_text .. "\n"
end
local last_row =
mw.html.create("table"):css("width", "100%"):css("text-align", "center")
:tag("tr")
:tag("td"):css("width", "20%"):wikitext(previous_codepoint_text):done()
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(left_unassigned_text and "'''...'''" or ""):attr("title", left_unassigned_text or ""):done():done()
:tag("td"):css("width", "60%"):css("font-size", "110%"):css("font-weight", "bold"):wikitext(block_name_text)
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(right_unassigned_text and "'''...'''" or ""):attr("title", right_unassigned_text or ""):done():done()
:tag("td"):css("width", "20%"):wikitext(next_codepoint_text):done()
:allDone()
ins(tostring(last_row) .."\n")
ins("|}")
if not args.nocat then
ins(
require(utilities_module).format_categories(categories, require(languages_module).getByCode("mul")))
end
ins(require("Module:TemplateStyles")("Template:character info/style.css"))
return concat(table_markup)
end
function export.show(frame)
local params = {
[1] = {alias_of = "codepoint"},
["codepoint"] = {},
["previous_codepoint"] = {},
["next_codepoint"] = {},
["name"] = {},
["previous_codepoint_name"] = {},
["next_codepoint_name"] = {},
["combining"] = {type = "boolean"},
["previous_codepoint_combining"] = {type = "boolean"},
["next_codepoint_combining"] = {type = "boolean"},
["printable"] = {type = "boolean"},
["previous_codepoint_printable"] = {type = "boolean"},
["next_codepoint_printable"] = {type = "boolean"},
["previous_codepoint_title"] = {},
["next_codepoint_title"] = {},
["sc"] = {type = "script"},
["next_codepoint_sc"] = {type = "script"},
["previous_codepoint_sc"] = {type = "script"},
["caption"] = {},
["aliases"] = {},
["image"] = {},
["image_emoji"] = {},
["block"] = {},
["gardiner"] = {},
["mdc"] = {},
["egpz"] = {},
["nocat"] = {type = "boolean"},
["pagename"] = {}, -- for testing etc.
}
local parent_frame = frame:getParent()
local args = require("Module:parameters").process(parent_frame.args, params)
return export._show(args, parent_frame:getTitle())
end
return export
si0zujnybey3d7w8d3gjjgfkyd7jxc4
238753
238752
2026-11-11T12:26:22Z
Lee
19
පැරණි සංස්කරණයකින් ගත් කොටස්...
238753
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local export = {}
local m_str_utils = require("Module:string utilities")
local ucp = m_str_utils.codepoint
local decode_entities = m_str_utils.decode_entities
local encode_entities = m_str_utils.encode_entities
local floor = math.floor
local gcodepoint = m_str_utils.gcodepoint
local toNFD = mw.ustring.toNFD
local u = m_str_utils.char
local ulen = m_str_utils.len
local m_unicode = require("Module:Unicode data")
local char_to_script = require("Module:scripts").charToScript
local languages_module = "Module:languages"
local utilities_module = "Module:utilities"
local insert = table.insert
local concat = table.concat
local dingbat_scripts = {
["Zsym"] = true;
["Zmth"] = true;
["Zyyy"] = true;
}
local function page_exists(title)
local ok, title_obj = pcall(mw.title.new, title)
if ok and title_obj then
local ok2, content = pcall(function() return title_obj:getContent() end)
return ok2 and not not content
else
return false
end
end
function export.exotic_symbol_warning(frame)
local title = mw.title.getCurrentTitle()
if title:getContent() then
return ""
end
local pagename = mw.loadData("Module:headword/data").pagename
if ulen(pagename) ~= 1 then
return ""
end
local codepoint = ucp(pagename)
local script_code = char_to_script(codepoint)
if dingbat_scripts[script_code] then
return frame:expandTemplate { title = "editnotice-exotic symbols" }
end
return ""
end
local function get_codepoint(codepoint, param_name)
codepoint = tonumber(codepoint) or decode_entities(codepoint)
if type(codepoint) == "string" and ulen(codepoint) == 1 then
codepoint = ucp(codepoint)
elseif type(codepoint) ~= "number" then
error("Unrecognised string given for the " .. param_name .. " parameter")
end
return codepoint
end
function export._show(args, parent_title)
local codepoint = args.codepoint
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
local title = mw.title.getCurrentTitle()
local namespace = title.nsText
local categories = {}
if codepoint then
codepoint = get_codepoint(codepoint, "codepoint")
else
if not args.pagename and title.fullText == parent_title then
-- On template page itself
codepoint = 0xfffd
elseif ulen(pagename) == 1 then
codepoint = ucp(pagename)
else
error("Page title is not a single Unicode character")
end
end
local image, image_emoji
if args.image == "-" then
image = nil
image_emoji = nil
else
image = args.image or m_unicode.lookup_image(codepoint)
image_emoji = args.image_emoji or m_unicode.lookup_image_emoji(codepoint)
end
local table_markup = {}
local function ins(txt)
insert(table_markup, txt)
end
-- "display: table !important" overrides MediaWiki style rules for narrow screens
-- that collapse the table to a ridiculously narrow width
ins(
'{| class="wikitable floatright character-info" style="display: table !important;width:25em;"\n')
if image or image_emoji then
local category = {cat = "Character boxes with images", sort_key = "*" .. string.format("%010d", codepoint)}
if image and not image:match("\127") then -- <hiero> tags generate these; pass them through
if image:match("^%[?%[?[Ff]ile:") or image:match("^%[?%[?[Ii]mage:") then
image = image:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image = "[[File:" .. image .. "|120x140px|class=skin-invert-image]]"
insert(categories, category)
end
if image_emoji then
if image then
ins('|-\n! Text style !! Emoji style\n')
end
if image_emoji:match("^%[?%[?[Ff]ile:") or image_emoji:match("^%[?%[?[Ii]mage:") then
image_emoji = image_emoji:gsub("^%[%[", ""):gsub("^[Ff]ile:", ""):gsub("^[Ii]mage:", ""):gsub("|.*", ""):gsub("]]", "")
end
image_emoji = "[[File:" .. image_emoji .. "|120x140px]]"
if not image then
-- FIXME: Yuck this code.
insert(categories, category)
end
if image then
ins(
('|-\n| style="text-align: center; width: 50%s;" | %s || style="text-align: center; width: 50%s;" | %s\n'):format(
'%', image, '%', image_emoji
)
)
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
image_emoji
)
)
end
else
ins(
('|-\n| colspan="2" style="text-align: center;" | %s<br/>%s\n'):format(
image, args.caption or ""
)
)
end
end
local show_different_styles_if_no_emoji_image = false
-- https://en.wikipedia.org/wiki/List_of_emojis
-- Basic Latin (see https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)#Variants)
if codepoint == 35 or codepoint == 42 or (codepoint > 47 and codepoint < 58)
-- Latin-1 Supplement
or codepoint == 169 or codepoint == 174
-- General Punctuation
or codepoint == 8252 or codepoint == 8265
-- Letterlike Symbols
or codepoint == 8482 or codepoint == 8505
-- Arrows
or (codepoint > 8595 and codepoint < 8602) or codepoint == 8617 or codepoint == 8618
-- Miscellaneous Technical
or codepoint == 8986 or codepoint == 8987 or codepoint == 9000 or codepoint == 9167 or (codepoint > 9192 and codepoint < 9204) or (codepoint > 9207 and codepoint < 9211)
-- Enclosed Alphanumerics
or codepoint == 9410
-- Geometric Shapes
or codepoint == 9642 or codepoint == 9643 or codepoint == 9654 or codepoint == 9664 or (codepoint > 9722 and codepoint < 9727)
-- Miscellaneous Symbols
or (codepoint > 9727 and codepoint < 9733) or codepoint == 9742 or codepoint == 9745 or codepoint == 9748 or codepoint == 9749 or codepoint == 9752 or codepoint == 9757 or codepoint == 9760 or codepoint == 9762 or codepoint == 9763 or codepoint == 9766 or codepoint == 9770 or codepoint == 9774 or codepoint == 9775 or (codepoint > 9783 and codepoint < 9787) or codepoint == 9792 or codepoint == 9794 or (codepoint > 9799 and codepoint < 9812) or codepoint == 9823 or codepoint == 9824 or codepoint == 9827 or codepoint == 9829 or codepoint == 9830 or codepoint == 9832 or codepoint == 9851 or codepoint == 9854 or codepoint == 9855 or (codepoint > 9873 and codepoint < 9880) or codepoint == 9881 or codepoint == 9883 or codepoint == 9884 or codepoint == 9888 or codepoint == 9889 or codepoint == 9895 or codepoint == 9898 or codepoint == 9899 or codepoint == 9904 or codepoint == 9905 or codepoint == 9917 or codepoint == 9918 or codepoint == 9924 or codepoint == 9925 or codepoint == 9928 or codepoint == 9934 or codepoint == 9935 or codepoint == 9937 or codepoint == 9939 or codepoint == 9940 or codepoint == 9961 or codepoint == 9962 or (codepoint > 9967 and codepoint < 9974) or (codepoint > 9974 and codepoint < 9979) or codepoint == 9981
-- Dingbats
or codepoint == 9986 or codepoint == 9989 or (codepoint > 9991 and codepoint < 9998) or codepoint == 9999 or codepoint == 10002 or codepoint == 10004 or codepoint == 10006 or codepoint == 10013 or codepoint == 10017 or codepoint == 10024 or codepoint == 10035 or codepoint == 10036 or codepoint == 10052 or codepoint == 10055 or codepoint == 10060 or codepoint == 10062 or (codepoint > 10066 and codepoint < 10070) or codepoint == 10071 or codepoint == 10083 or codepoint == 10084 or (codepoint > 10132 and codepoint < 10136) or codepoint == 10145 or codepoint == 10160 or codepoint == 10175
-- Supplemental Arrows-B
or codepoint == 10548 or codepoint == 10549
-- Miscellaneous Symbols and Arrows
or (codepoint > 11012 and codepoint < 11016) or codepoint == 11035 or codepoint == 11036 or codepoint == 11088 or codepoint == 11093
-- CJK Symbols and Punctuation
or codepoint == 12336 or codepoint == 12349
-- Enclosed CJK Letters and Months
or codepoint == 12951 or codepoint == 12953
-- Mahjong Tiles
or codepoint == 126980
-- Playing Cards
or codepoint == 127183
-- Enclosed Alphanumeric Supplement
or codepoint == 127344 or codepoint == 127345 or codepoint == 127358 or codepoint == 127359 or codepoint == 127374 or (codepoint > 127376 and codepoint < 127387)
-- Enclosed Ideographic Supplement
or codepoint == 127489 or codepoint == 127490 or codepoint == 127514 or codepoint == 127535 or (codepoint > 127537 and codepoint < 127547) or codepoint == 127568 or codepoint == 127569
-- Miscellaneous Symbols and Pictographs
or (codepoint > 127743 and codepoint < 127778) or (codepoint > 127779 and codepoint < 127892) or codepoint == 127894 or codepoint == 127895 or (codepoint > 127896 and codepoint < 127900) or (codepoint > 127901 and codepoint < 127985) or (codepoint > 127986 and codepoint < 127990) or (codepoint > 127990 and codepoint < 128254) or (codepoint > 128254 and codepoint < 128318) or (codepoint > 128328 and codepoint < 128335) or (codepoint > 128335 and codepoint < 128360) or codepoint == 128367 or codepoint == 128368 or (codepoint > 128370 and codepoint < 128379) or codepoint == 128391 or (codepoint > 128393 and codepoint < 128398) or codepoint == 128400 or codepoint == 128405 or codepoint == 128406 or codepoint == 128420 or codepoint == 128421 or codepoint == 128424 or codepoint == 128433 or codepoint == 128434 or codepoint == 128444 or (codepoint > 128449 and codepoint < 128453) or (codepoint > 128464 and codepoint < 128468) or (codepoint > 128475 and codepoint < 128479) or codepoint == 128481 or codepoint == 128483 or codepoint == 128488 or codepoint == 128495 or codepoint == 128499 or (codepoint > 128505 and codepoint < 128512)
-- Emoticons
or (codepoint > 128511 and codepoint < 128592)
-- Transport and Map Symbols
or (codepoint > 128639 and codepoint < 128710) or (codepoint > 128714 and codepoint < 128723) or (codepoint > 128724 and codepoint < 128732) or (codepoint > 128731 and codepoint < 128742) or codepoint == 128745 or codepoint == 128747 or codepoint == 128748 or codepoint == 128752 or (codepoint > 128754 and codepoint < 128765)
-- Geometric Shapes Extended
or (codepoint > 128991 and codepoint < 129004) or codepoint == 129008
-- Supplemental Symbols and Pictographs
or (codepoint > 129291 and codepoint < 129339) or (codepoint > 129339 and codepoint < 129350) or (codepoint > 129350 and codepoint < 129536)
-- Symbols and Pictographs Extended-A
or (codepoint > 129647 and codepoint < 129661) or (codepoint > 129663 and codepoint < 129673) or (codepoint > 129679 and codepoint < 129726) or (codepoint > 129726 and codepoint < 129734) or (codepoint > 129741 and codepoint < 129756) or (codepoint > 129759 and codepoint < 129769) or (codepoint > 129775 and codepoint < 129785)
then
show_different_styles_if_no_emoji_image = true
end
if show_different_styles_if_no_emoji_image and not (image and image_emoji) then
ins('|-\n! Text style !! Emoji style\n')
end
if show_different_styles_if_no_emoji_image or image_emoji or m_unicode.lookup_image_emoji(codepoint) then
ins(
('|- style="font-size: 250%; text-align: center; background: rgba(128,128,128,0.15);"\n| style="padding: 0;" | ' .. u(codepoint) .. '︎ || style="padding: 0;" | ' .. u(codepoint) .. '️\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&#xFE0E;⟩ and emoji style with ⟨&#xFE0F;⟩.\n')
)
end
if args.caption and (image_emoji or (not image and not image_emoji)) then
ins(
('|-\n| colspan="2" style="text-align: center;" | %s\n'):format(
args.caption
)
)
end
local sc = args.sc or require("Module:scripts").getByCode(char_to_script(codepoint))
-- FIXME? This fetches the default name for scripts with multiple lang-specific names.
-- Should we fetch all names?
-- Formerly the sort key included the codepoint, but if we have two Unicode chars sharing the same page
-- (e.g. for [[א]], regular alef U+05D0 and wide alef U+FB21 share the same page), with two calls to
-- {{character info}}, the sort key of the later-specified one seems to take priority, which often
-- results in weird ordering. Just specifying a space will cause MediaWiki's secondary sorting algorithm
-- to sort by codepoint of the page. If that doesn't work for some reason, explicitly specify the page's
-- codepoint rather than the codepoint in 1=.
insert(categories, {cat = sc:getCategoryName() .. " තුළ භාවිතා වන අනුලක්ෂණ", sort = " "})
local block_name = encode_entities(args.block or m_unicode.lookup_block(codepoint))
local function present_codepoint(cp, np, script, combining, name, printable, cptitle)
local display
local link_target
if combining == nil then
combining = m_unicode.is_combining(cp)
end
if printable == nil then
printable = m_unicode.is_printable(cp)
end
local char = u(cp)
if cptitle == "self" or page_exists(char) then
link_target = char
elseif cptitle ~= "-" then
link_target = m_unicode.get_entry_title(cp)
end
if printable then
display = ('<span class="character-sample-secondary %s">%s&#x%04X;</span>'):format(
script and script:getCode() or char_to_script(cp),
combining and "◌" or "", cp
)
end
local arrow_and_maybe_char
if np then
arrow_and_maybe_char = (display or "") .. " →"
else
arrow_and_maybe_char = "← " .. (display or "")
end
local text = ('<span title="%s">%s<br><small>[U+%04X]</small></span>')
:format(encode_entities(name or m_unicode.lookup_name(cp)),
arrow_and_maybe_char, cp)
if link_target then
return ("[[" .. link_target .. "|" .. text .. "]]")
else
return text
end
end
local function get_next(cp, step)
-- Skip past noncharacters and reserved characters (Cn), private-use
-- characters (Co), surrogates (Cs), and control characters (Cc), all
-- of which have a label beginning in "<" rather than a proper name.
if step < 0 and 0 < cp or step > 0 and cp < 0x10FFFF then
repeat
cp = cp + step
until m_unicode.lookup_name(cp):sub(1, 1) ~= "<"
or not (0 < cp and cp < 0x10FFFF)
end
return cp
end
local previous_codepoint =
args.previous_codepoint and get_codepoint(args.previous_codepoint, "previous_codepoint")
or get_next(codepoint, -1)
local next_codepoint =
args.next_codepoint and get_codepoint(args.next_codepoint, "next_codepoint")
or get_next(codepoint, 1)
local combining = args.combining
if combining == nil then
combining = m_unicode.is_combining(codepoint)
end
if combining then
insert(categories, "Combining characters")
end
ins('|-\n| style="width: 70px;" colspan="2" | ' ..
"<table>" ..
"<tr>" ..
"<td>" ..
('<span class="character-sample-primary %s">%s&#%u;</span>')
:format(sc:getCode(), combining and "◌" or "", codepoint) ..
"</td>" ..
"<td>" ..
(" [https://util.unicode.org/UnicodeJsps/character.jsp?a=%.4X U+%.4X]"):format(codepoint, codepoint) ..
", [[w:List of XML and HTML character entity references|&#" .. codepoint .. ";]]\n" ..
'<div class="character-sample-name">' ..
encode_entities(args.name or m_unicode.lookup_name(codepoint)) ..
"</div>")
local function parse_aliases()
local result = {}
local aliases
if args.aliases == "-" then
aliases = nil
else
aliases = mw.loadData("Module:Unicode data/aliases")[codepoint]
end
if aliases then
local classif = {}
for i, alias in ipairs(aliases) do
if not classif[alias[1]] then
classif[alias[1]] = {}
end
insert(classif[alias[1]], encode_entities(alias[2]))
end
if classif.correction then
for i, name in ipairs(classif.correction) do
insert(categories, "Character boxes with corrected names")
insert(result, ("Corrected: %s"):format(name))
end
end
if classif.alternate then
for i, name in ipairs(classif.alternate) do
insert(categories, "Character boxes with alternative names")
insert(result, ("Alternative: %s"):format(name))
end
end
if classif.abbreviation then
insert(categories, "Character boxes with abbreviations")
insert(result, ("Abbreviation: %s"):format(concat(classif.abbreviation, ", ")))
end
local parsed_result = concat(result, ", ")
return "<div>(" .. parsed_result .. ")</div>"
end
return ""
end
ins(parse_aliases())
ins("</td></tr></table>")
local rows = {}
local function insert_row(row_title, row_contents)
insert(rows, ('<tr><td style="text-align: left">%s:</td><td>%s</td></tr>'):format(row_title, row_contents))
end
local result = nil
if block_name == "Hangul Syllables" then
local initial_to_letter = { [0] =
0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142,
0x3143, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local vowel_to_letter = { [0] =
0x314F, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156,
0x3157, 0x3158, 0x3159, 0x315A, 0x315B, 0x315C, 0x315D, 0x315E,
0x315F, 0x3160, 0x3161, 0x3162, 0x3163,
}
local final_to_letter = {
0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3139,
0x313A, 0x313B, 0x313C, 0x313D, 0x313E, 0x313F, 0x3140, 0x3141,
0x3142, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148, 0x314A, 0x314B,
0x314C, 0x314D, 0x314E,
}
local index = codepoint - 0xAC00
local li, vi, ti = floor(index / 588), floor((index % 588) / 28), index % 28
result = ((ti ~= 0) and
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]] + [[&#%u;]]</big>' or
'<big class="Kore" lang="">[[&#%u;]] + [[&#%u;]]</big>'):format(
initial_to_letter[li],
vowel_to_letter[vi],
final_to_letter[ti]
)
else
local nfd = toNFD(u(codepoint))
if ulen(nfd) ~= 1 then
local compo = {}
for nfdcp in gcodepoint(nfd) do
local dotted_circle = (m_unicode.is_combining(nfdcp) and "◌" or "")
local link_target = m_unicode.get_entry_title(nfdcp)
if not link_target or not page_exists(link_target) then
link_target = nil
end
local script = char_to_script(nfdcp)
local character_text =
link_target and ('[[%s|<span class="%s">%s&#%u;</span> [U+%04X]]]')
:format(link_target, script, dotted_circle, nfdcp, nfdcp)
or ('<span class="%s">%s&#%u;</span> [U+%04X]')
:format(script, dotted_circle, nfdcp, nfdcp)
insert(compo, '<span class="character-sample-secondary">' .. character_text .. "</span> ")
end
result = concat(compo, " + ")
end
end
if result then
insert_row("Composition", result)
insert(categories, "Character boxes with compositions")
end
-- [[ Egyptian Hieroglyphs
if args.gardiner then
insert_row("Gardiner number", (
"[http://vincent.euverte.free.fr/Rosette/Rosette_410.php?Hiero=%s&Lang=E %s]\n"):format(
args.gardiner, args.gardiner
))
end
if args.mdc then
insert_row("Manuel de Codage", args.mdc)
end
if args.egpz then
insert_row("EGPZ 1.0", args.egpz)
end
if args.gardiner or args.mdc or args.egpz then
insert(categories, "Character boxes with additional information for Egyptian Hieroglyphs")
end
-- ]]
if rows[1] then
ins(('<table style="margin: 0 auto;">%s</table>'):format(concat(rows, "")))
end
local previous_unassigned_first = previous_codepoint + 1
local previous_unassigned_last = codepoint - 1
local next_unassigned_first = codepoint + 1
local next_unassigned_last = next_codepoint - 1
local left_unassigned_text
local right_unassigned_text
if previous_codepoint == 0 then
previous_unassigned_first = 0
end
if previous_unassigned_first <= previous_unassigned_last or next_unassigned_first <= next_unassigned_last then
if previous_unassigned_first < previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(previous_unassigned_first, previous_unassigned_last)
elseif previous_unassigned_first == previous_unassigned_last then
left_unassigned_text = ("[unassigned: U+%.4X]"):format(previous_unassigned_first)
end
if next_unassigned_first < next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X–U+%.4X]"):format(next_unassigned_first, next_unassigned_last)
elseif next_unassigned_first == next_unassigned_last then
right_unassigned_text = ("[unassigned: U+%.4X]"):format(next_unassigned_first)
end
end
local unassigneds_row =
mw.html.create("table"):css("width", "100%"):css("font-size", "80%"):css("white-space", "nowrap")
:tag("tr")
:tag("td"):css("width", "50%"):css("text-align", "left"):wikitext(left_unassigned_text or ""):done()
:tag("td"):css("width", "50%"):css("text-align", "right"):wikitext(right_unassigned_text or ""):done()
:allDone()
ins(tostring(unassigneds_row) .."\n")
local previous_codepoint_text = ""
local next_codepoint_text = ("%s\n")
:format(present_codepoint(next_codepoint, true,
args.next_codepoint_sc, args.next_codepoint_combining,
args.next_codepoint_name, args.next_codepoint_printable,
args.next_codepoint_title))
if previous_codepoint > 0 then
previous_codepoint_text = ("%s\n")
:format(present_codepoint(previous_codepoint, false,
args.previous_codepoint_sc, args.previous_codepoint_combining,
args.previous_codepoint_name, args.previous_codepoint_printable,
args.previous_codepoint_title))
end
local block_name_text = ("[[Appendix:Unicode/%s|%s]]")
:format(block_name, block_name)
if namespace == "" then
block_name_text = block_name_text .. ("[[ප්රවර්ගය:%s කාණ්ඩය|*%010d]]\n")
:format(m_sinhala.sinhala(block_name), codepoint)
else
block_name_text = block_name_text .. "\n"
end
local last_row =
mw.html.create("table"):css("width", "100%"):css("text-align", "center")
:tag("tr")
:tag("td"):css("width", "20%"):wikitext(previous_codepoint_text):done()
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(left_unassigned_text and "'''...'''" or ""):attr("title", left_unassigned_text or ""):done():done()
:tag("td"):css("width", "60%"):css("font-size", "110%"):css("font-weight", "bold"):wikitext(block_name_text)
-- :tag("td"):css("width", "15%")
-- :tag("span"):wikitext(right_unassigned_text and "'''...'''" or ""):attr("title", right_unassigned_text or ""):done():done()
:tag("td"):css("width", "20%"):wikitext(next_codepoint_text):done()
:allDone()
ins(tostring(last_row) .."\n")
ins("|}")
if not args.nocat then
ins(
require(utilities_module).format_categories(categories, require(languages_module).getByCode("mul")))
end
ins(require("Module:TemplateStyles")("Template:character info/style.css"))
return concat(table_markup)
end
function export.show(frame)
local params = {
[1] = {alias_of = "codepoint"},
["codepoint"] = {},
["previous_codepoint"] = {},
["next_codepoint"] = {},
["name"] = {},
["previous_codepoint_name"] = {},
["next_codepoint_name"] = {},
["combining"] = {type = "boolean"},
["previous_codepoint_combining"] = {type = "boolean"},
["next_codepoint_combining"] = {type = "boolean"},
["printable"] = {type = "boolean"},
["previous_codepoint_printable"] = {type = "boolean"},
["next_codepoint_printable"] = {type = "boolean"},
["previous_codepoint_title"] = {},
["next_codepoint_title"] = {},
["sc"] = {type = "script"},
["next_codepoint_sc"] = {type = "script"},
["previous_codepoint_sc"] = {type = "script"},
["caption"] = {},
["aliases"] = {},
["image"] = {},
["image_emoji"] = {},
["block"] = {},
["gardiner"] = {},
["mdc"] = {},
["egpz"] = {},
["nocat"] = {type = "boolean"},
["pagename"] = {}, -- for testing etc.
}
local parent_frame = frame:getParent()
local args = require("Module:parameters").process(parent_frame.args, params)
return export._show(args, parent_frame:getTitle())
end
return export
gwr1xxwgqfckf58xnz8131txf2ui0cz
සැකිල්ල:blockquote/documentation
10
10366
238766
234722
2026-11-11T12:43:08Z
Pinthura
2424
Bot: Replacing category Box templates with [[:ප්රවර්ගය:පැනල සැකිලි|පැනල සැකිලි]]
238766
wikitext
text/x-wiki
{{documentation subpage}}
{{templatestyles|blockquote/styles.css}}
This template displays a block quotation in a page. This should not typically be used in mainspace entries.
==See also==
* {{temp|quote}}
* {{temp|quote box}}
==TemplateData==
{{TemplateData header}}
<templatedata>
{
"params": {
"1": {
"aliases": [
"text",
"quote"
],
"description": "The text to quote",
"label": "Quotation",
"type": "string",
"required": true
},
"2": {
"aliases": [
"author"
],
"description": "The writer of the source",
"type": "string",
"suggested": true,
"label": "Author"
},
"3": {
"aliases": [
"title"
],
"description": "The source for the quote",
"type": "string",
"label": "Title"
},
"align": {
"label": "Alignment",
"description": "The alignment of the box",
"suggestedvalues": [
"left",
"right",
"center"
],
"autovalue": "center"
},
"style": {
"label": "Styles",
"description": "Additional CSS styles to apply",
"type": "string"
},
"class": {
"label": "Classes",
"description": "Additional CSS classes to apply",
"type": "string"
}
},
"description": "Displays a block quotation in a page.",
"paramOrder": [
"1",
"2",
"3",
"align",
"class",
"style"
]
}
</templatedata>
<includeonly>
[[ප්රවර්ගය:පැනල සැකිලි]]
</includeonly>
fg1syma1zmp0kyhbwruevynclgt87oq
සැකිල්ල:cite-web/documentation
10
12243
238744
238674
2026-11-11T11:59:59Z
Pinthura
2424
Bot: Replacing category Citation templates with [[:ප්රවර්ගය:උපහරණ සැකිලි|උපහරණ සැකිලි]]
238744
wikitext
text/x-wiki
{{documentation subpage}}
See {{tl|quote-web}} for usage.
{{citation templates}}
<includeonly>
[[ප්රවර්ගය:උපහරණ සැකිලි]]
</includeonly>
eo7x08vbsktnwsagwptsb0x304t7r9w
සැකිල්ල:mul-Deva/documentation
10
66929
238829
211578
2026-11-12T08:00:16Z
Pinthura
2424
Bot: Replacing category Devanagari script templates with [[:ප්රවර්ගය:දේවනාගරි අක්ෂරක්රමය පිළිබඳ සැකිලි|දේවනාගරි අක්ෂරක්රමය පිළිබඳ සැකිලි]]
238829
wikitext
text/x-wiki
{{documentation subpage}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
===Usage===
===See also===
<includeonly>
<!-- CATEGORIES AND INTERWIKIS HERE, THANKS -->
[[ප්රවර්ගය:සර්ව භාෂාමය යොමු වචන පේළි සැකිලි|Deva]]
[[ප්රවර්ගය:දේවනාගරි අක්ෂරක්රමය පිළිබඳ සැකිලි|mul Deva]]
</includeonly>
lttm9c2we67hhcfvc34l506hohoftzj
සැකිල්ල:R:Merriam-Webster Online/documentation
10
114219
238747
238696
2026-11-11T12:00:29Z
Pinthura
2424
Bot: Replacing category English reference templates with [[:ප්රවර්ගය:ඉංග්රීසි මූලාශ්ර සැකිලි|ඉංග්රීසි මූලාශ්ර සැකිලි]]
238747
wikitext
text/x-wiki
{{documentation subpage}}
===Usage===
{{shortcut|Template:R:MWO|Template:R:MWOnline}}
This template may be used in "References" and "Further reading" sections, and on talk pages, to provide a citation to the ''[https://www.merriam-webster.com Merriam-Webster Online]'' ("MW Online") website.
===Parameters===
* {{para|1}} or {{para|entry}} – the name of the entry on MW Online. If this parameter is not stated, the name of the Wiktionary entry is used.
* {{para|pos}} or {{para|part of speech}} – the [[part of speech]] of the entry. By default, the template italicizes the value assigned to the parameter and adds a [[full stop]] ([[period]]) to the end. To turn off the default formatting for the purpose of specifying a different formatting using wikitext markup and templates, specify {{para|noformat|1}} or {{para|noformat|yes}}.
* {{para|2}} or {{para|url}} – if the default [[URL]] is not linking to the correct webpage, use this parameter to indicate the URL of the MW Online webpage to be linked to.
* {{para|subentry}} – a term that appears as a subentry under an entry.
* {{para|subpos}} – the part of speech of the subentry.
* {{para|source}} – use {{para|source|1}} or {{para|source|yes}} to display the source originally relied on by MW Online, per [https://www.merriam-webster.com/about-us/faq FAQ]: ''[[w:Webster's Dictionary#Merriam-Webster's Collegiate Dictionary|Merriam-Webster's Collegiate Dictionary]]'' (11th edition, 2003).
* {{para|3}}, {{para|text}}, or {{para|passage}} – a passage quoted from the website.
* {{para|nodot}} – by default, the template adds a full stop (period) at the end of the citation. To suppress this punctuation, use {{para|nodot|1}} or {{para|nodot|yes}}.
===Examples===
* '''Wikitext''': {{temp|R:Merriam-Webster Online}} (assuming the template is used on the {{m|en|quahog}} page)
* '''Result''': {{R:Merriam-Webster Online|entry=quahog}}
* '''Wikitext''': {{temp|R:Merriam-Webster Online|2=<nowiki>entry=Kung</nowiki>}}
* '''Result''': {{R:Merriam-Webster Online|entry=Kung}}
* '''Wikitext''':
** {{temp|R:Merriam Webster Online|2=entry=meet one's Waterloo|3=pos=idiom|4=url=<nowiki>https://www.merriam-webster.com/dictionary/meet%20one%27s%20Waterloo</nowiki>|5=source=1}}; or
** {{temp|R:Merriam Webster Online|2=meet one's Waterloo|3=pos=idiom|4=<nowiki>https://www.merriam-webster.com/dictionary/meet%20one%27s%20Waterloo</nowiki>|5=source=1}}
* '''Result''': {{R:Merriam-Webster Online|entry=meet one's Waterloo|pos=idiom|url=https://www.merriam-webster.com/dictionary/meet%20one%27s%20Waterloo|source=1}}
* '''Wikitext''': {{temp|R:Merriam-Webster Online|2=entry=dilemma|3=pos=n|4=text=<nowiki>Although some commentators insist that ''dilemma'' be restricted to instances in which the alternatives to be chosen are equally unsatisfactory, their concern is misplaced.</nowiki>|5=nodot=1}}
* '''Result''': {{R:Merriam-Webster Online|entry=dilemma|pos=n|text=Although some commentators insist that ''dilemma'' be restricted to instances in which the alternatives to be chosen are equally unsatisfactory, their concern is misplaced.|nodot=1}}
* '''Wikitext''': {{temp|R:Merriam-Webster Online|2=subentry=level best|3=subpos=phrase|4=entry=level|5=pos=adj}}
* '''Result''': {{R:Merriam-Webster Online|subentry=level best|subpos=phrase|entry=level|pos=adj}}
<includeonly>
[[ප්රවර්ගය:ඉංග්රීසි මූලාශ්ර සැකිලි|Merriam-Webster Online]]
</includeonly>
ks4n0i47g4lnbrenl1rcf4pp8t1jg0f
Module:category tree/lects
828
119911
238792
228628
2026-10-07T02:54:59Z
en>Benwing2
0
don't mutate countries[] list
238792
Scribunto
text/plain
local export = {}
local raw_categories = {}
local raw_handlers = {}
local labels_module = "Module:labels"
local labels_utilities_module = "Module:labels/utilities"
local languages_module = "Module:languages"
local parse_utilities_module = "Module:parse utilities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local m_table = require(table_module)
local get_lang = require(languages_module).getByCode
local insert_if_not = m_table.insertIfNot
local pattern_escape = require(string_pattern_escape_module)
local replacement_escape = require(string_replacement_escape_module)
local serial_comma_join = m_table.serialCommaJoin
local split = require(string_utilities_module).split
local split_on_comma = require(parse_utilities_module).split_on_comma
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/lects/PAGE]]
return require("Module:debug/track")("category tree/lects/" .. page)
end
-- This module handles lect/variety categories of all sorts, e.g. regional lect categories such as
-- [[:Category:American English]] and [[:Category:Provençal]]; temporal lect categories such as
-- [[:Category:Early Modern English]]; sociolect categories such as [[:Category:Polari]]; and umbrella categories of the
-- form e.g. [[:Category:Varieties of English]] and [[:Category:Regional French]].
-- FIXME: Eliminate the word "dialect" here and in the {{auto cat}} parameter in favor of "lect" or "variety". [DONE]
--[=[
FIXME:
1. Support multiple parents. [DONE]
2. Support cat: in parents to indicate a category. [DONE]
3. When linking a description without embedded links, use the equivalent of {{wtorw}} to auto-link to Wikipedia. [DONE]
4. Support the = true. [DONE]
]=]
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["Language varieties"] = {
description = "Categories that group terms in varieties of various languages (regional, temporal, sociolectal, etc.).",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"Fundamental",
},
}
raw_categories["Regionalisms"] = {
description = "Categories that group terms in regional varieties of various languages.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"Fundamental",
"Language varieties",
},
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
local function ucfirst(text)
return mw.getContentLanguage():ucfirst(text)
end
local function lcfirst(text)
return mw.getContentLanguage():lcfirst(text)
end
local function page_exists(page)
local title = mw.title.new(page)
return title and title.exists
end
-- Handle categories such as [[:Category:Varieties of French]] and [[:Category:Varieties of Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^Varieties of (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in varieties of " .. lang:makeCategoryLink() .. " (regional, temporal, sociolectal, etc.).",
parents = {
"{{{langcat}}}",
{name = "Language varieties", sort = langname},
},
breadcrumb = "Varieties",
}
end
end
end)
-- Handle categories such as [[:Category:Regional French]] and [[:Category:Regional Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^Regional (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in regional varieties of " .. lang:makeCategoryLink() .. ".",
additional = "This category sometimes also directly contains terms that are uncategorized regionalisms: such terms should be recategorized by the particular regional variety they belong to, or categorized as dialectal.",
parents = {
"Varieties of {{{langname}}}",
{name = "Regionalisms", sort = langname},
},
breadcrumb = "Regional",
}
end
end
end)
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then return nil end
arg = mw.text.trim(arg)
if arg == "" then return nil end
return arg
end
-- Get the full language to use e.g. in the settings.
local function get_returnable_lang(lang)
if lang:hasType("family") then
return nil
else
return lang:getFull()
end
end
-- Get the full language code to return in the settings.
local function get_returnable_lang_code(lang)
if lang:hasType("family") then
return "und"
else
return lang:getFullCode()
end
end
local memoizing_lect_handler
local function category_to_lang_name(category)
local getByCanonicalName = require("Module:languages").getByCanonicalName
local lang
lang = getByCanonicalName(category, nil, "allow etym", "allow family")
if not lang then
-- Some languages have lowercase-initial names e.g. 'the BMAC substrate', but the category begins with an
-- uppercase letter.
lang = getByCanonicalName(lcfirst(category), nil, "allow etym", "allow family")
end
return lang
end
-- Given a category (without the "Category:" prefix), look up the page defining the category, find the call to
-- {{auto cat}} (if any), and return a table of its arguments. If the category page doesn't exist or doesn't have
-- an {{auto cat}} invocation, return nil.
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("Category:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and canonicalizes them, so uses of {{autocat}}
-- will also be found.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
-- Try to figure out if this variety is extinct or reconstructed, if type= not given.
local function determine_lect_type(category, lang, default_parent_cat)
if category:find("^Proto%-") or lang:getCanonicalName():find("^Proto%-") or lang:hasType("reconstructed") then
-- Is it reconstructed?
return "reconstructed"
end
if lang:getCode():find("^qsb%-") then
-- Substrate.
return "unattested"
end
if lang:hasType("full") then
-- If a full language, scrape the {{auto cat}} call and check for extinct=1.
local parent_args = scrape_category_for_auto_cat_args(lang:getCategoryName())
if parent_args and ine(parent_args.extinct) and require("Module:yesno")(parent_args.extinct, false) then
return "extinct"
end
end
-- Otherwise, call the lect handler recursively for the parent category. This is correct e.g. for
-- things like subvarieties of Classical Persian, where the lang itself (Persian) isn't extinct but the
-- parent category refers to an extinct variety. If the lect handler fails to return a type, it's because
-- the parent category doesn't exist or isn't defined using {{auto cat}}, and doesn't have a language as a
-- suffix. In that case, if we're dealing with an etymology-only language, check the parent language. Finally,
-- fall back to returning "extant" if all else fails.
local parent_type
if default_parent_cat then
export.register_likely_lect_parent_cat(default_parent_cat)
parent_type = select(2, memoizing_lect_handler(default_parent_cat, nil, true))
end
if parent_type then
return parent_type
end
local parent_lang = lang:getParent()
if parent_lang then
return determine_lect_type(category, parent_lang, nil)
end
return "extant"
end
-- Try to figure out the region (used as the default breadcrumb and region description) from the language. If the
-- language name is an etymology-only language, try to derive a region based on a parent etymology-only or full
-- language. For example, if the pagename is '[[:Category:British English]]', the language is 'en-GB' (British English)
-- and the same as the pagename, but we'd like to return a region 'British'. This is also called in cases where the
-- language is explicitly given but we need to infer the region from the parent language; e.g.
-- [[:Category:Lucerne Alemmanic German]] is a type of High Alemannic German but we want to infer 'Lucerne' based on
-- the parent 'Alemannic German'. If this doesn't work and the language name has a space in it, we try using
-- progressively smaller suffixes of the language. For example, for [[:Category:Walser German]]', the language is
-- 'wae' (Walser German), but the parent is 'Highest Alemannic German', whose parent is 'Alemannic German' (a full
-- language), and just "German" is nowhere in the parent-child relationships but found as a suffix in the parent
-- language. Another such case is with [[:Category:Ionic Greek]], whose parent is 'Ancient Greek'.
local function infer_region_from_lang(pagename, lang)
local langname = lang:getCanonicalName()
local lang_to_check = lang
if ucfirst(langname) == pagename then
lang_to_check = lang_to_check:getParent()
end
-- First check against the language name and progressively smaller suffixes; then repeat for any parents (of
-- etymology languages). If the language name is the same as the page name, we need to start with the parent;
-- otherwise we will always match against a suffix, but that's not what we want.
while lang_to_check do
local suffix = lang_to_check:getCanonicalName()
while true do
local region = pagename:match("^(.*) " .. pattern_escape(suffix) .. "$")
if region then
return region
end
suffix = suffix:match("^.- (.*)$")
if not suffix then
break
end
end
lang_to_check = lang_to_check:getParent()
end
return nil
end
-- Modeled after splitLabelLang() in [[Module:category tree]]. Try to split off a maximally long language (full or
-- etymology-only) on the right, and return the resulting language object and the region preceding it. We need to
-- check the maximally long language because of cases like 'English' vs 'Middle English' and 'Chinese Pidgin English';
-- [[:Category:Late Middle English]] should split as 'Late' and 'Middle English', not as 'Late Middle' and 'English'.
local function split_region_lang(pagename)
local lang
local region
-- Try the entire title as a language; if not, chop off a word on the left and repeat.
local words = split(pagename, " ")
for i = 1, #words do
lang = category_to_lang_name(table.concat(words, " ", i, #words))
if lang then
if i == 1 then
region = nil
else
region = table.concat(words, " ", 1, i - 1)
end
break
end
end
if not region and lang then
-- The pagename is the same as a language name. Try to infer the region from the parent. See comment at
-- function.
region = infer_region_from_lang(pagename, lang)
end
return lang, region
end
-- Return the default parent cat for the given language and category. If the language and category are the same, we're
-- dealing with the overall cat for an etymology-only language, so use the category of the parent language; otherwise
-- we're dealing with a subcategory of a regular or etymology-only language (e.g. [[:Category:Issime Walser]], a
-- subcategory of [[:Category:Walser German]]), so use the language's category itself. If the resulting language is an
-- etymology-only language or a family, the parent category is that language or family's category, which for
-- etymology-only languages is named the same as the etymology-only language, and for families is named
-- "FAMILY languages"; otherwise, use "Regional LANG" as the category unless `noreg` is given, in which case we use
-- "Varieties of LANG".
local function get_default_parent_cat_from_category(category, lang, noreg)
if lang:getCode():find("^qsb%-") then
-- substrate
return "Substrate languages"
end
local lang_for_cat
if ucfirst(lang:getCanonicalName()) == category then
lang_for_cat = lang:getParent()
if not lang_for_cat then
error(("Category '%s' has a name the same as a full language; you probably need to explicitly specify a different language using |lang="):format(category))
end
else
lang_for_cat = lang
end
if lang_for_cat:hasType("etymology-only") or lang_for_cat:hasType("family") then
return lang_for_cat:getCategoryName()
elseif noreg then
return "Varieties of " .. lang_for_cat:getCanonicalName()
else
return "Regional " .. lang_for_cat:getCanonicalName()
end
end
-- Find the labels that categorize into `category`. Only categories specified using the `regional_categories` and
-- `plain_categories` fields will be returned. `lang` is the language object to use when looking up categories specified
-- using the `regional_categories` field, which append the language onto the specified category prefix. If `lang` is a
-- family or is omitted, no categories specified using `regional_categories` will be returned. Lang-specific modules for
-- all languages will be checked for matching labels that specify `category` as their category using `plain_categories`;
-- this helps e.g. with varieties of Chinese, whose labels are found in [[Module:labels/data/lang/zh]]. The return value
-- is a table in the same format as returned by `find_labels_for_category` in [[Module:labels/utilities]].
--
-- FIXME: It should be possible to check for categories specified using `regional_categories` even when `lang` is nil.
local function find_labels_for_category(category, lang)
local regional_cat_labels, plain_cat_labels
local full_lang
local m_labels_utilities = require(labels_utilities_module)
if lang and lang:hasType("language") then
full_lang = lang:getFull()
local regional_component = category:match("^(.-) " .. pattern_escape(full_lang:getCanonicalName()) .. "$")
if regional_component then
regional_cat_labels = m_labels_utilities.find_labels_for_category(regional_component,
"regional", full_lang)
end
end
plain_cat_labels = m_labels_utilities.find_labels_for_category(category, "plain", full_lang, "check all langs")
local all_labels
if regional_cat_labels and plain_cat_labels then
all_labels = regional_cat_labels
for k, v in pairs(plain_cat_labels) do
all_labels[k] = v
end
else
all_labels = regional_cat_labels or plain_cat_labels
end
return all_labels
end
-- Find the labels for category `category` and language object `lang` (which can be nil or a family, but in that case,
-- no labels on a category specified using `regional_categories`; FIXME: it should be possible to implement this). Then
-- filter them down to those that are specified using a lang-specific module and sort them for use in checking
-- properties such as parent and description. We filter down to only lang-specific labels because those specified in a
-- general module (especially [[Module:labels/data/regional]]) won't be able to have proper descriptions and especially
-- parents, which tend to be language-specific. The sort order prioritizes labels that match the category exactly
-- (either through the canonical version or any alias); this is followed by labels that are a prefix of the category
-- (again, either through the canonical version or any alias), so that labels whose categories are specified using
-- `regional_categories` are prioritized. Any other labels are sorted last, so that e.g. if both the label "Alberta" and
-- "Canada" (with alias "Canadian") for lang=en categorize into [[:Category:Canadian English]], we prefer the label
-- "Canada". For cases where e.g. both labels match the category as prefixes, ties are broken by prioritizing the labels
-- found in the lang-specific module whose language matches `lang`.
--
-- Returns two items. The first is a table of all labels categorizing into `category` (subject to the provisos described
-- in `find_labels_for_category()`), in the same format as returned by `find_labels_for_category` in
-- [[Module:labels/utilities]]. (Specifically, the values are objects containing all relevant information on a given
-- label, and the keys are less important.) The second is a list of label objects after filtering and sorting, in the
-- same format as the values in the `all_labels` table. The first return value will be nil if no labels could be found
-- categorizing into `category`, and the second return value will be nil if no labels remain after filtering.
local function get_sorted_labels(category, lang)
local all_labels = find_labels_for_category(category, lang)
if not all_labels then
return nil
end
local m_labels = require(labels_module)
local lang_specific_pattern = "^" .. pattern_escape(m_labels.lang_specific_data_modules_prefix)
local sorted_labels = {}
for _, labelobj in pairs(all_labels) do
if labelobj.module:find(lang_specific_pattern) then
table.insert(sorted_labels, labelobj)
end
end
local function sort_labelobj(a, b)
local function matches_exactly(labelobj)
if labelobj.canonical == category then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if alias == category then
return true
end
end
return false
end
local function matches_as_prefix(labelobj)
if category:find("^" .. pattern_escape(labelobj.canonical) .. " ") then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if category:find("^" .. pattern_escape(alias) .. " ") then
return true
end
end
return false
end
local function tiebreak()
local a_matches_lang = lang and a.lang:getFullCode() == lang:getFullCode()
local b_matches_lang = lang and b.lang:getFullCode() == lang:getFullCode()
if a_matches_lang and not b_matches_lang then
return true
elseif b_matches_lang and not a_matches_lang then
return false
else
return a.canonical < b.canonical
end
end
local a_matches_exactly = matches_exactly(a)
local b_matches_exactly = matches_exactly(b)
if a_matches_exactly and not b_matches_exactly then
return true
elseif b_matches_exactly and not a_matches_exactly then
return false
elseif a_matches_exactly and b_matches_exactly then
return tiebreak()
end
local a_matches_as_prefix = matches_as_prefix(a)
local b_matches_as_prefix = matches_as_prefix(b)
if a_matches_as_prefix and not b_matches_as_prefix then
return true
elseif b_matches_as_prefix and not a_matches_as_prefix then
return false
else
return tiebreak()
end
end
table.sort(sorted_labels, sort_labelobj)
if #sorted_labels > 0 then
return all_labels, sorted_labels
else
return all_labels, nil
end
end
-- Find the categories (only of type `regional_categories` and `plain_categories`) that label `label` categorizes into.
-- Return value is nil if the label couldn't be located at all, otherwise a list of categories (which may be empty).
local function get_categories_for_label(label, lang)
local m_labels = require(labels_module)
local labret = m_labels.get_label_info { label = label, lang = lang }
if not labret.recognized then
return nil
end
local categories = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["plain_categories"] = true})
local reg_cats = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["regional_categories"] = true})
if #reg_cats > 0 then
for _, cat in ipairs(reg_cats) do
table.insert(categories, cat)
end
end
return categories
end
-- Given the sorted labels that categorize into `category`, return the parent categories for the first label that specifies
-- any parents. `default` is the default parent category, usually "Regional LANG" or (if noreg=1 is specified) "Varieties of LANG";
-- it is used if the parent is explicitly given as `true` or "+" (or one of these values occurs among others), or if a parent label
-- was given but didn't categorize into any regional or plain categories, or if no labels with parents could be found. If
-- `all_cats` is specified, all categories associated with all specified parent labels (if more than one is present) are returned;
-- otherwise, only the categories for the first parent label are returned.
--
-- Returns two values: the list of parent categories and the label object from which the categories were derived (or nil if no
-- label object could be found with a `parent` field, in which case the return value of the list of categories is a simple-element
-- list consisting of `default`). The format of the parent category list is such that the list can directly be specified as the
-- value of the `parents` field returned by the raw handler. This means that usually the individual list elements are strings
-- (referring to raw poscat labels), but they may be strings prefixed by "Category:" (for arbitrary categories), or objects of the
-- form {name = "CATEGORY", lang = "LANGCODE", is_label = true} for poscat language labels.
local function get_parents_from_sorted_labels(sorted_labels, category, all_cats)
for _, labobj in ipairs(sorted_labels) do
local parent = labobj.labdata.parent
if parent == true then
parent = {parent}
elseif parent and type(parent) == "string" then
parent = split_on_comma(parent)
end
local function get_parent_cats(par)
if par == true or par == "+" then
return {"+"}
end
if par:find("^cat:") then
return {"Category:" .. par:gsub("^cat:", "")}
end
if par:find("^Category:") then
return {par}
end
if par:find("^rawposcat:") then
return {(par:gsub("^rawposcat:", ""))}
end
if par:find("^poscat:") then
local langcode, label = par:match("^poscat:([^:]+):(.*)$")
if not langcode then
error(("Parent poscatboiler language label '%s' for label '%s' for category '%s' (defined in module [[%s]]) needs to be of the form 'poscat:LANGCODE:LABEL'"):format(
par, labobj.canonical, category, labobj.module))
end
return {{name = label, lang = langcode, is_label = true}}
end
local this_cats = get_categories_for_label(par, labobj.lang)
if not this_cats then
error(("Parent label '%s' for label '%s' for category '%s' (defined in module [[%s]]) couldn't be located"):format(
par, labobj.canonical, category, labobj.module))
end
return this_cats
end
if parent then
if type(parent) ~= "table" then
error(("Internal error: Expected a string, boolean `true` or list for the value of the parent field for label '%s' for category '%s' (defined in module [[%s]]), but saw type '%s': %s"):format(
labobj.canonical, category, labobj.module, type(parent), mw.dumpObject(parent)))
end
local cats
if all_cats then
cats = {}
for _, par in ipairs(parent) do
local this_cats = get_parent_cats(par)
for _, this_cat in ipairs(this_cats) do
insert_if_not(cats, this_cat)
end
end
else
cats = get_parent_cats(parent[1])
end
if #cats > 0 then
return cats, labobj
end
-- FIXME: If the parent doesn't specify any categories, should we try the next parent or fall back
-- to the parent determined through get_default_parent_cat_from_category() (which is what we currently
-- do)?
return {"+"}, labobj
end
end
return {"+"}, nil
end
local likely_lect_parent_cat = {}
-- Register that `cat` is likely to be a lect cat, so we try to handle it as such in the lect handler when
-- we are called on that category. This avoids the need to have manual allow-lists of nonstandardly-named parent
-- lect categories to handle, such as [[:Category:Assyrian]], [[:Category:Ripuarian Franconian]] ("Franconian" is
-- not a language) and [[:Category:Limburgan-Ripuarian transitional dialects]].
function export.register_likely_lect_parent_cat(cat)
if type(cat) == "string" and not cat:find("^Category:") then
likely_lect_parent_cat[cat] = true
end
end
-- Handle lect categories such as [[:Category:New Zealand English]], [[:Category:Late Middle English]],
-- [[:Category:Arbëresh Albanian]], [[:Category:Provençal]] or arbitrarily-named categories like
-- [[:Category:Issime Walser]]. We currently require that lect=1 is specified to the call to {{auto cat}} to avoid
-- overfiring. However, if called from inside, we are processing the breadcrumb for the parent (or conceivably the
-- child) of a lect category, and won't have any params set, so we can't rely on lect=1. In that case, only fire
-- if the category is or ends in the name of a full or etymology-only language, and scrape the category's call to
-- {{auto cat}} to get the appropriate params. This means that nonstandardly-named categories like
-- [[:Category:Issime Walser]] can't be parents of other lect categories. To work around this, either we have to
-- relax the code below to operate on all raw categories (not necessarily a good idea), or we rename the
-- nonstandardly-named categories (e.g. in the case above, to [[:Category:Issime Walser German]], since Walser German
-- is a recognized etymology-only language).
--
-- NOTE: We are able to handle categories for etymology-only families (currently only [[:Category:Middle Iranian]] and
-- [[:Category:Old Iranian]]) and for etymology-only substrate languages (e.g. [[:Category:BMAC substrate]]).
-- There is some special "family" code for the former.
local function lect_handler(category, raw_args, called_from_inside)
if called_from_inside then
-- Avoid infinite loops from wrongly processing non-lect categories. We have a check around line 344 below
-- for categories whose {{auto cat}} doesn't say lect=1, but we still need the following in case of
-- non-existent categories we're being asked to process (e.g. [[:Category:User bcc]] ->
-- [[:Category:Southern Balochi]] (nonexistent) -> [[:Category:Regional Baluchi]] (nonexistent), which
-- causes an infinite loop without the check below.
if category:find("^Regional ") or category:find("^Varieties of ") or category:find("^Rhymes:") then
return nil
end
-- If called from inside we won't have any params available. See comment above about this. We scrape the
-- category page's call to {{auto cat}} to get the appropriate params, and if that fails, we currently fall back
-- to defaults based on the label(s) that categorize(s) into the category or the name of the category. Since the
-- call from inside is only to get the parent category and breadcrumb, these defaults actually work in most
-- cases but not all; e.g. in the chain [[:Category:Regional Yoruba]] -> [[:Category:Central Yoruba]] ->
-- [[:Category:Ekiti Yoruba]] -> [[:Category:Akurẹ Yoruba]], if we are forced to use default values, we will
-- produce the right parent for [[:Category:Central Yoruba]] but not for [[:Category:Ekiti Yoruba]], where the
-- default parent would be [[:Category:Regional Yoruba]] instead of the correct [[:Category:Central Yoruba]].
local lang, breadcrumb = split_region_lang(category)
if lang or likely_lect_parent_cat[category] then
raw_args = scrape_category_for_auto_cat_args(category)
if raw_args and not ine(raw_args.lect) then
-- We are scraping something like [[:Category:American Sign Language]] that ends in a valid language but is not
-- a lect.
return nil
end
if not raw_args then
-- If we can't parse the scraped {{auto cat}} spec, return default values. This helps e.g. in converting
-- from the old {{dialectboiler}} template and generally when adding new varieties.
local parents, label_with_parent
local function getprop(prop)
return -- ine(raw_args[prop]) or
label_with_parent and label_with_parent.labdata[prop]
end
local sorted_labels = select(2, get_sorted_labels(category, lang))
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category)
if not lang and label_with_parent then
lang = label_with_parent.lang
end
else
parents = {"+"}
end
if not lang then
-- We were instructed to scrape by virtue of `register_likely_lect_parent_cat`, but couldn't scrape
-- anything.
return nil
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang,
getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
local first_parent_cat = parents[1]
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^Category:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect
-- handler label).
first_parent_cat = nil
end
track("lect")
export.register_likely_lect_parent_cat(parents[1])
-- NOTE: When called from inside, the description doesn't matter; nor do any parents other than the
-- first. This is because called_from_inside is only set when computing the breadcrumb trail, which
-- only needs the language, first parent and breadcrumb.
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
description = "Foo",
parents = parents,
breadcrumb = breadcrumb or lang:getCanonicalName(),
umbrella = false,
can_be_empty = true,
}, determine_lect_type(category, lang, first_parent_cat)
end
else
return nil
end
end
if not called_from_inside and not ine(raw_args.lect) then
return nil
end
-------------------- 1. Process parameters. -------------------
local boolean = {type = "boolean"}
local sublist = {sublist = "comma without whitespace"}
local args = require("Module:parameters").process(raw_args, {
[1] = true,
lect = boolean,
lang = true,
verb = true,
prep = true,
the = boolean,
def = true,
fulldef = true,
addl = true,
nolink = boolean,
noreg = boolean, -- don't make the default parent be "Regional LANG"; instead, "Varieties of LANG"
type = {set = {"extinct", "extant", "reconstructed", "unattested", "constructed"}},
cat = true,
othercat = sublist,
country = sublist,
wp = true,
wikidata = true,
breadcrumb = true,
also = {type = "title", sublist = "comma without whitespace", namespace = 14},
pagename = true, -- for testing or demonstration
})
-------------------- 2. Initialize breadcrumb, regiondesc and language from category. -------------------
-- They may be overridden later.
local lang, breadcrumb, regiondesc, langname
category = args.pagename or category
if not args.lang then
lang, breadcrumb = split_region_lang(category)
if lang then
langname = lang:getCanonicalName()
end
-- The lang and/or breadcrumb may be nil at this point (e.g. we're processing a category like
-- [[:Category:Singlish]] or [[:Category:Polari]] that doesn't have a language in it). We don't throw an error
-- yet because we may be able to fetch the lang, regiondesc and breadcrumb from a label that categorizes into
-- the category.
regiondesc = breadcrumb
else
lang = get_lang(args.lang, "lang", "allow etym")
langname = lang:getCanonicalName()
if category == ucfirst(langname) then
-- breadcrumb and regiondesc should stay nil; breadcrumb will get `category` as a default, and the lack of
-- regiondesc will cause an error to be thrown unless the user gave it explicitly or specified def=.
else
breadcrumb = category:match("^(.*) " .. pattern_escape(langname) .. "$")
if not breadcrumb then
-- Try to infer the region from the parent. See comment at function.
breadcrumb = infer_region_from_lang(category, lang)
end
regiondesc = breadcrumb
end
end
-------------------- 3. Determine labels categorizing into this category. -------------------
local all_labels, sorted_labels = get_sorted_labels(category, lang)
-------------------- 4. Determine parent categories and initialize additional properties. -------------------
-- The first label with a parent is used to fetch additional properties, such as region= and addl=.
local parents
local first_parent_cat = args.cat
local label_with_parent
local function getprop(prop)
return args[prop] or label_with_parent and label_with_parent.labdata[prop]
end
if first_parent_cat then
parents = {first_parent_cat}
if not lang then
error(("lang= not given and unable to parse language from category '%s' (didn't check labels categorizing into the category because cat= explicitly given)"):format(category))
end
else
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category, "all cats")
if not lang and label_with_parent then
lang = label_with_parent.lang
langname = lang:getCanonicalName()
end
else
parents = {"+"}
end
if not lang then
error(("lang= not given, unable to parse language from category '%s' and can't find a label categorizing into the category"):format(category))
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang, getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
first_parent_cat = parents[1]
end
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^Category:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect handler label).
-- WARNING: Code below using `first_parent_cat` must handle nil.
first_parent_cat = nil
end
local othercat = getprop("othercat")
if type(othercat) == "string" then
othercat = split_on_comma(othercat)
end
if othercat then
for _, cat in ipairs(othercat) do
if not cat:find("^Category:") then
cat = "Category:" .. cat
end
table.insert(parents, cat)
end
end
local countries = getprop("country") or {}
if type(countries) == "string" then
countries = split_on_comma(countries)
end
-- If no breadcrumb, this often happens when the langname and category are the same (happens only with etym-only
-- languages), and the parent category is set below to the full parent, so the breadcrumb should show the
-- language name (or equivalently, the category). If the langname and category are different, we should fall back to
-- the category. E.g. for Singlish, lang=en is specified and we can't infer a breadcrumb because the lect name
-- doesn't end in "English"; in this case we want the breadcrumb to show "Singlish".
breadcrumb = getprop("breadcrumb") or breadcrumb or category
local the_prefix
if args[1] then
regiondesc = args[1]
else
local regionprop = getprop("region")
if regionprop then
regiondesc = regionprop
elseif label_with_parent then
-- It's not clear which of the following two are better. The second one uses the actual label display form,
-- which might be argued to be better, except that it will often be linked to a Wikipedia article about the
-- lect rather than the place. The first one just uses the canonical label directly (which will later be
-- linked to itself if unlinked). A third possibility is to use `label_with_parent.display` if present,
-- otherwise `label_with_parent.canonical`.
regiondesc = label_with_parent.canonical
if label_with_parent.display and regiondesc ~= label_with_parent.display then
track("display-different-from-canonical")
end
-- regiondesc = require(labels_module).get_displayed_label(label_with_parent.canonical, label_with_parent.labdata, lang)
end
end
the_prefix = getprop("the") and "the " or ""
if #countries == 0 then
countries = {regiondesc and the_prefix .. regiondesc or nil}
end
for _, country in ipairs(countries) do
if not country:find("[<=]") then
country = require("Module:links").remove_links(country)
local cat = "Category:Languages of " .. country
if page_exists(cat) then
table.insert(parents, cat)
end
end
end
-------------------- 5. Refine the language to an etymology-only child if possible. -------------------
-- Now that we've determined the parent, we look up the parent hierarchy until we find a category naming an
-- etymology-only language. If we find one and it's a child of the language we've determined, use it.
local ancestral_cat = first_parent_cat
local refined_lang
while true do
refined_lang = category_to_lang_name(ancestral_cat)
if refined_lang then
break
end
export.register_likely_lect_parent_cat(ancestral_cat)
local settings, _ = memoizing_lect_handler(ancestral_cat, nil, true)
if not settings then
break
end
ancestral_cat = settings.parents[1]
end
if refined_lang and refined_lang:hasParent(lang) then
lang = refined_lang
langname = lang:getCanonicalName()
end
-------------------- 6. Initialize `additional` with user-specified text and info about labels. -------------------
local additional = getprop("addl")
local function append_addl(addl_text)
if not addl_text then
return
end
if additional then
additional = additional .. "\n\n" .. addl_text
else
additional = addl_text
end
end
if all_labels then
local m_labels_utilities = require(labels_utilities_module)
append_addl(m_labels_utilities.format_labels_categorizing(all_labels, nil,
get_returnable_lang(lang)))
end
-------------------- 7. Augment `additional` with information about etymology-only codes. -------------------
local langname_for_desc
local etymcodes = {}
local function make_code(code)
return ("<code>%s</code>"):format(code)
end
if lang:hasType("etymology-only") and ucfirst(langname) == category then
langname_for_desc = lang:getParentName()
local langcode = lang:getCode()
table.insert(etymcodes, make_code(langcode))
-- Find all alias codes for the etymology-only language.
-- FIXME: There should be a better/easier way of doing this.
local ety_code_to_name = mw.loadData("Module:etymology languages/code to canonical name")
for code, canon_name in pairs(ety_code_to_name) do
if canon_name == langname and code ~= langcode then
table.insert(etymcodes, make_code(code))
end
end
local addl_etym_codes = ("[[Module:etymology_languages/data|Etymology-only language]] code: %s."):format(
serial_comma_join(etymcodes, {conj = "or"}))
append_addl(addl_etym_codes)
else
langname_for_desc = langname
end
-------------------- 8. Try to figure out if this variety is extinct or reconstructed. -------------------
local lect_type = getprop("type")
if not lect_type then
lect_type = determine_lect_type(category, lang, first_parent_cat)
end
local function prefix_addl(addl_text)
if additional then
additional = addl_text .. "\n\n" .. additional
else
additional = addl_text
end
end
if lect_type == "extinct" then
prefix_addl("This lect is [[extinct language|extinct]].")
table.insert(parents, "Category:All extinct languages")
elseif lect_type == "reconstructed" then
prefix_addl("This lect is [[reconstructed language|reconstructed]].")
table.insert(parents, "Category:Reconstructed languages")
elseif lect_type == "unattested" then
prefix_addl("This lect is {{w|unattested language|unattested}}.")
table.insert(parents, "Category:Unattested languages")
elseif lect_type == "constructed" then
prefix_addl("This lect is [[constructed language|constructed]].")
table.insert(parents, "Category:Constructed languages")
end
-------------------- 9. Add pseudo-familes to parents. -------------------
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
table.insert(parents, "Category:" .. pseudofam:getCategoryName())
end
-------------------- 10. Compute `description`. -------------------
local description
local fulldef = getprop("fulldef")
if fulldef then
description = fulldef .. "."
end
if not description then
local def = getprop("def")
if def then
description = ("Terms or senses in %s."):format(def)
end
end
if not description then
if not regiondesc then
-- We need regiondesc for the description unless def= or fulldef= is given, which overrides the part that needs it.
error(("1= (region) not given and unable to infer region from category '%s' given language name '%s'"):
format(category, langname))
end
local lang_en = get_lang("en", true)
local linked_regiondesc = regiondesc
-- Don't try to link if HTML, = sign, template call or embedded link found in text. Embedded links will
-- automatically be converted to English links by JavaScript.
local function linkable(text)
return not text:find("[<={}%[%]|]")
end
if linked_regiondesc:find("<country>") then
if not countries then
error(("Can't specify <country> in region description '%s' when country= not given"):format(linked_regiondesc))
end
-- Link the countries individually before calling serialCommaJoin(), which inserts HTML.
local linked_countries = {}
for _, country in ipairs(countries) do
if linkable(country) then
country = require("Module:links").full_link { lang = lang_en, term = country }
end
table.insert(linked_countries, country)
end
linked_countries = serial_comma_join(linked_countries)
linked_regiondesc = linked_regiondesc:gsub("<country>", replacement_escape(linked_countries))
elseif not getprop("nolink") and linkable(linked_regiondesc) then
-- Even if nolink not given, don't try to link if HTML or = sign found in linked_regiondesc, otherwise
-- we're likely to get an error.
if page_exists(linked_regiondesc) then
-- Only construct a Wiktionary link if the page exists; otherwise construct a Wikipedia link.
linked_regiondesc = require("Module:links").full_link { lang = lang_en, term = linked_regiondesc }
else
linked_regiondesc = ("[[w:%s|%s]]"):format(linked_regiondesc, linked_regiondesc)
end
end
linked_regiondesc = the_prefix .. linked_regiondesc
local no_longer_spoken = lect_type == "extinct" or lect_type == "reconstructed" or lect_type == "unattested"
local verb = getprop("verb") or no_longer_spoken and "formerly spoken" or "spoken"
local prep = getprop("prep")
if not langname_for_desc then
error(category)
end
description = ("Terms or senses in %s as %s%s %s."):format(
langname_for_desc, verb, prep == "-" and "" or " " .. (prep or "in"), linked_regiondesc)
end
-------------------- 11. Compute the Wikipedia articles that go into `topright`. -------------------
local topright_parts = {}
-- Insert Wikipedia article `article` for Wikimedia language `wmcode` into `topright_parts`, avoiding duplication.
local function insert_wikipedia_article(wmcode, article)
if wmcode == "commons" then
insert_if_not(topright_parts, ("{{commons%s}}"):format(
article == category and "" or "|" .. article
))
else
local wparg = ("%s%s"):format(
wmcode == "en" and "" or wmcode .. ":",
article == category and "" or article
)
insert_if_not(topright_parts, ("{{wp%s}}"):format(
wparg == "" and wparg or "|" .. wparg
))
end
end
local function insert_wikipedia_articles_for_wikipedia_specs(specs, default)
for _, article in ipairs(specs) do
local foreign_wiki
if article == true then
article = default
else
if article:find(":[^ ]") then
local actual_article
foreign_wiki, actual_article = article:match("^([a-z][a-z][a-z-]*):([^ ].*)$")
if actual_article then
article = actual_article
end
end
if article == "+" then
article = default
elseif article == "-" then
article = nil
else
article = require("Module:yesno")(article, article)
if article == true then
article = default
end
end
end
if article then
insert_wikipedia_article(foreign_wiki or "en", article)
end
end
end
local function insert_wikipedia_articles_for_wikidata_specs(specs, lang)
if not mw.wikibase then
error(("Unable to retrieve data from Wikidata ID's '%s'; `mw.wikibase` not defined"):format(args.wikidata))
end
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
local ids_without_wmcodes = {}
local ids_with_wmcodes = {}
for _, id in ipairs(specs) do
if id:find(":") then
table.insert(ids_with_wmcodes, id)
else
table.insert(ids_without_wmcodes, id)
end
end
for _, wmcode in ipairs(wikipedia_langs) do
for _, id in ipairs(ids_without_wmcodes) do
local article = mw.wikibase.sitelink(id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
for _, id in ipairs(ids_with_wmcodes) do
local wmcode, wikidata_id = id:match("^(.-):(.*)$")
local article = mw.wikibase.sitelink(wikidata_id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if args.wp or args.wikidata then
if args.wp then
insert_wikipedia_articles_for_wikipedia_specs(split_on_comma(args.wp), category)
end
if args.wikidata then
insert_wikipedia_articles_for_wikidata_specs(split(args.wikidata, "%s*,%s*"), lang)
end
elseif category == ucfirst(langname) then
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
for _, wmcode in ipairs(wikipedia_langs) do
local article = lang:getWikipediaArticle("no category fallback", wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if #topright_parts == 0 and sorted_labels then
for _, labobj in pairs(all_labels) do
local wp_specs = labobj.labdata.Wikipedia
if wp_specs then
if type(wp_specs) ~= "table" then
wp_specs = {wp_specs}
end
insert_wikipedia_articles_for_wikipedia_specs(wp_specs, labobj.canonical)
end
local wikidata_specs = labobj.labdata.Wikidata
if wikidata_specs then
if type(wikidata_specs) ~= "table" then
wikidata_specs = {wikidata_specs}
end
insert_wikipedia_articles_for_wikidata_specs(wikidata_specs, labobj.lang)
end
end
end
local topright
if #topright_parts > 0 then
topright = table.concat(topright_parts)
end
-------------------- 12. Return the combined structure of all information. -------------------
track("lect")
export.register_likely_lect_parent_cat(parents[1])
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
topright = topright,
description = description,
additional = additional,
parents = parents,
breadcrumb = {name = breadcrumb, nocap = true},
umbrella = false,
can_be_empty = true,
}, lect_type
end
local memoized_responses = {}
memoizing_lect_handler = function(category, raw_args, called_from_inside)
mw.log(category)
local retval = memoized_responses[category]
if not retval then
retval = {lect_handler(category, raw_args, called_from_inside)}
memoized_responses[category] = retval
end
local obj, lect_type = retval[1], retval[2]
return obj, lect_type
end
-- Actual handler for lect categories. See lect_handler() above.
table.insert(raw_handlers, function(data)
local settings, _ = memoizing_lect_handler(data.category, data.args, data.called_from_inside)
return settings, not not settings
end)
return {RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers, export = export}
n5oyfykk8t3p9gagb53z5slmp69so4k
238793
238792
2026-11-12T05:55:45Z
Lee
19
[[:en:Module:category_tree/lects]] වෙතින් එක් සංශෝධනයක්
238792
Scribunto
text/plain
local export = {}
local raw_categories = {}
local raw_handlers = {}
local labels_module = "Module:labels"
local labels_utilities_module = "Module:labels/utilities"
local languages_module = "Module:languages"
local parse_utilities_module = "Module:parse utilities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local m_table = require(table_module)
local get_lang = require(languages_module).getByCode
local insert_if_not = m_table.insertIfNot
local pattern_escape = require(string_pattern_escape_module)
local replacement_escape = require(string_replacement_escape_module)
local serial_comma_join = m_table.serialCommaJoin
local split = require(string_utilities_module).split
local split_on_comma = require(parse_utilities_module).split_on_comma
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/lects/PAGE]]
return require("Module:debug/track")("category tree/lects/" .. page)
end
-- This module handles lect/variety categories of all sorts, e.g. regional lect categories such as
-- [[:Category:American English]] and [[:Category:Provençal]]; temporal lect categories such as
-- [[:Category:Early Modern English]]; sociolect categories such as [[:Category:Polari]]; and umbrella categories of the
-- form e.g. [[:Category:Varieties of English]] and [[:Category:Regional French]].
-- FIXME: Eliminate the word "dialect" here and in the {{auto cat}} parameter in favor of "lect" or "variety". [DONE]
--[=[
FIXME:
1. Support multiple parents. [DONE]
2. Support cat: in parents to indicate a category. [DONE]
3. When linking a description without embedded links, use the equivalent of {{wtorw}} to auto-link to Wikipedia. [DONE]
4. Support the = true. [DONE]
]=]
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["Language varieties"] = {
description = "Categories that group terms in varieties of various languages (regional, temporal, sociolectal, etc.).",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"Fundamental",
},
}
raw_categories["Regionalisms"] = {
description = "Categories that group terms in regional varieties of various languages.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"Fundamental",
"Language varieties",
},
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
local function ucfirst(text)
return mw.getContentLanguage():ucfirst(text)
end
local function lcfirst(text)
return mw.getContentLanguage():lcfirst(text)
end
local function page_exists(page)
local title = mw.title.new(page)
return title and title.exists
end
-- Handle categories such as [[:Category:Varieties of French]] and [[:Category:Varieties of Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^Varieties of (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in varieties of " .. lang:makeCategoryLink() .. " (regional, temporal, sociolectal, etc.).",
parents = {
"{{{langcat}}}",
{name = "Language varieties", sort = langname},
},
breadcrumb = "Varieties",
}
end
end
end)
-- Handle categories such as [[:Category:Regional French]] and [[:Category:Regional Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^Regional (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in regional varieties of " .. lang:makeCategoryLink() .. ".",
additional = "This category sometimes also directly contains terms that are uncategorized regionalisms: such terms should be recategorized by the particular regional variety they belong to, or categorized as dialectal.",
parents = {
"Varieties of {{{langname}}}",
{name = "Regionalisms", sort = langname},
},
breadcrumb = "Regional",
}
end
end
end)
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then return nil end
arg = mw.text.trim(arg)
if arg == "" then return nil end
return arg
end
-- Get the full language to use e.g. in the settings.
local function get_returnable_lang(lang)
if lang:hasType("family") then
return nil
else
return lang:getFull()
end
end
-- Get the full language code to return in the settings.
local function get_returnable_lang_code(lang)
if lang:hasType("family") then
return "und"
else
return lang:getFullCode()
end
end
local memoizing_lect_handler
local function category_to_lang_name(category)
local getByCanonicalName = require("Module:languages").getByCanonicalName
local lang
lang = getByCanonicalName(category, nil, "allow etym", "allow family")
if not lang then
-- Some languages have lowercase-initial names e.g. 'the BMAC substrate', but the category begins with an
-- uppercase letter.
lang = getByCanonicalName(lcfirst(category), nil, "allow etym", "allow family")
end
return lang
end
-- Given a category (without the "Category:" prefix), look up the page defining the category, find the call to
-- {{auto cat}} (if any), and return a table of its arguments. If the category page doesn't exist or doesn't have
-- an {{auto cat}} invocation, return nil.
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("Category:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and canonicalizes them, so uses of {{autocat}}
-- will also be found.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
-- Try to figure out if this variety is extinct or reconstructed, if type= not given.
local function determine_lect_type(category, lang, default_parent_cat)
if category:find("^Proto%-") or lang:getCanonicalName():find("^Proto%-") or lang:hasType("reconstructed") then
-- Is it reconstructed?
return "reconstructed"
end
if lang:getCode():find("^qsb%-") then
-- Substrate.
return "unattested"
end
if lang:hasType("full") then
-- If a full language, scrape the {{auto cat}} call and check for extinct=1.
local parent_args = scrape_category_for_auto_cat_args(lang:getCategoryName())
if parent_args and ine(parent_args.extinct) and require("Module:yesno")(parent_args.extinct, false) then
return "extinct"
end
end
-- Otherwise, call the lect handler recursively for the parent category. This is correct e.g. for
-- things like subvarieties of Classical Persian, where the lang itself (Persian) isn't extinct but the
-- parent category refers to an extinct variety. If the lect handler fails to return a type, it's because
-- the parent category doesn't exist or isn't defined using {{auto cat}}, and doesn't have a language as a
-- suffix. In that case, if we're dealing with an etymology-only language, check the parent language. Finally,
-- fall back to returning "extant" if all else fails.
local parent_type
if default_parent_cat then
export.register_likely_lect_parent_cat(default_parent_cat)
parent_type = select(2, memoizing_lect_handler(default_parent_cat, nil, true))
end
if parent_type then
return parent_type
end
local parent_lang = lang:getParent()
if parent_lang then
return determine_lect_type(category, parent_lang, nil)
end
return "extant"
end
-- Try to figure out the region (used as the default breadcrumb and region description) from the language. If the
-- language name is an etymology-only language, try to derive a region based on a parent etymology-only or full
-- language. For example, if the pagename is '[[:Category:British English]]', the language is 'en-GB' (British English)
-- and the same as the pagename, but we'd like to return a region 'British'. This is also called in cases where the
-- language is explicitly given but we need to infer the region from the parent language; e.g.
-- [[:Category:Lucerne Alemmanic German]] is a type of High Alemannic German but we want to infer 'Lucerne' based on
-- the parent 'Alemannic German'. If this doesn't work and the language name has a space in it, we try using
-- progressively smaller suffixes of the language. For example, for [[:Category:Walser German]]', the language is
-- 'wae' (Walser German), but the parent is 'Highest Alemannic German', whose parent is 'Alemannic German' (a full
-- language), and just "German" is nowhere in the parent-child relationships but found as a suffix in the parent
-- language. Another such case is with [[:Category:Ionic Greek]], whose parent is 'Ancient Greek'.
local function infer_region_from_lang(pagename, lang)
local langname = lang:getCanonicalName()
local lang_to_check = lang
if ucfirst(langname) == pagename then
lang_to_check = lang_to_check:getParent()
end
-- First check against the language name and progressively smaller suffixes; then repeat for any parents (of
-- etymology languages). If the language name is the same as the page name, we need to start with the parent;
-- otherwise we will always match against a suffix, but that's not what we want.
while lang_to_check do
local suffix = lang_to_check:getCanonicalName()
while true do
local region = pagename:match("^(.*) " .. pattern_escape(suffix) .. "$")
if region then
return region
end
suffix = suffix:match("^.- (.*)$")
if not suffix then
break
end
end
lang_to_check = lang_to_check:getParent()
end
return nil
end
-- Modeled after splitLabelLang() in [[Module:category tree]]. Try to split off a maximally long language (full or
-- etymology-only) on the right, and return the resulting language object and the region preceding it. We need to
-- check the maximally long language because of cases like 'English' vs 'Middle English' and 'Chinese Pidgin English';
-- [[:Category:Late Middle English]] should split as 'Late' and 'Middle English', not as 'Late Middle' and 'English'.
local function split_region_lang(pagename)
local lang
local region
-- Try the entire title as a language; if not, chop off a word on the left and repeat.
local words = split(pagename, " ")
for i = 1, #words do
lang = category_to_lang_name(table.concat(words, " ", i, #words))
if lang then
if i == 1 then
region = nil
else
region = table.concat(words, " ", 1, i - 1)
end
break
end
end
if not region and lang then
-- The pagename is the same as a language name. Try to infer the region from the parent. See comment at
-- function.
region = infer_region_from_lang(pagename, lang)
end
return lang, region
end
-- Return the default parent cat for the given language and category. If the language and category are the same, we're
-- dealing with the overall cat for an etymology-only language, so use the category of the parent language; otherwise
-- we're dealing with a subcategory of a regular or etymology-only language (e.g. [[:Category:Issime Walser]], a
-- subcategory of [[:Category:Walser German]]), so use the language's category itself. If the resulting language is an
-- etymology-only language or a family, the parent category is that language or family's category, which for
-- etymology-only languages is named the same as the etymology-only language, and for families is named
-- "FAMILY languages"; otherwise, use "Regional LANG" as the category unless `noreg` is given, in which case we use
-- "Varieties of LANG".
local function get_default_parent_cat_from_category(category, lang, noreg)
if lang:getCode():find("^qsb%-") then
-- substrate
return "Substrate languages"
end
local lang_for_cat
if ucfirst(lang:getCanonicalName()) == category then
lang_for_cat = lang:getParent()
if not lang_for_cat then
error(("Category '%s' has a name the same as a full language; you probably need to explicitly specify a different language using |lang="):format(category))
end
else
lang_for_cat = lang
end
if lang_for_cat:hasType("etymology-only") or lang_for_cat:hasType("family") then
return lang_for_cat:getCategoryName()
elseif noreg then
return "Varieties of " .. lang_for_cat:getCanonicalName()
else
return "Regional " .. lang_for_cat:getCanonicalName()
end
end
-- Find the labels that categorize into `category`. Only categories specified using the `regional_categories` and
-- `plain_categories` fields will be returned. `lang` is the language object to use when looking up categories specified
-- using the `regional_categories` field, which append the language onto the specified category prefix. If `lang` is a
-- family or is omitted, no categories specified using `regional_categories` will be returned. Lang-specific modules for
-- all languages will be checked for matching labels that specify `category` as their category using `plain_categories`;
-- this helps e.g. with varieties of Chinese, whose labels are found in [[Module:labels/data/lang/zh]]. The return value
-- is a table in the same format as returned by `find_labels_for_category` in [[Module:labels/utilities]].
--
-- FIXME: It should be possible to check for categories specified using `regional_categories` even when `lang` is nil.
local function find_labels_for_category(category, lang)
local regional_cat_labels, plain_cat_labels
local full_lang
local m_labels_utilities = require(labels_utilities_module)
if lang and lang:hasType("language") then
full_lang = lang:getFull()
local regional_component = category:match("^(.-) " .. pattern_escape(full_lang:getCanonicalName()) .. "$")
if regional_component then
regional_cat_labels = m_labels_utilities.find_labels_for_category(regional_component,
"regional", full_lang)
end
end
plain_cat_labels = m_labels_utilities.find_labels_for_category(category, "plain", full_lang, "check all langs")
local all_labels
if regional_cat_labels and plain_cat_labels then
all_labels = regional_cat_labels
for k, v in pairs(plain_cat_labels) do
all_labels[k] = v
end
else
all_labels = regional_cat_labels or plain_cat_labels
end
return all_labels
end
-- Find the labels for category `category` and language object `lang` (which can be nil or a family, but in that case,
-- no labels on a category specified using `regional_categories`; FIXME: it should be possible to implement this). Then
-- filter them down to those that are specified using a lang-specific module and sort them for use in checking
-- properties such as parent and description. We filter down to only lang-specific labels because those specified in a
-- general module (especially [[Module:labels/data/regional]]) won't be able to have proper descriptions and especially
-- parents, which tend to be language-specific. The sort order prioritizes labels that match the category exactly
-- (either through the canonical version or any alias); this is followed by labels that are a prefix of the category
-- (again, either through the canonical version or any alias), so that labels whose categories are specified using
-- `regional_categories` are prioritized. Any other labels are sorted last, so that e.g. if both the label "Alberta" and
-- "Canada" (with alias "Canadian") for lang=en categorize into [[:Category:Canadian English]], we prefer the label
-- "Canada". For cases where e.g. both labels match the category as prefixes, ties are broken by prioritizing the labels
-- found in the lang-specific module whose language matches `lang`.
--
-- Returns two items. The first is a table of all labels categorizing into `category` (subject to the provisos described
-- in `find_labels_for_category()`), in the same format as returned by `find_labels_for_category` in
-- [[Module:labels/utilities]]. (Specifically, the values are objects containing all relevant information on a given
-- label, and the keys are less important.) The second is a list of label objects after filtering and sorting, in the
-- same format as the values in the `all_labels` table. The first return value will be nil if no labels could be found
-- categorizing into `category`, and the second return value will be nil if no labels remain after filtering.
local function get_sorted_labels(category, lang)
local all_labels = find_labels_for_category(category, lang)
if not all_labels then
return nil
end
local m_labels = require(labels_module)
local lang_specific_pattern = "^" .. pattern_escape(m_labels.lang_specific_data_modules_prefix)
local sorted_labels = {}
for _, labelobj in pairs(all_labels) do
if labelobj.module:find(lang_specific_pattern) then
table.insert(sorted_labels, labelobj)
end
end
local function sort_labelobj(a, b)
local function matches_exactly(labelobj)
if labelobj.canonical == category then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if alias == category then
return true
end
end
return false
end
local function matches_as_prefix(labelobj)
if category:find("^" .. pattern_escape(labelobj.canonical) .. " ") then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if category:find("^" .. pattern_escape(alias) .. " ") then
return true
end
end
return false
end
local function tiebreak()
local a_matches_lang = lang and a.lang:getFullCode() == lang:getFullCode()
local b_matches_lang = lang and b.lang:getFullCode() == lang:getFullCode()
if a_matches_lang and not b_matches_lang then
return true
elseif b_matches_lang and not a_matches_lang then
return false
else
return a.canonical < b.canonical
end
end
local a_matches_exactly = matches_exactly(a)
local b_matches_exactly = matches_exactly(b)
if a_matches_exactly and not b_matches_exactly then
return true
elseif b_matches_exactly and not a_matches_exactly then
return false
elseif a_matches_exactly and b_matches_exactly then
return tiebreak()
end
local a_matches_as_prefix = matches_as_prefix(a)
local b_matches_as_prefix = matches_as_prefix(b)
if a_matches_as_prefix and not b_matches_as_prefix then
return true
elseif b_matches_as_prefix and not a_matches_as_prefix then
return false
else
return tiebreak()
end
end
table.sort(sorted_labels, sort_labelobj)
if #sorted_labels > 0 then
return all_labels, sorted_labels
else
return all_labels, nil
end
end
-- Find the categories (only of type `regional_categories` and `plain_categories`) that label `label` categorizes into.
-- Return value is nil if the label couldn't be located at all, otherwise a list of categories (which may be empty).
local function get_categories_for_label(label, lang)
local m_labels = require(labels_module)
local labret = m_labels.get_label_info { label = label, lang = lang }
if not labret.recognized then
return nil
end
local categories = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["plain_categories"] = true})
local reg_cats = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["regional_categories"] = true})
if #reg_cats > 0 then
for _, cat in ipairs(reg_cats) do
table.insert(categories, cat)
end
end
return categories
end
-- Given the sorted labels that categorize into `category`, return the parent categories for the first label that specifies
-- any parents. `default` is the default parent category, usually "Regional LANG" or (if noreg=1 is specified) "Varieties of LANG";
-- it is used if the parent is explicitly given as `true` or "+" (or one of these values occurs among others), or if a parent label
-- was given but didn't categorize into any regional or plain categories, or if no labels with parents could be found. If
-- `all_cats` is specified, all categories associated with all specified parent labels (if more than one is present) are returned;
-- otherwise, only the categories for the first parent label are returned.
--
-- Returns two values: the list of parent categories and the label object from which the categories were derived (or nil if no
-- label object could be found with a `parent` field, in which case the return value of the list of categories is a simple-element
-- list consisting of `default`). The format of the parent category list is such that the list can directly be specified as the
-- value of the `parents` field returned by the raw handler. This means that usually the individual list elements are strings
-- (referring to raw poscat labels), but they may be strings prefixed by "Category:" (for arbitrary categories), or objects of the
-- form {name = "CATEGORY", lang = "LANGCODE", is_label = true} for poscat language labels.
local function get_parents_from_sorted_labels(sorted_labels, category, all_cats)
for _, labobj in ipairs(sorted_labels) do
local parent = labobj.labdata.parent
if parent == true then
parent = {parent}
elseif parent and type(parent) == "string" then
parent = split_on_comma(parent)
end
local function get_parent_cats(par)
if par == true or par == "+" then
return {"+"}
end
if par:find("^cat:") then
return {"Category:" .. par:gsub("^cat:", "")}
end
if par:find("^Category:") then
return {par}
end
if par:find("^rawposcat:") then
return {(par:gsub("^rawposcat:", ""))}
end
if par:find("^poscat:") then
local langcode, label = par:match("^poscat:([^:]+):(.*)$")
if not langcode then
error(("Parent poscatboiler language label '%s' for label '%s' for category '%s' (defined in module [[%s]]) needs to be of the form 'poscat:LANGCODE:LABEL'"):format(
par, labobj.canonical, category, labobj.module))
end
return {{name = label, lang = langcode, is_label = true}}
end
local this_cats = get_categories_for_label(par, labobj.lang)
if not this_cats then
error(("Parent label '%s' for label '%s' for category '%s' (defined in module [[%s]]) couldn't be located"):format(
par, labobj.canonical, category, labobj.module))
end
return this_cats
end
if parent then
if type(parent) ~= "table" then
error(("Internal error: Expected a string, boolean `true` or list for the value of the parent field for label '%s' for category '%s' (defined in module [[%s]]), but saw type '%s': %s"):format(
labobj.canonical, category, labobj.module, type(parent), mw.dumpObject(parent)))
end
local cats
if all_cats then
cats = {}
for _, par in ipairs(parent) do
local this_cats = get_parent_cats(par)
for _, this_cat in ipairs(this_cats) do
insert_if_not(cats, this_cat)
end
end
else
cats = get_parent_cats(parent[1])
end
if #cats > 0 then
return cats, labobj
end
-- FIXME: If the parent doesn't specify any categories, should we try the next parent or fall back
-- to the parent determined through get_default_parent_cat_from_category() (which is what we currently
-- do)?
return {"+"}, labobj
end
end
return {"+"}, nil
end
local likely_lect_parent_cat = {}
-- Register that `cat` is likely to be a lect cat, so we try to handle it as such in the lect handler when
-- we are called on that category. This avoids the need to have manual allow-lists of nonstandardly-named parent
-- lect categories to handle, such as [[:Category:Assyrian]], [[:Category:Ripuarian Franconian]] ("Franconian" is
-- not a language) and [[:Category:Limburgan-Ripuarian transitional dialects]].
function export.register_likely_lect_parent_cat(cat)
if type(cat) == "string" and not cat:find("^Category:") then
likely_lect_parent_cat[cat] = true
end
end
-- Handle lect categories such as [[:Category:New Zealand English]], [[:Category:Late Middle English]],
-- [[:Category:Arbëresh Albanian]], [[:Category:Provençal]] or arbitrarily-named categories like
-- [[:Category:Issime Walser]]. We currently require that lect=1 is specified to the call to {{auto cat}} to avoid
-- overfiring. However, if called from inside, we are processing the breadcrumb for the parent (or conceivably the
-- child) of a lect category, and won't have any params set, so we can't rely on lect=1. In that case, only fire
-- if the category is or ends in the name of a full or etymology-only language, and scrape the category's call to
-- {{auto cat}} to get the appropriate params. This means that nonstandardly-named categories like
-- [[:Category:Issime Walser]] can't be parents of other lect categories. To work around this, either we have to
-- relax the code below to operate on all raw categories (not necessarily a good idea), or we rename the
-- nonstandardly-named categories (e.g. in the case above, to [[:Category:Issime Walser German]], since Walser German
-- is a recognized etymology-only language).
--
-- NOTE: We are able to handle categories for etymology-only families (currently only [[:Category:Middle Iranian]] and
-- [[:Category:Old Iranian]]) and for etymology-only substrate languages (e.g. [[:Category:BMAC substrate]]).
-- There is some special "family" code for the former.
local function lect_handler(category, raw_args, called_from_inside)
if called_from_inside then
-- Avoid infinite loops from wrongly processing non-lect categories. We have a check around line 344 below
-- for categories whose {{auto cat}} doesn't say lect=1, but we still need the following in case of
-- non-existent categories we're being asked to process (e.g. [[:Category:User bcc]] ->
-- [[:Category:Southern Balochi]] (nonexistent) -> [[:Category:Regional Baluchi]] (nonexistent), which
-- causes an infinite loop without the check below.
if category:find("^Regional ") or category:find("^Varieties of ") or category:find("^Rhymes:") then
return nil
end
-- If called from inside we won't have any params available. See comment above about this. We scrape the
-- category page's call to {{auto cat}} to get the appropriate params, and if that fails, we currently fall back
-- to defaults based on the label(s) that categorize(s) into the category or the name of the category. Since the
-- call from inside is only to get the parent category and breadcrumb, these defaults actually work in most
-- cases but not all; e.g. in the chain [[:Category:Regional Yoruba]] -> [[:Category:Central Yoruba]] ->
-- [[:Category:Ekiti Yoruba]] -> [[:Category:Akurẹ Yoruba]], if we are forced to use default values, we will
-- produce the right parent for [[:Category:Central Yoruba]] but not for [[:Category:Ekiti Yoruba]], where the
-- default parent would be [[:Category:Regional Yoruba]] instead of the correct [[:Category:Central Yoruba]].
local lang, breadcrumb = split_region_lang(category)
if lang or likely_lect_parent_cat[category] then
raw_args = scrape_category_for_auto_cat_args(category)
if raw_args and not ine(raw_args.lect) then
-- We are scraping something like [[:Category:American Sign Language]] that ends in a valid language but is not
-- a lect.
return nil
end
if not raw_args then
-- If we can't parse the scraped {{auto cat}} spec, return default values. This helps e.g. in converting
-- from the old {{dialectboiler}} template and generally when adding new varieties.
local parents, label_with_parent
local function getprop(prop)
return -- ine(raw_args[prop]) or
label_with_parent and label_with_parent.labdata[prop]
end
local sorted_labels = select(2, get_sorted_labels(category, lang))
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category)
if not lang and label_with_parent then
lang = label_with_parent.lang
end
else
parents = {"+"}
end
if not lang then
-- We were instructed to scrape by virtue of `register_likely_lect_parent_cat`, but couldn't scrape
-- anything.
return nil
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang,
getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
local first_parent_cat = parents[1]
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^Category:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect
-- handler label).
first_parent_cat = nil
end
track("lect")
export.register_likely_lect_parent_cat(parents[1])
-- NOTE: When called from inside, the description doesn't matter; nor do any parents other than the
-- first. This is because called_from_inside is only set when computing the breadcrumb trail, which
-- only needs the language, first parent and breadcrumb.
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
description = "Foo",
parents = parents,
breadcrumb = breadcrumb or lang:getCanonicalName(),
umbrella = false,
can_be_empty = true,
}, determine_lect_type(category, lang, first_parent_cat)
end
else
return nil
end
end
if not called_from_inside and not ine(raw_args.lect) then
return nil
end
-------------------- 1. Process parameters. -------------------
local boolean = {type = "boolean"}
local sublist = {sublist = "comma without whitespace"}
local args = require("Module:parameters").process(raw_args, {
[1] = true,
lect = boolean,
lang = true,
verb = true,
prep = true,
the = boolean,
def = true,
fulldef = true,
addl = true,
nolink = boolean,
noreg = boolean, -- don't make the default parent be "Regional LANG"; instead, "Varieties of LANG"
type = {set = {"extinct", "extant", "reconstructed", "unattested", "constructed"}},
cat = true,
othercat = sublist,
country = sublist,
wp = true,
wikidata = true,
breadcrumb = true,
also = {type = "title", sublist = "comma without whitespace", namespace = 14},
pagename = true, -- for testing or demonstration
})
-------------------- 2. Initialize breadcrumb, regiondesc and language from category. -------------------
-- They may be overridden later.
local lang, breadcrumb, regiondesc, langname
category = args.pagename or category
if not args.lang then
lang, breadcrumb = split_region_lang(category)
if lang then
langname = lang:getCanonicalName()
end
-- The lang and/or breadcrumb may be nil at this point (e.g. we're processing a category like
-- [[:Category:Singlish]] or [[:Category:Polari]] that doesn't have a language in it). We don't throw an error
-- yet because we may be able to fetch the lang, regiondesc and breadcrumb from a label that categorizes into
-- the category.
regiondesc = breadcrumb
else
lang = get_lang(args.lang, "lang", "allow etym")
langname = lang:getCanonicalName()
if category == ucfirst(langname) then
-- breadcrumb and regiondesc should stay nil; breadcrumb will get `category` as a default, and the lack of
-- regiondesc will cause an error to be thrown unless the user gave it explicitly or specified def=.
else
breadcrumb = category:match("^(.*) " .. pattern_escape(langname) .. "$")
if not breadcrumb then
-- Try to infer the region from the parent. See comment at function.
breadcrumb = infer_region_from_lang(category, lang)
end
regiondesc = breadcrumb
end
end
-------------------- 3. Determine labels categorizing into this category. -------------------
local all_labels, sorted_labels = get_sorted_labels(category, lang)
-------------------- 4. Determine parent categories and initialize additional properties. -------------------
-- The first label with a parent is used to fetch additional properties, such as region= and addl=.
local parents
local first_parent_cat = args.cat
local label_with_parent
local function getprop(prop)
return args[prop] or label_with_parent and label_with_parent.labdata[prop]
end
if first_parent_cat then
parents = {first_parent_cat}
if not lang then
error(("lang= not given and unable to parse language from category '%s' (didn't check labels categorizing into the category because cat= explicitly given)"):format(category))
end
else
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category, "all cats")
if not lang and label_with_parent then
lang = label_with_parent.lang
langname = lang:getCanonicalName()
end
else
parents = {"+"}
end
if not lang then
error(("lang= not given, unable to parse language from category '%s' and can't find a label categorizing into the category"):format(category))
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang, getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
first_parent_cat = parents[1]
end
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^Category:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect handler label).
-- WARNING: Code below using `first_parent_cat` must handle nil.
first_parent_cat = nil
end
local othercat = getprop("othercat")
if type(othercat) == "string" then
othercat = split_on_comma(othercat)
end
if othercat then
for _, cat in ipairs(othercat) do
if not cat:find("^Category:") then
cat = "Category:" .. cat
end
table.insert(parents, cat)
end
end
local countries = getprop("country") or {}
if type(countries) == "string" then
countries = split_on_comma(countries)
end
-- If no breadcrumb, this often happens when the langname and category are the same (happens only with etym-only
-- languages), and the parent category is set below to the full parent, so the breadcrumb should show the
-- language name (or equivalently, the category). If the langname and category are different, we should fall back to
-- the category. E.g. for Singlish, lang=en is specified and we can't infer a breadcrumb because the lect name
-- doesn't end in "English"; in this case we want the breadcrumb to show "Singlish".
breadcrumb = getprop("breadcrumb") or breadcrumb or category
local the_prefix
if args[1] then
regiondesc = args[1]
else
local regionprop = getprop("region")
if regionprop then
regiondesc = regionprop
elseif label_with_parent then
-- It's not clear which of the following two are better. The second one uses the actual label display form,
-- which might be argued to be better, except that it will often be linked to a Wikipedia article about the
-- lect rather than the place. The first one just uses the canonical label directly (which will later be
-- linked to itself if unlinked). A third possibility is to use `label_with_parent.display` if present,
-- otherwise `label_with_parent.canonical`.
regiondesc = label_with_parent.canonical
if label_with_parent.display and regiondesc ~= label_with_parent.display then
track("display-different-from-canonical")
end
-- regiondesc = require(labels_module).get_displayed_label(label_with_parent.canonical, label_with_parent.labdata, lang)
end
end
the_prefix = getprop("the") and "the " or ""
if #countries == 0 then
countries = {regiondesc and the_prefix .. regiondesc or nil}
end
for _, country in ipairs(countries) do
if not country:find("[<=]") then
country = require("Module:links").remove_links(country)
local cat = "Category:Languages of " .. country
if page_exists(cat) then
table.insert(parents, cat)
end
end
end
-------------------- 5. Refine the language to an etymology-only child if possible. -------------------
-- Now that we've determined the parent, we look up the parent hierarchy until we find a category naming an
-- etymology-only language. If we find one and it's a child of the language we've determined, use it.
local ancestral_cat = first_parent_cat
local refined_lang
while true do
refined_lang = category_to_lang_name(ancestral_cat)
if refined_lang then
break
end
export.register_likely_lect_parent_cat(ancestral_cat)
local settings, _ = memoizing_lect_handler(ancestral_cat, nil, true)
if not settings then
break
end
ancestral_cat = settings.parents[1]
end
if refined_lang and refined_lang:hasParent(lang) then
lang = refined_lang
langname = lang:getCanonicalName()
end
-------------------- 6. Initialize `additional` with user-specified text and info about labels. -------------------
local additional = getprop("addl")
local function append_addl(addl_text)
if not addl_text then
return
end
if additional then
additional = additional .. "\n\n" .. addl_text
else
additional = addl_text
end
end
if all_labels then
local m_labels_utilities = require(labels_utilities_module)
append_addl(m_labels_utilities.format_labels_categorizing(all_labels, nil,
get_returnable_lang(lang)))
end
-------------------- 7. Augment `additional` with information about etymology-only codes. -------------------
local langname_for_desc
local etymcodes = {}
local function make_code(code)
return ("<code>%s</code>"):format(code)
end
if lang:hasType("etymology-only") and ucfirst(langname) == category then
langname_for_desc = lang:getParentName()
local langcode = lang:getCode()
table.insert(etymcodes, make_code(langcode))
-- Find all alias codes for the etymology-only language.
-- FIXME: There should be a better/easier way of doing this.
local ety_code_to_name = mw.loadData("Module:etymology languages/code to canonical name")
for code, canon_name in pairs(ety_code_to_name) do
if canon_name == langname and code ~= langcode then
table.insert(etymcodes, make_code(code))
end
end
local addl_etym_codes = ("[[Module:etymology_languages/data|Etymology-only language]] code: %s."):format(
serial_comma_join(etymcodes, {conj = "or"}))
append_addl(addl_etym_codes)
else
langname_for_desc = langname
end
-------------------- 8. Try to figure out if this variety is extinct or reconstructed. -------------------
local lect_type = getprop("type")
if not lect_type then
lect_type = determine_lect_type(category, lang, first_parent_cat)
end
local function prefix_addl(addl_text)
if additional then
additional = addl_text .. "\n\n" .. additional
else
additional = addl_text
end
end
if lect_type == "extinct" then
prefix_addl("This lect is [[extinct language|extinct]].")
table.insert(parents, "Category:All extinct languages")
elseif lect_type == "reconstructed" then
prefix_addl("This lect is [[reconstructed language|reconstructed]].")
table.insert(parents, "Category:Reconstructed languages")
elseif lect_type == "unattested" then
prefix_addl("This lect is {{w|unattested language|unattested}}.")
table.insert(parents, "Category:Unattested languages")
elseif lect_type == "constructed" then
prefix_addl("This lect is [[constructed language|constructed]].")
table.insert(parents, "Category:Constructed languages")
end
-------------------- 9. Add pseudo-familes to parents. -------------------
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
table.insert(parents, "Category:" .. pseudofam:getCategoryName())
end
-------------------- 10. Compute `description`. -------------------
local description
local fulldef = getprop("fulldef")
if fulldef then
description = fulldef .. "."
end
if not description then
local def = getprop("def")
if def then
description = ("Terms or senses in %s."):format(def)
end
end
if not description then
if not regiondesc then
-- We need regiondesc for the description unless def= or fulldef= is given, which overrides the part that needs it.
error(("1= (region) not given and unable to infer region from category '%s' given language name '%s'"):
format(category, langname))
end
local lang_en = get_lang("en", true)
local linked_regiondesc = regiondesc
-- Don't try to link if HTML, = sign, template call or embedded link found in text. Embedded links will
-- automatically be converted to English links by JavaScript.
local function linkable(text)
return not text:find("[<={}%[%]|]")
end
if linked_regiondesc:find("<country>") then
if not countries then
error(("Can't specify <country> in region description '%s' when country= not given"):format(linked_regiondesc))
end
-- Link the countries individually before calling serialCommaJoin(), which inserts HTML.
local linked_countries = {}
for _, country in ipairs(countries) do
if linkable(country) then
country = require("Module:links").full_link { lang = lang_en, term = country }
end
table.insert(linked_countries, country)
end
linked_countries = serial_comma_join(linked_countries)
linked_regiondesc = linked_regiondesc:gsub("<country>", replacement_escape(linked_countries))
elseif not getprop("nolink") and linkable(linked_regiondesc) then
-- Even if nolink not given, don't try to link if HTML or = sign found in linked_regiondesc, otherwise
-- we're likely to get an error.
if page_exists(linked_regiondesc) then
-- Only construct a Wiktionary link if the page exists; otherwise construct a Wikipedia link.
linked_regiondesc = require("Module:links").full_link { lang = lang_en, term = linked_regiondesc }
else
linked_regiondesc = ("[[w:%s|%s]]"):format(linked_regiondesc, linked_regiondesc)
end
end
linked_regiondesc = the_prefix .. linked_regiondesc
local no_longer_spoken = lect_type == "extinct" or lect_type == "reconstructed" or lect_type == "unattested"
local verb = getprop("verb") or no_longer_spoken and "formerly spoken" or "spoken"
local prep = getprop("prep")
if not langname_for_desc then
error(category)
end
description = ("Terms or senses in %s as %s%s %s."):format(
langname_for_desc, verb, prep == "-" and "" or " " .. (prep or "in"), linked_regiondesc)
end
-------------------- 11. Compute the Wikipedia articles that go into `topright`. -------------------
local topright_parts = {}
-- Insert Wikipedia article `article` for Wikimedia language `wmcode` into `topright_parts`, avoiding duplication.
local function insert_wikipedia_article(wmcode, article)
if wmcode == "commons" then
insert_if_not(topright_parts, ("{{commons%s}}"):format(
article == category and "" or "|" .. article
))
else
local wparg = ("%s%s"):format(
wmcode == "en" and "" or wmcode .. ":",
article == category and "" or article
)
insert_if_not(topright_parts, ("{{wp%s}}"):format(
wparg == "" and wparg or "|" .. wparg
))
end
end
local function insert_wikipedia_articles_for_wikipedia_specs(specs, default)
for _, article in ipairs(specs) do
local foreign_wiki
if article == true then
article = default
else
if article:find(":[^ ]") then
local actual_article
foreign_wiki, actual_article = article:match("^([a-z][a-z][a-z-]*):([^ ].*)$")
if actual_article then
article = actual_article
end
end
if article == "+" then
article = default
elseif article == "-" then
article = nil
else
article = require("Module:yesno")(article, article)
if article == true then
article = default
end
end
end
if article then
insert_wikipedia_article(foreign_wiki or "en", article)
end
end
end
local function insert_wikipedia_articles_for_wikidata_specs(specs, lang)
if not mw.wikibase then
error(("Unable to retrieve data from Wikidata ID's '%s'; `mw.wikibase` not defined"):format(args.wikidata))
end
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
local ids_without_wmcodes = {}
local ids_with_wmcodes = {}
for _, id in ipairs(specs) do
if id:find(":") then
table.insert(ids_with_wmcodes, id)
else
table.insert(ids_without_wmcodes, id)
end
end
for _, wmcode in ipairs(wikipedia_langs) do
for _, id in ipairs(ids_without_wmcodes) do
local article = mw.wikibase.sitelink(id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
for _, id in ipairs(ids_with_wmcodes) do
local wmcode, wikidata_id = id:match("^(.-):(.*)$")
local article = mw.wikibase.sitelink(wikidata_id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if args.wp or args.wikidata then
if args.wp then
insert_wikipedia_articles_for_wikipedia_specs(split_on_comma(args.wp), category)
end
if args.wikidata then
insert_wikipedia_articles_for_wikidata_specs(split(args.wikidata, "%s*,%s*"), lang)
end
elseif category == ucfirst(langname) then
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
for _, wmcode in ipairs(wikipedia_langs) do
local article = lang:getWikipediaArticle("no category fallback", wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if #topright_parts == 0 and sorted_labels then
for _, labobj in pairs(all_labels) do
local wp_specs = labobj.labdata.Wikipedia
if wp_specs then
if type(wp_specs) ~= "table" then
wp_specs = {wp_specs}
end
insert_wikipedia_articles_for_wikipedia_specs(wp_specs, labobj.canonical)
end
local wikidata_specs = labobj.labdata.Wikidata
if wikidata_specs then
if type(wikidata_specs) ~= "table" then
wikidata_specs = {wikidata_specs}
end
insert_wikipedia_articles_for_wikidata_specs(wikidata_specs, labobj.lang)
end
end
end
local topright
if #topright_parts > 0 then
topright = table.concat(topright_parts)
end
-------------------- 12. Return the combined structure of all information. -------------------
track("lect")
export.register_likely_lect_parent_cat(parents[1])
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
topright = topright,
description = description,
additional = additional,
parents = parents,
breadcrumb = {name = breadcrumb, nocap = true},
umbrella = false,
can_be_empty = true,
}, lect_type
end
local memoized_responses = {}
memoizing_lect_handler = function(category, raw_args, called_from_inside)
mw.log(category)
local retval = memoized_responses[category]
if not retval then
retval = {lect_handler(category, raw_args, called_from_inside)}
memoized_responses[category] = retval
end
local obj, lect_type = retval[1], retval[2]
return obj, lect_type
end
-- Actual handler for lect categories. See lect_handler() above.
table.insert(raw_handlers, function(data)
local settings, _ = memoizing_lect_handler(data.category, data.args, data.called_from_inside)
return settings, not not settings
end)
return {RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers, export = export}
n5oyfykk8t3p9gagb53z5slmp69so4k
238794
238793
2026-11-12T05:56:12Z
Lee
19
පැරණි සංස්කරණයකින් ගත් කොටස්...
238794
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local export = {}
local raw_categories = {}
local raw_handlers = {}
local labels_module = "Module:labels"
local labels_utilities_module = "Module:labels/utilities"
local languages_module = "Module:languages"
local parse_utilities_module = "Module:parse utilities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local m_table = require(table_module)
local get_lang = require(languages_module).getByCode
local insert_if_not = m_table.insertIfNot
local pattern_escape = require(string_pattern_escape_module)
local replacement_escape = require(string_replacement_escape_module)
local serial_comma_join = m_table.serialCommaJoin
local split = require(string_utilities_module).split
local split_on_comma = require(parse_utilities_module).split_on_comma
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/lects/PAGE]]
return require("Module:debug/track")("category tree/lects/" .. page)
end
-- This module handles lect/variety categories of all sorts, e.g. regional lect categories such as
-- [[:Category:American English]] and [[:Category:Provençal]]; temporal lect categories such as
-- [[:Category:Early Modern English]]; sociolect categories such as [[:Category:Polari]]; and umbrella categories of the
-- form e.g. [[:Category:Varieties of English]] and [[:Category:Regional French]].
-- FIXME: Eliminate the word "dialect" here and in the {{auto cat}} parameter in favor of "lect" or "variety". [DONE]
--[=[
FIXME:
1. Support multiple parents. [DONE]
2. Support cat: in parents to indicate a category. [DONE]
3. When linking a description without embedded links, use the equivalent of {{wtorw}} to auto-link to Wikipedia. [DONE]
4. Support the = true. [DONE]
]=]
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා ප්රභේද"] = {
description = "Categories that group terms in varieties of various languages (regional, temporal, sociolectal, etc.).",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"මූලධර්ම",
},
}
raw_categories["Regionalisms"] = {
description = "Categories that group terms in regional varieties of various languages.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"මූලධර්ම",
"භාෂා ප්රභේද",
},
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
local function ucfirst(text)
return mw.getContentLanguage():ucfirst(text)
end
local function lcfirst(text)
return mw.getContentLanguage():lcfirst(text)
end
local function page_exists(page)
local title = mw.title.new(page)
return title and title.exists
end
-- Handle categories such as [[:Category:Varieties of French]] and [[:Category:Varieties of Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^(.*) ප්රභේද$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in varieties of " .. lang:makeCategoryLink() .. " (regional, temporal, sociolectal, etc.).",
parents = {
"{{{langcat}}}",
{name = "භාෂා ප්රභේද", sort = langname},
},
breadcrumb = "ප්රභේද",
}
end
end
end)
-- Handle categories such as [[:Category:Regional French]] and [[:Category:Regional Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^කලාපීය (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in regional varieties of " .. lang:makeCategoryLink() .. ".",
additional = "This category sometimes also directly contains terms that are uncategorized regionalisms: such terms should be recategorized by the particular regional variety they belong to, or categorized as dialectal.",
parents = {
"{{{langname}}} ප්රභේද",
{name = "Regionalisms", sort = langname},
},
breadcrumb = "කලාපීය",
}
end
end
end)
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then return nil end
arg = mw.text.trim(arg)
if arg == "" then return nil end
return arg
end
-- Get the full language to use e.g. in the settings.
local function get_returnable_lang(lang)
if lang:hasType("family") then
return nil
else
return lang:getFull()
end
end
-- Get the full language code to return in the settings.
local function get_returnable_lang_code(lang)
if lang:hasType("family") then
return "und"
else
return lang:getFullCode()
end
end
local memoizing_lect_handler
local function category_to_lang_name(category)
local getByCanonicalName = require("Module:languages").getByCanonicalName
local lang
lang = getByCanonicalName(category, nil, "allow etym", "allow family")
if not lang then
-- Some languages have lowercase-initial names e.g. 'the BMAC substrate', but the category begins with an
-- uppercase letter.
lang = getByCanonicalName(lcfirst(category), nil, "allow etym", "allow family")
end
return lang
end
-- Given a category (without the "Category:" prefix), look up the page defining the category, find the call to
-- {{auto cat}} (if any), and return a table of its arguments. If the category page doesn't exist or doesn't have
-- an {{auto cat}} invocation, return nil.
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and canonicalizes them, so uses of {{autocat}}
-- will also be found.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
-- Try to figure out if this variety is extinct or reconstructed, if type= not given.
local function determine_lect_type(category, lang, default_parent_cat)
if category:find("^Proto%-") or lang:getCanonicalName():find("^Proto%-") or lang:hasType("reconstructed") then
-- Is it reconstructed?
return "reconstructed"
end
if lang:getCode():find("^qsb%-") then
-- Substrate.
return "unattested"
end
if lang:hasType("full") then
-- If a full language, scrape the {{auto cat}} call and check for extinct=1.
local parent_args = scrape_category_for_auto_cat_args(lang:getCategoryName())
if parent_args and ine(parent_args.extinct) and require("Module:yesno")(parent_args.extinct, false) then
return "extinct"
end
end
-- Otherwise, call the lect handler recursively for the parent category. This is correct e.g. for
-- things like subvarieties of Classical Persian, where the lang itself (Persian) isn't extinct but the
-- parent category refers to an extinct variety. If the lect handler fails to return a type, it's because
-- the parent category doesn't exist or isn't defined using {{auto cat}}, and doesn't have a language as a
-- suffix. In that case, if we're dealing with an etymology-only language, check the parent language. Finally,
-- fall back to returning "extant" if all else fails.
local parent_type
if default_parent_cat then
export.register_likely_lect_parent_cat(default_parent_cat)
parent_type = select(2, memoizing_lect_handler(default_parent_cat, nil, true))
end
if parent_type then
return parent_type
end
local parent_lang = lang:getParent()
if parent_lang then
return determine_lect_type(category, parent_lang, nil)
end
return "extant"
end
-- Try to figure out the region (used as the default breadcrumb and region description) from the language. If the
-- language name is an etymology-only language, try to derive a region based on a parent etymology-only or full
-- language. For example, if the pagename is '[[:Category:British English]]', the language is 'en-GB' (British English)
-- and the same as the pagename, but we'd like to return a region 'British'. This is also called in cases where the
-- language is explicitly given but we need to infer the region from the parent language; e.g.
-- [[:Category:Lucerne Alemmanic German]] is a type of High Alemannic German but we want to infer 'Lucerne' based on
-- the parent 'Alemannic German'. If this doesn't work and the language name has a space in it, we try using
-- progressively smaller suffixes of the language. For example, for [[:Category:Walser German]]', the language is
-- 'wae' (Walser German), but the parent is 'Highest Alemannic German', whose parent is 'Alemannic German' (a full
-- language), and just "German" is nowhere in the parent-child relationships but found as a suffix in the parent
-- language. Another such case is with [[:Category:Ionic Greek]], whose parent is 'Ancient Greek'.
local function infer_region_from_lang(pagename, lang)
local langname = lang:getCanonicalName()
local lang_to_check = lang
if ucfirst(langname) == pagename then
lang_to_check = lang_to_check:getParent()
end
-- First check against the language name and progressively smaller suffixes; then repeat for any parents (of
-- etymology languages). If the language name is the same as the page name, we need to start with the parent;
-- otherwise we will always match against a suffix, but that's not what we want.
while lang_to_check do
local suffix = lang_to_check:getCanonicalName()
while true do
local region = pagename:match("^(.*) " .. pattern_escape(suffix) .. "$")
if region then
return region
end
suffix = suffix:match("^.- (.*)$")
if not suffix then
break
end
end
lang_to_check = lang_to_check:getParent()
end
return nil
end
-- Modeled after splitLabelLang() in [[Module:category tree]]. Try to split off a maximally long language (full or
-- etymology-only) on the right, and return the resulting language object and the region preceding it. We need to
-- check the maximally long language because of cases like 'English' vs 'Middle English' and 'Chinese Pidgin English';
-- [[:Category:Late Middle English]] should split as 'Late' and 'Middle English', not as 'Late Middle' and 'English'.
local function split_region_lang(pagename)
local lang
local region
-- Try the entire title as a language; if not, chop off a word on the left and repeat.
local words = split(pagename, " ")
for i = 1, #words do
lang = category_to_lang_name(table.concat(words, " ", i, #words))
if lang then
if i == 1 then
region = nil
else
region = table.concat(words, " ", 1, i - 1)
end
break
end
end
if not region and lang then
-- The pagename is the same as a language name. Try to infer the region from the parent. See comment at
-- function.
region = infer_region_from_lang(pagename, lang)
end
return lang, region
end
-- Return the default parent cat for the given language and category. If the language and category are the same, we're
-- dealing with the overall cat for an etymology-only language, so use the category of the parent language; otherwise
-- we're dealing with a subcategory of a regular or etymology-only language (e.g. [[:Category:Issime Walser]], a
-- subcategory of [[:Category:Walser German]]), so use the language's category itself. If the resulting language is an
-- etymology-only language or a family, the parent category is that language or family's category, which for
-- etymology-only languages is named the same as the etymology-only language, and for families is named
-- "FAMILY languages"; otherwise, use "Regional LANG" as the category unless `noreg` is given, in which case we use
-- "Varieties of LANG".
local function get_default_parent_cat_from_category(category, lang, noreg)
if lang:getCode():find("^qsb%-") then
-- substrate
return "Substrate languages"
end
local lang_for_cat
if ucfirst(lang:getCanonicalName()) == category then
lang_for_cat = lang:getParent()
if not lang_for_cat then
error(("Category '%s' has a name the same as a full language; you probably need to explicitly specify a different language using |lang="):format(category))
end
else
lang_for_cat = lang
end
if lang_for_cat:hasType("etymology-only") or lang_for_cat:hasType("family") then
return lang_for_cat:getCategoryName()
elseif noreg then
return ("%s ප්රභේද"):format(lang_for_cat:getCanonicalName())
else
return "කලාපීය " .. lang_for_cat:getCanonicalName()
end
end
-- Find the labels that categorize into `category`. Only categories specified using the `regional_categories` and
-- `plain_categories` fields will be returned. `lang` is the language object to use when looking up categories specified
-- using the `regional_categories` field, which append the language onto the specified category prefix. If `lang` is a
-- family or is omitted, no categories specified using `regional_categories` will be returned. Lang-specific modules for
-- all languages will be checked for matching labels that specify `category` as their category using `plain_categories`;
-- this helps e.g. with varieties of Chinese, whose labels are found in [[Module:labels/data/lang/zh]]. The return value
-- is a table in the same format as returned by `find_labels_for_category` in [[Module:labels/utilities]].
--
-- FIXME: It should be possible to check for categories specified using `regional_categories` even when `lang` is nil.
local function find_labels_for_category(category, lang)
local regional_cat_labels, plain_cat_labels
local full_lang
local m_labels_utilities = require(labels_utilities_module)
if lang and lang:hasType("language") then
full_lang = lang:getFull()
local regional_component = category:match("^(.-) " .. pattern_escape(full_lang:getCanonicalName()) .. "$")
if regional_component then
regional_cat_labels = m_labels_utilities.find_labels_for_category(regional_component,
"regional", full_lang)
end
end
plain_cat_labels = m_labels_utilities.find_labels_for_category(category, "plain", full_lang, "check all langs")
local all_labels
if regional_cat_labels and plain_cat_labels then
all_labels = regional_cat_labels
for k, v in pairs(plain_cat_labels) do
all_labels[k] = v
end
else
all_labels = regional_cat_labels or plain_cat_labels
end
return all_labels
end
-- Find the labels for category `category` and language object `lang` (which can be nil or a family, but in that case,
-- no labels on a category specified using `regional_categories`; FIXME: it should be possible to implement this). Then
-- filter them down to those that are specified using a lang-specific module and sort them for use in checking
-- properties such as parent and description. We filter down to only lang-specific labels because those specified in a
-- general module (especially [[Module:labels/data/regional]]) won't be able to have proper descriptions and especially
-- parents, which tend to be language-specific. The sort order prioritizes labels that match the category exactly
-- (either through the canonical version or any alias); this is followed by labels that are a prefix of the category
-- (again, either through the canonical version or any alias), so that labels whose categories are specified using
-- `regional_categories` are prioritized. Any other labels are sorted last, so that e.g. if both the label "Alberta" and
-- "Canada" (with alias "Canadian") for lang=en categorize into [[:Category:Canadian English]], we prefer the label
-- "Canada". For cases where e.g. both labels match the category as prefixes, ties are broken by prioritizing the labels
-- found in the lang-specific module whose language matches `lang`.
--
-- Returns two items. The first is a table of all labels categorizing into `category` (subject to the provisos described
-- in `find_labels_for_category()`), in the same format as returned by `find_labels_for_category` in
-- [[Module:labels/utilities]]. (Specifically, the values are objects containing all relevant information on a given
-- label, and the keys are less important.) The second is a list of label objects after filtering and sorting, in the
-- same format as the values in the `all_labels` table. The first return value will be nil if no labels could be found
-- categorizing into `category`, and the second return value will be nil if no labels remain after filtering.
local function get_sorted_labels(category, lang)
local all_labels = find_labels_for_category(category, lang)
if not all_labels then
return nil
end
local m_labels = require(labels_module)
local lang_specific_pattern = "^" .. pattern_escape(m_labels.lang_specific_data_modules_prefix)
local sorted_labels = {}
for _, labelobj in pairs(all_labels) do
if labelobj.module:find(lang_specific_pattern) then
table.insert(sorted_labels, labelobj)
end
end
local function sort_labelobj(a, b)
local function matches_exactly(labelobj)
if labelobj.canonical == category then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if alias == category then
return true
end
end
return false
end
local function matches_as_prefix(labelobj)
if category:find("^" .. pattern_escape(labelobj.canonical) .. " ") then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if category:find("^" .. pattern_escape(alias) .. " ") then
return true
end
end
return false
end
local function tiebreak()
local a_matches_lang = lang and a.lang:getFullCode() == lang:getFullCode()
local b_matches_lang = lang and b.lang:getFullCode() == lang:getFullCode()
if a_matches_lang and not b_matches_lang then
return true
elseif b_matches_lang and not a_matches_lang then
return false
else
return a.canonical < b.canonical
end
end
local a_matches_exactly = matches_exactly(a)
local b_matches_exactly = matches_exactly(b)
if a_matches_exactly and not b_matches_exactly then
return true
elseif b_matches_exactly and not a_matches_exactly then
return false
elseif a_matches_exactly and b_matches_exactly then
return tiebreak()
end
local a_matches_as_prefix = matches_as_prefix(a)
local b_matches_as_prefix = matches_as_prefix(b)
if a_matches_as_prefix and not b_matches_as_prefix then
return true
elseif b_matches_as_prefix and not a_matches_as_prefix then
return false
else
return tiebreak()
end
end
table.sort(sorted_labels, sort_labelobj)
if #sorted_labels > 0 then
return all_labels, sorted_labels
else
return all_labels, nil
end
end
-- Find the categories (only of type `regional_categories` and `plain_categories`) that label `label` categorizes into.
-- Return value is nil if the label couldn't be located at all, otherwise a list of categories (which may be empty).
local function get_categories_for_label(label, lang)
local m_labels = require(labels_module)
local labret = m_labels.get_label_info { label = label, lang = lang }
if not labret.recognized then
return nil
end
local categories = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["plain_categories"] = true})
local reg_cats = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["regional_categories"] = true})
if #reg_cats > 0 then
for _, cat in ipairs(reg_cats) do
table.insert(categories, cat)
end
end
return categories
end
-- Given the sorted labels that categorize into `category`, return the parent categories for the first label that specifies
-- any parents. `default` is the default parent category, usually "Regional LANG" or (if noreg=1 is specified) "Varieties of LANG";
-- it is used if the parent is explicitly given as `true` or "+" (or one of these values occurs among others), or if a parent label
-- was given but didn't categorize into any regional or plain categories, or if no labels with parents could be found. If
-- `all_cats` is specified, all categories associated with all specified parent labels (if more than one is present) are returned;
-- otherwise, only the categories for the first parent label are returned.
--
-- Returns two values: the list of parent categories and the label object from which the categories were derived (or nil if no
-- label object could be found with a `parent` field, in which case the return value of the list of categories is a simple-element
-- list consisting of `default`). The format of the parent category list is such that the list can directly be specified as the
-- value of the `parents` field returned by the raw handler. This means that usually the individual list elements are strings
-- (referring to raw poscat labels), but they may be strings prefixed by "Category:" (for arbitrary categories), or objects of the
-- form {name = "CATEGORY", lang = "LANGCODE", is_label = true} for poscat language labels.
local function get_parents_from_sorted_labels(sorted_labels, category, all_cats)
for _, labobj in ipairs(sorted_labels) do
local parent = labobj.labdata.parent
if parent == true then
parent = {parent}
elseif parent and type(parent) == "string" then
parent = split_on_comma(parent)
end
local function get_parent_cats(par)
if par == true or par == "+" then
return {"+"}
end
if par:find("^cat:") then
return {"ප්රවර්ගය:" .. par:gsub("^cat:", "")}
end
if par:find("^ප්රවර්ගය:") then
return {par}
end
if par:find("^rawposcat:") then
return {(par:gsub("^rawposcat:", ""))}
end
if par:find("^poscat:") then
local langcode, label = par:match("^poscat:([^:]+):(.*)$")
if not langcode then
error(("Parent poscatboiler language label '%s' for label '%s' for category '%s' (defined in module [[%s]]) needs to be of the form 'poscat:LANGCODE:LABEL'"):format(
par, labobj.canonical, category, labobj.module))
end
return {{name = label, lang = langcode, is_label = true}}
end
local this_cats = get_categories_for_label(par, labobj.lang)
if not this_cats then
error(("Parent label '%s' for label '%s' for category '%s' (defined in module [[%s]]) couldn't be located"):format(
par, labobj.canonical, category, labobj.module))
end
return this_cats
end
if parent then
if type(parent) ~= "table" then
error(("Internal error: Expected a string, boolean `true` or list for the value of the parent field for label '%s' for category '%s' (defined in module [[%s]]), but saw type '%s': %s"):format(
labobj.canonical, category, labobj.module, type(parent), mw.dumpObject(parent)))
end
local cats
if all_cats then
cats = {}
for _, par in ipairs(parent) do
local this_cats = get_parent_cats(par)
for _, this_cat in ipairs(this_cats) do
insert_if_not(cats, this_cat)
end
end
else
cats = get_parent_cats(parent[1])
end
if #cats > 0 then
return cats, labobj
end
-- FIXME: If the parent doesn't specify any categories, should we try the next parent or fall back
-- to the parent determined through get_default_parent_cat_from_category() (which is what we currently
-- do)?
return {"+"}, labobj
end
end
return {"+"}, nil
end
local likely_lect_parent_cat = {}
-- Register that `cat` is likely to be a lect cat, so we try to handle it as such in the lect handler when
-- we are called on that category. This avoids the need to have manual allow-lists of nonstandardly-named parent
-- lect categories to handle, such as [[:Category:Assyrian]], [[:Category:Ripuarian Franconian]] ("Franconian" is
-- not a language) and [[:Category:Limburgan-Ripuarian transitional dialects]].
function export.register_likely_lect_parent_cat(cat)
if type(cat) == "string" and not cat:find("^ප්රවර්ගය:") then
likely_lect_parent_cat[cat] = true
end
end
-- Handle lect categories such as [[:Category:New Zealand English]], [[:Category:Late Middle English]],
-- [[:Category:Arbëresh Albanian]], [[:Category:Provençal]] or arbitrarily-named categories like
-- [[:Category:Issime Walser]]. We currently require that lect=1 is specified to the call to {{auto cat}} to avoid
-- overfiring. However, if called from inside, we are processing the breadcrumb for the parent (or conceivably the
-- child) of a lect category, and won't have any params set, so we can't rely on lect=1. In that case, only fire
-- if the category is or ends in the name of a full or etymology-only language, and scrape the category's call to
-- {{auto cat}} to get the appropriate params. This means that nonstandardly-named categories like
-- [[:Category:Issime Walser]] can't be parents of other lect categories. To work around this, either we have to
-- relax the code below to operate on all raw categories (not necessarily a good idea), or we rename the
-- nonstandardly-named categories (e.g. in the case above, to [[:Category:Issime Walser German]], since Walser German
-- is a recognized etymology-only language).
--
-- NOTE: We are able to handle categories for etymology-only families (currently only [[:Category:Middle Iranian]] and
-- [[:Category:Old Iranian]]) and for etymology-only substrate languages (e.g. [[:Category:BMAC substrate]]).
-- There is some special "family" code for the former.
local function lect_handler(category, raw_args, called_from_inside)
if called_from_inside then
-- Avoid infinite loops from wrongly processing non-lect categories. We have a check around line 344 below
-- for categories whose {{auto cat}} doesn't say lect=1, but we still need the following in case of
-- non-existent categories we're being asked to process (e.g. [[:Category:User bcc]] ->
-- [[:Category:Southern Balochi]] (nonexistent) -> [[:Category:Regional Baluchi]] (nonexistent), which
-- causes an infinite loop without the check below.
if category:find("^Regional ") or category:find("ප්රභේද$") or category:find("^Rhymes:") then
return nil
end
-- If called from inside we won't have any params available. See comment above about this. We scrape the
-- category page's call to {{auto cat}} to get the appropriate params, and if that fails, we currently fall back
-- to defaults based on the label(s) that categorize(s) into the category or the name of the category. Since the
-- call from inside is only to get the parent category and breadcrumb, these defaults actually work in most
-- cases but not all; e.g. in the chain [[:Category:Regional Yoruba]] -> [[:Category:Central Yoruba]] ->
-- [[:Category:Ekiti Yoruba]] -> [[:Category:Akurẹ Yoruba]], if we are forced to use default values, we will
-- produce the right parent for [[:Category:Central Yoruba]] but not for [[:Category:Ekiti Yoruba]], where the
-- default parent would be [[:Category:Regional Yoruba]] instead of the correct [[:Category:Central Yoruba]].
local lang, breadcrumb = split_region_lang(category)
if lang or likely_lect_parent_cat[category] then
raw_args = scrape_category_for_auto_cat_args(category)
if raw_args and not ine(raw_args.lect) then
-- We are scraping something like [[:Category:American Sign Language]] that ends in a valid language but is not
-- a lect.
return nil
end
if not raw_args then
-- If we can't parse the scraped {{auto cat}} spec, return default values. This helps e.g. in converting
-- from the old {{dialectboiler}} template and generally when adding new varieties.
local parents, label_with_parent
local function getprop(prop)
return -- ine(raw_args[prop]) or
label_with_parent and label_with_parent.labdata[prop]
end
local sorted_labels = select(2, get_sorted_labels(category, lang))
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category)
if not lang and label_with_parent then
lang = label_with_parent.lang
end
else
parents = {"+"}
end
if not lang then
-- We were instructed to scrape by virtue of `register_likely_lect_parent_cat`, but couldn't scrape
-- anything.
return nil
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang,
getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
local first_parent_cat = parents[1]
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^ප්රවර්ගය:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect
-- handler label).
first_parent_cat = nil
end
track("lect")
export.register_likely_lect_parent_cat(parents[1])
-- NOTE: When called from inside, the description doesn't matter; nor do any parents other than the
-- first. This is because called_from_inside is only set when computing the breadcrumb trail, which
-- only needs the language, first parent and breadcrumb.
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
description = "Foo",
parents = parents,
breadcrumb = breadcrumb or lang:getCanonicalName(),
umbrella = false,
can_be_empty = true,
}, determine_lect_type(category, lang, first_parent_cat)
end
else
return nil
end
end
if not called_from_inside and not ine(raw_args.lect) then
return nil
end
-------------------- 1. Process parameters. -------------------
local boolean = {type = "boolean"}
local sublist = {sublist = "comma without whitespace"}
local args = require("Module:parameters").process(raw_args, {
[1] = true,
lect = boolean,
lang = true,
verb = true,
prep = true,
the = boolean,
def = true,
fulldef = true,
addl = true,
nolink = boolean,
noreg = boolean, -- don't make the default parent be "Regional LANG"; instead, "LANG ප්රභේද"
type = {set = {"extinct", "extant", "reconstructed", "unattested", "constructed"}},
cat = true,
othercat = sublist,
country = sublist,
wp = true,
wikidata = true,
breadcrumb = true,
also = {type = "title", sublist = "comma without whitespace", namespace = 14},
pagename = true, -- for testing or demonstration
})
-------------------- 2. Initialize breadcrumb, regiondesc and language from category. -------------------
-- They may be overridden later.
local lang, breadcrumb, regiondesc, langname
category = args.pagename or category
if not args.lang then
lang, breadcrumb = split_region_lang(category)
if lang then
langname = lang:getCanonicalName()
end
-- The lang and/or breadcrumb may be nil at this point (e.g. we're processing a category like
-- [[:Category:Singlish]] or [[:Category:Polari]] that doesn't have a language in it). We don't throw an error
-- yet because we may be able to fetch the lang, regiondesc and breadcrumb from a label that categorizes into
-- the category.
regiondesc = breadcrumb
else
lang = get_lang(args.lang, "lang", "allow etym")
langname = lang:getCanonicalName()
if category == ucfirst(langname) then
-- breadcrumb and regiondesc should stay nil; breadcrumb will get `category` as a default, and the lack of
-- regiondesc will cause an error to be thrown unless the user gave it explicitly or specified def=.
else
breadcrumb = category:match("^(.*) " .. pattern_escape(langname) .. "$")
if not breadcrumb then
-- Try to infer the region from the parent. See comment at function.
breadcrumb = infer_region_from_lang(category, lang)
end
regiondesc = breadcrumb
end
end
-------------------- 3. Determine labels categorizing into this category. -------------------
local all_labels, sorted_labels = get_sorted_labels(category, lang)
-------------------- 4. Determine parent categories and initialize additional properties. -------------------
-- The first label with a parent is used to fetch additional properties, such as region= and addl=.
local parents
local first_parent_cat = args.cat
local label_with_parent
local function getprop(prop)
return args[prop] or label_with_parent and label_with_parent.labdata[prop]
end
if first_parent_cat then
parents = {first_parent_cat}
if not lang then
error(("lang= not given and unable to parse language from category '%s' (didn't check labels categorizing into the category because cat= explicitly given)"):format(category))
end
else
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category, "all cats")
if not lang and label_with_parent then
lang = label_with_parent.lang
langname = lang:getCanonicalName()
end
else
parents = {"+"}
end
if not lang then
error(("lang= not given, unable to parse language from category '%s' and can't find a label categorizing into the category"):format(category))
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang, getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
first_parent_cat = parents[1]
end
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^ප්රවර්ගය:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect handler label).
-- WARNING: Code below using `first_parent_cat` must handle nil.
first_parent_cat = nil
end
local othercat = getprop("othercat")
if type(othercat) == "string" then
othercat = split_on_comma(othercat)
end
if othercat then
for _, cat in ipairs(othercat) do
if not cat:find("^ප්රවර්ගය:") then
cat = "ප්රවර්ගය:" .. cat
end
table.insert(parents, cat)
end
end
local countries = getprop("country") or {}
if type(countries) == "string" then
countries = split_on_comma(countries)
end
-- If no breadcrumb, this often happens when the langname and category are the same (happens only with etym-only
-- languages), and the parent category is set below to the full parent, so the breadcrumb should show the
-- language name (or equivalently, the category). If the langname and category are different, we should fall back to
-- the category. E.g. for Singlish, lang=en is specified and we can't infer a breadcrumb because the lect name
-- doesn't end in "English"; in this case we want the breadcrumb to show "Singlish".
breadcrumb = getprop("breadcrumb") or breadcrumb or category
local the_prefix
if args[1] then
regiondesc = args[1]
else
local regionprop = getprop("region")
if regionprop then
regiondesc = regionprop
elseif label_with_parent then
-- It's not clear which of the following two are better. The second one uses the actual label display form,
-- which might be argued to be better, except that it will often be linked to a Wikipedia article about the
-- lect rather than the place. The first one just uses the canonical label directly (which will later be
-- linked to itself if unlinked). A third possibility is to use `label_with_parent.display` if present,
-- otherwise `label_with_parent.canonical`.
regiondesc = label_with_parent.canonical
if label_with_parent.display and regiondesc ~= label_with_parent.display then
track("display-different-from-canonical")
end
-- regiondesc = require(labels_module).get_displayed_label(label_with_parent.canonical, label_with_parent.labdata, lang)
end
end
the_prefix = getprop("the") and "the " or ""
if #countries == 0 then
countries = {regiondesc and the_prefix .. regiondesc or nil}
end
for _, country in ipairs(countries) do
if not country:find("[<=]") then
country = require("Module:links").remove_links(country)
local cat = "ප්රවර්ගය:" .. m_sinhala.sinhala(country) .. " තුළ භාවිතා වන භාෂා"
if page_exists(cat) then
table.insert(parents, cat)
end
end
end
-------------------- 5. Refine the language to an etymology-only child if possible. -------------------
-- Now that we've determined the parent, we look up the parent hierarchy until we find a category naming an
-- etymology-only language. If we find one and it's a child of the language we've determined, use it.
local ancestral_cat = first_parent_cat
local refined_lang
while true do
refined_lang = category_to_lang_name(ancestral_cat)
if refined_lang then
break
end
export.register_likely_lect_parent_cat(ancestral_cat)
local settings, _ = memoizing_lect_handler(ancestral_cat, nil, true)
if not settings then
break
end
ancestral_cat = settings.parents[1]
end
if refined_lang and refined_lang:hasParent(lang) then
lang = refined_lang
langname = lang:getCanonicalName()
end
-------------------- 6. Initialize `additional` with user-specified text and info about labels. -------------------
local additional = getprop("addl")
local function append_addl(addl_text)
if not addl_text then
return
end
if additional then
additional = additional .. "\n\n" .. addl_text
else
additional = addl_text
end
end
if all_labels then
local m_labels_utilities = require(labels_utilities_module)
append_addl(m_labels_utilities.format_labels_categorizing(all_labels, nil,
get_returnable_lang(lang)))
end
-------------------- 7. Augment `additional` with information about etymology-only codes. -------------------
local langname_for_desc
local etymcodes = {}
local function make_code(code)
return ("<code>%s</code>"):format(code)
end
if lang:hasType("etymology-only") and ucfirst(langname) == category then
langname_for_desc = lang:getParentName()
local langcode = lang:getCode()
table.insert(etymcodes, make_code(langcode))
-- Find all alias codes for the etymology-only language.
-- FIXME: There should be a better/easier way of doing this.
local ety_code_to_name = mw.loadData("Module:etymology languages/code to canonical name")
for code, canon_name in pairs(ety_code_to_name) do
if canon_name == langname and code ~= langcode then
table.insert(etymcodes, make_code(code))
end
end
local addl_etym_codes = ("[[Module:etymology_languages/data|Etymology-only language]] code: %s."):format(
serial_comma_join(etymcodes, {conj = "or"}))
append_addl(addl_etym_codes)
else
langname_for_desc = langname
end
-------------------- 8. Try to figure out if this variety is extinct or reconstructed. -------------------
local lect_type = getprop("type")
if not lect_type then
lect_type = determine_lect_type(category, lang, first_parent_cat)
end
local function prefix_addl(addl_text)
if additional then
additional = addl_text .. "\n\n" .. additional
else
additional = addl_text
end
end
if lect_type == "extinct" then
prefix_addl("This lect is [[extinct language|extinct]].")
table.insert(parents, "ප්රවර්ගය:All extinct languages")
elseif lect_type == "reconstructed" then
prefix_addl("This lect is [[reconstructed language|reconstructed]].")
table.insert(parents, "ප්රවර්ගය:Reconstructed languages")
elseif lect_type == "unattested" then
prefix_addl("This lect is {{w|unattested language|unattested}}.")
table.insert(parents, "ප්රවර්ගය:Unattested languages")
elseif lect_type == "constructed" then
prefix_addl("This lect is [[constructed language|constructed]].")
table.insert(parents, "ප්රවර්ගය:Constructed languages")
end
-------------------- 9. Add pseudo-familes to parents. -------------------
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
table.insert(parents, "Category:" .. pseudofam:getCategoryName())
end
-------------------- 10. Compute `description`. -------------------
local description
local fulldef = getprop("fulldef")
if fulldef then
description = fulldef .. "."
end
if not description then
local def = getprop("def")
if def then
description = ("Terms or senses in %s."):format(def)
end
end
if not description then
if not regiondesc then
-- We need regiondesc for the description unless def= or fulldef= is given, which overrides the part that needs it.
error(("1= (region) not given and unable to infer region from category '%s' given language name '%s'"):
format(category, langname))
end
local lang_en = get_lang("en", true)
local linked_regiondesc = regiondesc
-- Don't try to link if HTML, = sign, template call or embedded link found in text. Embedded links will
-- automatically be converted to English links by JavaScript.
local function linkable(text)
return not text:find("[<={}%[%]|]")
end
if linked_regiondesc:find("<country>") then
if not countries then
error(("Can't specify <country> in region description '%s' when country= not given"):format(linked_regiondesc))
end
-- Link the countries individually before calling serialCommaJoin(), which inserts HTML.
local linked_countries = {}
for _, country in ipairs(countries) do
if linkable(country) then
country = require("Module:links").full_link { lang = lang_en, term = country }
end
table.insert(linked_countries, country)
end
linked_countries = serial_comma_join(linked_countries)
linked_regiondesc = linked_regiondesc:gsub("<country>", replacement_escape(linked_countries))
elseif not getprop("nolink") and linkable(linked_regiondesc) then
-- Even if nolink not given, don't try to link if HTML or = sign found in linked_regiondesc, otherwise
-- we're likely to get an error.
if page_exists(linked_regiondesc) then
-- Only construct a Wiktionary link if the page exists; otherwise construct a Wikipedia link.
linked_regiondesc = require("Module:links").full_link { lang = lang_en, term = linked_regiondesc }
else
linked_regiondesc = ("[[w:%s|%s]]"):format(linked_regiondesc, linked_regiondesc)
end
end
linked_regiondesc = the_prefix .. linked_regiondesc
local no_longer_spoken = lect_type == "extinct" or lect_type == "reconstructed" or lect_type == "unattested"
local verb = getprop("verb") or no_longer_spoken and "formerly spoken" or "spoken"
local prep = getprop("prep")
if not langname_for_desc then
error(category)
end
description = ("Terms or senses in %s as %s%s %s."):format(
langname_for_desc, verb, prep == "-" and "" or " " .. (prep or "in"), linked_regiondesc)
end
-------------------- 11. Compute the Wikipedia articles that go into `topright`. -------------------
local topright_parts = {}
-- Insert Wikipedia article `article` for Wikimedia language `wmcode` into `topright_parts`, avoiding duplication.
local function insert_wikipedia_article(wmcode, article)
if wmcode == "commons" then
insert_if_not(topright_parts, ("{{commons%s}}"):format(
article == category and "" or "|" .. article
))
else
local wparg = ("%s%s"):format(
wmcode == "en" and "" or wmcode .. ":",
article == category and "" or article
)
insert_if_not(topright_parts, ("{{wp%s}}"):format(
wparg == "" and wparg or "|" .. wparg
))
end
end
local function insert_wikipedia_articles_for_wikipedia_specs(specs, default)
for _, article in ipairs(specs) do
local foreign_wiki
if article == true then
article = default
else
if article:find(":[^ ]") then
local actual_article
foreign_wiki, actual_article = article:match("^([a-z][a-z][a-z-]*):([^ ].*)$")
if actual_article then
article = actual_article
end
end
if article == "+" then
article = default
elseif article == "-" then
article = nil
else
article = require("Module:yesno")(article, article)
if article == true then
article = default
end
end
end
if article then
insert_wikipedia_article(foreign_wiki or "en", article)
end
end
end
local function insert_wikipedia_articles_for_wikidata_specs(specs, lang)
if not mw.wikibase then
error(("Unable to retrieve data from Wikidata ID's '%s'; `mw.wikibase` not defined"):format(args.wikidata))
end
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
local ids_without_wmcodes = {}
local ids_with_wmcodes = {}
for _, id in ipairs(specs) do
if id:find(":") then
table.insert(ids_with_wmcodes, id)
else
table.insert(ids_without_wmcodes, id)
end
end
for _, wmcode in ipairs(wikipedia_langs) do
for _, id in ipairs(ids_without_wmcodes) do
local article = mw.wikibase.sitelink(id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
for _, id in ipairs(ids_with_wmcodes) do
local wmcode, wikidata_id = id:match("^(.-):(.*)$")
local article = mw.wikibase.sitelink(wikidata_id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if args.wp or args.wikidata then
if args.wp then
insert_wikipedia_articles_for_wikipedia_specs(split_on_comma(args.wp), category)
end
if args.wikidata then
insert_wikipedia_articles_for_wikidata_specs(split(args.wikidata, "%s*,%s*"), lang)
end
elseif category == ucfirst(langname) then
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
for _, wmcode in ipairs(wikipedia_langs) do
local article = lang:getWikipediaArticle("no category fallback", wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if #topright_parts == 0 and sorted_labels then
for _, labobj in pairs(all_labels) do
local wp_specs = labobj.labdata.Wikipedia
if wp_specs then
if type(wp_specs) ~= "table" then
wp_specs = {wp_specs}
end
insert_wikipedia_articles_for_wikipedia_specs(wp_specs, labobj.canonical)
end
local wikidata_specs = labobj.labdata.Wikidata
if wikidata_specs then
if type(wikidata_specs) ~= "table" then
wikidata_specs = {wikidata_specs}
end
insert_wikipedia_articles_for_wikidata_specs(wikidata_specs, labobj.lang)
end
end
end
local topright
if #topright_parts > 0 then
topright = table.concat(topright_parts)
end
-------------------- 12. Return the combined structure of all information. -------------------
track("lect")
export.register_likely_lect_parent_cat(parents[1])
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
topright = topright,
description = description,
additional = additional,
parents = parents,
breadcrumb = {name = breadcrumb, nocap = true},
umbrella = false,
can_be_empty = true,
}, lect_type
end
local memoized_responses = {}
memoizing_lect_handler = function(category, raw_args, called_from_inside)
mw.log(category)
local retval = memoized_responses[category]
if not retval then
retval = {lect_handler(category, raw_args, called_from_inside)}
memoized_responses[category] = retval
end
local obj, lect_type = retval[1], retval[2]
return obj, lect_type
end
-- Actual handler for lect categories. See lect_handler() above.
table.insert(raw_handlers, function(data)
local settings, _ = memoizing_lect_handler(data.category, data.args, data.called_from_inside)
return settings, not not settings
end)
return {RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers, export = export}
qhcb0z7kodbacabc2kdoz413d11mlax
238795
238794
2026-11-12T06:04:36Z
Lee
19
"All extinct languages" සිට "නෂ්ට වූ භාෂා සියල්ල" වෙතට
238795
Scribunto
text/plain
local m_sinhala = require("Module:sinhala")
local export = {}
local raw_categories = {}
local raw_handlers = {}
local labels_module = "Module:labels"
local labels_utilities_module = "Module:labels/utilities"
local languages_module = "Module:languages"
local parse_utilities_module = "Module:parse utilities"
local string_pattern_escape_module = "Module:string/patternEscape"
local string_replacement_escape_module = "Module:string/replacementEscape"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local m_table = require(table_module)
local get_lang = require(languages_module).getByCode
local insert_if_not = m_table.insertIfNot
local pattern_escape = require(string_pattern_escape_module)
local replacement_escape = require(string_replacement_escape_module)
local serial_comma_join = m_table.serialCommaJoin
local split = require(string_utilities_module).split
local split_on_comma = require(parse_utilities_module).split_on_comma
local function track(page)
-- [[Special:WhatLinksHere/Wiktionary:Tracking/category tree/lects/PAGE]]
return require("Module:debug/track")("category tree/lects/" .. page)
end
-- This module handles lect/variety categories of all sorts, e.g. regional lect categories such as
-- [[:Category:American English]] and [[:Category:Provençal]]; temporal lect categories such as
-- [[:Category:Early Modern English]]; sociolect categories such as [[:Category:Polari]]; and umbrella categories of the
-- form e.g. [[:Category:Varieties of English]] and [[:Category:Regional French]].
-- FIXME: Eliminate the word "dialect" here and in the {{auto cat}} parameter in favor of "lect" or "variety". [DONE]
--[=[
FIXME:
1. Support multiple parents. [DONE]
2. Support cat: in parents to indicate a category. [DONE]
3. When linking a description without embedded links, use the equivalent of {{wtorw}} to auto-link to Wikipedia. [DONE]
4. Support the = true. [DONE]
]=]
-----------------------------------------------------------------------------
-- --
-- RAW CATEGORIES --
-- --
-----------------------------------------------------------------------------
raw_categories["භාෂා ප්රභේද"] = {
description = "Categories that group terms in varieties of various languages (regional, temporal, sociolectal, etc.).",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"මූලධර්ම",
},
}
raw_categories["Regionalisms"] = {
description = "Categories that group terms in regional varieties of various languages.",
additional = "{{{umbrella_meta_msg}}}",
parents = {
"මූලධර්ම",
"භාෂා ප්රභේද",
},
}
-----------------------------------------------------------------------------
-- --
-- RAW HANDLERS --
-- --
-----------------------------------------------------------------------------
local function ucfirst(text)
return mw.getContentLanguage():ucfirst(text)
end
local function lcfirst(text)
return mw.getContentLanguage():lcfirst(text)
end
local function page_exists(page)
local title = mw.title.new(page)
return title and title.exists
end
-- Handle categories such as [[:Category:Varieties of French]] and [[:Category:Varieties of Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^(.*) ප්රභේද$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in varieties of " .. lang:makeCategoryLink() .. " (regional, temporal, sociolectal, etc.).",
parents = {
"{{{langcat}}}",
{name = "භාෂා ප්රභේද", sort = langname},
},
breadcrumb = "ප්රභේද",
}
end
end
end)
-- Handle categories such as [[:Category:Regional French]] and [[:Category:Regional Ancient Greek]].
table.insert(raw_handlers, function(data)
local langname = data.category:match("^කලාපීය (.*)$")
if langname then
local lang = require("Module:languages").getByCanonicalName(langname)
if lang then
return {
lang = lang:getCode(),
description = "Categories containing terms in regional varieties of " .. lang:makeCategoryLink() .. ".",
additional = "This category sometimes also directly contains terms that are uncategorized regionalisms: such terms should be recategorized by the particular regional variety they belong to, or categorized as dialectal.",
parents = {
"{{{langname}}} ප්රභේද",
{name = "Regionalisms", sort = langname},
},
breadcrumb = "කලාපීය",
}
end
end
end)
-- Fancy version of ine() (if-not-empty). Converts empty string to nil, but also strips leading/trailing space.
local function ine(arg)
if not arg then return nil end
arg = mw.text.trim(arg)
if arg == "" then return nil end
return arg
end
-- Get the full language to use e.g. in the settings.
local function get_returnable_lang(lang)
if lang:hasType("family") then
return nil
else
return lang:getFull()
end
end
-- Get the full language code to return in the settings.
local function get_returnable_lang_code(lang)
if lang:hasType("family") then
return "und"
else
return lang:getFullCode()
end
end
local memoizing_lect_handler
local function category_to_lang_name(category)
local getByCanonicalName = require("Module:languages").getByCanonicalName
local lang
lang = getByCanonicalName(category, nil, "allow etym", "allow family")
if not lang then
-- Some languages have lowercase-initial names e.g. 'the BMAC substrate', but the category begins with an
-- uppercase letter.
lang = getByCanonicalName(lcfirst(category), nil, "allow etym", "allow family")
end
return lang
end
-- Given a category (without the "Category:" prefix), look up the page defining the category, find the call to
-- {{auto cat}} (if any), and return a table of its arguments. If the category page doesn't exist or doesn't have
-- an {{auto cat}} invocation, return nil.
local function scrape_category_for_auto_cat_args(cat)
local cat_page = mw.title.new("ප්රවර්ගය:" .. cat)
if cat_page then
local contents = cat_page:getContent()
if contents then
for template in require("Module:template parser").find_templates(contents) do
-- The template parser automatically handles redirects and canonicalizes them, so uses of {{autocat}}
-- will also be found.
if template:get_name() == "auto cat" then
return template:get_arguments()
end
end
end
end
return nil
end
-- Try to figure out if this variety is extinct or reconstructed, if type= not given.
local function determine_lect_type(category, lang, default_parent_cat)
if category:find("^Proto%-") or lang:getCanonicalName():find("^Proto%-") or lang:hasType("reconstructed") then
-- Is it reconstructed?
return "reconstructed"
end
if lang:getCode():find("^qsb%-") then
-- Substrate.
return "unattested"
end
if lang:hasType("full") then
-- If a full language, scrape the {{auto cat}} call and check for extinct=1.
local parent_args = scrape_category_for_auto_cat_args(lang:getCategoryName())
if parent_args and ine(parent_args.extinct) and require("Module:yesno")(parent_args.extinct, false) then
return "extinct"
end
end
-- Otherwise, call the lect handler recursively for the parent category. This is correct e.g. for
-- things like subvarieties of Classical Persian, where the lang itself (Persian) isn't extinct but the
-- parent category refers to an extinct variety. If the lect handler fails to return a type, it's because
-- the parent category doesn't exist or isn't defined using {{auto cat}}, and doesn't have a language as a
-- suffix. In that case, if we're dealing with an etymology-only language, check the parent language. Finally,
-- fall back to returning "extant" if all else fails.
local parent_type
if default_parent_cat then
export.register_likely_lect_parent_cat(default_parent_cat)
parent_type = select(2, memoizing_lect_handler(default_parent_cat, nil, true))
end
if parent_type then
return parent_type
end
local parent_lang = lang:getParent()
if parent_lang then
return determine_lect_type(category, parent_lang, nil)
end
return "extant"
end
-- Try to figure out the region (used as the default breadcrumb and region description) from the language. If the
-- language name is an etymology-only language, try to derive a region based on a parent etymology-only or full
-- language. For example, if the pagename is '[[:Category:British English]]', the language is 'en-GB' (British English)
-- and the same as the pagename, but we'd like to return a region 'British'. This is also called in cases where the
-- language is explicitly given but we need to infer the region from the parent language; e.g.
-- [[:Category:Lucerne Alemmanic German]] is a type of High Alemannic German but we want to infer 'Lucerne' based on
-- the parent 'Alemannic German'. If this doesn't work and the language name has a space in it, we try using
-- progressively smaller suffixes of the language. For example, for [[:Category:Walser German]]', the language is
-- 'wae' (Walser German), but the parent is 'Highest Alemannic German', whose parent is 'Alemannic German' (a full
-- language), and just "German" is nowhere in the parent-child relationships but found as a suffix in the parent
-- language. Another such case is with [[:Category:Ionic Greek]], whose parent is 'Ancient Greek'.
local function infer_region_from_lang(pagename, lang)
local langname = lang:getCanonicalName()
local lang_to_check = lang
if ucfirst(langname) == pagename then
lang_to_check = lang_to_check:getParent()
end
-- First check against the language name and progressively smaller suffixes; then repeat for any parents (of
-- etymology languages). If the language name is the same as the page name, we need to start with the parent;
-- otherwise we will always match against a suffix, but that's not what we want.
while lang_to_check do
local suffix = lang_to_check:getCanonicalName()
while true do
local region = pagename:match("^(.*) " .. pattern_escape(suffix) .. "$")
if region then
return region
end
suffix = suffix:match("^.- (.*)$")
if not suffix then
break
end
end
lang_to_check = lang_to_check:getParent()
end
return nil
end
-- Modeled after splitLabelLang() in [[Module:category tree]]. Try to split off a maximally long language (full or
-- etymology-only) on the right, and return the resulting language object and the region preceding it. We need to
-- check the maximally long language because of cases like 'English' vs 'Middle English' and 'Chinese Pidgin English';
-- [[:Category:Late Middle English]] should split as 'Late' and 'Middle English', not as 'Late Middle' and 'English'.
local function split_region_lang(pagename)
local lang
local region
-- Try the entire title as a language; if not, chop off a word on the left and repeat.
local words = split(pagename, " ")
for i = 1, #words do
lang = category_to_lang_name(table.concat(words, " ", i, #words))
if lang then
if i == 1 then
region = nil
else
region = table.concat(words, " ", 1, i - 1)
end
break
end
end
if not region and lang then
-- The pagename is the same as a language name. Try to infer the region from the parent. See comment at
-- function.
region = infer_region_from_lang(pagename, lang)
end
return lang, region
end
-- Return the default parent cat for the given language and category. If the language and category are the same, we're
-- dealing with the overall cat for an etymology-only language, so use the category of the parent language; otherwise
-- we're dealing with a subcategory of a regular or etymology-only language (e.g. [[:Category:Issime Walser]], a
-- subcategory of [[:Category:Walser German]]), so use the language's category itself. If the resulting language is an
-- etymology-only language or a family, the parent category is that language or family's category, which for
-- etymology-only languages is named the same as the etymology-only language, and for families is named
-- "FAMILY languages"; otherwise, use "Regional LANG" as the category unless `noreg` is given, in which case we use
-- "Varieties of LANG".
local function get_default_parent_cat_from_category(category, lang, noreg)
if lang:getCode():find("^qsb%-") then
-- substrate
return "Substrate languages"
end
local lang_for_cat
if ucfirst(lang:getCanonicalName()) == category then
lang_for_cat = lang:getParent()
if not lang_for_cat then
error(("Category '%s' has a name the same as a full language; you probably need to explicitly specify a different language using |lang="):format(category))
end
else
lang_for_cat = lang
end
if lang_for_cat:hasType("etymology-only") or lang_for_cat:hasType("family") then
return lang_for_cat:getCategoryName()
elseif noreg then
return ("%s ප්රභේද"):format(lang_for_cat:getCanonicalName())
else
return "කලාපීය " .. lang_for_cat:getCanonicalName()
end
end
-- Find the labels that categorize into `category`. Only categories specified using the `regional_categories` and
-- `plain_categories` fields will be returned. `lang` is the language object to use when looking up categories specified
-- using the `regional_categories` field, which append the language onto the specified category prefix. If `lang` is a
-- family or is omitted, no categories specified using `regional_categories` will be returned. Lang-specific modules for
-- all languages will be checked for matching labels that specify `category` as their category using `plain_categories`;
-- this helps e.g. with varieties of Chinese, whose labels are found in [[Module:labels/data/lang/zh]]. The return value
-- is a table in the same format as returned by `find_labels_for_category` in [[Module:labels/utilities]].
--
-- FIXME: It should be possible to check for categories specified using `regional_categories` even when `lang` is nil.
local function find_labels_for_category(category, lang)
local regional_cat_labels, plain_cat_labels
local full_lang
local m_labels_utilities = require(labels_utilities_module)
if lang and lang:hasType("language") then
full_lang = lang:getFull()
local regional_component = category:match("^(.-) " .. pattern_escape(full_lang:getCanonicalName()) .. "$")
if regional_component then
regional_cat_labels = m_labels_utilities.find_labels_for_category(regional_component,
"regional", full_lang)
end
end
plain_cat_labels = m_labels_utilities.find_labels_for_category(category, "plain", full_lang, "check all langs")
local all_labels
if regional_cat_labels and plain_cat_labels then
all_labels = regional_cat_labels
for k, v in pairs(plain_cat_labels) do
all_labels[k] = v
end
else
all_labels = regional_cat_labels or plain_cat_labels
end
return all_labels
end
-- Find the labels for category `category` and language object `lang` (which can be nil or a family, but in that case,
-- no labels on a category specified using `regional_categories`; FIXME: it should be possible to implement this). Then
-- filter them down to those that are specified using a lang-specific module and sort them for use in checking
-- properties such as parent and description. We filter down to only lang-specific labels because those specified in a
-- general module (especially [[Module:labels/data/regional]]) won't be able to have proper descriptions and especially
-- parents, which tend to be language-specific. The sort order prioritizes labels that match the category exactly
-- (either through the canonical version or any alias); this is followed by labels that are a prefix of the category
-- (again, either through the canonical version or any alias), so that labels whose categories are specified using
-- `regional_categories` are prioritized. Any other labels are sorted last, so that e.g. if both the label "Alberta" and
-- "Canada" (with alias "Canadian") for lang=en categorize into [[:Category:Canadian English]], we prefer the label
-- "Canada". For cases where e.g. both labels match the category as prefixes, ties are broken by prioritizing the labels
-- found in the lang-specific module whose language matches `lang`.
--
-- Returns two items. The first is a table of all labels categorizing into `category` (subject to the provisos described
-- in `find_labels_for_category()`), in the same format as returned by `find_labels_for_category` in
-- [[Module:labels/utilities]]. (Specifically, the values are objects containing all relevant information on a given
-- label, and the keys are less important.) The second is a list of label objects after filtering and sorting, in the
-- same format as the values in the `all_labels` table. The first return value will be nil if no labels could be found
-- categorizing into `category`, and the second return value will be nil if no labels remain after filtering.
local function get_sorted_labels(category, lang)
local all_labels = find_labels_for_category(category, lang)
if not all_labels then
return nil
end
local m_labels = require(labels_module)
local lang_specific_pattern = "^" .. pattern_escape(m_labels.lang_specific_data_modules_prefix)
local sorted_labels = {}
for _, labelobj in pairs(all_labels) do
if labelobj.module:find(lang_specific_pattern) then
table.insert(sorted_labels, labelobj)
end
end
local function sort_labelobj(a, b)
local function matches_exactly(labelobj)
if labelobj.canonical == category then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if alias == category then
return true
end
end
return false
end
local function matches_as_prefix(labelobj)
if category:find("^" .. pattern_escape(labelobj.canonical) .. " ") then
return true
end
for _, alias in ipairs(labelobj.aliases) do
if category:find("^" .. pattern_escape(alias) .. " ") then
return true
end
end
return false
end
local function tiebreak()
local a_matches_lang = lang and a.lang:getFullCode() == lang:getFullCode()
local b_matches_lang = lang and b.lang:getFullCode() == lang:getFullCode()
if a_matches_lang and not b_matches_lang then
return true
elseif b_matches_lang and not a_matches_lang then
return false
else
return a.canonical < b.canonical
end
end
local a_matches_exactly = matches_exactly(a)
local b_matches_exactly = matches_exactly(b)
if a_matches_exactly and not b_matches_exactly then
return true
elseif b_matches_exactly and not a_matches_exactly then
return false
elseif a_matches_exactly and b_matches_exactly then
return tiebreak()
end
local a_matches_as_prefix = matches_as_prefix(a)
local b_matches_as_prefix = matches_as_prefix(b)
if a_matches_as_prefix and not b_matches_as_prefix then
return true
elseif b_matches_as_prefix and not a_matches_as_prefix then
return false
else
return tiebreak()
end
end
table.sort(sorted_labels, sort_labelobj)
if #sorted_labels > 0 then
return all_labels, sorted_labels
else
return all_labels, nil
end
end
-- Find the categories (only of type `regional_categories` and `plain_categories`) that label `label` categorizes into.
-- Return value is nil if the label couldn't be located at all, otherwise a list of categories (which may be empty).
local function get_categories_for_label(label, lang)
local m_labels = require(labels_module)
local labret = m_labels.get_label_info { label = label, lang = lang }
if not labret.recognized then
return nil
end
local categories = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["plain_categories"] = true})
local reg_cats = m_labels.fetch_categories(labret.canonical or label, labret.data, lang, nil, nil,
{["regional_categories"] = true})
if #reg_cats > 0 then
for _, cat in ipairs(reg_cats) do
table.insert(categories, cat)
end
end
return categories
end
-- Given the sorted labels that categorize into `category`, return the parent categories for the first label that specifies
-- any parents. `default` is the default parent category, usually "Regional LANG" or (if noreg=1 is specified) "Varieties of LANG";
-- it is used if the parent is explicitly given as `true` or "+" (or one of these values occurs among others), or if a parent label
-- was given but didn't categorize into any regional or plain categories, or if no labels with parents could be found. If
-- `all_cats` is specified, all categories associated with all specified parent labels (if more than one is present) are returned;
-- otherwise, only the categories for the first parent label are returned.
--
-- Returns two values: the list of parent categories and the label object from which the categories were derived (or nil if no
-- label object could be found with a `parent` field, in which case the return value of the list of categories is a simple-element
-- list consisting of `default`). The format of the parent category list is such that the list can directly be specified as the
-- value of the `parents` field returned by the raw handler. This means that usually the individual list elements are strings
-- (referring to raw poscat labels), but they may be strings prefixed by "Category:" (for arbitrary categories), or objects of the
-- form {name = "CATEGORY", lang = "LANGCODE", is_label = true} for poscat language labels.
local function get_parents_from_sorted_labels(sorted_labels, category, all_cats)
for _, labobj in ipairs(sorted_labels) do
local parent = labobj.labdata.parent
if parent == true then
parent = {parent}
elseif parent and type(parent) == "string" then
parent = split_on_comma(parent)
end
local function get_parent_cats(par)
if par == true or par == "+" then
return {"+"}
end
if par:find("^cat:") then
return {"ප්රවර්ගය:" .. par:gsub("^cat:", "")}
end
if par:find("^ප්රවර්ගය:") then
return {par}
end
if par:find("^rawposcat:") then
return {(par:gsub("^rawposcat:", ""))}
end
if par:find("^poscat:") then
local langcode, label = par:match("^poscat:([^:]+):(.*)$")
if not langcode then
error(("Parent poscatboiler language label '%s' for label '%s' for category '%s' (defined in module [[%s]]) needs to be of the form 'poscat:LANGCODE:LABEL'"):format(
par, labobj.canonical, category, labobj.module))
end
return {{name = label, lang = langcode, is_label = true}}
end
local this_cats = get_categories_for_label(par, labobj.lang)
if not this_cats then
error(("Parent label '%s' for label '%s' for category '%s' (defined in module [[%s]]) couldn't be located"):format(
par, labobj.canonical, category, labobj.module))
end
return this_cats
end
if parent then
if type(parent) ~= "table" then
error(("Internal error: Expected a string, boolean `true` or list for the value of the parent field for label '%s' for category '%s' (defined in module [[%s]]), but saw type '%s': %s"):format(
labobj.canonical, category, labobj.module, type(parent), mw.dumpObject(parent)))
end
local cats
if all_cats then
cats = {}
for _, par in ipairs(parent) do
local this_cats = get_parent_cats(par)
for _, this_cat in ipairs(this_cats) do
insert_if_not(cats, this_cat)
end
end
else
cats = get_parent_cats(parent[1])
end
if #cats > 0 then
return cats, labobj
end
-- FIXME: If the parent doesn't specify any categories, should we try the next parent or fall back
-- to the parent determined through get_default_parent_cat_from_category() (which is what we currently
-- do)?
return {"+"}, labobj
end
end
return {"+"}, nil
end
local likely_lect_parent_cat = {}
-- Register that `cat` is likely to be a lect cat, so we try to handle it as such in the lect handler when
-- we are called on that category. This avoids the need to have manual allow-lists of nonstandardly-named parent
-- lect categories to handle, such as [[:Category:Assyrian]], [[:Category:Ripuarian Franconian]] ("Franconian" is
-- not a language) and [[:Category:Limburgan-Ripuarian transitional dialects]].
function export.register_likely_lect_parent_cat(cat)
if type(cat) == "string" and not cat:find("^ප්රවර්ගය:") then
likely_lect_parent_cat[cat] = true
end
end
-- Handle lect categories such as [[:Category:New Zealand English]], [[:Category:Late Middle English]],
-- [[:Category:Arbëresh Albanian]], [[:Category:Provençal]] or arbitrarily-named categories like
-- [[:Category:Issime Walser]]. We currently require that lect=1 is specified to the call to {{auto cat}} to avoid
-- overfiring. However, if called from inside, we are processing the breadcrumb for the parent (or conceivably the
-- child) of a lect category, and won't have any params set, so we can't rely on lect=1. In that case, only fire
-- if the category is or ends in the name of a full or etymology-only language, and scrape the category's call to
-- {{auto cat}} to get the appropriate params. This means that nonstandardly-named categories like
-- [[:Category:Issime Walser]] can't be parents of other lect categories. To work around this, either we have to
-- relax the code below to operate on all raw categories (not necessarily a good idea), or we rename the
-- nonstandardly-named categories (e.g. in the case above, to [[:Category:Issime Walser German]], since Walser German
-- is a recognized etymology-only language).
--
-- NOTE: We are able to handle categories for etymology-only families (currently only [[:Category:Middle Iranian]] and
-- [[:Category:Old Iranian]]) and for etymology-only substrate languages (e.g. [[:Category:BMAC substrate]]).
-- There is some special "family" code for the former.
local function lect_handler(category, raw_args, called_from_inside)
if called_from_inside then
-- Avoid infinite loops from wrongly processing non-lect categories. We have a check around line 344 below
-- for categories whose {{auto cat}} doesn't say lect=1, but we still need the following in case of
-- non-existent categories we're being asked to process (e.g. [[:Category:User bcc]] ->
-- [[:Category:Southern Balochi]] (nonexistent) -> [[:Category:Regional Baluchi]] (nonexistent), which
-- causes an infinite loop without the check below.
if category:find("^Regional ") or category:find("ප්රභේද$") or category:find("^Rhymes:") then
return nil
end
-- If called from inside we won't have any params available. See comment above about this. We scrape the
-- category page's call to {{auto cat}} to get the appropriate params, and if that fails, we currently fall back
-- to defaults based on the label(s) that categorize(s) into the category or the name of the category. Since the
-- call from inside is only to get the parent category and breadcrumb, these defaults actually work in most
-- cases but not all; e.g. in the chain [[:Category:Regional Yoruba]] -> [[:Category:Central Yoruba]] ->
-- [[:Category:Ekiti Yoruba]] -> [[:Category:Akurẹ Yoruba]], if we are forced to use default values, we will
-- produce the right parent for [[:Category:Central Yoruba]] but not for [[:Category:Ekiti Yoruba]], where the
-- default parent would be [[:Category:Regional Yoruba]] instead of the correct [[:Category:Central Yoruba]].
local lang, breadcrumb = split_region_lang(category)
if lang or likely_lect_parent_cat[category] then
raw_args = scrape_category_for_auto_cat_args(category)
if raw_args and not ine(raw_args.lect) then
-- We are scraping something like [[:Category:American Sign Language]] that ends in a valid language but is not
-- a lect.
return nil
end
if not raw_args then
-- If we can't parse the scraped {{auto cat}} spec, return default values. This helps e.g. in converting
-- from the old {{dialectboiler}} template and generally when adding new varieties.
local parents, label_with_parent
local function getprop(prop)
return -- ine(raw_args[prop]) or
label_with_parent and label_with_parent.labdata[prop]
end
local sorted_labels = select(2, get_sorted_labels(category, lang))
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category)
if not lang and label_with_parent then
lang = label_with_parent.lang
end
else
parents = {"+"}
end
if not lang then
-- We were instructed to scrape by virtue of `register_likely_lect_parent_cat`, but couldn't scrape
-- anything.
return nil
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang,
getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
local first_parent_cat = parents[1]
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^ප්රවර්ගය:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect
-- handler label).
first_parent_cat = nil
end
track("lect")
export.register_likely_lect_parent_cat(parents[1])
-- NOTE: When called from inside, the description doesn't matter; nor do any parents other than the
-- first. This is because called_from_inside is only set when computing the breadcrumb trail, which
-- only needs the language, first parent and breadcrumb.
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
description = "Foo",
parents = parents,
breadcrumb = breadcrumb or lang:getCanonicalName(),
umbrella = false,
can_be_empty = true,
}, determine_lect_type(category, lang, first_parent_cat)
end
else
return nil
end
end
if not called_from_inside and not ine(raw_args.lect) then
return nil
end
-------------------- 1. Process parameters. -------------------
local boolean = {type = "boolean"}
local sublist = {sublist = "comma without whitespace"}
local args = require("Module:parameters").process(raw_args, {
[1] = true,
lect = boolean,
lang = true,
verb = true,
prep = true,
the = boolean,
def = true,
fulldef = true,
addl = true,
nolink = boolean,
noreg = boolean, -- don't make the default parent be "Regional LANG"; instead, "LANG ප්රභේද"
type = {set = {"extinct", "extant", "reconstructed", "unattested", "constructed"}},
cat = true,
othercat = sublist,
country = sublist,
wp = true,
wikidata = true,
breadcrumb = true,
also = {type = "title", sublist = "comma without whitespace", namespace = 14},
pagename = true, -- for testing or demonstration
})
-------------------- 2. Initialize breadcrumb, regiondesc and language from category. -------------------
-- They may be overridden later.
local lang, breadcrumb, regiondesc, langname
category = args.pagename or category
if not args.lang then
lang, breadcrumb = split_region_lang(category)
if lang then
langname = lang:getCanonicalName()
end
-- The lang and/or breadcrumb may be nil at this point (e.g. we're processing a category like
-- [[:Category:Singlish]] or [[:Category:Polari]] that doesn't have a language in it). We don't throw an error
-- yet because we may be able to fetch the lang, regiondesc and breadcrumb from a label that categorizes into
-- the category.
regiondesc = breadcrumb
else
lang = get_lang(args.lang, "lang", "allow etym")
langname = lang:getCanonicalName()
if category == ucfirst(langname) then
-- breadcrumb and regiondesc should stay nil; breadcrumb will get `category` as a default, and the lack of
-- regiondesc will cause an error to be thrown unless the user gave it explicitly or specified def=.
else
breadcrumb = category:match("^(.*) " .. pattern_escape(langname) .. "$")
if not breadcrumb then
-- Try to infer the region from the parent. See comment at function.
breadcrumb = infer_region_from_lang(category, lang)
end
regiondesc = breadcrumb
end
end
-------------------- 3. Determine labels categorizing into this category. -------------------
local all_labels, sorted_labels = get_sorted_labels(category, lang)
-------------------- 4. Determine parent categories and initialize additional properties. -------------------
-- The first label with a parent is used to fetch additional properties, such as region= and addl=.
local parents
local first_parent_cat = args.cat
local label_with_parent
local function getprop(prop)
return args[prop] or label_with_parent and label_with_parent.labdata[prop]
end
if first_parent_cat then
parents = {first_parent_cat}
if not lang then
error(("lang= not given and unable to parse language from category '%s' (didn't check labels categorizing into the category because cat= explicitly given)"):format(category))
end
else
if sorted_labels then
parents, label_with_parent = get_parents_from_sorted_labels(sorted_labels, category, "all cats")
if not lang and label_with_parent then
lang = label_with_parent.lang
langname = lang:getCanonicalName()
end
else
parents = {"+"}
end
if not lang then
error(("lang= not given, unable to parse language from category '%s' and can't find a label categorizing into the category"):format(category))
end
local default_parent_cat_from_category = get_default_parent_cat_from_category(category, lang, getprop("noreg"))
for i, parent in ipairs(parents) do
if parent == "+" then
parents[i] = default_parent_cat_from_category
end
end
first_parent_cat = parents[1]
end
if type(first_parent_cat) ~= "string" or first_parent_cat:find("^ප්රවර්ගය:") then
-- Only keep `first_parent_cat` if it refers to a raw poscat label (which is probably a lect handler label).
-- WARNING: Code below using `first_parent_cat` must handle nil.
first_parent_cat = nil
end
local othercat = getprop("othercat")
if type(othercat) == "string" then
othercat = split_on_comma(othercat)
end
if othercat then
for _, cat in ipairs(othercat) do
if not cat:find("^ප්රවර්ගය:") then
cat = "ප්රවර්ගය:" .. cat
end
table.insert(parents, cat)
end
end
local countries = getprop("country") or {}
if type(countries) == "string" then
countries = split_on_comma(countries)
end
-- If no breadcrumb, this often happens when the langname and category are the same (happens only with etym-only
-- languages), and the parent category is set below to the full parent, so the breadcrumb should show the
-- language name (or equivalently, the category). If the langname and category are different, we should fall back to
-- the category. E.g. for Singlish, lang=en is specified and we can't infer a breadcrumb because the lect name
-- doesn't end in "English"; in this case we want the breadcrumb to show "Singlish".
breadcrumb = getprop("breadcrumb") or breadcrumb or category
local the_prefix
if args[1] then
regiondesc = args[1]
else
local regionprop = getprop("region")
if regionprop then
regiondesc = regionprop
elseif label_with_parent then
-- It's not clear which of the following two are better. The second one uses the actual label display form,
-- which might be argued to be better, except that it will often be linked to a Wikipedia article about the
-- lect rather than the place. The first one just uses the canonical label directly (which will later be
-- linked to itself if unlinked). A third possibility is to use `label_with_parent.display` if present,
-- otherwise `label_with_parent.canonical`.
regiondesc = label_with_parent.canonical
if label_with_parent.display and regiondesc ~= label_with_parent.display then
track("display-different-from-canonical")
end
-- regiondesc = require(labels_module).get_displayed_label(label_with_parent.canonical, label_with_parent.labdata, lang)
end
end
the_prefix = getprop("the") and "the " or ""
if #countries == 0 then
countries = {regiondesc and the_prefix .. regiondesc or nil}
end
for _, country in ipairs(countries) do
if not country:find("[<=]") then
country = require("Module:links").remove_links(country)
local cat = "ප්රවර්ගය:" .. m_sinhala.sinhala(country) .. " තුළ භාවිතා වන භාෂා"
if page_exists(cat) then
table.insert(parents, cat)
end
end
end
-------------------- 5. Refine the language to an etymology-only child if possible. -------------------
-- Now that we've determined the parent, we look up the parent hierarchy until we find a category naming an
-- etymology-only language. If we find one and it's a child of the language we've determined, use it.
local ancestral_cat = first_parent_cat
local refined_lang
while true do
refined_lang = category_to_lang_name(ancestral_cat)
if refined_lang then
break
end
export.register_likely_lect_parent_cat(ancestral_cat)
local settings, _ = memoizing_lect_handler(ancestral_cat, nil, true)
if not settings then
break
end
ancestral_cat = settings.parents[1]
end
if refined_lang and refined_lang:hasParent(lang) then
lang = refined_lang
langname = lang:getCanonicalName()
end
-------------------- 6. Initialize `additional` with user-specified text and info about labels. -------------------
local additional = getprop("addl")
local function append_addl(addl_text)
if not addl_text then
return
end
if additional then
additional = additional .. "\n\n" .. addl_text
else
additional = addl_text
end
end
if all_labels then
local m_labels_utilities = require(labels_utilities_module)
append_addl(m_labels_utilities.format_labels_categorizing(all_labels, nil,
get_returnable_lang(lang)))
end
-------------------- 7. Augment `additional` with information about etymology-only codes. -------------------
local langname_for_desc
local etymcodes = {}
local function make_code(code)
return ("<code>%s</code>"):format(code)
end
if lang:hasType("etymology-only") and ucfirst(langname) == category then
langname_for_desc = lang:getParentName()
local langcode = lang:getCode()
table.insert(etymcodes, make_code(langcode))
-- Find all alias codes for the etymology-only language.
-- FIXME: There should be a better/easier way of doing this.
local ety_code_to_name = mw.loadData("Module:etymology languages/code to canonical name")
for code, canon_name in pairs(ety_code_to_name) do
if canon_name == langname and code ~= langcode then
table.insert(etymcodes, make_code(code))
end
end
local addl_etym_codes = ("[[Module:etymology_languages/data|Etymology-only language]] code: %s."):format(
serial_comma_join(etymcodes, {conj = "or"}))
append_addl(addl_etym_codes)
else
langname_for_desc = langname
end
-------------------- 8. Try to figure out if this variety is extinct or reconstructed. -------------------
local lect_type = getprop("type")
if not lect_type then
lect_type = determine_lect_type(category, lang, first_parent_cat)
end
local function prefix_addl(addl_text)
if additional then
additional = addl_text .. "\n\n" .. additional
else
additional = addl_text
end
end
if lect_type == "extinct" then
prefix_addl("This lect is [[extinct language|extinct]].")
table.insert(parents, "ප්රවර්ගය:නෂ්ට වූ භාෂා සියල්ල")
elseif lect_type == "reconstructed" then
prefix_addl("This lect is [[reconstructed language|reconstructed]].")
table.insert(parents, "ප්රවර්ගය:Reconstructed languages")
elseif lect_type == "unattested" then
prefix_addl("This lect is {{w|unattested language|unattested}}.")
table.insert(parents, "ප්රවර්ගය:Unattested languages")
elseif lect_type == "constructed" then
prefix_addl("This lect is [[constructed language|constructed]].")
table.insert(parents, "ප්රවර්ගය:Constructed languages")
end
-------------------- 9. Add pseudo-familes to parents. -------------------
for _, pseudofam in ipairs(lang:getPseudoFamilies()) do
table.insert(parents, "Category:" .. pseudofam:getCategoryName())
end
-------------------- 10. Compute `description`. -------------------
local description
local fulldef = getprop("fulldef")
if fulldef then
description = fulldef .. "."
end
if not description then
local def = getprop("def")
if def then
description = ("Terms or senses in %s."):format(def)
end
end
if not description then
if not regiondesc then
-- We need regiondesc for the description unless def= or fulldef= is given, which overrides the part that needs it.
error(("1= (region) not given and unable to infer region from category '%s' given language name '%s'"):
format(category, langname))
end
local lang_en = get_lang("en", true)
local linked_regiondesc = regiondesc
-- Don't try to link if HTML, = sign, template call or embedded link found in text. Embedded links will
-- automatically be converted to English links by JavaScript.
local function linkable(text)
return not text:find("[<={}%[%]|]")
end
if linked_regiondesc:find("<country>") then
if not countries then
error(("Can't specify <country> in region description '%s' when country= not given"):format(linked_regiondesc))
end
-- Link the countries individually before calling serialCommaJoin(), which inserts HTML.
local linked_countries = {}
for _, country in ipairs(countries) do
if linkable(country) then
country = require("Module:links").full_link { lang = lang_en, term = country }
end
table.insert(linked_countries, country)
end
linked_countries = serial_comma_join(linked_countries)
linked_regiondesc = linked_regiondesc:gsub("<country>", replacement_escape(linked_countries))
elseif not getprop("nolink") and linkable(linked_regiondesc) then
-- Even if nolink not given, don't try to link if HTML or = sign found in linked_regiondesc, otherwise
-- we're likely to get an error.
if page_exists(linked_regiondesc) then
-- Only construct a Wiktionary link if the page exists; otherwise construct a Wikipedia link.
linked_regiondesc = require("Module:links").full_link { lang = lang_en, term = linked_regiondesc }
else
linked_regiondesc = ("[[w:%s|%s]]"):format(linked_regiondesc, linked_regiondesc)
end
end
linked_regiondesc = the_prefix .. linked_regiondesc
local no_longer_spoken = lect_type == "extinct" or lect_type == "reconstructed" or lect_type == "unattested"
local verb = getprop("verb") or no_longer_spoken and "formerly spoken" or "spoken"
local prep = getprop("prep")
if not langname_for_desc then
error(category)
end
description = ("Terms or senses in %s as %s%s %s."):format(
langname_for_desc, verb, prep == "-" and "" or " " .. (prep or "in"), linked_regiondesc)
end
-------------------- 11. Compute the Wikipedia articles that go into `topright`. -------------------
local topright_parts = {}
-- Insert Wikipedia article `article` for Wikimedia language `wmcode` into `topright_parts`, avoiding duplication.
local function insert_wikipedia_article(wmcode, article)
if wmcode == "commons" then
insert_if_not(topright_parts, ("{{commons%s}}"):format(
article == category and "" or "|" .. article
))
else
local wparg = ("%s%s"):format(
wmcode == "en" and "" or wmcode .. ":",
article == category and "" or article
)
insert_if_not(topright_parts, ("{{wp%s}}"):format(
wparg == "" and wparg or "|" .. wparg
))
end
end
local function insert_wikipedia_articles_for_wikipedia_specs(specs, default)
for _, article in ipairs(specs) do
local foreign_wiki
if article == true then
article = default
else
if article:find(":[^ ]") then
local actual_article
foreign_wiki, actual_article = article:match("^([a-z][a-z][a-z-]*):([^ ].*)$")
if actual_article then
article = actual_article
end
end
if article == "+" then
article = default
elseif article == "-" then
article = nil
else
article = require("Module:yesno")(article, article)
if article == true then
article = default
end
end
end
if article then
insert_wikipedia_article(foreign_wiki or "en", article)
end
end
end
local function insert_wikipedia_articles_for_wikidata_specs(specs, lang)
if not mw.wikibase then
error(("Unable to retrieve data from Wikidata ID's '%s'; `mw.wikibase` not defined"):format(args.wikidata))
end
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
local ids_without_wmcodes = {}
local ids_with_wmcodes = {}
for _, id in ipairs(specs) do
if id:find(":") then
table.insert(ids_with_wmcodes, id)
else
table.insert(ids_without_wmcodes, id)
end
end
for _, wmcode in ipairs(wikipedia_langs) do
for _, id in ipairs(ids_without_wmcodes) do
local article = mw.wikibase.sitelink(id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
for _, id in ipairs(ids_with_wmcodes) do
local wmcode, wikidata_id = id:match("^(.-):(.*)$")
local article = mw.wikibase.sitelink(wikidata_id, wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if args.wp or args.wikidata then
if args.wp then
insert_wikipedia_articles_for_wikipedia_specs(split_on_comma(args.wp), category)
end
if args.wikidata then
insert_wikipedia_articles_for_wikidata_specs(split(args.wikidata, "%s*,%s*"), lang)
end
elseif category == ucfirst(langname) then
local wikipedia_langs = require(labels_module).get_langs_to_extract_wikipedia_articles_from_wikidata(lang)
for _, wmcode in ipairs(wikipedia_langs) do
local article = lang:getWikipediaArticle("no category fallback", wmcode .. "wiki")
if article then
insert_wikipedia_article(wmcode, article)
end
end
end
if #topright_parts == 0 and sorted_labels then
for _, labobj in pairs(all_labels) do
local wp_specs = labobj.labdata.Wikipedia
if wp_specs then
if type(wp_specs) ~= "table" then
wp_specs = {wp_specs}
end
insert_wikipedia_articles_for_wikipedia_specs(wp_specs, labobj.canonical)
end
local wikidata_specs = labobj.labdata.Wikidata
if wikidata_specs then
if type(wikidata_specs) ~= "table" then
wikidata_specs = {wikidata_specs}
end
insert_wikipedia_articles_for_wikidata_specs(wikidata_specs, labobj.lang)
end
end
end
local topright
if #topright_parts > 0 then
topright = table.concat(topright_parts)
end
-------------------- 12. Return the combined structure of all information. -------------------
track("lect")
export.register_likely_lect_parent_cat(parents[1])
return {
-- FIXME, allow etymological codes here
lang = get_returnable_lang_code(lang),
topright = topright,
description = description,
additional = additional,
parents = parents,
breadcrumb = {name = breadcrumb, nocap = true},
umbrella = false,
can_be_empty = true,
}, lect_type
end
local memoized_responses = {}
memoizing_lect_handler = function(category, raw_args, called_from_inside)
mw.log(category)
local retval = memoized_responses[category]
if not retval then
retval = {lect_handler(category, raw_args, called_from_inside)}
memoized_responses[category] = retval
end
local obj, lect_type = retval[1], retval[2]
return obj, lect_type
end
-- Actual handler for lect categories. See lect_handler() above.
table.insert(raw_handlers, function(data)
local settings, _ = memoizing_lect_handler(data.category, data.args, data.called_from_inside)
return settings, not not settings
end)
return {RAW_CATEGORIES = raw_categories, RAW_HANDLERS = raw_handlers, export = export}
c32vrrir066faflj52199m336cncab7
සැකිල්ල:ja-see-kango/documentation
10
120323
238749
238717
2026-11-11T12:00:51Z
Pinthura
2424
Bot: Replacing category Japanese templates with [[:ප්රවර්ගය:ජපන් සැකිලි|ජපන් සැකිලි]]
238749
wikitext
text/x-wiki
{{documentation subpage}}
{{rfd|section=Template:ja-see-kango, Template:ja-gv}}
Variant of {{temp|ja-see}}, grouping redirects to several Sino-Japanese words ([[漢語#Japanese|''kango'']]) in one Etymology section.
Sometimes different Sino-Japanese morpheme strings sharing identical pronunciation and similar meaning, such as [[器械]] and [[機械]], are treated as one word on Wiktionary. In this case just redirect to the lemma entry (such as [[器械]]), and the template will display both strings of kanji.
Note: Currently {{temp|ja-see}} can redirect to several words at once as well. The two templates are now more similar than different.
<includeonly>
[[ප්රවර්ගය:ජපන් සැකිලි|see-kango]]
[[Category:Disambiguation templates]]
</includeonly>
lalaa43p6jxwixlo6k1amh8zlq0hppc
238750
238749
2026-11-11T12:01:01Z
Pinthura
2424
Bot: Replacing category Disambiguation templates with [[:ප්රවර්ගය:බහුරුත්හරණ සැකිලි|බහුරුත්හරණ සැකිලි]]
238750
wikitext
text/x-wiki
{{documentation subpage}}
{{rfd|section=Template:ja-see-kango, Template:ja-gv}}
Variant of {{temp|ja-see}}, grouping redirects to several Sino-Japanese words ([[漢語#Japanese|''kango'']]) in one Etymology section.
Sometimes different Sino-Japanese morpheme strings sharing identical pronunciation and similar meaning, such as [[器械]] and [[機械]], are treated as one word on Wiktionary. In this case just redirect to the lemma entry (such as [[器械]]), and the template will display both strings of kanji.
Note: Currently {{temp|ja-see}} can redirect to several words at once as well. The two templates are now more similar than different.
<includeonly>
[[ප්රවර්ගය:ජපන් සැකිලි|see-kango]]
[[ප්රවර්ගය:බහුරුත්හරණ සැකිලි]]
</includeonly>
ffelineqcgctpitb4oa6ktkmdei1buo
සැකිල්ල:grc-decl/documentation
10
122098
238772
188206
2026-11-11T12:44:17Z
Pinthura
2424
Bot: Replacing category Ancient Greek inflection-table templates with [[:ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි|පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි]]
238772
wikitext
text/x-wiki
{{documentation subpage}}
This template is intended to be very simple to use. In most cases, it takes two obligatory arguments, the nominative and genitive singular forms of the noun to be declined. [[Module:grc-decl]] figures out what declension they belong to, and generates a table of forms.
==Parameters==
===Numbered parameters===
====Regular nouns====
; {{para|1}}
: Nominative singular.
; {{para|2}}
: Genitive singular.
====Irregular or indeclinable nouns====
; {{para|1}}
: A flag <code>indecl</code> or <code>irreg</code> to indicate that the noun is indeclinable or that its declension is irregular.
; {{para|2}}
# If the noun is indeclinable, the form used for all grammatical cases.
# If the noun is irregular, the nominative singular.
===Named parameters===
; {{para|form}}
: Takes up to three different sets of values:
:# the gender, to add the correct forms of the definite article: one of <code>M</code>, <code>F</code>{{,}} or <code>N</code>. Use <code>MF</code> for words such as {{m|grc|παῖς}} that can be either masculine or feminine, or <code>X</code> to remove articles altogether. Gender is automatically determined by the module for first- and second-declension nouns and some third-declension nouns, but is required otherwise.
:# the numbers shown, one or more of <code>S</code>, <code>D</code>{{,}} or <code>P</code>, or <code>sing</code>, <code>dual</code>{{,}} or <code>plur</code>, for singular, dual{{,}} or plural. <code>full</code> is an alias of <code>SDP</code>, but is not needed, as it is the default for all nouns except <!-- first-declension nouns in {{m|grc||-ᾶς|tr=-}} --> those in {{m|grc||-κλῆς|tr=-}} and {{m|grc||-ώ|tr=-}}, which are only declined in the singular. Note that regardless of the number(s) of the noun, the nominative and genitive must be in the singular.
:# whether to show only the contracted or uncontracted tables of stems in {{m|grc||-εσ, -ᾰσ, -κλῆς|tr=-}}. If <code>open</code> is passed as an argument, only the uncontracted table is shown; if <code>con</code> is passed, only the contracted table is shown; if neither is passed then both tables will be shown.
: The order of the arguments to {{para|form}} does not matter; arguments such as <code>M-plur</code>, <code>MF</code>, <code>sing-F-open</code> are all acceptable. The hyphens are unnecessary, but recommended for clarity.
; {{para|dial}}
: Determines which dialect's forms will be shown. The default is <code>att</code> ([[w:Attic Greek|Attic]]). A code (<code>att</code>) or a dialect name (<code>Attic</code>) can be used, as long as it is found in [[Module:grc:Dialects]]. The dialect name will be shown in parentheses in the title of the table.
: Parameter values containing tildes (<code>~</code>) or slashes (<code>/</code>) are no longer supported. Any template with these values will default to Attic (as long as the parameter does not contain <code>~</code> and <code>att</code>).
: Most dialectal forms are added in [[Module:grc-decl/decl/data]], but a few paradigms are divergent enough to be given in [[Module:grc-decl/decl/staticdata/paradigms]]. Not all dialects have forms assigned to them. To find out if a dialect does, search for the dialect code in [[Module:grc-decl/decl/data]] (if you can decrypt the Lua code).
; {{para|voc|α}}
: Indicates vocative singular in {{m|grc||-ᾰ}} rather than {{m|grc|-η}}, for first-declension masculine nouns in {{m|grc||-ης}}, such as {{m|grc|γεωμέτρης}}, vocative {{m|grc|γεωμέτρᾰ}}. This parameter is not needed for nouns in {{m|grc|-της}}, whose vocative always ends in {{m|grc||-ᾰ}}.
; {{para|voc|-}}
: Indicates that a noun has no vocative.
; {{para|NS}}, {{para|GD}}, {{para|DP}}, ...
: used to supply specific irregular forms (the given examples are the nominative singular, genitive dual, and dative plural, respectively). If both contracted and uncontracted tables are shown, 1 and 2 may be appended to the end (VS1, AP2, etc.) to differentiate between tables (if no number is appended the irregular form will be shown for both tables.)
; {{para|titleapp}}
: which adds text to the end of the titlebar. This overrides a titleapp automatically generated by {{para|dial}}.
; {{para|title}}
: overrides the entire title.
; {{para|notes}}
: adds supplementary text to be displayed below the footnotes.
==Notes==
* Even when the noun in question is declined only in the plural, this template takes the nominative and genitive singular.
* With few exceptions, the Attic nominative and genitive should be given, even if the inflection displayed is a dialectical alternative (but with the dialectical stem: e.g. {{temp|grc-decl|[[ἄνηθον]]|ἀνήθου|dial=~aio}}, but {{temp|grc-decl|[[ἄνητον]]|ἀνήτου|dial=aio}} (not **ἀνήτω, even though that form will be displayed.)
* If the noun has an irregular nominative or genitive singular, it must still be supplied as if it were regular, and then overriden with {{para|NS}} or {{para|GS}} (see below).
* With first and second declension nouns, as well as some third declension nouns (specifically stems in -εσ, -ᾰσ, -ῐ, -ῠ, -ωϝ, -οι) it is usually acceptable to use simply the genitive ending instead of the entire genitive (e.g. ῐ̔́ππος|ου), however with most third-declension nouns it is necessary to supply the entire genitive.
* Length marks on α,ι,υ are mandatory in case endings. See [[WT:AGRC]] for instructions on how to order combining diacritics.
* Forms with parentheses that represent a pair of forms, such as forms with and without movable nu, are expanded so that they will show up in search results: {{lang|grc|οἷσι(ν)}} → {{lang|grc|οἷσι}}, {{lang|grc|οἷσιν}}
{{isAccelerated}}
<includeonly>
[[ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි]]
[[Category:Ancient Greek noun inflection-table templates]]
</includeonly>
nbddn6492vudhsft8vsfdzysbudp8rt
සැකිල්ල:grc-conj/documentation
10
122126
238770
188236
2026-11-11T12:43:57Z
Pinthura
2424
Bot: Replacing category Ancient Greek inflection-table templates with [[:ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි|පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි]]
238770
wikitext
text/x-wiki
{{documentation subpage}}
This template uses [[Module:grc-conj]] to generate verb inflection table templates. The first argument is the type of table to be generated, followed by one to four stems depending on the tense. Each stem should have no accents, but all short {{lang|grc|α}}, {{lang|grc|ι}}, {{lang|grc|υ}} should be marked with a breve, either combining ({{lang|grc|ᾰ}}, {{lang|grc|ῐ}}, {{lang|grc|ῠ}}) or spacing ({{lang|grc|ἀ˘}}). The breve can be added with {{temp|subst:chars|grc}}. (See {{section link|Template:chars/documentation#Ancient_Greek}} for more information.)
==Parameters==
===Tenses===
The first parameter receives a code for a tense, with an optional suffix. The codes are <code>pres</code> (present tense), <code>imperf</code> (imperfect tense), <code>fut</code> (future tense), <code>perf</code> (perfect tense), <code>plup</code> (pluperfect tense), <code>futp</code> (future perfect tense). The suffixes are listed below. If there are two or more conjugation tables in a section, they are commonly placed in order by tense.
====Present====
The present tense requires one argument: the stem used for both the present and the mediopassive.
; <code>pres</code>
: simple {{lang|grc|-ω}} presents
:* {{temp|grc-conj|pres|λῡ}} ({{m|grc|λύω}})
; <code>pres-con-a</code>
: contracted {{lang|grc|-άω}} presents
:* {{temp|grc-conj|pres-con-a|τῑμ}} ({{m|grc|τῑμάω}})
; <code>pres-con-e</code>
: contracted {{lang|grc|-έω}} presents
:* {{temp|grc-conj|pres-con-e|ποι}} ({{m|grc|ποιέω}})
; <code>pres-con-o</code>
: contracted {{lang|grc|-όω}} presents
:* {{temp|grc-conj|pres-con-o|δηλ}} ({{m|grc|δηλόω}})
; <code>pres-con-eta</code>
: contracted {{lang|grc|-ήω}} presents ({{m|grc|διψάω}}, {{m|grc|πεινάω}}, {{m|grc|χράω}}, etc.)
:* {{temp|grc-conj|pres-con-eta|ζ}} ({{m|grc|ζῶ}})
; <code>pres-con-e-mono</code>
: contracted two-syllable {{lang|grc|-έω}} presents which do not contract {{lang|grc|ε}} with {{lang|grc|ο}}/{{lang|grc|ω}} ({{m|grc|θέω}}, {{m|grc|πνέω}}, {{m|grc|ῥέω}}, {{m|grc|χέω}}, etc.)
:* {{temp|grc-conj|pres-con-e-mono|πλ}} ({{m|grc|πλέω}})
; <code>pres-ami</code>
: athematic {{lang|grc|-ημῐ}} presents with underlying {{lang|grc|-α-}}
:* {{temp|grc-conj|pres-ami|ἱ˘στ}} ({{m|grc|ἵστημι|ἵστημῐ}})
; <code>pres-emi</code>
: athematic {{lang|grc|-ημῐ}} presents with underlying {{lang|grc|-ε-}}
:* {{temp|grc-conj|pres-emi|τῐθ}} ({{m|grc|τίθημι|τίθημῐ}})
; <code>pres-omi</code>
: athematic {{lang|grc|-ωμῐ}} presents
:* {{temp|grc-conj|pres-omi|δῐδ}} ({{m|grc|δίδωμι|δίδωμῐ}})
; <code>pres-numi</code>
: athematic {{lang|grc|-νῡμῐ}} presents
:* {{temp|grc-conj|pres-numi|δεικ}} ({{m|grc|δείκνῡμι|δείκνῡμῐ}})
====Imperfect====
The imperfect tense requires one argument: the stem used for both the present and the mediopassive (which usually has an [[w:Ancient Greek augment|augment]]).
; <code>imperf</code>
: simple {{lang|grc|-ον}} imperfects
:* {{temp|grc-conj|imperf|ἐλῡ}} ({{m|grc|ἔλῡον}})
; <code>imperf-con-a</code>
: contracted {{lang|grc|-ᾰον}} imperfects
:* {{temp|grc-conj|imperf-con-a|ἐτῑμ}} ({{m|grc|ἐτίμων}})
; <code>imperf-con-e</code>
: contracted {{lang|grc|-εον}} imperfects
:* {{temp|grc-conj|imperf-con-e|ἐποι}} ({{m|grc|ἐποίουν}})
; <code>imperf-con-o</code>
: contracted {{lang|grc|-οον}} imperfects
:* {{temp|grc-conj|imperf-con-o|ἐδηλ}} ({{m|grc|ἐδήλουν}})
; <code>imperf-con-eta</code>
: contracted {{lang|grc|-ηον}} imperfects
:* {{temp|grc-conj|imperf-con-eta|ἐζ}} ({{m|grc|ἔζων}})
; <code>imperf-con-e-mono</code>
: contracted two-syllable {{lang|grc|-εον}} imperfects which do not contract {{lang|grc|ε}} with {{lang|grc|ο}}/{{lang|grc|ω}}
:* {{temp|grc-conj|imperf-con-e-mono|ἐπλ}} ({{m|grc|ἔπλεον}})
; <code>imperf-ami</code>
: athematic {{lang|grc|-ημῐ}} imperfects with underlying {{lang|grc|-α-}}
:* {{temp|grc-conj|imperf-ami|ἱστ}} ({{m|grc|ἵστην}})
; <code>imperf-emi</code>
: athematic {{lang|grc|-ημῐ}} imperfects with underlying {{lang|grc|-ε-}}
:* {{temp|grc-conj|imperf-emi|ἐτῐθ}} ({{m|grc|ἐτίθην}})
; <code>imperf-omi</code>
: athematic {{lang|grc|-ωμῐ}} imperfects
:* {{temp|grc-conj|imperf-omi|ἐδῐδ}} ({{m|grc|ἐδίδουν}})
; <code>imperf-numi</code>
: athematic {{lang|grc|-νῡμῐ}} imperfects
:* {{temp|grc-conj|imperf-numi|ἐδεικ}} ({{m|grc|ἐδείκνῡν}})
====Future====
The future tense takes two arguments: the active and middle stem, and the passive stem. If the passive stem is omitted the template will omit the passive.
; <code>fut</code>
: simple {{lang|grc|-ω}} futures
:* {{temp|grc-conj|fut|λῡσ|λῠθ}} ({{m|grc|λύσω}}, {{m|grc|λῠθήσομαι}})
; <code>fut-ln</code> or <code>fut-con-e</code>
: contracted futures in {{lang|grc|-ῶ}} (active) or {{lang|grc|-οῦμαι}} (middle), whose stem often ends in a liquid or nasal ({{lang|grc|λ}}, {{lang|grc|μ}}, {{lang|grc|ν}}, {{lang|grc|ρ}}); the future passive endings are no different from those of <code>fut</code>
:* {{temp|grc-conj|fut-ln|φᾰν|φᾰν}} ({{m|grc|φανῶ}}, {{m|grc|φᾰνήσομαι}})
; <code>fut-con-a</code>
: contracted future with α-contract endings (active {{lang|grc|-ῶ}}, middle {{lang|grc|-ῶμαι}}; in Attic Greek this usually developed from {{lang|grc|-ᾰ́σω}} when the {{lang|grc|σ}} disappeared); the future passive endings are no different from <code>fut</code>
:* {{temp|grc-conj|fut-con-a|ἐλ|ἐλᾰθ}} ({{m|grc|ἐλῶ}}, {{m|grc|ἐλᾰθήσομαι}})
====Aorist====
The aorist tense takes four arguments: the active and middle stem with augment, the active and middle stem without augment, the passive stem with augment, the passive stem without augment.
; <code>aor-1</code>
: first aorists
:* {{temp|grc-conj|aor-1|ἐλῡσ|λῡσ|ἐλῠθ|λῠθ}} ({{m|grc|ἔλῡσᾰ}}, {{m|grc|ἐλύθην}})
; <code>aor-2</code>
: second aorists
:* {{temp|grc-conj|aor-2|ἐλῐπ|λῐπ|ἐλειφθ|λειφθ}} ({{m|grc|ἔλῐπον}}, {{m|grc|ἐλείφθην}})
; <code>aor-ami</code>
: athematic second aorists with underlying {{lang|grc|-α-}}
:* {{temp|grc-conj|aor-ami|ἐστ|στ|ἐστᾰθ|στᾰθ}} ({{m|grc|ἔστην}}, {{m|grc|ἐστάθην}})
; <code>aor-emi</code>
: athematic second aorists with underlying {{lang|grc|-ε-}}
:* {{temp|grc-conj|aor-emi|ἐθ|θ|ἐτεθ|τεθ}} ({{m|grc|ἔθετον}}, {{m|grc|ἐτέθην}})
; <code>aor-hmi</code>
: athematic second aorists with underlying {{lang|grc|-η-}}
:* {{tl|grc-conj|aor-hmi|ἐπλ|πλ|form=mid}} ({{m|grc|ἐπλήμην}}
; <code>aor-omi</code>
: athematic second aorists with underlying {{lang|grc|-ο-}}
:* {{temp|grc-conj|aor-omi|ἐδ|δ|ἐδοθ|δοθ}} ({{m|grc|ἔδοτον}}, {{m|grc|ἐδόθην}})
; <code>aor-wmi</code>
: athematic second aorists with underlying {{lang|grc|-ω-}}
:* {{temp|grc-conj|aor-wmi|ἐγν|γν|form=act}} ({{m|grc|ἔγνων}}
; <code>aor-numi</code>
: athematic second aorists, somewhat reminiscent of verbs whose present tense ends in {{lang|grc|-νῡμῐ}}
:* {{temp|grc-conj|aor-numi|ἐδ|δ}} ({{m|grc|ἔδῡν}})
====Perfect====
The perfect tense takes two arguments: the active stem and the mediopassive stem (both usually [[w:Ancient Greek verbs#Perfect tenses|reduplicated]]). If the mediopassive stem ends in a consonant, the template will detect and modify it.
; <code>perf</code>
: typical perfects
:* {{temp|grc-conj|perf|λελῠκ|λελῠ}} ({{m|grc|λέλῠκᾰ}}, {{m|grc|λέλῠμαι}})
:* {{temp|grc-conj|perf|λελοιπ|λελειπ}} ({{m|grc|λέλοιπᾰ}}, {{m|grc|λέλειμμαι}})
:* {{temp|grc-conj|perf|πεποιθ|πεπειθ}} ({{m|grc|πέποιθᾰ}}, {{m|grc|πέπεισμαι}})
:* {{temp|grc-conj|perf|πεπρᾱγ|πεπρᾱγ}} ({{m|grc|πέπρᾱγᾰ}}, {{m|grc|πέπρᾱγμαι}})
:* {{temp|grc-conj|perf|ἠγγελκ|ἠγγελ}} ({{m|grc|ἤγγελκᾰ}}, {{m|grc|ἤγγελμαι}})
;* {{temp|grc-conj|perf|πεφην|πεφᾰν}} ({{m|grc|πέφηνᾰ}}, {{m|grc|πέφᾰσμαι}})
:* {{temp|grc-conj|perf|πεπομφ|πεπεμφ}} ({{m|grc|πέπομφᾰ}}, {{m|grc|πέπεμμαι}})
;* {{temp|grc-conj|perf||ἐληλεγχ|form=mp}} ({{m|grc|ἐλήλεγμαι}})
; <code>perf-ami</code>
: athematic second perfects (only supports active)
* {{temp|grc-conj|perf-ami|ἐστ}} ({{m|grc|ἔστᾰτον}})
====Pluperfect====
The pluperfect tense takes two arguments: the pluperfect active stem and the pluperfect mediopassive stem (both usually with reduplication and augment). Formerly an additional argument was used to form the perfect mediopassive participle if the pluperfect mediopassive stem ends in a consonant: the perfect mediopassive stem (usually with reduplication but without augment). If the mediopassive stem ends in a consonant, the template will detect and modify it.
; <code>plup</code>
: typical pluperfects
:* {{temp|grc-conj|plup|ἐλελῠκ|ἐλελῠ}} ({{m|grc|ἐλελύκειν}}, {{m|grc|ἐλέλῠμην}})
:* {{temp|grc-conj|plup|ἐλελοιπ|ἐλελειπ|λελειπ}} ({{m|grc|ἐλελοίπειν}}, {{m|grc|ἐλελείμμην}})
:* {{temp|grc-conj|plup|ἐπεποιθ|ἐπεπειθ|πεπειθ}} ({{m|grc|ἐπεποίθειν}}, {{m|grc|ἐπεπείσμην}})
:* {{temp|grc-conj|plup|ἐπεπρᾱγ|ἐπεπρᾱγ|πεπρᾱγ}} ({{m|grc|ἐπεπράγειν}}, {{m|grc|ἐπεπράγμην}})
:* {{temp|grc-conj|plup|ἠγγελκ|ἠγγελ|ἠγγελ}} ({{m|grc|ἠγγήλκειν}}, {{m|grc|ἤγγελμαι}})
:* {{temp|grc-conj|plup|ἐπεφην|ἐπεφᾰν|πεφᾰν}} ({{m|grc|ἐπεφήνειν}}, {{m|grc|ἐπεφάσμην}})
:* {{temp|grc-conj|plup|ἐπεπομφ|ἐπεπεμφ|πεπομφ}} ({{m|grc|ἐπεπόμφειν}}, {{m|grc|ἐπεπέμμην}})
:* {{temp|grc-conj|plup||ἐληλεγχ|ἐληλεγχ|form=mp}} ({{m|grc|ἐληλέγμην}})
; <code>plup-ami</code>
: athematic second perfects (only supports active)
* {{temp|grc-conj|plup-ami|ἐστ}}
====Future perfect====
The future perfect requires one argument: the bare stem. It generates middle forms by default, as future perfect active is attested in scant few verbs.
* {{temp|grc-conj|futp|λελῡσ}} ({{m|grc|λελύσομαι}})
* {{temp|grc-conj|futp|τεθνηξ|form=full}} ({{m|grc|τεθνήξω}})
===Voice and contraction===
{{para|form}} controls which voices will be displayed, and whether uncontracted or contracted forms are displayed. At most two hyphen-separated values can be included.
The voice codes are <code>act</code> (active voice), <code>mid</code> (middle voice), <code>pass</code> (passive voice), <code>am</code> (active and middle voices), <code>ap</code> (active and passive voices), <code>mp</code> (middle and passive voices or mediopassive voice), <code>full</code> (all voices).
The contraction codes are <code>con</code> (contracted forms), <code>open</code> (uncontracted forms; not currently used).
The default for most tenses is <code>full</code>, but the future perfect shows middle forms by default, and the athematic second perfect and the athematic second pluperfect can only show active forms (there are no mediopassive forms in these paradigms). For the future, aorist, perfect{{,}} and pluperfect, the displayed voices depend on the stems provided. A future-tense table shows active and middle forms if the passive stem is omitted and passive forms if the active and middle stem is omitted. An aorist-tense table shows active and middle forms if the passive indicative stem is omitted and passive forms if the active and middle indicative stem is omitted. Perfect- and pluperfect-tense tables show active forms if the mediopassive stem is omitted and mediopassive forms if the active stem is omitted.
===Dialect===
The dialect can be specified in the {{para|dial}} parameter. The most commonly used codes are <code>aio</code> (Aeolic), <code>att</code> (Attic), <code>dor</code> (Doric), <code>epi</code> (Epic), <code>ion</code> (Ionic), <code>koi</code> (Koine), and <code>poi</code> (Poetic); see [[Module:grc:Dialects]] for more. If {{para|dial}} is not present, the table displays Attic or Koine forms. For some dialects, [[Module:grc-conj]] will display conjugated forms with endings that are different from the Attic or Koine endings. Some examples of entries with a particularly large number of dialectal tables: {{m|grc|ἀκούω}}, {{m|grc|ἔρχομαι}}, {{m|grc|λαμβάνω}}, {{m|grc|ὁράω}}.<!--
Entries with more than one dialect:
αἰνέω att, dor, epi, ion
αἱρέω epi, koi
βάλλω att, epi, koi
βούλομαι att, koi
γαμέω epi, koi
γηθέω boi, dor, epi
γιγνώσκω aio, ion, koi
δαμνάω epi, ion
δείκνυμι epi, ion
διαρρέω Koine, att, epi
δύω epi, koi
εἴρω epi, koi
θέω epi, ion
θεάομαι att, dor, koi
καθίζω dor, epi, ion
καταλαμβάνω aio, ion
κλαίω ato, att, epi, ion, les
κτάομαι att, ion
κτείνω epi, les
λαμβάνω epi, ion, koi, tra
λείπω epi, koi
λούω dor, epi, hom, koi
μάχομαι att, epi
μέλλω epi, ion
μεταλλάω dor, epi
νέω epi, ion
ναυμαχέω att, ion
νικάω dor, epi, ion
νοέω epi, ion
νωμάω dor, epi
οἰκέω epi, ion
οὐτάω epi, ion
πάσχω dor, epi
πέλω epi, ion
πέμπω dor, epi, ion
πέρνημι att, epi, ion, late
πήγνυμι aio, dor, epi
πίνω epi, ion
πείθω hom, poi
πειράω att, ion
πετάννυμι att, epi
πλάσσω att, epi, poi
πλήσσω att, dor, epi
ποιέω dor, epi, ion
πολιορκέω att, ion
πράσσω att, epi, ion
προΐημι att, epi
πυνθάνομαι dor, epi, poi
σείω epi, ion
σπεύδω epi, kre
συμπίνω epi, ion
συνάγω dor, epi
σχίζω epi, poi
τέμνω att, epi
τίθημι epi, ion
τίνω att, epi
φεύγω epi, ion, koi
φορέω epi, ion, koi
φύω epi, koi
χέω epi, late
ἀΐσσω att, ion
ἀγγέλλω att, dor, epi, ion, koi
ἀείδω att, epi
ἀκούω ato, epi, ion, koi, lak
ἀνίστημι att, epi, poi
ἀποδείκνυμι epi, ion
ἀποπλέω att, ion
ἀποπλήσσω att, dor, epi
ἀπόλλυμι dor, epi
ἀράομαι aio, ion
ἀφίημι epi, ion
ἀφαιρέω ion, koi
ἁνδάνω epi, ion
ἄγω dor, ion
ἐγείρω aio, epi
ἐθέλω epi, ion
ἐκβάλλω epi, koi
ἐκρέω att, epi
ἐμέω att, epi
ἐμβάλλω epi, koi
ἐπιλαμβάνω ion, late
ἐπιτέμνω att, epi
ἐργάζομαι dor, ion
ἔρχομαι dor, epi, ion, koi, tra
ἵζω ion, koi
ἵημι att, epi, ion
ἵστημι dor, epi
ὀδύρομαι epi, ion
ὁράω aio, att, dor, epi, ion
ὄζω dor, ion
ὄλλυμι dor, epi
ὑφαίνω epi, koi
ῥέω Koine, att, epi
ῥαίνω att, ion
-->
If the forms in the table are used in more than one dialect, specify one in the {{para|dial}} parameter and use <code>titleapp</code> to list all the dialects in the titlebar. When two dialects have different sets of forms, add two tables; there is no way to display them in the same table except by manually inputting the forms (which is not recommended).
===Other parameters===
* {{para|indonly|1}}, which suppresses participles, infinitives, and all moods except the indicative
* {{para|titleapp}}, which specifies text to be appended to the titlebar (for example, dialectal information. Typical usage: {{temp|grc-conj|perf|κεκληγ|titleapp=(<nowiki>{{grc-epi}}</nowiki>)}}, yielding '''Perfect: {{l-self|grc|κέκληγᾰ|tr=-}} ({{grc-epi}})'''.
* {{para|prefix}}, required in certain compound verbs due to special rules regarding accent:
** Required if the stem contains augment or reduplication, has only one vowel (including said augment/reduplication) after the prefix, and is not contracted or athematic. Pluperfects and future perfects are exempt. Example: second aorist {{l|grc|εἰσῆλθον}}. (Without this argument the template would generate {{lang|grc|**εἴσηλθον}}.
** Required for actives of present, future, and first aorist, if the stem has only one vowel after the prefix. Example: present {{l|grc|ἐκλείπω}}. (The form in question is {{l|grc|ἐκλεῖπον}}; without this argument the template would generate {{lang|grc|**ἔκλειπον}}.)
:The examples above would be coded, respectively:
:* {{temp|grc-conj|aor-2|εἰσηλθ|εἰσελθ|form=act|prefix=εἰσ}}
:* {{temp|grc-conj|pres|ἐκλειπ|prefix=ἐκ}}
===Customizing forms===
Also, every form can be specifically customized in an entry. For example, if the active subjunctive first singular form specified by the template is {{lang|grc|λύω}}, but the actual form used for the word is {{lang|grc|λυῶ}}, this would be accomplished with the syntax: <code>AS1S=λυῶ</code>.<!-- Find real example. --> The cells are each named with an abbreviated form of their name in the following order: Voice, Mood, Person, Number. So:
* Active indicative first singular = AI1S
* Passive (or middle/passive) optative third plural = PO3P
* Imperative forms use C (think command). I was already taken by indicative. Thus:
* Active imperative second dual = AC2D
* Infinitives have only two characters: active infinitive = AI
* Participles are sorted by gender and have three characters: middle participle feminine = MPF
<includeonly>[[ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි|conj]] [[Category:Ancient Greek verb inflection-table templates| ]]</includeonly>
p0lgj7f7kd6svziws8b8lzqbzmfq27o
සැකිල්ල:grc-adecl/documentation
10
122191
238771
188336
2026-11-11T12:44:07Z
Pinthura
2424
Bot: Replacing category Ancient Greek inflection-table templates with [[:ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි|පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි]]
238771
wikitext
text/x-wiki
{{documentation subpage}}
This template invokes [[Module:grc-decl]] to generate declension tables for Ancient Greek adjectives. It is intended to be very simple to use. It takes up to two numbered parameters, depending on the form of the adjective:
* '''Three-part''' adjectives take the '''masculine''' nominative singular, followed by the '''feminine''' nominative singular, e.g. {{temp|grc-adecl|ᾰ̓γᾰθός|ᾰ̓γᾰθή}}, {{temp|grc-adecl|ἡδῠ́ς|ἡδεῖᾰ}}.
* '''Two-part''' adjectives of the '''second declension''' take the '''masculine''' nominative singular, followed by the '''neuter''' nominative singular, e.g. {{temp|grc-adecl|ῑ̔́λεως|ῑ̔́λεω}}.
* '''Two-part''' adjectives of the '''third declension''' take the pure stem '''only''', e.g. {{temp|grc-adecl|εὔελπῐδ}}, except ''s''-stems, which take the masculine and neuter nominative singular forms: {{temp|grc-adecl|ἀ˘ληθής|ες}}. The accentuation should match that of the neuter nominative singular.
* '''One-part''' adjectives lacking a neuter form should use {{temp|grc-decl|2=form=MF}}.
===Notes===
* If the noun has an irregular nominative singular, it must still be supplied as if it were regular, and then overridden with {{para|MNS}}, {{para|FNS}}, or {{para|NNS}} (see below).
* With three-part adjectives, and second-declension two-part adjectives, it is usually acceptable to pass just the ending as the second argument (e.g. {{temp|grc-adecl|ᾰ̓γᾰθός|ή}}, {{temp|grc-adecl|ῑ̔́λεως|ω}}, {{temp|grc-adecl|ἑκών|οῦσᾰ}}).
* Length marks on {{m|grc|α}}, {{m|grc|ι}}{{,}} or {{m|grc|υ}} are mandatory in case endings if they cannot be inferred based on accent or the supported inflectional patterns. See [[WT:AGRC]] for instructions on how to order combining diacritics, or use {{temp|subst:chars|grc}}
* The second parameter (the feminine or neuter form) can be shortened to just the ending, except when there is a stem augmentation: {{temp|grc-adecl|ἡδῠ́ς|εῖᾰ}} will work, but {{temp|grc-adecl|ἡδύς|ᾰ}} will not.
* To remove unattested adverbs, comparatives and superlatives, use
*: {{para|adv|-}}
*: {{para|comp|-}}
*: {{para|super|-}}
===Other arguments===
; {{para|form}}
: Determines whether to show only the contracted or uncontracted tables of stems in {{lang|grc|-εσ}}, as well as {{lang|grc|-εος/-έᾱ/-εον}}. If <code>open</code> is passed as an argument, only the uncontracted table is shown; if <code>con</code> is passed, only the contracted table is shown; if neither is passed then both tables will be shown.
: {{para|form|comp}} indicates that the Attic contracted forms of comparatives will be shown, such as {{m|grc|μείζω}}, the masculine and feminine accusative singular of {{m|grc|μείζων}}. {{para|deg|comp}} should be used instead, because it also removes the automatically generated comparative and superlative forms.
; {{para|deg|comp}}, {{para|deg|super}}
: Indicates that the adjective being declined is a comparative and superlative. Both of these prevent automatically generated comparative and superlative forms from being shown, and {{para|deg|comp}} adds the Attic contracted forms of comparatives, such as {{m|grc|μείζω}}, the masculine and feminine accusative singular of {{m|grc|μείζων}}, if applicable.
; {{para|dial}}
: Used to control the dialects shown by displaying a table of dialectical forms. Choose a dialect by supplying the appropriate dialect code from [[Module:grc:Dialects]]: for example, <code>ion</code> for Ionic. This will also add the dialect to the titlebar, which can be overridden with {{para|titleapp}}. Only one dialect can be displayed in a given instance of the template.
; {{para|MNS}}, {{para|FGD}}, {{para|NDP}}, ...
: Used to supply specific irregular forms (the given examples are the masculine nominative singular, feminine genitive dual, and neuter dative plural, respectively). If both contracted and uncontracted tables are shown, 1 and 2 may be appended to the end (MVS1, FAP2, etc.) to differentiate between tables (if no number is appended the irregular form will be shown for both tables.)
; {{para|MNSn}}, {{para|FGDn}}, {{para|NDPn}}, ...
: Used to add new footnotes or override existing ones.
; {{para|titleapp}}
: Adds text to the end of the titlebar. This overrides a titleapp automatically generated by {{para|dial}}.
; {{para|title}}
: Overrides the entire title.
; {{para|notes}}
: Adds supplementary text to be displayed below the footnotes.
; {{para|fstem}}
: Supplied to override the feminine stem (e.g. {{temp|grc-adecl|δῐπλόος|δῐπλόᾱ|4=fstem=δῐπλε}}; {{temp|grc-adecl|βᾰθῠ́ς|βᾰθεῖᾰ|4=fstem=βᾰθε|5=dial=ion}}).
; {{para|hp}}
: Short for "heavy penult", to be used as a shortcut when an adjective in {{m|grc|-ος}} has a penult that is long by position: that is, contains two consonants, including {{m|grc|ξ}}, {{m|grc|ψ}}, {{m|grc|ζ}}. Such an adjective will have comparative and superlative forms in {{m|grc||-ότερος, -ότᾰτος}}; without this argument the template would generate {{m|grc||-ώτερος, -ώτᾰτος}}.
{{isAccelerated}}
<includeonly>
[[ප්රවර්ගය:පුරාතන ග්රීක වරනැගීම්-වගු සැකිලි]]
</includeonly>
5wu1szris70fnx2nyvlpuwc1nh21cx5
ප්රවර්ගය:Unattested languages
14
125209
238806
200775
2026-09-23T01:34:07Z
en>Benwing2
0
use {{auto cat}}
238806
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238807
238806
2026-11-12T06:36:26Z
Lee
19
[[:en:Category:Unattested_languages]] වෙතින් එක් සංශෝධනයක්
238806
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
සැකිල්ල:movecat
10
126866
238810
197475
2026-02-07T12:34:33Z
en>Kutchkutch
0
238810
wikitext
text/x-wiki
__EXPECTUNUSEDCATEGORY__
{{#invoke:checkparams|error}}<!-- Validate template parameters
--><strong style="font-size:larger; font-weight:normal;">''This category should be empty. The contents of this category should now be found at [[:Category:{{{1|}}}|{{{alt1|{{{1}}}}}}]]{{#if:{{{2|}}}| or [[:Category:{{{2}}}|{{{alt2|{{{2}}}}}}]]}}{{#if:{{{3|}}}| or [[:Category:{{{3}}}|{{{alt3|{{{3}}}}}}]]}}{{#if:{{{4|}}}| or [[:Category:{{{4}}}|{{{alt4|{{{4}}}}}}]]}}{{#if:{{{5|}}}| or [[:Category:{{{5}}}|{{{alt5|{{{5}}}}}}]]}}. If any pages [[Special:WhatLinksHere/{{FULLPAGENAME}}|link here]], please update the link, as this page may be deleted.''</strong>
<includeonly><!--
-->{{{Category|<!--
-->{{#ifeq:{{NAMESPACE}}|Category<!--
-->|<!--
-->[[Category:Category redirects]]<!--
-->{{#ifeq:{{PAGESINCATEGORY:{{PAGENAME}}|all}}|0<!--
-->|<!--
-->[[Category:Empty category redirects]]<!--
-->|<!--
-->[[Category:Non-empty category redirects]]<!--
-->[[Category:{{{1|}}}|!{{PAGENAME}}]]<!--
-->}}<!--
-->{{#ifeq:{{PAGENAME}}|{{{1|}}}<!--
-->|<!--
-->[[Category:Broken category redirects|!{{PAGENAME}}]]<!--
-->|<!--
-->{{#ifexist:Category:{{{1|}}}<!--
-->|<!--
do nothing
-->|<!--
-->[[Category:Broken category redirects]]<!--
-->}}<!--
-->}}<!--
-->}}<!--
-->}}}<!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
botqag9jqhciz2b5g06x9b8y18ebypy
238811
238810
2026-11-12T06:42:58Z
Lee
19
[[:en:Template:movecat]] වෙතින් එක් සංශෝධනයක්
238810
wikitext
text/x-wiki
__EXPECTUNUSEDCATEGORY__
{{#invoke:checkparams|error}}<!-- Validate template parameters
--><strong style="font-size:larger; font-weight:normal;">''This category should be empty. The contents of this category should now be found at [[:Category:{{{1|}}}|{{{alt1|{{{1}}}}}}]]{{#if:{{{2|}}}| or [[:Category:{{{2}}}|{{{alt2|{{{2}}}}}}]]}}{{#if:{{{3|}}}| or [[:Category:{{{3}}}|{{{alt3|{{{3}}}}}}]]}}{{#if:{{{4|}}}| or [[:Category:{{{4}}}|{{{alt4|{{{4}}}}}}]]}}{{#if:{{{5|}}}| or [[:Category:{{{5}}}|{{{alt5|{{{5}}}}}}]]}}. If any pages [[Special:WhatLinksHere/{{FULLPAGENAME}}|link here]], please update the link, as this page may be deleted.''</strong>
<includeonly><!--
-->{{{Category|<!--
-->{{#ifeq:{{NAMESPACE}}|Category<!--
-->|<!--
-->[[Category:Category redirects]]<!--
-->{{#ifeq:{{PAGESINCATEGORY:{{PAGENAME}}|all}}|0<!--
-->|<!--
-->[[Category:Empty category redirects]]<!--
-->|<!--
-->[[Category:Non-empty category redirects]]<!--
-->[[Category:{{{1|}}}|!{{PAGENAME}}]]<!--
-->}}<!--
-->{{#ifeq:{{PAGENAME}}|{{{1|}}}<!--
-->|<!--
-->[[Category:Broken category redirects|!{{PAGENAME}}]]<!--
-->|<!--
-->{{#ifexist:Category:{{{1|}}}<!--
-->|<!--
do nothing
-->|<!--
-->[[Category:Broken category redirects]]<!--
-->}}<!--
-->}}<!--
-->}}<!--
-->}}}<!--
--></includeonly><!--
--><noinclude>{{documentation}}</noinclude>
botqag9jqhciz2b5g06x9b8y18ebypy
සැකිල්ල:movecat/documentation
10
126867
238812
208899
2025-05-18T07:28:15Z
en>Surjection
0
Reverted edits by [[Special:Contributions/187.190.132.247|187.190.132.247]]. If you think this rollback is in error, please leave a message on my [[User talk:Surjection|talk page]].
238812
wikitext
text/x-wiki
{{documentation subpage}}
==Documentation==
This template is used on category pages where a decision has been made to rename the category or merge it with another. Redirects do not work well for categories, and categories cannot be renamed in the same way that other namespaces can be. This template adds categories to {{category|Category redirects}} and {{category|Non-empty category redirects}} if this is this case. Category redirects are usually deleted when empty, but in some cases they are kept for longer periods to avoid confusion.
===Syntax===
{{temp|movecat|name of the target category, without the prefix Category:}}<includeonly>
[[Category:Category redirects|!]][[Category:Administration templates]]
[[fr:Modèle:catégorie redirigée]]
[[nb:Mal:tømkat]]
[[pt:Predefinição:redirecionamento de categoria]]
[[vi:Tiêu bản:Đổi hướng thể loại]]</includeonly>
cjj3j16k219uiy8lgixxqqqcgo07ish
238813
238812
2026-11-12T06:43:29Z
Lee
19
[[:en:Template:movecat/documentation]] වෙතින් එක් සංශෝධනයක්
238812
wikitext
text/x-wiki
{{documentation subpage}}
==Documentation==
This template is used on category pages where a decision has been made to rename the category or merge it with another. Redirects do not work well for categories, and categories cannot be renamed in the same way that other namespaces can be. This template adds categories to {{category|Category redirects}} and {{category|Non-empty category redirects}} if this is this case. Category redirects are usually deleted when empty, but in some cases they are kept for longer periods to avoid confusion.
===Syntax===
{{temp|movecat|name of the target category, without the prefix Category:}}<includeonly>
[[Category:Category redirects|!]][[Category:Administration templates]]
[[fr:Modèle:catégorie redirigée]]
[[nb:Mal:tømkat]]
[[pt:Predefinição:redirecionamento de categoria]]
[[vi:Tiêu bản:Đổi hướng thể loại]]</includeonly>
cjj3j16k219uiy8lgixxqqqcgo07ish
ප්රවර්ගය:Non-empty category redirects
14
126868
238808
208900
2026-08-30T00:56:28Z
en>Benwing2
0
use {{auto cat}}
238808
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238809
238808
2026-11-12T06:41:07Z
Lee
19
[[:en:Category:Non-empty_category_redirects]] වෙතින් එක් සංශෝධනයක්
238808
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
ප්රවර්ගය:ja:ගෘහ නිර්මාණ ශිල්පය
14
131965
238784
209451
2026-11-11T14:23:53Z
Lee
19
Lee විසින් [[ප්රවර්ගය:ja:Architecture]] සිට [[ප්රවර්ගය:ja:ගෘහ නිර්මාණ ශිල්පය]] වෙත පිටුව ගෙන යන ලදී
209450
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
සැකිල්ල:R:New English Dictionary/documentation
10
134399
238748
214976
2026-11-11T12:00:39Z
Pinthura
2424
Bot: Replacing category English reference templates with [[:ප්රවර්ගය:ඉංග්රීසි මූලාශ්ර සැකිලි|ඉංග්රීසි මූලාශ්ර සැකිලි]]
238748
wikitext
text/x-wiki
{{documentation subpage}}
===Usage===
{{shortcut|Template:R:NED}}
This template may be used in the "References" and "Further reading" sections of an entry and on talk pages to provide a citation to ''A New English Dictionary on Historical Principles'' (the ''[[w:Oxford English Dictionary|Oxford English Dictionary]]'', 1st edition, 1884–1928) and the Supplement and Bibliography volume of the ''Oxford English Dictionary'' (1st edition, 1933). It can be used to create a link to online versions of the ''Dictionary'' at the [https://archive.org Internet Archive]:
{| class="wikitable" style="width: 75%; margin-left: auto; margin-right: auto; border: none"
|+ Links to archived versions of the ''New English Dictionary''
! width="10%"|Volume !! width="25%"|Link !! width="1%"| !! width="10%"|Volume !! width="25%"|Link
|-
| style="text-align:center" |'''I''' || [https://archive.org/details/oed01arch/page/n24/mode/1up (A–B)] ||
| style="text-align:center" |'''VII''' || [https://archive.org/details/oed07arch/page/n6/mode/1up (O–P)]
|-
| style="text-align:center" |'''II''' || [https://archive.org/details/oed02arch/page/n6/mode/1up (C)] ||
| rowspan="2" style="text-align:center" | '''VIII''' || [https://archive.org/details/oed8aarch/page/n6/mode/1up Part 1 (Q–R)]
|-
| style="text-align:center" |'''III''' || [https://archive.org/details/in.ernet.dli.2015.210033/page/n5/mode/1up (D–E)] ([https://archive.org/details/in.ernet.dli.2015.31134/page/n328/mode/1up pages 310–311]) ||
| [https://archive.org/details/oed8barch/page/n6/mode/1up Part 2 (S–Sh)]
|-
| style="text-align:center" |'''IV''' || [https://archive.org/details/oed04arch/page/n6/mode/1up (F–G)] ||
| rowspan="2" style="text-align:center" | '''IX''' || [https://archive.org/details/oed9aarch/page/n6/mode/1up Part 1 (Si–St)]
|-
| style="text-align:center" |'''V''' || [https://archive.org/details/newenglishdict05murrmiss/page/n8/mode/1up (H–K)] ||
| [https://archive.org/details/oed9barch/page/n6/mode/1up Part 2 (Su–Th)]
|-
| rowspan="2" style="text-align:center" | '''VI''' || [https://archive.org/details/oed6aarch/page/n6/mode/1up Part 1 (L)] ||
| rowspan="2" style="text-align:center" | '''X''' || [https://archive.org/details/oedxaarch/page/n6/mode/1up Part 1 (Ti–U)]
|-
| [https://archive.org/details/oed6barch/page/n6/mode/1up Part 2 (M–N)] ||
| [https://archive.org/details/oedxbarch/page/n6/mode/1up Part 2 (V–Z)]
|}
<div style="text-align:center">[https://archive.org/details/in.ernet.dli.2015.120834/page/n2/mode/1up Supplement and Bibliography volume (1933)]<br><small>''Note'': This version is of poor quality and has erratic pagination. Replace it with a better version if possible.</small></div>
===Parameters===
The template takes the following parameters:
; 1st edition (1884–1928)
* {{para|2}} or {{para|volume}} – '''mandatory''': the volume of the ''Dictionary'' in which the entry appears in uppercase Roman numerals, from {{para|volume|I}} to {{para|volume|X}}.
* {{para|part}} – '''mandatory in some cases''': volumes VI, VIII, IX, and X are each divided into two parts. Use this parameter to specify either {{para|part|1}} or {{para|part|2}}.
* {{para|3}} or {{para|page}}, or {{para|pages}} – the page number(s) of the ''Dictionary'' on which the entry appears. When quoting a range of pages, note the following:
** Separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}.
** You must also use {{para|pageref}} to specify the page number that the template should link to (usually the page on which the Wiktionary entry appears).
: This parameter must be specified to have the template link to an online version of the work.
; Supplement and Bibliography volume (1933)
* {{para|2}} or {{para|volume}} – '''mandatory''' if quoting from the Supplement and Bibliography volume, specify {{para|volume|Supplement}}.
* {{para|3}} or {{para|page}}, or {{para|pages}} – the page number(s) of the ''Dictionary'' on which the entry appears. When quoting a range of pages, separate the first and last pages of the range with an [[en dash]], like this: {{para|pages|10–11}}.
* {{para|url}} or {{para|pageref}} – as the webpage pagination of the version of the work currently available at the Internet Archive is erratic, the template is unable to automatically determine the webpage to link to. Thus, you must either:
** use {{para|url}} to specify the [[URL]] of the webpage of the online version of the work to be linked to, like this: {{para|url|<nowiki>https://archive.org/details/in.ernet.dli.2015.120834/page/n10/mode/1up</nowiki>}}; or
** use {{para|pageref}} to specify the Internet Archive "page" to be linked to. For example, if the URL of the webpage to be linked to is <code><nowiki>https://archive.org/details/in.ernet.dli.2015.120834/page/n10/mode/1up</nowiki></code>, specify {{para|pageref|10}}.
: This parameter must be specified to have the template link to the online version of the work.
; Both versions
* {{para|1}} or {{para|entry}} – the entry in the ''Dictionary'' cited. If not specified, the name of the Wiktionary entry is used.
* {{para|part of speech}} or {{para|pos}} – the [[part of speech]] of the entry. By default, the template italicizes the value assigned to the parameter and adds a [[full stop]] ([[period]]) to the end. To turn off the default formatting for the purpose of specifying a different formatting using wikitext markup and templates, for example: {{para|pos|<nowiki>''sb.''{{sup|1}}</nowiki>}}, specify {{para|noformat|1}} or {{para|noformat|yes}}: see the example [[#Examples|below]].
* {{para|4}} or {{para|column}}, or {{para|columns}} – the column number(s) of the ''Dictionary'' cited. When quoting a range of columns, separate the columns of the range with an en dash, like this: {{para|columns|1–2}}.
* {{para|5}}, {{para|text}}, or {{para|passage}} – a passage cited from the source.
* {{para|footer}} – a comment on the entry or passage cited.
* {{para|nodot}} – by default, the template adds a full stop (period) at the end of the citation. To suppress this punctuation, use {{para|nodot|1}} or {{para|nodot|yes}}.
===Examples===
; 1st edition (1884–1928)
* '''Wikitext''':
** {{temp|R:New English Dictionary|2=entry=Dictionary|3=volume=III|4=page=331|5=column=2}}; or
** {{temp|R:New English Dictionary|2=Dictionary|3=III|4=331|5=2}}; or
* '''Result''': {{R:New English Dictionary|entry=Dictionary|volume=III|page=331|column=2}}
* '''Wikitext''': {{temp|R:New English Dictionary|2=entry=Dock|3=part of speech=<nowiki>''sb.''{{sup|1}}</nowiki>|4=noformat=1|5=volume=III|6=page=568|7=column=2|8=passage=<nowiki>The common name of various species of the genus ''Rumex''{{nb...}}</nowiki>}}
* '''Result''': {{R:New English Dictionary|entry=Dock|part of speech=''sb.''{{sup|1}}|noformat=1|volume=III|page=568|column=2|passage=The common name of various species of the genus ''Rumex''{{nb...}}}}
; Supplement and Bibliography volume (1933)
* '''Wikitext''':
** {{temp|R:New English Dictionary|2=volume=Supplement|3=entry=Aasvogel|4=page=3|5=url=<nowiki>https://archive.org/details/in.ernet.dli.2015.120834/page/n10/mode/1up</nowiki>|6=column=1}}; or
** {{temp|R:New English Dictionary|2=volume=Supplement|3=entry=Aasvogel|4=page=3|5=pageref=10|6=column=1}}
* '''Result''': {{R:New English Dictionary|volume=Supplement|entry=Aasvogel|page=3|pageref=10|column=1}}
===See also===
* {{temp|RQ:New English Dictionary}} – a quotation template for use below definitions in entries to format quotations from the ''Dictionary''
{{OED reference templates}}
<includeonly>
[[ප්රවර්ගය:ඉංග්රීසි මූලාශ්ර සැකිලි|New English Dictionary]]
</includeonly>
2931nopavihnexyvtw9gd8ul84kzy9s
වික්ෂනරි:බාස්ක් ප්රවේශ මාර්ගෝපදේශ
4
134945
238769
229010
2026-11-11T12:43:46Z
Pinthura
2424
Bot: Replacing category Basque language with [[:ප්රවර්ගය:බාස්ක් භාෂාව|බාස්ක් භාෂාව]]
238769
wikitext
text/x-wiki
{{ඉංග්රීසි ව්යාපෘතියෙන් ආයාත කළ පිටුව}}
{{policy-ED}}{{shortcut|WT:AEU}}
'''Note 1''': This guide is intended to provide guidelines both for creating Basque entries on English Wiktionary as well as for adding Basque translations to English words. '''The main guidelines for creating any entry on English Wiktionary is set forth in [[Wiktionary:Entry layout explained]]; this page is an addition to that page, not a replacement.'''
'''Note 2''': If a change occurs in the basic Wiktionary template (currently at [[Wiktionary:Entry layout explained]] that affects Basque entries, then that change should be reflected here.
----
==Pronunciation==
For pronunciation, {{temp|eu-pr}} is available. Basque spelling is highly regular, so usually it won't need any parameters (see the template documentation for more). The pronunciation generated by the template corresponds quite closely to the prescriptive pronunciation of Standard Basque, with some minor adjustments (such as giving the pronunciation of ⟨j⟩ as {{IPAchar|/x/}} in Southern dialects).
As the prescribed pronunciation allows for dialectal variation, when necessary the template will give two different pronunciations: "generic" Southern and "generic" Northern. Some dialectal pronunciations will be generated in some cases too.
Keep in mind that the template generates dialectal pronunciations of Standard Basque, the actual dialectal forms might differ.
===Stress===
Most dialects (and Standard Basque) don't have phonemic stress, so it shouldn't be included in phonemic transcriptions. In the case of dialects with non-contrastive stress, it can be added in the phonetic transcription.
The only exception is the Souletin dialect, which does have phonemic stress. When adding Souletin pronounciations, it is therefore strongly recommended to add stress in the phonemic transcription (see for example {{m|eu|txakhür}}).
==Parts of speech==
===Nouns===
* In Basque, nouns can be inanimate or animate. Animate nouns refer to humans and animals, while the rest are inanimate. Both types differ only in the form and meaning of some declined forms. Some nouns can both inanimate and animate depending on the meaning (for example, {{m|eu|katu}}); and some inanimate nouns can be declined as animate for stylistic purposes or personification.
* The headword template for nouns is {{temp|1=eu-noun}}. The first parameter is used to specify the animacy of the noun.
* In Basque, nouns are declined for a variety of cases. There is only one basic declension pattern, with minor variations depending on the ending of the noun. For adding declension tables, use the templates {{temp|eu-decl-anim}}, {{temp|eu-decl-both}} and {{temp|eu-decl-inanim}}; in most cases they don't require any parameters. For proper nouns, the similar templates {{temp|eu-decl-proper-anim}}, {{temp|eu-decl-proper-inanim}} and {{temp|eu-decl-proper-both}} are used.
* For example, for an inanimate noun:
<pre><nowiki>
===Noun===
{{eu-noun|in}}
# definition
====Declension====
{{eu-decl-inanim}}
</nowiki></pre>
===Adjectives===
In Basque, there are two types of adjectives: {{m|eu|izenondo}} and {{m|eu|izenlagun}}. The first type is more common, so it can be translated "adjective" for simplicity; while the second is usually translated as "adnominal" or "indeclinable adjective".
====''Izenondo''====
* This is the most numerous class of adjectives. They are always placed after the noun they modify, and they are fully declinable.
* The headword template for nouns is {{temp|1=eu-adj}}. The template will generate the comparative forms automatically. If the adjective is not comparable, use it as {{temp|1=eu-adj|2=-}}.
* In Basque, adjectives are declined for a variety of cases. For the inflection table, the template {{temp|eu-decl-adj}} is used, in most cases it won't require any parameters.
* For example, for a comparable adjective:
<pre><nowiki>
===Adjective===
{{eu-adj}}
# definition
====Declension====
{{eu-decl-adj}}
</nowiki></pre>
====''Izenlagun''====
* They are placed before the noun they modify, and cannot be declined. Adnominals are not comparable.
* The headword template for adnominals/indeclinable adjectives is {{temp|1=eu-adj|2=#}}. The POS header is '''Adjective''' as in the previous case.
* The layout is:
<pre><nowiki>
===Adjective===
{{eu-adn}}
# definition
</nowiki></pre>
===Determiners===
In Basque, determiners ({{m|eu|determinatzaile|determinatzaileak}}) are often classified as follows:
* {{m|eu|mugatzaile|Mugatzaileak}}
** the article {{m|eu|-a}}
** {{m|eu|erakusle|erakusleak|t=demonstratives}}: {{m|eu|hau}}, {{m|eu|hori}}, {{m|eu|hura}}...
* {{m|eu|zenbatzaile|Zenbatzaileak|t=Numerals}}
** definite: {{m|eu|bat|t=one}}, {{m|eu|bi|t=two}}, {{m|eu|hiru|t=three}}...
** indefinite: {{m|eu|bizpahiru|t=two or three}}, {{m|eu|zenbait|t=some}}...
** general: {{m|eu|guzti|t=all}}...
* Indefinite: {{m|eu|zer|t=what}}...
Here, definite numerals are placed under the POS header '''Numerals''', while all others use '''Determiner'''.
==Dialects==
Despite being spoken in a small area, Basque has probably a larger dialectal variation than its neighboring languages. Dialectal entries are listed under the <nowiki>==Basque==</nowiki> heading as normal, and their status as dialectal should be marked using the template {{temp|lb}}. Note that most regional/dialectal terms are included in Standard Basque, so these entries can use {{temp|eu-pr}} and the normal declension templates (see for example {{m|eu|zuhamuxka}}).
In the case of dialectal terms not present in the standard language (such as {{m|eu|txakhür}}), pronunciation should be added manually only for the dialect(s) in which the term is used. Declension templates shouldn't be added to these entries, because the generated inflectional suffixes might not be the same as in the dialect in which the particular word is found. However, dialectal declension templates might be created in the future.
==Lemmatisation==
For nouns, the lemma is the absolutive indefinite form. However, there are some proper nouns (such as {{m|eu|Jaungoikoa|t=God}}, {{m|eu|Ternua|t=Newfoundland}}, {{m|eu|Estatu Batuak|t=United States}}...) which include an article (either in the singular or in the plural). In such cases, the lemma form should include the article; compare the formatting of {{m|eu|lur|t=earth, soil}} and {{m|eu|Lurra|t=the Earth}}.
==Resources==
This is a list of the most commonly used sources for Basque in Wiktionary:
===Published by the Basque Academy===
* {{temp|R:eu:EH}} the Dictionary of the Basque Academy, the main normative dictionary of Standard Basque
* {{temp|R:eu:OEH}} the General Basque Dictionary, includes uncommon/dialectal/archaic words and quotations
* {{temp|R:eu:EODA}} the Basque Onomastic Database
* {{temp|R:eu:Arau}} the norms of Euskaltzaindia for Standard Basque
* {{temp|R:eu:EBE}} the Handbook of Standard Basque
* {{temp|R:eu:EHHA}}, includes detailed information about dialectal forms of common words
* {{temp|R:eu:EHHE}}, Historic-Etymological Dictionary of Basque
===Other===
* {{temp|R:eu:EDB}} Etymological Dictionary of Basque by Larry Trask
==Alphabet==
Basque uses these letters:
{{list:Latin script letters/eu/simple}}
They have these names:
{{list:Latin script letter names/eu/simple}}
[[ප්රවර්ගය:බාස්ක් භාෂාව| ]]
[[Category:Wiktionary language considerations]]
0wjovzy5tayaul8czpm06cnbeulvd5s
සැකිල්ල:da-noun/documentation
10
135218
238821
216967
2026-11-12T07:58:55Z
Pinthura
2424
Bot: Replacing category Danish headword-line templates with [[:ප්රවර්ගය:ඩෙන්මාර්ක යොමු වචන පේළි සැකිලි|ඩෙන්මාර්ක යොමු වචන පේළි සැකිලි]]
238821
wikitext
text/x-wiki
{{documentation subpage}}
{{isAccelerated}}
<pre>
==Danish==
===Noun===
{{da-noun|en|er}}
# [[car]], [[automobile]]
</pre>
==Usage==
# ('''optional''') the suffix for the singular definite: '''en''', '''n''', '''et''' or '''t'''; otherwise it is taken as the complete word.
# ('''optional''') the suffix for the plural indefinite: er, r, e, s; otherwise it is taken as the complete word. If a single hyphen ("-"), the word is taken to be uncountable. If missing, plural indefinite is the same as singular indefinite.
* '''com''': the word when used as the first part of a compound: e, s, - are interpreted as suffixes or no change; otherwise the whole word should be given, including a hyphen at the end.
* '''g''': the gender, ''c'' or ''n''; if first unnamed argument is one of "en|n|et|t" it is not needed, but else it should be given.
* '''base''': is the singular indefinite, default PAGENAME, usually not needed
* '''dc=1''': for when consonant doubling is in effect.
* '''stem''': for when the inflected forms are not simply the lemma with a suffix, e.g. {{m|da|gymnasium}} (gymnasi- +et, +er; equivalently, gymnasie- +t, +r).
* '''sg-def-2''': if there are two correct variations of the singular definite, must be the complete word.
* '''pl-indef-2''': if there are two correct variations of the plural indefinite, must be the complete word.
* '''pl-indef-3''': if there are three correct variations of the plural indefinite, must be the complete word.
==Examples==
{{l|da|stol}}:
: <nowiki>{{da-noun|en|e|e}}</nowiki>
: {{da-noun|base=stol|en|e|stole-}}
{{l|da|nul}}:
: <nowiki>{{da-noun|et|er|-|dc=1}}</nowiki>
: {{da-noun|base=nul|et|er|nul-|stem=null}}
{{l|da|chip}}:
: <nowiki>{{da-noun|en|chips|pl-indef-2=chip|dc=1}}</nowiki>
: {{da-noun|base=chip|en|chips|pl-indef-2=chip|stem=chipp}}
{{l|da|mus}}:
: <nowiki>{{da-noun|en||e}}</nowiki>
: {{da-noun|base=mus|en||muse-}}
{{l|da|banke}}:
: <nowiki>{{da-noun|r|ne}}</nowiki>
: {{da-noun|base=banke|r|ne}}
{{l|da|arbejde}}:
: <nowiki>{{da-noun|t|-|arbejds-}}</nowiki>
: {{da-noun|base=arbejde|t|-|arbejds-}}
==See also==
*{{temp|da-noun-infl}} (full declension table)
*{{temp|da-noun-pl}} (for {{l|en|pluralia tantum}})
<includeonly>
[[ප්රවර්ගය:ඩෙන්මාර්ක යොමු වචන පේළි සැකිලි|noun]]
</includeonly>
a6kxdvnkg8ccnl9zog9wvbos69vz4fa
සැකිල්ල:transclude/documentation
10
135246
238827
217034
2026-11-12T07:59:56Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238827
wikitext
text/x-wiki
{{documentation subpage}}
{{shortcut|Template:tcl}}
{{uses lua|Module:transclude}}
This template is used to provide richer definitions for non-English terms based on existing English definitions. A link to the corresponding English sense is generated, accompanied by the labels and categories used within the English entry along with the full English definition, presented in the form of a gloss. If the English definition is corrected or expanded, the change automatically propagates to all transcluding entries. If the full English definition is too verbose, it can be suppressed using {{para|nogloss|1}} which still has the benefit of labels and categories propagating. Scientific categories are often refined once there are enough entries to justify a new subcategory; this refinement would also propagate to all transcluding entries.
If a sense currently lacks {{tl|senseid}} and you want to add it, please first check if [[:d:|Wikidata]] has an entry for that sense. If so, please use Wikidata's [[QID]] as the sense ID. If an entry already contains {{tl|senseid}}, you can use {{tl|transclude}} without specifying {{para|id}}, preview the page and the preview error message will suggest sense ID codes from that entry to you for convenience.
For categories to propagate correctly, they have to appear on the definition line, too. They are best placed after {{tl|senseid}} but before {{tl|lb}}.
Beyond plain-text definitions, the following definition templates are also handled correctly:
* {{tl|place}}
* {{tl|abbreviation of}}
* {{tl|acronym of}}
* {{tl|contraction of}}
* {{tl|initialism of}}
'''Only''' use {{tl|transclude}} if the English and non-English senses are '''perfect translations''' of one another. Perfect translations usually come in the form of proper nouns (mostly toponyms) or scientific vocabulary. If you have to think about whether something is a perfect translation, it probably isn't and you should always err on the side of not using this template.
==Example==
(In [[Belgia#Breton]])
<syntaxhighlight lang="wikitext">
# {{transclude|br|Belgium|id=Q31}}
</syntaxhighlight>
gives
# {{transclude|br|Belgium|id=Q31}}
==TemplateData==
{{TemplateData header}}
<templatedata>
{
"params": {
"1": {
"label": "Language code",
"description": "The code of the language for which a definition is to be provided.",
"example": "ro",
"type": "string",
"required": true
},
"2": {
"label": "English entry",
"description": "The word to link to.",
"example": "Belgium",
"type": "string",
"required": true
},
"id": {
"label": "English entry sense ID",
"description": "The sense ID of the English sense to link to.",
"example": "Q31",
"type": "string",
"required": true
},
"sort": {
"label": "Sort key",
"description": "The sort key to provide to the invoked templates.",
"type": "string",
"required": false
},
"nogloss": {
"label": "Suppressing gloss",
"description": "Whether to suppress the gloss (the definition copied over from the English entry).",
"type": "boolean",
"required": false
},
"lb": {
"label": "Additional labels",
"description": "A semicolon-separated list of additional labels to be prepended to the transcluded labels.",
"type": "string",
"required": false
}
},
"description": "Creates a rich definition based on an existing English definition."
}
</templatedata>
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
</includeonly>
nbdn47n75vzh5nqdyixh177end871xw
සැකිල්ල:transcluded pagename/documentation
10
135680
238741
217980
2026-11-11T11:59:28Z
Pinthura
2424
Bot: Replacing category Metatemplates with [[:ප්රවර්ගය:මෙටා සැකිලි|මෙටා සැකිලි]]
238741
wikitext
text/x-wiki
{{documentation subpage}}
{{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. -->
<includeonly>
[[ප්රවර්ගය:මෙටා සැකිලි]]
</includeonly>
0qzsfjzdhvjxy1u07v0gzllilwuvjn8
සැකිල්ල:Navbar/documentation
10
135725
238740
218085
2026-11-11T11:59:18Z
Pinthura
2424
Bot: Replacing category Metatemplates with [[:ප්රවර්ගය:මෙටා සැකිලි|මෙටා සැකිලි]]
238740
wikitext
text/x-wiki
{{documentation subpage}}
{{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. -->
<includeonly>
[[ප්රවර්ගය:මෙටා සැකිලි]]
[[Category:Navigation templates]]
</includeonly>
9xnq05dujizxerv9evrolx1fo7szvfx
සැකිල්ල:category tree data submodule documentation/documentation
10
137320
238830
221312
2026-11-12T08:00:27Z
Pinthura
2424
Bot: Replacing category Documentation templates with [[:ප්රවර්ගය:උපදෙස් සැකිලි|උපදෙස් සැකිලි]]
238830
wikitext
text/x-wiki
{{documentation subpage}}
Documentation for poscatboiler subpages of [[Module:category tree]]. Automatically transcluded by [[Module:documentation]].
<includeonly>
[[ප්රවර්ගය:උපදෙස් සැකිලි]]
</includeonly>
4p5v0gql2j5z4vpxrmwmw1pqh36agha
Module talk:category tree/topic/Science and technology
829
137432
238775
221551
2026-11-11T14:09:33Z
Lee
19
Lee විසින් [[Module talk:category tree/topic/Sciences]] සිට [[Module talk:category tree/topic/Science and technology]] වෙත පිටුව ගෙන යන ලදී
221551
wikitext
text/x-wiki
{| class="wikitable"
! oldid || date/time || username || edit summary
|----
| 85059148 || 2025-06-07T21:58:32Z || Benwing || <nowiki>Changed protection settings for "[[Module:category tree/topic/Sciences]]": per discussion at [[Wiktionary:Beer_parlour/2025/June#upped_protection_for_category_tree_topic_data_pages]] ([Edit=Allow only template editors and administrators] (indefinite) [Move=Allow only template editors and administrators] (indefinite))</nowiki>
|----
| 85042370 || 2025-06-06T02:00:45Z || Benwing || <nowiki>Changed protection settings for "[[Module:category tree/topic/Sciences]]": all topic additions should be prior-cleared at [[WT:BP]] ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite))</nowiki>
|----
| 84736651 || 2025-05-06T20:18:30Z || Surjection || <nowiki>+control theory</nowiki>
|----
| 84703559 || 2025-05-02T12:33:08Z || Saph || <nowiki></nowiki>
|----
| 84696537 || 2025-05-01T16:13:33Z || Saph || <nowiki>+rotation</nowiki>
|----
| 84663439 || 2025-04-28T05:02:31Z || WingerBot || <nowiki>WingerBot moved page [[Module:category tree/topic cat/data/Sciences]] to [[Module:category tree/topic/Sciences]]: rename category tree subpage per [[Wiktionary:Grease_pit/2025/February#cleaning_up_and_renaming_the_category_tree_modules]]</nowiki>
|----
| 84614530 || 2025-04-22T09:22:04Z || Inpacod2 || <nowiki></nowiki>
|----
| 84614529 || 2025-04-22T09:21:43Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369629 || 2025-03-24T12:25:38Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369627 || 2025-03-24T12:25:08Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369624 || 2025-03-24T12:23:39Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369615 || 2025-03-24T12:21:17Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369612 || 2025-03-24T12:20:13Z || Inpacod2 || <nowiki></nowiki>
|----
| 84369591 || 2025-03-24T12:16:02Z || Inpacod2 || <nowiki></nowiki>
|----
| 84239705 || 2025-03-16T20:09:08Z || Fskel || <nowiki></nowiki>
|----
| 83744108 || 2025-01-27T08:08:56Z || Benwing2 || <nowiki>some fixes for category types</nowiki>
|----
| 83703768 || 2025-01-24T07:21:35Z || Benwing2 || <nowiki>fix typo</nowiki>
|----
| 83703763 || 2025-01-24T07:20:36Z || Benwing2 || <nowiki>add 'units of time' per [[Wiktionary:Beer_parlour/2025/January#proposed_set_categories]]</nowiki>
|----
| 83698444 || 2025-01-23T22:31:15Z || Benwing2 || <nowiki>add 'taxonomic ranks' per discussion in [[Wiktionary:Beer_parlour/2025/January#adding_a_topic_category_'Religions']]</nowiki>
|----
| 83590073 || 2025-01-12T18:06:10Z || Surjection || <nowiki>+ballistics</nowiki>
|----
| 82623188 || 2024-11-11T23:29:59Z || Theknightwho || <nowiki></nowiki>
|----
| 82623181 || 2024-11-11T23:29:31Z || Theknightwho || <nowiki></nowiki>
|----
| 82622979 || 2024-11-11T23:09:28Z || Theknightwho || <nowiki>Add "obsolete scientific theories" to alchemy and flat earth, and move "constellations of the zodiac" to [[Module:category tree/topic cat/data/Culture]].</nowiki>
|----
| 82622890 || 2024-11-11T23:01:31Z || Theknightwho || <nowiki>Update description.</nowiki>
|----
| 82622872 || 2024-11-11T22:59:52Z || Theknightwho || <nowiki>Add obsolete scientific theories.</nowiki>
|----
| 82323008 || 2024-10-09T00:04:19Z || Dpleibovitz || <nowiki>cats for signal processing</nowiki>
|----
| 81768989 || 2024-09-24T02:20:24Z || AryamanA || <nowiki></nowiki>
|----
| 81723310 || 2024-09-22T00:14:58Z || Dpleibovitz || <nowiki>renamed wpcat for units of measure</nowiki>
|----
| 81723184 || 2024-09-21T23:54:01Z || Dpleibovitz || <nowiki>cats for software engineering</nowiki>
|----
| 81722152 || 2024-09-21T23:10:44Z || Dpleibovitz || <nowiki>cats for metrology</nowiki>
|----
| 81656879 || 2024-09-18T20:42:48Z || AryamanA || <nowiki>split off machine learning</nowiki>
|----
| 81626942 || 2024-09-17T13:35:45Z || Theknightwho || <nowiki>Medicine is a type of healthcare, not the other way around.</nowiki>
|----
| 81626870 || 2024-09-17T13:13:14Z || Theknightwho || <nowiki>Nest "pathology" under "disease"</nowiki>
|----
| 81606042 || 2024-09-15T20:53:58Z || Einstein2 || <nowiki>Undo revision [[Special:Diff/81605950|81605950]] by [[Special:Contributions/Einstein2|Einstein2]] ([[User talk:Einstein2|talk]])</nowiki>
|----
| 81605950 || 2024-09-15T20:44:27Z || Einstein2 || <nowiki>+multiplicity</nowiki>
|----
| 80991879 || 2024-08-09T21:16:54Z || Chuck Entz || <nowiki></nowiki>
|----
| 80883955 || 2024-07-26T21:45:22Z || Akaibu || <nowiki></nowiki>
|----
| 80489250 || 2024-06-23T03:40:11Z || Theknightwho || <nowiki>Add chemical notation, electrochemistry, element nomenclature and photochemistry.</nowiki>
|----
| 80489090 || 2024-06-23T03:09:10Z || Theknightwho || <nowiki>Add catalysis.</nowiki>
|----
| 79462669 || 2024-05-30T14:58:19Z || Theknightwho || <nowiki>Add parasitology.</nowiki>
|----
| 79075955 || 2024-05-01T05:32:47Z || Ioaxxere || <nowiki>sorting algorithms</nowiki>
|----
| 78560621 || 2024-03-23T11:55:33Z || Adam78 || <nowiki>for veterinary medicine + parent: animals</nowiki>
|----
| 78495135 || 2024-03-16T14:30:44Z || Fay Freak || <nowiki>Rah, this is just [[Template:also]]</nowiki>
|----
| 78495096 || 2024-03-16T14:24:15Z || Fay Freak || <nowiki>"{{also|Category:{{{langcode}}}:Forms of discrimination}}", to biases, because e.g. [[gender bias]] vs. [[sexism]] but the latter is not yet a [[conspiracy theory]] or mere ideology construct.</nowiki>
|----
| 78494776 || 2024-03-16T13:50:00Z || Fay Freak || <nowiki>labels["biases"] = { type = "set", description = "{{{langname}}} terms for [[bias|biases]], [[inclination]]s of views towards [[inaccurate]] [[representation]].", additional = "{{also|Category:{{{langcode}}}:Logical fallacies}}", parents = {"psychology", "statistics"}, }</nowiki>
|----
| 78219609 || 2024-02-25T02:08:16Z || Theknightwho || <nowiki>+decision theory and potential theory.</nowiki>
|----
| 77451508 || 2023-12-28T00:37:25Z || This, that and the other || <nowiki>+gardens (moved from Miscellaneous)</nowiki>
|----
| 76349854 || 2023-10-16T00:06:29Z || Benwing2 || <nowiki>[[User:Geographyinitiative]] [[User:Qwertygiy]] add 'demarcation lines'</nowiki>
|----
| 76320401 || 2023-10-12T21:43:18Z || WingerBot || <nowiki>category type 'topic' -> 'related-to'; misc bug fixes (manually assisted)</nowiki>
|----
| 76295188 || 2023-10-08T21:28:58Z || WingerBot || <nowiki>convert data in 'topic cat' module; support new data format with `type` field with four-way split of topic/set/name/type and smarter default descriptions; misc cleanup (manually assisted)</nowiki>
|----
| 76262584 || 2023-10-04T03:46:42Z || Benwing2 || <nowiki>add space</nowiki>
|----
| 76262582 || 2023-10-04T03:46:30Z || Benwing2 || <nowiki>use commonscat=/wpcat=</nowiki>
|----
| 76256569 || 2023-10-03T06:19:33Z || Benwing2 || <nowiki>add umbrella commonscat and wikipedia links for physics, archaeology, units of measure</nowiki>
|----
| 76201225 || 2023-09-25T01:35:02Z || Sokkjo || <nowiki></nowiki>
|----
| 75989587 || 2023-09-05T19:56:07Z || Sokkjo || <nowiki></nowiki>
|----
| 75980934 || 2023-09-04T19:25:30Z || Sokkjo || <nowiki></nowiki>
|----
| 73408641 || 2023-06-12T02:40:00Z || Chuck Entz || <nowiki>putting NASA and Russian space program here until I can find a better place</nowiki>
|----
| 72832261 || 2023-04-27T05:49:00Z || Koavf || <nowiki></nowiki>
|----
| 72832254 || 2023-04-27T05:47:39Z || Koavf || <nowiki></nowiki>
|----
| 72832250 || 2023-04-27T05:46:43Z || Koavf || <nowiki></nowiki>
|----
| 72832242 || 2023-04-27T05:44:48Z || Koavf || <nowiki></nowiki>
|----
| 72832237 || 2023-04-27T05:43:36Z || Koavf || <nowiki></nowiki>
|----
| 72831849 || 2023-04-27T03:30:43Z || Chuck Entz || <nowiki></nowiki>
|----
| 72831806 || 2023-04-27T03:21:12Z || Chuck Entz || <nowiki>restoring Anthropology, and making it a parent of archaeology</nowiki>
|----
| 72831555 || 2023-04-27T01:29:12Z || Koavf || <nowiki></nowiki>
|----
| 72831547 || 2023-04-27T01:27:55Z || Koavf || <nowiki></nowiki>
|----
| 72831537 || 2023-04-27T01:26:22Z || Koavf || <nowiki></nowiki>
|----
| 72831529 || 2023-04-27T01:25:29Z || Koavf || <nowiki></nowiki>
|----
| 72831501 || 2023-04-27T01:18:27Z || Koavf || <nowiki></nowiki>
|----
| 72831499 || 2023-04-27T01:17:57Z || Koavf || <nowiki></nowiki>
|----
| 72831494 || 2023-04-27T01:15:47Z || Koavf || <nowiki></nowiki>
|----
| 72831487 || 2023-04-27T01:14:28Z || Koavf || <nowiki></nowiki>
|----
| 72831476 || 2023-04-27T01:10:55Z || Koavf || <nowiki></nowiki>
|----
| 72728189 || 2023-04-20T23:29:15Z || -sche || <nowiki>drop, see RFM</nowiki>
|----
| 72720405 || 2023-04-20T07:46:18Z || -sche || <nowiki>begin to orphan "systematics" (a needless, unused level just containing taxonomy), see RFM</nowiki>
|----
| 71572463 || 2023-03-04T17:21:59Z || Sgconlaw || <nowiki>Added parent category</nowiki>
|----
| 71370111 || 2023-02-22T14:20:16Z || WordyAndNerdy || <nowiki></nowiki>
|----
| 71370108 || 2023-02-22T14:19:28Z || WordyAndNerdy || <nowiki>subcat</nowiki>
|----
| 71310179 || 2023-02-16T13:34:04Z || Mudsk || <nowiki>Add "medicine" as a parent to bacteriology</nowiki>
|----
| 69535647 || 2022-10-17T11:32:21Z || TongcyDai || <nowiki></nowiki>
|----
| 67224306 || 2022-06-01T20:07:03Z || TongcyDai || <nowiki></nowiki>
|----
| 67221472 || 2022-06-01T18:08:19Z || Theknightwho || <nowiki>Add hydroacoustics.</nowiki>
|----
| 66736466 || 2022-05-14T14:14:11Z || ChemPro || <nowiki></nowiki>
|----
| 66729925 || 2022-05-14T12:59:05Z || ChemPro || <nowiki>+ chemical reactions</nowiki>
|----
| 66516524 || 2022-04-27T00:39:02Z || Inqilābī || <nowiki></nowiki>
|----
| 66516508 || 2022-04-27T00:34:46Z || Inqilābī || <nowiki></nowiki>
|----
| 66510584 || 2022-04-26T03:31:37Z || Fish bowl || <nowiki>"onomastics": add parent "names"</nowiki>
|----
| 65978353 || 2022-02-27T04:57:42Z || WordyAndNerdy || <nowiki>+orgonomy (alternative medicine goes under science, I guess?)</nowiki>
|----
| 64639358 || 2021-11-13T06:00:07Z || Chuck Entz || <nowiki></nowiki>
|----
| 64215724 || 2021-10-14T11:31:39Z || Jberkel || <nowiki>add urban studies</nowiki>
|----
| 64002113 || 2021-09-22T17:30:40Z || Dpleibovitz || <nowiki>acceleration to support [[Category:en:Acceleration]]</nowiki>
|----
| 63166065 || 2021-07-14T14:59:13Z || Fay Freak || <nowiki>[[Special:Diff/63165963|“we should have a category for linguistics terms specific to the Semitic languages”]]</nowiki>
|----
| 63106512 || 2021-07-07T11:49:13Z || Fish bowl || <nowiki>add Chinese as parent of Chinese phonetics</nowiki>
|----
| 62954836 || 2021-06-25T14:02:52Z || MJL || <nowiki>+politics parent for political science</nowiki>
|----
| 62390959 || 2021-04-18T12:45:01Z || This, that and the other || <nowiki>+isolines</nowiki>
|----
| 62173179 || 2021-03-18T22:16:04Z || Numberguy6 || <nowiki></nowiki>
|----
| 61563185 || 2021-01-15T01:56:05Z || Hazarasp || <nowiki></nowiki>
|----
| 61563174 || 2021-01-15T01:54:18Z || Hazarasp || <nowiki></nowiki>
|----
| 61563150 || 2021-01-15T01:49:40Z || Hazarasp || <nowiki></nowiki>
|----
| 61481951 || 2021-01-04T06:55:10Z || Benwing2 || <nowiki>use 'no singularize'</nowiki>
|----
| 61481729 || 2021-01-04T06:16:03Z || WingerBot || <nowiki>clean up 'topic cat' descriptions and support additional= (manually assisted)</nowiki>
|----
| 60701534 || 2020-09-30T06:34:38Z || Hazarasp || <nowiki></nowiki>
|----
| 60700914 || 2020-09-30T06:25:54Z || Hazarasp || <nowiki></nowiki>
|----
| 60132353 || 2020-08-23T21:17:29Z || Fish bowl || <nowiki>phonetics</nowiki>
|----
| 60132350 || 2020-08-23T21:17:13Z || Fish bowl || <nowiki>create [[Cat:Chinese phonology]]</nowiki>
|----
| 59721240 || 2020-07-11T00:01:23Z || Numberguy6 || <nowiki></nowiki>
|----
| 59387128 || 2020-05-19T14:16:25Z || Einstein2 || <nowiki></nowiki>
|----
| 58745446 || 2020-02-25T11:41:59Z || Koavf || <nowiki>fix</nowiki>
|----
| 58744031 || 2020-02-25T01:49:21Z || Koavf || <nowiki>Per my user talk</nowiki>
|----
| 58456098 || 2020-01-19T05:51:37Z || Koavf || <nowiki>Protected "[[Module:category tree/topic cat/data/Sciences]]": High-value pages like these modules shouldn't be open to editing from IPs. ([Edit=Allow only autoconfirmed users] (indefinite) [Move=Allow only autoconfirmed users] (indefinite))</nowiki>
|----
| 56091054 || 2019-10-17T03:16:11Z || Chuck Entz || <nowiki></nowiki>
|----
| 53851262 || 2019-08-09T18:54:27Z || Sgconlaw || <nowiki>Added label</nowiki>
|----
| 52765053 || 2019-05-09T11:24:36Z || Rua || <nowiki>Link scientific fields to categories for the things they study, where possible.</nowiki>
|----
| 52141063 || 2019-03-30T20:20:00Z || Rua || <nowiki></nowiki>
|----
| 51186830 || 2019-01-03T08:07:01Z || Hergilei || <nowiki></nowiki>
|----
| 51186695 || 2019-01-03T07:12:03Z || Hergilei || <nowiki></nowiki>
|----
| 50940124 || 2018-11-28T04:13:38Z || Hergilei || <nowiki></nowiki>
|----
| 50660208 || 2018-11-10T00:48:31Z || Hergilei || <nowiki></nowiki>
|----
| 50653292 || 2018-11-08T22:46:36Z || Hergilei || <nowiki></nowiki>
|----
| 50653261 || 2018-11-08T22:34:00Z || Hergilei || <nowiki></nowiki>
|----
| 50525791 || 2018-10-19T13:50:31Z || 65.94.42.168 || <nowiki></nowiki>
|----
| 50525786 || 2018-10-19T13:48:47Z || 65.94.42.168 || <nowiki></nowiki>
|----
| 50525766 || 2018-10-19T13:46:22Z || 65.94.42.168 || <nowiki></nowiki>
|----
| 50525760 || 2018-10-19T13:45:17Z || 65.94.42.168 || <nowiki></nowiki>
|----
| 50111421 || 2018-08-09T19:52:43Z || Fay Freak || <nowiki>So it goes for other languages</nowiki>
|----
| 49985908 || 2018-07-21T15:35:08Z || Sgconlaw || <nowiki>Corrected typo</nowiki>
|----
| 49985906 || 2018-07-21T15:34:17Z || Sgconlaw || <nowiki>Updated usage note</nowiki>
|----
| 47800344 || 2017-10-17T12:31:00Z || Rua || <nowiki></nowiki>
|----
| 47800282 || 2017-10-17T12:22:44Z || Rua || <nowiki></nowiki>
|----
| 47796402 || 2017-10-16T14:07:29Z || Rua || <nowiki></nowiki>
|----
| 47796398 || 2017-10-16T14:05:23Z || Rua || <nowiki></nowiki>
|----
| 47315711 || 2017-08-21T15:28:01Z || Koavf || <nowiki></nowiki>
|----
| 47306641 || 2017-08-21T01:29:18Z || DerekWinters || <nowiki></nowiki>
|----
| 47095615 || 2017-07-24T15:18:54Z || Rua || <nowiki>Reverted edits by [[Special:Contributions/114.124.214.81|114.124.214.81]]. If you think this rollback is in error, please leave a message on my talk page.</nowiki>
|----
| 47094977 || 2017-07-24T13:11:39Z || 114.124.214.81 || <nowiki></nowiki>
|----
| 46748648 || 2017-06-21T21:55:28Z || Justinrleung || <nowiki></nowiki>
|----
| 46748465 || 2017-06-21T20:55:13Z || Justinrleung || <nowiki>+Chinese astronomy</nowiki>
|----
| 46042443 || 2017-06-03T16:17:47Z || Sgconlaw || <nowiki>Updated category tree</nowiki>
|----
| 43003794 || 2017-05-16T09:17:32Z || Erutuon || <nowiki>+ nephrology, for [[Category:zh:Nephrology]]</nowiki>
|----
| 42846380 || 2017-05-09T22:40:41Z || Rua || <nowiki></nowiki>
|----
| 42565047 || 2017-04-03T17:32:28Z || Koavf || <nowiki>and for maize as a plant, see [[:Category:Maize (plant)]]</nowiki>
|----
| 42564928 || 2017-04-03T17:02:42Z || Koavf || <nowiki>Note</nowiki>
|----
| 42554382 || 2017-04-01T19:56:42Z || Chuck Entz || <nowiki></nowiki>
|----
| 42343158 || 2017-02-26T05:16:14Z || Justinrleung || <nowiki>+andrology</nowiki>
|----
| 42235340 || 2017-02-12T21:33:53Z || Justinrleung || <nowiki>+urology</nowiki>
|----
| 42206119 || 2017-02-07T00:40:01Z || Justinrleung || <nowiki>+hepatology</nowiki>
|----
| 42193838 || 2017-02-04T20:21:57Z || Justinrleung || <nowiki>+gastroenterology</nowiki>
|----
| 42190333 || 2017-02-04T05:47:02Z || Erutuon || <nowiki>adding rheumatology as a child of medicine</nowiki>
|----
| 41853318 || 2016-12-11T05:32:41Z || Kc kennylau || <nowiki></nowiki>
|----
| 41852752 || 2016-12-11T01:52:00Z || Justinrleung || <nowiki>+TCM</nowiki>
|----
| 37603764 || 2016-03-15T17:22:36Z || DTLHS || <nowiki></nowiki>
|----
| 37432379 || 2016-02-26T13:21:34Z || DCDuring || <nowiki></nowiki>
|----
| 37430374 || 2016-02-26T01:59:01Z || DCDuring || <nowiki></nowiki>
|----
| 37204101 || 2016-02-10T08:39:46Z || Kc kennylau || <nowiki>+asterisms</nowiki>
|----
| 36148586 || 2016-01-08T03:12:15Z || Rua || <nowiki>Genetic disorders is a set</nowiki>
|----
| 36148534 || 2016-01-08T03:08:56Z || Ungoliant MMDCCLXIV || <nowiki>Adding "medical genetics" and "genetic disorders"</nowiki>
|----
| 35369613 || 2015-11-04T10:23:46Z || Benwing2 || <nowiki>add phrenology</nowiki>
|----
| 35360319 || 2015-11-03T01:09:30Z || Ungoliant MMDCCLXIV || <nowiki>Adding geopolitics</nowiki>
|----
| 35292341 || 2015-10-28T19:27:01Z || Ungoliant MMDCCLXIV || <nowiki>adding "phytopathology" and "plant diseases"</nowiki>
|----
| 34398935 || 2015-09-14T20:54:37Z || Ungoliant MMDCCLXIV || <nowiki>Restoring pseudoscience as a parent of parapsychology.</nowiki>
|----
| 34398420 || 2015-09-14T18:09:55Z || 84.161.10.22 || <nowiki></nowiki>
|----
| 33703690 || 2015-08-01T19:14:24Z || Ungoliant MMDCCLXIV || <nowiki>Metamaterials</nowiki>
|----
| 32168554 || 2015-01-31T18:10:37Z || Purplebackpack89 || <nowiki>OK, we'll put stats under math THIS way...BTW, why is Kephir following me around again?</nowiki>
|----
| 31915707 || 2015-01-04T05:42:58Z || Chuck Entz || <nowiki></nowiki>
|----
| 31915698 || 2015-01-04T05:28:47Z || Chuck Entz || <nowiki></nowiki>
|----
| 29093938 || 2014-10-01T21:14:05Z || Rua || <nowiki>CodeCat moved page [[Module:category tree/topic cat/Sciences]] to [[Module:category tree/topic cat/data/Sciences]] without leaving a redirect</nowiki>
|----
| 28220376 || 2014-08-06T18:30:54Z || Rua || <nowiki></nowiki>
|----
| 28219615 || 2014-08-06T18:14:57Z || Rua || <nowiki></nowiki>
|----
| 28215663 || 2014-08-06T16:51:46Z || Rua || <nowiki></nowiki>
|----
| 27805306 || 2014-07-20T11:52:42Z || Rua || <nowiki></nowiki>
|----
| 27802288 || 2014-07-19T12:24:17Z || Rua || <nowiki></nowiki>
|----
| 27802111 || 2014-07-19T11:48:07Z || Rua || <nowiki></nowiki>
|----
| 27800297 || 2014-07-18T21:35:45Z || Rua || <nowiki></nowiki>
|----
| 27800075 || 2014-07-18T19:30:41Z || Rua || <nowiki></nowiki>
|----
| 27796317 || 2014-07-17T18:29:46Z || Rua || <nowiki></nowiki>
|----
| 27433975 || 2014-07-07T11:49:46Z || Rua || <nowiki></nowiki>
|----
| 27430404 || 2014-07-06T19:28:51Z || Rua || <nowiki></nowiki>
|----
| 27428779 || 2014-07-06T10:42:51Z || Rua || <nowiki></nowiki>
|----
| 27428777 || 2014-07-06T10:42:11Z || Rua || <nowiki></nowiki>
|----
| 27426713 || 2014-07-05T16:45:53Z || Rua || <nowiki></nowiki>
|----
| 27422846 || 2014-07-04T22:22:12Z || Rua || <nowiki></nowiki>
|----
| 27413827 || 2014-07-03T19:18:34Z || Rua || <nowiki></nowiki>
|----
| 27411553 || 2014-07-03T15:39:24Z || Rua || <nowiki></nowiki>
|----
| 27408014 || 2014-07-02T20:13:15Z || Rua || <nowiki></nowiki>
|----
| 27407954 || 2014-07-02T19:54:21Z || Rua || <nowiki></nowiki>
|----
| 27368149 || 2014-06-30T17:06:14Z || Rua || <nowiki></nowiki>
|----
| 27344788 || 2014-06-29T14:51:10Z || Rua || <nowiki></nowiki>
|----
| 27327121 || 2014-06-28T12:59:49Z || Rua || <nowiki></nowiki>
|----
| 27326985 || 2014-06-28T12:28:07Z || Rua || <nowiki></nowiki>
|----
| 27312872 || 2014-06-27T15:42:56Z || Rua || <nowiki>Created page with "local labels = {} labels["Sciences"] = { description = "default with the lower", parent1 = "All topics", } labels["Acoustics"] = { description = "default", parent1 = "Ap..."</nowiki>
|}
ro1ma3qmzwklzf04n535ysi9nv0pyb6
සැකිල්ල:sic/documentation
10
137796
238746
222670
2026-11-11T12:00:19Z
Pinthura
2424
Bot: Replacing category Citation templates with [[:ප්රවර්ගය:උපහරණ සැකිලි|උපහරණ සැකිලි]]
238746
wikitext
text/x-wiki
{{documentation subpage}}
{{names|SIC|sic.}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
===Usage===
This template displays the Latin word "''sic''" linked to [[Appendix:Glossary#sic]] between brackets, in superscript:
: {{sic}}
It means that a text has been reproduced [[verbatim]] from the source, despite any incorrect or unusual spelling, phrase, punctuation or meaning. It makes clear that any of these peculiarities is not a misquotation by the editor and that it should not be corrected by anyone.
===Parameters===
; {{para|1|opt=1}}
: The intended meaning, to be displayed in the bracket after the word ''sic''
; {{para|nolink|opt=1}}
: If set to <kbd>1</kbd>, does not link to the glossary. Mainly useful for embedding {{temp|sic}} inside external links, because having an internal link inside an external link breaks the formatting.
===Examples===
The template {{temp|sic}} should be added directly after an unusual or incorrect piece of directly quoted text. If a particular sentence contains multiple errors, the template should be placed at the end of the sentence after the punctuation mark.
If desired, the correct version of the text can be added as the first parameter of the template.
: '''Wikitext''': <tt>The word was misspeled{{temp|sic}} in the text.</tt>
: '''Result''': The word was misspeled{{sic}} in the text.
: '''Wikitext''': <tt>The word was misspeled{{temp|sic|misspelled}} in the text.</tt>
: '''Result''': The word was misspeled{{sic|misspelled}} in the text.
===See also===
* {{pedia|Sic}}
<includeonly>
<!-- CATEGORIES AND INTERWIKIS HERE, THANKS -->
[[ප්රවර්ගය:උපහරණ සැකිලි]]
[[Category:Text format templates]]
</includeonly>
ggwm4svfdi3k932giulhezn5ls8h0wx
සැකිල්ල:my-IPA/documentation
10
137854
238767
222786
2026-11-11T12:43:20Z
Pinthura
2424
Bot: Replacing category Burmese pronunciation templates with [[:ප්රවර්ගය:බුරුම උච්චාරණ සැකිලි|බුරුම උච්චාරණ සැකිලි]]
238767
wikitext
text/x-wiki
{{documentation subpage}}
Burmese pronunciation and romanisation template, relying on [[Module:my-pron]]. This generates the IPA pronunciation and romanisation of Burmese in four systems. See [[Wiktionary:Burmese transliteration]] for an introduction to Burmese spelling and romanisations.
==Parameters==
<pre>{{my-IPA|respelling 1|respelling 2|...}}</pre>
* Optional: For phonologically irregular words, parameters 1 – ∞ can be used to specify “phonetic respellings” from which IPA and romanisations can be accurately inferred. These respellings can be minor (using tricks to supplement the orthography, see below) or major (using complete phonetic respellings, also see below).
** Minor respellings are preferred over major respellings, when they are feasible.
** Of the four romanisation schemes, two are based on orthography (MLCTS and ALA-LC), and two are based on pronunciation (BGN-PCGN and Okell). Thus, the phonetic respellings will only affect the romanisations generated for the pronunciation-based romanisation schemes, not the orthography-based ones. i.e. if there are two specified respellings for word A, there will be one romanisation in each of the orthography-based schemes, and two romanisations in each of the pronunciation-based schemes.
* An additional <code>|word=</code> parameter is used to indicate the spelling, from which the orthography-based romanisations (MLCTS and ALA-LC) can be inferred. It should be cautiously used in the main namespace; it may be useful in cases where spaces in the romanisation are desired, or where the spelling does not conform to usual Burmese orthography rules.
===Minor respelling tricks===
* <code>'</code>: the previous syllable is a minor syllable.
* <code>+</code>: there is voicing of the following syllable.
* <code>-</code>: the following {{m|my|ဘ}} is pronounced {{IPAchar|/pʰ/}}.
* <code>*</code>: the following consonant is pronounced as it is spelled, i.e. {{IPAchar|/ɹ/}} for {{m|my|ရ|tr=-}}, {{IPAchar|/lj/}} for {{m|my||လျ|tr=-}} and {{IPAchar|/l̥j/}} for {{m|my||လျှ|tr=-}}, instead of {{IPAchar|/j/}}, {{IPAchar|/j/}} and {{IPAchar|/ʃ/}}, respectively.
===If a word requires major respelling===
The respelling can be in either the Burmese or the Latin (ASCII) script. The tables below demonstrate the possible initials and finals of a Burmese syllable, and the correspondences between the two respelling systems and the IPA pronunciation. This [https://r12a.github.io/pickers/mymr-my/ Burmese picker tool] can be helpful for generating a Burmese-script respelling.
====Initials====
{| class="wikitable" style=text-align:center
|+ Plain
|-style="font-size: 90%;"
! !! Bilabial !! Dental !! Alveolar !! Postalveolar<br>Palatal !! Velar !! Glottal !! Placeless
|-
! <small>Nasal</small>
| {{IPAchar|/m̥/}} {{lang|my|မှ}} ''hm''<br>{{IPAchar|/m/}} {{lang|my|မ}} ''m''
| colspan=2 | {{IPAchar|/n̥/}} {{lang|my|နှ}} ''hn''<br>{{IPAchar|/n/}} {{lang|my|န}} ''n''
| {{IPAchar|/ɲ̊/}} {{lang|my|ညှ}} ''hny''<br>{{IPAchar|/ɲ/}} {{lang|my|ည}} ''ny''
| {{IPAchar|/ŋ̊/}} {{lang|my|ငှ}} ''hng''<br>{{IPAchar|/ŋ/}} {{lang|my|င}} ''ng''
| ||
|-
! <small>Stop/Affricate</small>
| {{IPAchar|/p/}} {{lang|my|ပ}} ''p''<br />{{IPAchar|/pʰ/}} {{lang|my|ဖ}} ''hp''<br>{{IPAchar|/b/}} {{lang|my|ဗ}} ''b''
| colspan=2 | {{IPAchar|/t/}} {{lang|my|တ}} ''t''<br>{{IPAchar|/tʰ/}} {{lang|my|ထ}} ''ht''<br>{{IPAchar|/d/}} {{lang|my|ဒ}} ''d''
| {{IPAchar|/t͡ɕ/}} {{lang|my|ကျ}} ''c''<br />{{IPAchar|/t͡ɕʰ/}} {{lang|my|ချ}} ''hc''<br>{{IPAchar|/d͡ʑ/}} {{lang|my|ဂျ}} ''j''
| {{IPAchar|/k/}} {{lang|my|က}} ''k''<br />{{IPAchar|/kʰ/}} {{lang|my|ခ}} ''hk''<br>{{IPAchar|/ɡ/}} {{lang|my|ဂ}} ''g''
| {{IPAchar|/ʔ/}} {{lang|my|အ}}
|
|-
! <small>Fricative</small>
|
| {{IPAchar|/θ/}} {{lang|my|သ}} ''th''<br />{{IPAchar|/ð/}} {{lang|my|+သ}} ''+th''
| {{IPAchar|/s/}} {{lang|my|စ}} ''s''<br />{{IPAchar|/sʰ/}} {{lang|my|ဆ}} ''hs''<br>{{IPAchar|/z/}} {{lang|my|ဇ}} ''z''
| {{IPAchar|/ʃ/}} {{lang|my|ရှ}} ''hy''
|
| {{IPAchar|/h/}} {{lang|my|ဟ}} ''h''
|
|-
! rowspan=2 | <small>Approximant/Lateral</small>
|
| colspan=2 | ({{IPAchar|/ɹ/}} {{lang|my|*ရ}} ''r'')
| {{IPAchar|/j/}} {{lang|my|ယ}} ''y''
| ({{IPAchar|/w̥/}} {{lang|my|ဝှ}} ''hw'')<br>{{IPAchar|/w/}} {{lang|my|ဝ}} ''w''
| ||
|-
|
| colspan=2 | {{IPAchar|/l̥/}} {{lang|my|လှ}} ''hl''<br>{{IPAchar|/l/}} {{lang|my|လ}} ''l''
| || || ||
|}
{| class="wikitable" style=text-align:center
|+ With medial glide
|-style="font-size: 90%;"
! !! Bilabial !! Dental !! Alveolar !! Postalveolar<br>Palatal !! Velar !! Glottal !! Placeless
|-
! <small>Nasal</small>
| {{IPAchar|/m̥w/}} {{lang|my|မွှ}} ''hmw''<br>{{IPAchar|/mw/}} {{lang|my|မွ}} ''mw''<br>{{IPAchar|/m̥j/}} {{lang|my|မျှ}} ''hmy''<br>{{IPAchar|/mj/}} {{lang|my|မျ}} ''my''
| colspan=2 | {{IPAchar|/n̥w/}} {{lang|my|နွှ}} ''hnw''<br>{{IPAchar|/nw/}} {{lang|my|နွ}} ''nw''
| {{IPAchar|/ɲ̊w/}} {{lang|my|ညွှ}} ''hnyw''<br>{{IPAchar|/ɲw/}} {{lang|my|ညွ}} ''nyw''
| {{IPAchar|/ŋ̊w/}} {{lang|my|ငွှ}} ''hngw''<br>{{IPAchar|/ŋw/}} {{lang|my|ငွ}} ''ngw''
| ||
|-
! <small>Stop/Affricate</small>
| {{IPAchar|/pw/}} {{lang|my|ပွ}} ''pw''<br />{{IPAchar|/pʰw/}} {{lang|my|ဖွ}} ''hpw''<br>{{IPAchar|/bw/}} {{lang|my|ဗွ}} ''bw''<br>{{IPAchar|/pj/}} {{lang|my|ပျ}} ''py''<br />{{IPAchar|/pʰj/}} {{lang|my|ဖျ}} ''hpy''<br>{{IPAchar|/bj/}} {{lang|my|ဗျ}} ''by''
| colspan=2 | {{IPAchar|/tw/}} {{lang|my|တွ}} ''tw''<br>{{IPAchar|/tʰw/}} {{lang|my|ထွ}} ''htw''<br>{{IPAchar|/dw/}} {{lang|my|ဒွ}} ''dw''
| {{IPAchar|/t͡ɕw/}} {{lang|my|ကျွ}} ''cw''<br />{{IPAchar|/t͡ɕʰw/}} {{lang|my|ချွ}} ''hcw''<br>{{IPAchar|/d͡ʑw/}} {{lang|my|ဂျွ}} ''jw''
| {{IPAchar|/kw/}} {{lang|my|ကွ}} ''kw''<br />{{IPAchar|/kʰw/}} {{lang|my|ခွ}} ''hkw''<br>{{IPAchar|/ɡw/}} {{lang|my|ဂွ}} ''gw''
| ||
|-
! <small>Fricative</small>
|
| {{IPAchar|/θw/}} {{lang|my|သွ}} ''thw''
| {{IPAchar|/sw/}} {{lang|my|စွ}} ''sw''<br />{{IPAchar|/sʰw/}} {{lang|my|ဆွ}} ''hsw''<br>{{IPAchar|/zw/}} {{lang|my|ဇွ}} ''zw''
| {{IPAchar|/ʃw/}} {{lang|my|ရွှ}} ''hyw''
|
| {{IPAchar|/hw/}} {{lang|my|ဟွ}} ''hw''
|
|-
! rowspan=2 | <small>Approximant/Lateral</small>
|
| colspan=2 |
| {{IPAchar|/jw/}} {{lang|my|ယွ}} ''yw''
| || ||
|-
|
| colspan=2 | {{IPAchar|/l̥w/}} {{lang|my|လွှ}} ''hlw''<br>{{IPAchar|/lw/}} {{lang|my|လွ}} ''lw''<br>{{IPAchar|/l̥j/}} {{lang|my|*လျှ}} ''hly''<br>{{IPAchar|/lj/}} {{lang|my|*လျ}} ''ly''
| || || ||
|}
====Finals with tones====
Using {{lang|my|အ}} as base letter.
{| class="wikitable" style="text-align:center"
|-
! rowspan=2 | Vowel
! colspan=4 | Non-nasalised
! colspan=3 | Nasalised
|-
! Low tone !! High tone !! Creaky tone !! Checked tone
! Low tone !! High tone !! Creaky tone
|-
! {{IPAchar|/i/}}
| {{IPAchar|/ì/}} {{lang|my|အီ}} ''i''
| {{IPAchar|/í/}} {{lang|my|အီး}} ''i\''
| {{IPAchar|/ḭ/}} {{lang|my|အိ}} ''i/''
| {{IPAchar|/ɪʔ/}} {{lang|my|အစ်}} ''i?''
| {{IPAchar|/ɪ̀ɴ/}} {{lang|my|အင်}} ''i~''
| {{IPAchar|/ɪ́ɴ/}} {{lang|my|အင်း}} ''i\~''
| {{IPAchar|/ɪ̰ɴ/}} {{lang|my|အင့်}} ''i/~''
|-
! {{IPAchar|/e/}}
| {{IPAchar|/è/}} {{lang|my|အေ}} ''ei''
| {{IPAchar|/é/}} {{lang|my|အေး}} ''ei\''
| {{IPAchar|/ḛ/}} {{lang|my|အေ့}} ''ei/''
| {{IPAchar|/eɪʔ/}} {{lang|my|အိတ်}} ''ei?''
| {{IPAchar|/èɪɴ/}} {{lang|my|အိန်}} ''ei~''
| {{IPAchar|/éɪɴ/}} {{lang|my|အိန်း}} ''ei\~''
| {{IPAchar|/ḛɪɴ/}} {{lang|my|အိန့်}} ''ei/~''
|-
! {{IPAchar|/ɛ/}}
| {{IPAchar|/ɛ̀/}} {{lang|my|အယ်}} ''e''
| {{IPAchar|/ɛ́/}} {{lang|my|အဲ}} ''e\''
| {{IPAchar|/ɛ̰/}} {{lang|my|အယ့်}} ''e/''
| {{IPAchar|/ɛʔ/}} {{lang|my|အက်}} ''e?''
| {{IPAchar|/àɪɴ/}} {{lang|my|အိုင်}} ''ai~''
| {{IPAchar|/áɪɴ/}} {{lang|my|အိုင်း}} ''ai\~''
| {{IPAchar|/a̰ɪɴ/}} {{lang|my|အိုင့်}} ''ai/~''
|-
!
|
|
|
| {{IPAchar|/aɪʔ/}} {{lang|my|အိုက်}} ''ai?''
|
|
|
|-
! {{IPAchar|/a/}}
| {{IPAchar|/à/}} {{lang|my|အာ}} ''a''
| {{IPAchar|/á/}} {{lang|my|အား}} ''a\''
| {{IPAchar|/a̰/}} {{lang|my|အ}} ''a/''
| {{IPAchar|/aʔ/}} {{lang|my|အတ်}} ''a?''
| {{IPAchar|/àɴ/}} {{lang|my|အန်}} ''a~''
| {{IPAchar|/áɴ/}} {{lang|my|အန်း}} ''a\~''
| {{IPAchar|/a̰ɴ/}} {{lang|my|အန့်}} ''a/~''
|-
! {{IPAchar|/ɔ/}}
| {{IPAchar|/ɔ̀/}} {{lang|my|အော်}} ''o''
| {{IPAchar|/ɔ́/}} {{lang|my|အော}} ''o\''
| {{IPAchar|/ɔ̰/}} {{lang|my|အော့}} ''o/''
| {{IPAchar|/aʊʔ/}} {{lang|my|အောက်}} ''au?''
| {{IPAchar|/àʊɴ/}} {{lang|my|အောင်}} ''au~''
| {{IPAchar|/áʊɴ/}} {{lang|my|အောင်း}} ''au\~''
| {{IPAchar|/a̰ʊɴ/}} {{lang|my|အောင့်}} ''au/~''
|-
! {{IPAchar|/o/}}
| {{IPAchar|/ò/}} {{lang|my|အို}} ''ou''
| {{IPAchar|/ó/}} {{lang|my|အိုး}} ''ou\''
| {{IPAchar|/o̰/}} {{lang|my|အို့}} ''ou/''
| {{IPAchar|/oʊʔ/}} {{lang|my|အုပ်}} ''ou?''
| {{IPAchar|/òʊɴ/}} {{lang|my|အုန်}} ''ou~''
| {{IPAchar|/óʊɴ/}} {{lang|my|အုန်း}} ''ou\~''
| {{IPAchar|/o̰ʊɴ/}} {{lang|my|အုန့်}} ''ou/~''
|-
! {{IPAchar|/u/}}
| {{IPAchar|/ù/}} {{lang|my|အူ}} ''u''
| {{IPAchar|/ú/}} {{lang|my|အူး}} ''u\''
| {{IPAchar|/ṵ/}} {{lang|my|အု}} ''u/''
| {{IPAchar|/ʊʔ/}} {{lang|my|အွတ်}} ''u?''
| {{IPAchar|/ʊ̀ɴ/}} {{lang|my|အွန်}} ''u~''
| {{IPAchar|/ʊ́ɴ/}} {{lang|my|အွန်း}} ''u\~''
| {{IPAchar|/ʊ̰ɴ/}} {{lang|my|အွန့်}} ''u/~''
|-
! {{IPAchar|/ə/}}
| colspan=4 | {{IPAchar|/ə/}} {{lang|my|အ'}} ''a'''
| colspan=3 | —
|}
The combinations listed in [[Wiktionary:Burmese transliteration#ကွတ်, ဝတ်, etc.|Wiktionary:Burmese transliteration#{{lang|my|ကွတ်}}, {{lang|my|ဝတ်}}, etc.]] (i.e. {{lang|my|ွ}} or {{lang|my|ဝ}} followed by {{lang|my|တ်}}, {{lang|my|န်}}, {{lang|my|ပ်}}, {{lang|my|မ်}} or {{lang|my|ံ}}) will be interpreted intelligently by the module. If the unchanged pronunciation is desired, a slash <code>/</code> can be placed between the initial and final (e.g. <code>{{lang|my|ကွ/တ်}}</code>).
==Examples==
==={{l|my|ခလုတ်}}===
<pre>{{my-IPA|ခ'လုတ်}}</pre>
{{my-IPA|word=ခလုတ်|ခ'လုတ်}}
==={{l|my|စာရေး}}===
<pre>{{my-IPA|စာ'ရေး}}</pre>
{{my-IPA|word=စာရေး|စာ'ရေး}}
==={{l|my|ငါးဥ}}===
<pre>{{my-IPA|ငါး'ဥ}}</pre>
{{my-IPA|word=ငါးဥ|ငါး'ဥ}}
==={{l|my|သူငယ်}}===
<pre>{{my-IPA|သူ'ငယ်}}</pre>
{{my-IPA|word=သူငယ်|သူ'ငယ်}}
==={{l|my||အက်ယန်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=အက်ယန်}}
==={{l|my||အာကျန်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=အာကျန်}}
==={{l|my||ကတ်ဝက်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=ကတ်ဝက်}}
==={{l|my||ကာတွက်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=ကာတွက်}}
==={{l|my||တန်ဂါ}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=တန်ဂါ}}
==={{l|my||တာငါ}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=တာငါ}}
==={{l|my|ဆီပုံး}}===
<pre>{{my-IPA|ဆီ+ပုံး}}</pre>
{{my-IPA|word=ဆီပုံး|ဆီ+ပုံး}}
==={{l|my|အုန်းဆီ}}===
<pre>{{my-IPA|အုန်း+ဆီ}}</pre>
{{my-IPA|word=အုန်းဆီ|အုန်း+ဆီ}}
==={{l|my|အညာသား}}===
<pre>{{my-IPA|အ'ညာ+သား}}</pre>
{{my-IPA|word=အညာသား|အ'ညာ+သား}}
==={{l|my|နက်ဖြန်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=နက်ဖြန်}}
==={{l|my|ဖြည်းဖြည်း}}===
<pre>{{my-IPA|ဖြည်2း+ဖြည်2း}}</pre>
{{my-IPA|word=ဖြည်းဖြည်း|ဖြည်2း+ဖြည်2း}}
==={{l|my|အမြီး}}===
<pre>{{my-IPA|အ'မီး}}</pre>
{{my-IPA|word=အမြီး|အ'မီး}}
==={{l|my|ခြေထောက်}}===
<pre>{{my-IPA|ခြေ+ထောက်}}</pre>
{{my-IPA|word=ခြေထောက်|ခြေ+ထောက်}}
==={{l|my|အခွံ}}===
<pre>{{my-IPA|အ'ခွံ}}</pre>
{{my-IPA|word=အခွံ|အ'ခွံ}}
==={{l|my|လျှို့ဝှက်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=လျှို့ဝှက်}}
==={{l|my|မျက်စိ}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=မျက်စိ}}
==={{l|my|ကစား}}===
<pre>{{my-IPA|+က'+စား}}</pre>
{{my-IPA|word=ကစား|+က'+စား}}
==={{l|my|ကပျာကယာ}}===
<pre>{{my-IPA|+က'+ပျာ+က'ယာ}}</pre>
{{my-IPA|word=ကပျာကယာ|+က'+ပျာ+က'ယာ}}
==={{l|my|ဆန်ပြုတ်}}===
<pre>{{my-IPA|ဆန်+ပြုတ်}}</pre>
{{my-IPA|word=ဆန်ပြုတ်|ဆန်+ပြုတ်}}
==={{l|my|စာကြည့်တိုက်}}===
<pre>{{my-IPA|စာကြည့်+တိုက်}}</pre>
{{my-IPA|word=စာကြည့်တိုက်|စာကြည့်+တိုက်}}
==={{l|my|ဒူးထောက်}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=ဒူးထောက်}}
==={{l|my|မင်္ဂလာပါ}}===
<pre>{{my-IPA|မင်္ဂ'လာ+ပါ}}</pre>
{{my-IPA|word=မင်္ဂလာပါ|မင်္ဂ'လာ+ပါ}}
==={{l|my|ဘခင်}}===
<pre>{{my-IPA|-ဘ+ခင်}}</pre>
{{my-IPA|word=ဘခင်|-ဘ+ခင်}}
==={{l|my|ပရိဘောဂ}}===
<pre>{{my-IPA|ပ'*ရိဘောဂ}}</pre>
{{my-IPA|word=ပရိဘောဂ|ပ'*ရိဘောဂ}}
==={{l|my|လျှင်}}===
<pre>{{my-IPA|*လျှင်}}</pre>
{{my-IPA|word=လျှင်|*လျှင်}}
==={{l|my|ကွန်ပျူတာ}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=ကွန်ပျူတာ}}
==={{l|my|ဝက်ဝံ}}===
<pre>{{my-IPA}}</pre>
{{my-IPA|word=ဝက်ဝံ}}
==={{l|my|ပရိဘောဂ}}===
<pre>{{my-IPA|pa'ri/bo\ga/}}</pre>
{{my-IPA|word=ပရိဘောဂ|pa'ri/bo\ga/}}
==={{l|my|မင်္ဂလာပါ}}===
<pre>{{my-IPA|mi~ga'la+pa}}</pre>
{{my-IPA|word=မင်္ဂလာပါ|mi~ga'la+pa}}
==={{l|my|ကပျာကယာ}}===
<pre>{{my-IPA|+ka'+pya+ka'ya}}</pre>
{{my-IPA|word=ကပျာကယာ|+ka'+pya+ka'ya}}
==={{l|my|နက်ဖြန်}}===
<pre>{{my-IPA|ne?hpya~}}</pre>
{{my-IPA|word=နက်ဖြန်|ne?hpya~}}
==={{l|my|မြန်မာ}}===
<pre>{{my-IPA|မြန်မာ|မြန်'မာ}}</pre>
{{my-IPA|word=မြန်မာ|မြန်မာ|မြန်'မာ}}
==={{l|my|ကြိုဆိုပါ၏}}===
<pre>{{my-IPA|ကြို+ဆို +ပါ ၏}}</pre>
{{my-IPA|word=ကြိုဆို ပါ ၏|ကြို+ဆို +ပါ ၏}}
<includeonly>
[[ප්රවර්ගය:බුරුම උච්චාරණ සැකිලි|IPA]]
</includeonly>
s17jl8pcgtxqqdmm2bpetebzs6trcfg
සැකිල්ල:R:my:MED
10
137857
238768
222818
2026-11-11T12:43:32Z
Pinthura
2424
Bot: Replacing category Burmese reference templates with [[:ප්රවර්ගය:බුරුම මූලාශ්ර සැකිලි|බුරුම මූලාශ්ර සැකිලි]]
238768
wikitext
text/x-wiki
“{{l|my||{{{1|{{PAGENAME}}}}}|tr=-}}” in ''{{w|මියන්මාර්–ඉංග්රීසි ශබ්දකෝෂය}}'' (මියන්මාර් භාෂා කොමිසම 1993). මංගත සෙවීම [http://www.sealang.net/burmese/dictionary.htm SEAlang.net].<noinclude>[[ප්රවර්ගය:බුරුම මූලාශ්ර සැකිලි|MED]]</noinclude>
me5y9hw6owzhvgdvnsezrcbw4thi45z
සැකිල්ල:bibref/documentation
10
137946
238742
222972
2026-11-11T11:59:38Z
Pinthura
2424
Bot: Replacing category Citation templates with [[:ප්රවර්ගය:උපහරණ සැකිලි|උපහරණ සැකිලි]]
238742
wikitext
text/x-wiki
{{documentation subpage}}
{{shortcut|Template:R}}
{{uses lua|Module:bibliography/ref}}
Template for citations.
==Parameters==
; {{para|1}} : The language code.
; {{para|2}} : The source id, or an alias thereof.
; {{para|entry}} ~ {{para|3}} : Entry names, multiple may be listed (e.g. {{para|entry2}}, or {{para|4}}). Other accepted aliases are {{para|headword}}, {{para|head}} and {{para|h}}.
; {{para|page}} ~ {{para|p}} : Pages, multiple may be listed. Other accepted aliases are {{para|pages}}.
; {{para|section}} ~ {{para|§}} : Sections, multiple may be listed. Other accepted aliases are {{para|s}}.
; {{para|volume}} ~ {{para|vol}} : Volume. Only one may be listed per template call.
; {{para|id}} : Entry IDs, multiple may be listed. Generally not visible, but useful as it is considered for <code>entry_url</code> and similar.
==Example==
:<code><nowiki>{{R|gmy|DMic.|vol=1|mi-ta|p=454f.|mi-ta-qe|p2=455a|da-ra-[.]-mi-ta-qe|p3=157ab}}</nowiki></code>
:→ {{R|gmy|DMic.|vol=1|mi-ta|p=454f.|mi-ta-qe|p2=455a|da-ra-[.]-mi-ta-qe|p3=157ab}}
<includeonly>[[ප්රවර්ගය:උපහරණ සැකිලි]]</includeonly>
36j217vrbs03iwmez4nosdcv7zz8t8g
සැකිල්ල:affixusex/documentation
10
139058
238823
224983
2026-11-12T07:59:16Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238823
wikitext
text/x-wiki
{{documentation subpage}}
{{shortcut|Template:afex}}
{{uses lua|Module:affixusex/templates}}
This template creates usage examples for affix entries in the format ''word'' + ''-suffix'' → ''suffixed word'' or ''prefix-'' + ''word'' → ''prefixed word''. More complex entries are also possible, e.g.:
: ''word1'' + ''word2'' + ''-suffix'' → ''suffixed word''
: ''prefix-'' + ''word1'' + ''word2'' → ''prefixed word''
: ''word1'' + ''-suffix1'' → ''suffixed word 1'' + ''-suffix2'' → ''suffixed word 2''
: ''prefix1-'' + ''word1'' → ''prefixed word 1'' + ''-suffix2'' → ''suffixed word 2''
: ''word1'' (''qualifier'') + ''word2'' → ''combined word''
==Numbered parameters==
; {{para|1}}
: the language code;
; {{para|2}}, {{para|3}}, ...
: usage example components.
If the page's name is a prefix, it will normally be interpolated into the components before the first one. Similarly, if the page's name is a suffix, it will normally be interpolated into the components before the last one. Such interpolated affixes will be displayed without any link. This will not happen if the page's name (including if decorated with extra diacritics) appears among the components, or if an affix among the components is preceded by an exclamation point (!). Such affixes will likewise be displayed without any link. You can entirely suppress the interpolation of the page name into the components using {{para|nointerp}}, and override the form of the interpolated affix (e.g. adding extra diacritics, as an alternative to explicitly inserting the affix among the components) using {{para|altaff}}. Note that the value specified using {{para|altaff}} has to look like a prefix or suffix for it to be interpolated, as with the page's name.
Normally, components are separated by a plus sign (+), except that between the second-to-last and last components a right arrow will be displayed (→); but this can be overridden by <code><arrow:1></code> attached to the component or using {{para|arrowN}}.
If a given component is in a different language than what is specified in {{para|1}}, prefix the component with the language code of its language, e.g. <code>la:minūtia</code> or <code><nowiki>grc:[[φρέαρ|φρέᾱτος]]</nowiki></code>.
==Named parameters==
; {{para|altaff}}
: The affix's alternative display text (only used when no affix is present among the components and when {{para|nointerp}} isn't given).
; {{para|nointerp}}
: Suppress the automatic interpolation of an affix into the components when no affix is present among the components.
; {{para|t1}}, {{para|t2}}, {{para|t3}}, ... or {{para|gloss1}}, {{para|gloss2}}, {{para|gloss3}}, ...
: The translation of a given component.
; {{para|alt1}}, {{para|alt2}}, {{para|alt3}}, ...
: The alternative display text of a given component.
; {{para|tr1}}, {{para|tr2}}, {{para|tr3}}, ...
: The transliteration of a given component.
; {{para|ts1}}, {{para|ts2}}, {{para|ts3}}, ...
: The transcription of a given component, in languages where the transliteration and transcription differ markedly (see {{temp|m}}).
; {{para|g1}}, {{para|g2}}, {{para|g3}}, ...
: The gender of a given component (multiple comma-separated genders may be specified for a given component).
; {{para|lit1}}, {{para|lit2}}, {{para|lit3}}, ...
: The literal meaning of a given component.
; {{para|pos1}}, {{para|pos2}}, {{para|pos3}}, ...
: The part of speech of a given component.
; {{para|q1}}, {{para|q2}}, {{para|q3}}, ...
: Qualifier text to display before a given component, in parens and normally italicized.
; {{para|qq1}}, {{para|qq2}}, {{para|qq3}}, ...
: Qualifier text to display after a given component, in parens and normally italicized.
; {{para|arrow1}}, {{para|arrow2}}, {{para|arrow3}}, ...
: Should be a boolean value (<code>y</code>, <code>1</code>, <code>true</code>, etc.), and if specified, an arrow will appear before the component instead of a plus sign.
; {{para|joiner1}}, {{para|joiner2}}, {{para|joiner3}}, ...
: If specified, override the arrow or plus sign that appears before the component with the specified text or symbol.
; {{para|fulljoiner1}}, {{para|fulljoiner2}}, {{para|fulljoiner3}}, ...
: If specified, override the arrow or plus sign that appears before the component, as well as the spaces on either side, with the specified text or symbol (e.g. use {{para|fulljoiner2|,&#32;}} to insert a comma between the first and second components).
; {{para|id1}}, {{para|id2}}, {{para|id3}}, ...
: The sense ID of a given component (see {{temp|m}}).
; {{para|accel1}}, {{para|accel2}}, {{para|accel3}}, ...
: The acceleration tag of a given component (see {{temp|m}}).
; {{para|sc}}
: The script code of the components (rarely needs to be specified).
; {{para|lang1}}, {{para|lang2}}, {{para|lang3}}, ...
: The language code of a given component, if that component is in a different language from the remaining components. It is preferable to specify such a language code as a prefix to the component itself, e.g. using <code>la:minūtia</code> or <code><nowiki>grc:[[φρέαρ|φρέᾱτος]]</nowiki></code>, instead of using {{para|lang<var>N</var>}}.
; {{para|sc1}}, {{para|sc2}}, {{para|sc3}}, ...
: The script code of a given component where {{para|langN}} is also given (rarely needs to be specified).
; {{para|pagename}}
: Override the page name used when deciding whether to interpolate a prefix or suffix. Useful especially on documentation and test pages.
==Inline modifiers==
All of the per-term parameters described above can alternatively be specified as ''inline modifiers'', using a syntax like <code><nowiki>отсе́чь<t:to [[cut off]], to [[chop]] [[off]]><g:pf></nowiki></code> to specify modifiers such as transliterations, genders, glosses and qualifiers. In this example, for the Russian term {{m|ru|отсе́чь|t=to [[cut off]], to [[chop]] [[off]]}}, the gloss "to [[cut off]], to [[chop]] [[off]]" and gender <code>pf</code> (perfective) are given. Specifically, the following modifiers are recognized; see the above documentation for more information on the exact meaning of each modifier.
* <code>t</code> or <code>gloss</code>: gloss
* <code>alt</code>: alternative display text
* <code>tr</code>: transliteration
* <code>ts</code>: transcription, for languages where the transliteration and pronunciation are markedly different
* <code>g</code>: comma-separated list of gender/number specifications
* <code>lit</code>: literal meaning
* <code>pos</code>: part of speech
* <code>q</code>: qualifier, e.g. ''rare''; this appears before the component, parenthesized and italicized
* <code>qq</code>: qualifier, e.g. ''rare''; this appears after the component, parenthesized and italicized
* <code>pos</code>: part of speech
* <code>arrow</code>: change the plus sign before the component to a right arrow
* <code>joiner</code>: override the arrow or plus sign before the component with the specified text or symbol
* <code>fulljoiner</code>: override the arrow or plus sign before the component, along with the spaces on either side, with the specified text or symbol
* <code>id</code>: sense ID
* <code>accel</code>: acceleration tag
* <code>lang</code>: language code for the component; overrides the {{para|lang}} parameter; can also be specified inline using e.g. <code>la:minūtia</code> or <code><nowiki>grc:[[σκῶρ|σκατός]]</nowiki></code>
* <code>sc</code>: script code for the component
==Examples==
The following code, for use in {{m+|pt|-ada}}:
<syntaxhighlight lang="wikitext">#: {{afex|pt|chegar<t:to arrive>|chegada<t:arrival>}}</syntaxhighlight>
generates
#: {{afex|pt|chegar<t:to arrive>|chegada<t:arrival>|pagename=-ada}}
Note how the suffix is interpolated before the final component.
The following code, for use in {{m+|ru|-овый}}, is similar, but specifies the affix explicitly:
<syntaxhighlight lang="wikitext">#: {{afex|ru|зо́нтик<g:m-in><t:[[umbrella]]>|-овый|зо́нтиковый<t:umbrella {{q|relational}}>}}</syntaxhighlight>
It generates:
#: {{afex|ru|зо́нтик<g:m-in><t:[[umbrella]]>|-овый|зо́нтиковый<t:umbrella {{q|relational}}>|pagename=-овый}}
The following code for {{m+|pt|-ário}}, shows how to specify a term derived from a component in a different language:
<syntaxhighlight lang="wikitext">#: {{afex|pt|la:lūna<t:moon>|lunário<t:calendar based on moon phases>}}</syntaxhighlight>
It generates:
#: {{afex|pt|la:lūna<t:moon>|lunário<t:calendar based on moon phases>|pagename=-ário}}
Note how the Latin word {{m|la|lūna}}, with a macron in it, is correctly linked to a page that does not include the macron in its name.
The following code, for {{m+|la|-tūra}}, shows how to handle the situation where the suffix itself has extra decoration (a length mark, an acute accent indicating stress, etc.):
<syntaxhighlight lang="wikitext">#: {{afex|la|scrībō<t:to write>|-tūra|scrīptūra<t:scripture>}}</syntaxhighlight>
It generates:
#: {{afex|la|scrībō<t:to write>|-tūra|scrīptūra<t:scripture>|pagename=-tura}}
In this case, an explicit affix (or {{para|altaff}}) is needed because the entry itself is named {{m|la|-tura}}, without the length mark.
The following code is equivalent:
<syntaxhighlight lang="wikitext">#: {{afex|la|scrībō<t:to write>|altaff=-tūra|scrīptūra<t:scripture>}}</syntaxhighlight>
It generates:
#: {{afex|la|scrībō<t:to write>|altaff=-tūra|scrīptūra<t:scripture>|pagename=-tura}}
The following is a more complex example, for use in {{m+|ru|над-}}:
<syntaxhighlight lang="wikitext">#: {{afex|ru|гроб<t:[[grave]]><qq:poetic>|-ие<pos:noun-forming suffix>|надгро́бие<t:[[tombstone]]><lit:thing '''over''' the grave>}}</syntaxhighlight>
It generates (with the prefix interpolated before the first component):
#: {{afex|ru|над-|гроб<t:[[grave]]><qq:poetic>|-ие<pos:noun-forming suffix>|надгро́бие<t:[[tombstone]]><lit:thing '''over''' the grave>|pagename=над-}}
The following is a significantly more complex example, for use in {{m+|ru|-ать}} and demonstrating the way perfective verbs are derived from imperfective verbs and vice-versa:
<syntaxhighlight lang="wikitext">#: {{afex|ru|от-|сечь<t:to [[cut]], to [[chop]]><g:impf>|отсе́чь<t:to [[cut off]], to [[chop]] [[off]]><g:pf><arrow:1><qq:underlying stem {{lang|ru|отсе́к-}}>|-а́ть|отсека́ть<g:impf>}}</syntaxhighlight>
It generates:
#: {{afex|ru|от-|сечь<t:to [[cut]], to [[chop]]><g:impf>|отсе́чь<t:to [[cut off]], to [[chop]] [[off]]><g:pf><arrow:1><qq:underlying stem {{lang|ru|отсе́к-}}>|-а́ть|отсека́ть<g:impf>|pagename=-ать}}
==See also==
* {{temp|prefixusex}}/{{temp|prefex}}, {{temp|suffixusex}}/{{temp|sufex}}: alternatives specifically for prefixes or suffixes
* {{temp|ux}}: to format general usage examples
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
</includeonly>
7j6bujrchvawabsrfukwqt1tdfq83ja
සැකිල්ල:prefixusex/documentation
10
139062
238825
224987
2026-11-12T07:59:36Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238825
wikitext
text/x-wiki
{{documentation subpage}}
{{shortcut|Template:prefex}}
{{uses lua|Module:affixusex/templates}}
This template creates usage examples for prefix entries in the format ''prefix-'' + ''word'' → ''prefixed word''. More complex entries are also possible, e.g.:
: ''prefix-'' + ''word1'' + ''word2'' → ''prefixed word''
: ''prefix1-'' + ''word1'' → ''prefixed word 1'' + ''-suffix2'' → ''suffixed word 2''
: ''word1'' (''qualifier'') + ''word2'' → ''combined word''
==Parameters==
* This template takes almost exactly the same parameters as {{temp|affixusex}} and its shortcut {{temp|afex}}; see the documentation of that template for more information. There are only slight differences between the two:
# When {{tl|prefixusex}}/{{tl|prefex}} is used, the parameter {{para|altaff}} can also be named {{para|altpref}}, for compatibility purposes.
# When interpolating a prefix before the first component (taken from the {{para|altaff}} parameter or the page name), {{temp|affixusex}} checks that the prefix being inserted actually looks like a prefix (i.e. it ends with a hyphen and doesn't begin with a hyphen) before being interpolated. {{tl|prefixusex}} does not make this extra check. This may matter in languages where prefixes are not normally followed by a hyphen (e.g. East Asian languages), or are followed by a different character (e.g. Hebrew and Arabic). For Latin-script languages, it usually doesn't matter.
In practice, these are very minor differences, and it is recommended to use {{temp|affixusex}}/{{temp|afex}} in all circumstances; {{tl|prefixusex}} and {{tl|suffixusex}} are maintained largely for compatibility.
==See also==
* {{temp|suffixusex}}/{{temp|sufex}}: like {{temp|prefixusex}}/{{temp|prefex}}, but for suffixes
* {{temp|affixusex}}/{{temp|afex}}: general variant for prefixes, suffixes, interfixes, compounds, etc.
* {{temp|ux}}: to format general usage examples
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
</includeonly>
3l5zbkn517ybz9rskltgzt9605skevh
සැකිල්ල:coa/documentation
10
139066
238824
224991
2026-11-12T07:59:26Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238824
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:usex/templates}}
This template is used to format [[collocation]]s (similarly to {{temp|collocation}}), but when a translation or transliteration (or both) is specified, this template keeps all the information on one line if possible (approximately, if everything fits in a single line), otherwise using a multiline format. It is analogous to {{tl|uxa}} and auto-determines whether to use an inline or multiline format.
== Parameters ==
This template's parameters are identical to those of {{tl|ux}} and {{tl|uxi}}, except that:
* {{para|inline}} is not available, since internally it is set to {{cd|auto}}.
* {{para|nocat}} is not available. The term will always be categorized into the appropriate subcategory of [[:Category:Terms with collocations by language]], such as [[:Category:English terms with collocations]].)
==See also==
* [[Wiktionary:Collocations]]
* {{temp|collocation}}
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
</includeonly>
h2k1tbc0t03y5awo6yznowhhuz5gtrz
සැකිල්ල:&lit/documentation
10
139317
238822
225480
2026-11-12T07:59:06Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238822
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:definition/templates}}
This creates a definition line for literal senses in otherwise figurative or idiomatic expressions.
==Usage==
The template should be placed in a definition line.
<syntaxhighlight lang="wikitext">
# {{&lit}}
</syntaxhighlight>
The order of senses should be either figurative first or literal first, choosing the most appropriate for the given instance.<ref>{{slink|Wiktionary:Beer parlour/2025/October#Placement of <kbd><nowiki>{{&lit}}</nowiki></kbd>}}</ref> This notion also accords with the spirit of {{section link|Wiktionary:Style guide#Definition sequence}}, which wants the <em>usefulness to an average user</em> to be the chief criterion for the order of senses.
==Parameters==
;1=''[language code]'':Required
;2=, 3=, ..., if not wikified:<code><nowiki>{{&lit|en|foo|bar}}</nowiki></code> displays as {{&lit|en|foo|bar}}<br>If not provided, the title will be split at its white spaces: <code><nowiki>{{&lit|en}}</nowiki></code> in the article [[dirty linen]] displays as {{&lit|en|dirty|linen}}
:;alt1, alt2, etc.:display forms for the numbered parameter: <code><nowiki>{{&lit|en|foo|alt1=bar}}</nowiki></code> displays as {{&lit|en|foo|alt1=bar}}
;2=, 3=, ..., if the first is wikified: <code><nowiki>{{&lit|en|see [[foo]] or [[bar]]}}</nowiki></code> displays as {{&lit|en|see [[foo]] or [[bar]]}}
;qualifier=''[qualifier]'':Displays as "''[Qualifier]'' used other than as an idiom" if exists
;dot=''[anything]'':Displays "''[anything]''" instead of a trailing period (full stop).
;nodot=1:Suppress the display of the trailing period (full stop).
==References==
{{reflist}}
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
</includeonly>
j964duocc4fgcwry5hdcra4ele5tp1x
සැකිල්ල:uses templatestyles/documentation
10
140067
238833
226927
2026-11-12T08:00:57Z
Pinthura
2424
Bot: Replacing category Documentation templates with [[:ප්රවර්ගය:උපදෙස් සැකිලි|උපදෙස් සැකිලි]]
238833
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|uses templatestyles}}
This template generates a message box to be used in the template documentation's subpage indicating that it has CSS using [[mw:Help:TemplateStyles|TemplateStyles]].
Its parameters are similar to {{temp|uses lua}}.
<includeonly>
[[ප්රවර්ගය:උපදෙස් සැකිලි]]
</includeonly>
jcedlw45lvy8xesu1lldnljvfmm4jwf
සැකිල්ල:quote-meta/paramdoc/documentation
10
140571
238831
227935
2026-11-12T08:00:37Z
Pinthura
2424
Bot: Replacing category Documentation templates with [[:ප්රවර්ගය:උපදෙස් සැකිලි|උපදෙස් සැකිලි]]
238831
wikitext
text/x-wiki
{{documentation subpage}}
This template should be used for displaying the documentation of the parameters to quotation templates, for example [[:Category:English quotation templates|English quotation templates]].
==Description==
The template currently supports only a single parameter, {{para|1}}. Text in that parameter is output verbatim, except that certain ''parameter references'' using the syntax <code><<PARAM>></code> or <code><<PARAM:SYNONYM>></code> are replaced with documentation for that parameter.
===Examples===
For example, the following code:
<pre>{{quote-meta/paramdoc|1=
<<chapter:1>>
<<page:2>>
<<passage:3>>
<<trailing_params>>
}}
</pre>
generates the following text (not including the horizontal rules denoting the start and end of the text):
<hr />
{{quote-meta/paramdoc|1=
<<chapter:1>>
<<page:2>>
<<passage:3>>
<<trailing_params>>
}}
<hr />
Here, for example, <code><<page:2>></code> describes the {{para|page}} and {{para|pages}} parameters, where {{para|2}} is a synonym for {{para|page}}. If {{para|page}} has no synonym, you should just write <code><<page>></code>, which will omit mention of any synonymous parameter.
You can also intersperse arbitrary text among the parameter references. For example, the documentation page [[Template:RQ:Taylor Holy Living/documentation]] contains the following:
<pre>{{quote-meta/paramdoc|1=
<<page:2>>
<blockquote>
Note that page 424 is misprinted as 376; specify {{para|page|424}} if quoting from this page.
</blockquote>
<<passage:3>>
<<trailing_params>>
}}
</pre>
which generates:
<hr />
{{quote-meta/paramdoc|1=
<<page:2>>
<blockquote>
Note that page 424 is misprinted as 376; specify {{para|page|424}} if quoting from this page.
</blockquote>
<<passage:3>>
<<trailing_params>>
}}<hr />
Another example with text interspersed among parameter references is found on [[Template:RQ:Austen Sense and Sensibility/documentation]]:
<pre>{{quote-meta/paramdoc|1=
<<roman_chapter:2>> The chapter numbers restart from I in each volume.
<<page:3>>
<<passage:4>>
<<trailing_params>>
}}
</pre>
which generates:
<hr />
{{quote-meta/paramdoc|1=
<<roman_chapter:2>> The chapter numbers restart from I in each volume.
<<page:3>>
<<passage:4>>
<<trailing_params>>
}}<hr />
===Parameter references===
The following parameter references are currently recognized:
* <code><<page>></code> Text for the {{para|page}}/{{para|pages}} params.
* <code><<page:PARAM>></code> Same as <code><<page>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<page_with_roman_preface>></code> Text for the {{para|page}}/{{para|pages}} params where page numbers should be lowercase Roman numerals in the preface.
* <code><<page_with_roman_preface:PARAM>></code> Same as <code><<page_with_roman_preface>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<chapter>></code> Text for the {{para|chapter}} param when a chapter name should be provided.
* <code><<chapter:PARAM>></code> Same as <code><<chapter>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<roman_chapter>></code> Text for the {{para|chapter}} param when an uppercase Roman numeral chapter number should be provided.
* <code><<roman_chapter:PARAM>></code> Same as <code><<roman_chapter>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<arabic_chapter>></code> Text for the {{para|chapter}} param when an Arabic numeral chapter number should be provided.
* <code><<arabic_chapter:PARAM>></code> Same as <code><<arabic_chapter>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<passage>></code> Text for the {{para|text}}/{{para|passage}} params.
* <code><<passage:PARAM>></code> Same as <code><<passage>></code> but where {{para|PARAM}} is an additional synonym.
* <code><<trailing_params>></code> Text for additional params to mention at the end (currently {{para|footer}} and {{para|brackets}}).
==See also==
* [[Module:quote]] (implementation of this template)
* {{temp|quote-book}} (underlying template used by many quotation templates)
* {{temp|#invoke:quote|call_quote_template}} (module invocation syntax to simplify writing quotation templates)
<includeonly>
[[ප්රවර්ගය:උපදෙස් සැකිලි]]
</includeonly>
8ik5aoy9sp2ne231ugnaxbzf3qal0c6
සැකිල්ල:tea room sense/documentation
10
140578
238826
227950
2026-11-12T07:59:46Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238826
wikitext
text/x-wiki
{{documentation subpage}}
This template generates a link to the [[Wiktionary:Tea room|Tea Room]] for a given sense.
==Parameters==
; {{para|1|req=1}}
: The [[Wiktionary:LANGCODE|language code]] of the term in question. See [[Wiktionary:List of languages]].
; {{para|y|req=1}}
: Year of discussion to link to.
; {{para|m|req=1}}
: Month of discussion to link to (spelled out, e.g. "March", "December").
; {{para|fragment}}, {{para|section|opt=1}}
: The section of the Tea Room for the current month/year to link to; this goes into the URL, after the pound sign. Defaults to the page name.
; {{para|sort|opt=1}}
: The sort key for the page; rarely needs to be specified.
; {{para|nocat|1}}
: Disables categorization of this page.
This template adds the page to the following categories (where LANG is the language whose code is specified using {{para|1}}):
* [[:Category:Tea room]]
* [[:Category:Requests for attention by language|Category:Requests for attention concerning LANG]]
==See also==
* {{temp|tea room}}
==TemplateData==
<templatedata>
{
"params": {
"1": {
"label": "Language",
"description": "The language code of the language under discussion",
"type": "string",
"required": true
},
"2": {
"label": "Comment",
"description": "Reasoning for why entry was added to the Tea room for conversation. Comments should be limited to one or two sentences.",
"type": "string"
},
"y": {
"label": "Year",
"example": "2016",
"type": "number",
"required": true,
"description": "The year when the discussion took place"
},
"m": {
"label": "Month",
"description": "The month when the discussion took place (written out)",
"example": "March",
"type": "string",
"required": true
},
"fragment": {
"aliases": [
"section"
],
"label": "Title",
"description": "Title of Tea room discussion",
"type": "string"
},
"nocat": {
"label": "No categorization",
"description": "If set, supresses categorization",
"type": "boolean"
}
},
"paramOrder": [
"1",
"2",
"y",
"m",
"fragment",
"nocat"
],
"description": "This template generates an inline message linking to the Tea room.",
"format": "inline"
}
</templatedata>
<includeonly>
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
[[Category:Request templates]]
</includeonly>
k7hoevkrrzr89wqyso2zr2kchuabka4
architecture
0
140599
238777
228010
2026-11-11T14:16:24Z
Lee
19
/* නාම පදය */
238777
wikitext
text/x-wiki
{{also|architecturé}}
== ඉංග්රීසි ==
{{wp}}
=== නිරුක්තිය ===
{{root|en|ine-pro|*tetḱ-}}
Borrowed from {{bor|en|fr|architecture}}, from {{der|en|la|architectūra}}. Originally from {{m|en|architect}}, from {{der|en|grc|ἀρχιτέκτων|t=architect|lit=arch builder, ext. chief builder, principal craftsman}}.
=== උච්චාරණය ===
* {{IPA|en|/ˈɑː.kɪˌtɛk.tʃə/|a=RP}}
* {{IPA|en|/ˈɑɹ.kɪˌtɛk.t͡ʃɚ/|a=GenAm}}
* {{audio|en|en-us-architecture.ogg|a=US}}
* {{hyph|en|ar|chi|tec|ture}}
=== නාම පදය ===
{{en-noun|~}}
# {{senseid|en|Q12271}} [[ගෘහ නිර්මාණ ශිල්පය]] (The art and science of designing and managing the construction of [[building]]s and other [[structure]]s, particularly if they are well proportioned and decorated.)
#: {{ux|en|The '''architecture''' throughout NYC is amazing.}}
#* '''April 21, 2017''', Max Roscoe, ''How Your City Is Killing You With Ugliness''[https://web.archive.org/web/20201112015531/https://www.returnofkings.com/118275/how-your-city-is-killing-you-with-ugliness]
#*: '''Architecture''' is the visual public expression of a culture’s achievements, values, and outlook.# The profession of an [[architect]].
# Any particular style of building design.
# Construction, in a more general sense; frame or structure; workmanship.
#* {{RQ:Marlowe Tamburlaine|part=1|scene=vii|page=41|passage=Our ſoules, whoſe faculties can comprehend<br>The wondrous '''Architecture''' of the world:<br>And meaſure euery wandring planets courſe,<br>Still climing after knowledge infinite, {{...}}}}
#* {{quote-text|en|year=1871|author=w:John Tyndall|title=Fragments of Science for Unscientific People
|passage=the '''architecture''' of grasses, plants, and trees}}
#* '''1684-1690''', {{w|Thomas Burnet}}, ''Sacred Theory of the Earth''
#*: the formation of the first Earth, after such a wonderful manner, being a piece of Divine '''Architecture'''
# A unifying structure.
# {{lb|en|computing}} A [[family]] of [[CPU]]s sharing a common [[instruction set]] and having partial or full compatibility with software built on each other.
# {{lb|en|computing}} A specific model of a [[microchip]] or [[CPU]].
#: {{ux|en|The Intel '''architectures''' have more software written for them.}}
# The structure and design of a [[system]] or [[product]].
#* '''2004''', Prof P.C.P. Bhatt, {{monospace|(nptel.iitm.ac.in)}} [https://web.archive.org/web/20120105160326/http://nptel.iitm.ac.in/courses/Webcourse-contents/IISc-BANG/Operating%20Systems/pdf/Lecture_Notes/Mod%2014_LN.pdf Module 14: Unix Kernel Architecture]
#*: ''The kernel runs the show, i.e. it manages all the operations in a Unix flavored environment. The kernel [[architecture]] must support the primary Unix requirements. These requirements fall in two categories namely, functions for process management and functions for file management (files include device files). Process management entails allocation of resources including CPU, memory, and offers services that processes may need. The file management in itself involves handling all the files required by processes, communication with device drives and regulating transmission of data to and from peripherals.''
#: {{ux|en|The '''architecture''' of the company's billing system is designed to support its business goals.}}
====Hyponyms====
{{col4|en
|duck architecture
|enterprise architecture
|event-driven architecture|landscape architecture
|formula architecture
|microarchitecture
|model-driven architecture
|quality-driven archictecture
|service-oriented architecture
|software architecture
|system architecture|security architecture
|Cyclopean architecture|Harvard architecture|computer architecture|enterprise architecture model|kinetic architecture|load-store architecture|message-driven architecture|micro-architecture|origamic architecture|search-oriented architecture|systems architecture|vernacular architecture|von Neumann architecture|modified Harvard architecture|pandemonium architecture}}
==== ව්යුත්පන්න යෙදුම් ====
{{col|en|xenoarchitecture|advertecture|angioarchitecture|aquatecture|architectured|architecturesque|architextuality|architourism|architourist|arcology|astroarchitecture|barkitecture|bioarchitecture|biotecture|blobitecture|chemoarchitecture|cytoarchitecture|duplitecture|ecoarchitecture|ecotecture|hepatoarchitecture|histoarchitecture|immunoarchitecture|macroarchitecture|marchitecture|marketecture|multiarchitecture|mycotecture|myeloarchitecture|myoarchitecture|nanoarchitecture|neuroarchitecture|nonarchitecture|oyster-tecture|parkitecture|instruction set architecture|rearchitecture|starchitecture|subarchitecture|synaptoarchitecture|hostile architecture
|architectonic
|architect
|architectural
|dearchitecturization
}}
==== පරිවර්තන ====
{{trans-top|art and science of designing buildings and other structures}}
* Afrikaans: {{t|af|argitektuur}}
* Albanian: {{t+|sq|arkitekturë|f}}
* Amharic: {{t|am|ሥነ ሕንፃ}}
* Arabic: {{t|ar|هَنْدَسَة مِعْمَارِيَّة|f|tr=handasa miʕmāriyya}}, {{t+|ar|عِمَارَة|f}}
* Armenian: {{t+|hy|ճարտարապետություն}}
* Aromanian: {{t|rup|arhitecturâ|f}}
* Assamese: {{t|as|স্থাপত্যকলা}}
* Asturian: {{t+|ast|arquiteutura|f}}, {{t+|ast|arquitectura|f}}
* Azerbaijani: {{t|az|memarlıq}}
* Basque: {{t|eu|arkitektura}}
* Belarusian: {{t|be|архітэкту́ра|f}}
* Bengali: {{t-needed|bn}}
* Bulgarian: {{t+|bg|архитекту́ра|f}}
* Burmese: {{t|my|ဗိသုကာပညာ}}
* Catalan: {{t+|ca|arquitectura|f}}
* Chechen: {{t|ce|архитектура}}
* Cherokee: {{t|chr|ᎠᏓᏁᎳᏅᎯ}}
* Chinese:
*: Cantonese: {{t|yue|建築}}, {{t|yue|建築學}} {{qualifier|science}}
*: Hokkien: {{t+|nan-hbl|建築|tr=kiàn-tio̍k}}
*: Mandarin: {{t+|cmn|建築}}, {{t+|cmn|建築學}} {{qualifier|science}}
* Crimean Tatar: {{t|crh|mimarcılıq}}
* Czech: {{t+|cs|architektura|f}}
* Danish: {{t+|da|arkitektur|c}}
* Dutch: {{t+|nl|architectuur|f}}, {{t+|nl|bouwstijl|m}}
* Esperanto: {{t|eo|arkitekturo}}, {{t|eo|arĥitekturo}}
* Estonian: {{t|et|arhitektuur}}, {{t|et|ehituskunst}}
* Faroese: {{t|fo|byggilist|f}}
* Finnish: {{t+|fi|arkkitehtuuri}}, {{t+|fi|rakennustaide}}
* French: {{t+|fr|architecture|f}}
* Frisian:
*: North Frisian: {{t|frr|baukonst}}
*: Saterland Frisian: {{t|stq|Baukunst}}
*: West Frisian: {{t+|fy|boukeunst|c}}
* Galician: {{t+|gl|arquitectura|f}}
* Georgian: {{t|ka|არქიტექტურა}}
* German: {{t+|de|Architektur|f}}, {{t+|de|Baustil|m}}
* Greek: {{t+|el|αρχιτεκτονική|f}}
* Greenlandic: {{t|kl|ilusilersugaaneq}}
* Guarani:
*: Paraguayan Guarani: {{t-check|gug|jogapokuaa}}
* Gujarati: {{t|gu|વાસ્તુકલા|?|tr=vāstukalā}}
* Haitian Creole: {{t|ht|achitekti}}
* Hausa: {{t+|ha|handasa}}
* Hebrew: {{t+|he|אַדְרִיכָלוּת|f|tr=adrikhalút}}, {{t+|he|אַרְכִיטֶקְטוּרָה|f|tr=arxitekˈtura}}
* Hindi: {{t+|hi|वास्तुकला|f|tr=vāstukalā}}, {{t+|hi|स्थापत्य|m}}
* Hungarian: {{t+|hu|építészet}}
* Icelandic: {{t+|is|byggingarlist}}, {{t|is|húsagerðarlist|f}}
* Ido: {{t+|io|arkitekturo}}
* Indonesian: {{t+|id|arsitektur}}, {{t+|id|ilmu bangunan}}, {{t+|id|seni bina}} {{qualifier|Malay}}
* Interlingua: {{t|ia|architectura}}
* Inuktitut: {{t|iu|ᐃᒡᓗᕐᔪᐊᑦ ᐋᖅᑭᒃᓯᒪᓂᖏᑦ}}
* Irish: {{t|ga|ailtireacht|f}}
* Italian: {{t+|it|architettura|f}}
* Japanese: {{t+|ja|建築|tr=けんちく, kenchiku}}, {{t+|ja|建築学|tr=けんちくがく, kenchikugaku}} {{qualifier|science}}
* Javanese: {{t|jv|seni bangunan}}
* Kalmyk: {{t|xal|урн тосхлт}}
* Kannada: {{t|kn|ವಾಸ್ತುಶಿಲ್ಪಶಾಸ್ತ್ರ}}, {{t+|kn|ಕಟ್ಟಡದರಿಮೆ}}
* Kashubian: {{t|csb|architektura|f}}
* Kazakh: {{t|kk|сәулет}}
* Khmer: {{t+|km|ស្ថាបត្យកម្ម}}, {{t|km|និម្មាបនកម្ម}}
* Korean: {{t+|ko|건축(建築)}}, {{t|ko|건축학(建築學)}} {{qualifier|science}}
* Kurdish:
*: Northern Kurdish: {{t+|kmr|mîmarî}}, {{t+|kmr|bînasazî}}
* Kyrgyz: {{t+|ky|архитектура}}
* Lao: {{t|lo|ສະຖາປັດຕະຍະກຳ}}
* Latin: {{t|la|architectūra|f}}
* Latvian: {{t|lv|arhitektūra|f}}
* Lithuanian: {{t+|lt|architektūra|f}}
* Macedonian: {{t|mk|архитекту́ра|f}}
* Malagasy: {{t+|mg|maritrano}}
* Malay: {{t+|ms|seni bina}}
* Malayalam: {{t+|ml|വാസ്തുവിദ്യ}}
* Manx: {{t|gv|ard-obbrinys|m}}, {{t|gv|seyrnaght|f}}
* Māori: {{t|mi|hoahoanga}}
* Marathi: {{t|mr|वास्तुशास्त्र|?}}
* Mongolian:
*: Cyrillic: {{t|mn|уран барилга}}, {{t+|mn|архитектур}}
* Nahuatl: {{t|nah|arquitectura}}, {{t|nah|calmanayōtl}}, {{t+|nah|calmanaliztli}}
* Neapolitan: {{t|nap|archetettura}}
* Norwegian:
*: Bokmål: {{t+|nb|arkitektur|m}}
* Occitan: {{t+|oc|arquitectura|f}}, {{t|oc|architectura|f}}
* Pashto: {{t|ps|مهندسي|tr=muhandasī}}, {{t|ps|معماري|tr=miʿmārī}}
* Persian: {{t+|fa|معماری|tr=me'mâri}}, {{t+|fa|مهرازی|tr=mehrâzi}}, {{t+|fa|مهندسی|tr=mohandasi}} {{qualifier|Dari}}
* Pitcairn-Norfolk: {{t|pih|aarkitekchur}}
* Polish: {{t+|pl|architektura|f}}
* Portuguese: {{t+|pt|arquitetura|f}}
* Punjabi: {{t|pa|ਵਾਸਤੂਕਲਾ|?}}
* Quechua: {{t|qu|sumaq wasichay kamay}}, {{t|qu|arkhitiktura}}
* Romanian: {{t+|ro|arhitectură|f}}
* Russian: {{t+|ru|архитекту́ра|f}}, {{t+|ru|зо́дчество|n}} {{qualifier|dated or poetic}}
* Sanskrit: {{t|sa|स्थापत्यकर्म}}
* Scottish Gaelic: {{t|gd|ailtearachd|f}}
* Serbo-Croatian:
*: Cyrillic: {{t|sh|архитекту́ра|f}}
*: Latin: {{t+|sh|arhitektúra|f}}
* Silesian: {{t|szl|baukůnšt}}
* Sinhalese: {{t|si|වාස්තු විද්යාව|?}}
* Slovak: {{t|sk|architektúra|f}}
* Slovene: {{t+|sl|arhitektura|f}}
* Spanish: {{t+|es|arquitectura|f}}
* Swahili: {{t+|sw|ujenzi|c14}}, {{t|sw|usanifu majengo}}
* Swedish: {{t+|sv|arkitektur|c}}
* Tagalog: {{t|tl|arkitektura}}, {{t|tl|agbarugan}}
* Tajik: {{t+|tg|меъморӣ}}
* Tamil: {{t+|ta|கட்டிடக்கலை}}
* Tatar: {{t|tt|мигмарлык}}, {{t|tt|архитектура}}
* Telugu: {{t+|te|వాస్తుశాస్త్రము}}
* Thai: {{t+|th|สถาปัตยกรรม}}
* Tibetan: {{t|bo|ཁང་རྩིག་བཟོ་རིག}}
* Turkish: {{t+|tr|mimarlık}}
*: Ottoman Turkish: {{t|ota|معمارلق|tr=mi'mârlık}}
* Turkmen: {{t+|tk|arhitektura}}
* Ukrainian: {{t+|uk|архітекту́ра|f}}
* Uyghur: {{t|ug|بىناكارلىق}}
* Uzbek: {{t+|uz|meʼmorlik}}, {{t+|uz|me’morchilik}}, {{t+|uz|arxitektura}}
* Vietnamese: {{t+|vi|kiến trúc}}
* Volapük: {{t+|vo|bumav}}
* Võro: {{t|vro|ehitüskunst}}
* Welsh: {{t|cy|pensaernïaeth|f}}
* Yiddish: {{t|yi|אַרכיטעקטור|f}}
* Yoruba: {{t|yo|ákítẹ́ṣọ̀}}
{{trans-bottom}}
{{trans-top|style of building design}}
* Indonesian: {{t+|id|arsitektur}}
{{trans-bottom}}
{{trans-see|construction, in a more general sense; frame or structure; workmanship|construction|structure|workmanship}}
{{trans-top|computing: a family of CPUs sharing a common instruction set and having partial or full compatibility with software built on each other}}
* Indonesian: {{t+|id|arsitektur}}
{{trans-bottom}}
{{trans-top|computing: a specific model of a microchip or CPU}}
* Indonesian: {{t+|id|arsitektur}}
* Polish: {{t+|pl|architektura|f}}
{{trans-bottom}}
=== අමතර අවධානයට ===
[[Appendix:Glossary of architecture]]
{{C|en|Architecture|Systems theory}}
== ප්රංශ ==
=== නිරුක්තිය ===
From {{der|fr|la|architectūra}}.
=== උච්චාරණය ===
* {{fr-IPA}}
* {{audio|fr|Fr-architecture.ogg|text=une architecture}}
* {{audio|fr|LL-Q150 (fra)-LoquaxFR-architecture.wav|a=<<France>> (<<Vosges>>)}}
* {{audio|fr|LL-Q150 (fra)-Mecanautes-architecture.wav|a=France}}
* {{audio|fr|LL-Q150 (fra)-Poslovitch-architecture.wav|a=<<France>> (<<Vosges>>)}}
* {{audio|fr|LL-Q150 (fra)-Jérémy-Günther-Heinz Jähnick-architecture.wav|a=<<France>> (<<Somain>>)}}
=== නාම පදය ===
{{fr-noun|f}}
# {{l|en|architecture}}
==== ආශ්රිත යෙදුම් ====
{{col3|fr
|architecte
|architectural
|architecturer
}}
====Descendants====
* {{desctree|nl|bor=1|architectuur}}
=== වැඩිදුර් කියවීම සඳහා ===
* {{R:fr:TLFi}}
{{C|fr|Architecture}}
qzyqdodqwr5cp8gqyc8okgo687ohdxv
ගෘහ නිර්මාණ ශිල්පය
0
140600
238778
228029
2026-11-11T14:17:12Z
Lee
19
238778
wikitext
text/x-wiki
== සිංහල ==
=== නිරුක්තිය ===
{{rfe|si}}
=== නාම පදය ===
{{si-noun}}
# {{rfdef|si}}
==== පරිවර්තන ====
{{trans-top|පරිවර්තන}}
* ඉංග්රීසි: {{t|en|architecture}}
{{trans-bottom}}
=== අමතර අවධානයට ===
* {{l|si|වාස්තුවේදය}}
{{c|si|ගෘහ නිර්මාණ ශිල්පය}}
q5om0jj7qm54cde57sotepcyeewbtgc
සැකිල්ල:inc-ash-dial/documentation
10
141664
238820
230542
2026-11-12T07:58:44Z
Pinthura
2424
Bot: Replacing category Ashokan Prakrit templates with [[:ප්රවර්ගය:අශෝක ප්රාකෘත සැකිලි|අශෝක ප්රාකෘත සැකිලි]]
238820
wikitext
text/x-wiki
{{documentation subpage}}
{{documentation needed}}<!-- Replace this with a short description of the purpose of the template, and how to use it. -->
<includeonly>
[[ප්රවර්ගය:අශෝක ප්රාකෘත සැකිලි|dial]]
</includeonly>
t2r5sylgt7tz7aivm7towihzbzkp8h8
සැකිල්ල:see citations/documentation
10
141882
238745
230993
2026-11-11T12:00:09Z
Pinthura
2424
Bot: Replacing category Citation templates with [[:ප්රවර්ගය:උපහරණ සැකිලි|උපහරණ සැකිලි]]
238745
wikitext
text/x-wiki
{{documentation subpage}}
This template can be placed below a definition in a part of speech section, linking to the Citations namespace of a given entry.
The first parameter should be the [[Wiktionary:LANGCODE|language code]].
If the second parameter is provided, the link will be to <tt>[[Citations:{{{2}}}]]</tt>, otherwise it will link to the citations page of the current page.
==See also==
* {{temp|citation}}
* {{temp|see more citations}}
* {{temp|vi-see nom cites}}
<includeonly>
[[ප්රවර්ගය:උපහරණ සැකිලි]]
</includeonly>
34ho61lpg8pnv7tk0xfwk12oiosookh
සැකිල්ල:mul-Brah
10
142033
238754
231325
2026-11-11T12:28:28Z
Lee
19
ප්රවර්ගය:බ්රාහ්මී අක්ෂරක්රමය තුළ භාවිතා වන අනුලක්ෂණ
238754
wikitext
text/x-wiki
{{head|mul|symbol|sc=Brah}}<!--
-->{{#if:{{{1|}}}| ({{{1}}})}}<!--
-->{{#if:{{NAMESPACE}}||[[ප්රවර්ගය:බ්රාහ්මී අක්ෂරක්රමය තුළ භාවිතා වන අනුලක්ෂණ]]}}<!--
--><noinclude>{{documentation}}</noinclude>
0ew0ps84y8jcng08srew3hz7yzotf6g
සැකිල්ල:strip diacritics module documentation/documentation
10
142086
238832
231489
2026-11-12T08:00:47Z
Pinthura
2424
Bot: Replacing category Documentation templates with [[:ප්රවර්ගය:උපදෙස් සැකිලි|උපදෙස් සැකිලි]]
238832
wikitext
text/x-wiki
{{documentation subpage}}
{{uses lua|Module:documentation/strip diacritics}}
This template is used to automatically generate documentation for diacritic stripping modules such as [[Module:ar-stripdiacritics]].
<includeonly>
[[ප්රවර්ගය:උපදෙස් සැකිලි]]
</includeonly>
ep1yohk7w2z3gni5uy6fkdcf734fbod
සැකිල්ල:translation only/documentation
10
143995
238828
235090
2026-11-12T08:00:06Z
Pinthura
2424
Bot: Replacing category Definition templates with [[:ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි|අර්ථ දැක්වීම් සැකිලි]]
238828
wikitext
text/x-wiki
{{documentation subpage}}
<!-- PLEASE ADD CATEGORIES AND INTERWIKIS AT THE BOTTOM OF THIS PAGE -->
{{shortcut|Template:translation hub|Template:thub}}
===Usage===
This template is to be used as the definition line for English terms that are not idiomatic but are kept because their translations into other languages are desirable. It automatically adds the entry to [[:Category:English translation hubs]].
===See also===
*{{temp|&lit}}
<includeonly>
<!-- CATEGORIES AND INTERWIKIS HERE, THANKS -->
[[ප්රවර්ගය:අර්ථ දැක්වීම් සැකිලි]]
[[Category:Translation templates]]
</includeonly>
6ommegivkm2n395eicvvrlvp026lhvp
turbines
0
144001
238789
235117
2026-11-11T16:13:36Z
Lee
19
ශුද්ධ පවිත්ර කිරීම
238789
wikitext
text/x-wiki
{{also|turbinés}}
== ඉංග්රීසි ==
=== නාම පදය ===
{{head|en|noun form}}
# {{plural of|en|turbine}}
==Catalan==
=== උච්චාරණය ===
* {{ca-IPA}}
=== නාම පදය ===
{{head|ca|noun form}}
# {{plural of|ca|turbina}}
== ඕලන්ද ==
=== උච්චාරණය ===
* {{IPA|nl|/tʏrˈbinəs/}}
* {{audio|nl|Nl-turbines.ogg}}
=== නාම පදය ===
{{head|nl|noun form}}
# {{plural of|nl|turbine}}
== ප්රංශ ==
=== ක්රියා පදය ===
{{head|fr|verb form}}
# {{inflection of|fr|turbiner||2|s|pres|ind//sub}}
== ලතින් ==
=== නාම පදය ===
{{head|la|noun form|head=turbinēs}}
# {{inflection of|la|turbō||nom//acc//voc|p}}
== පෘතුගීසි ==
=== ක්රියා පදය ===
{{head|pt|verb form}}
# {{pt-verb form of|turbinar}}
== ස්පාඤ්ඤ ==
=== ක්රියා පදය ===
{{head|es|verb form}}
# {{es-verb form of|turbinar}}
nrv68obk1w6w4ywbqwcgr0co94a9of0
ප්රවර්ගය:සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද
14
145763
238755
2026-11-11T12:29:58Z
Pinthura
2424
සේවා: [[:[[en:Category:Translingual terms spelled with ◌𑁅]]]] තුළ තිබූ පෙළ මෙහි ඇතුළු කිරීම.
238755
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238756
238755
2026-11-11T12:30:08Z
Pinthura
2424
Pinthura විසින් [[ප්රවර්ගය:Translingual terms spelled with ◌𑁅]] සිට [[ප්රවර්ගය:සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද]] වෙත පිටුව ගෙන යන ලදී: සේවා: නව ප්රවර්ග නාමය වෙත ගෙනයාම.
238755
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238758
238756
2026-11-11T12:30:18Z
Pinthura
2424
සේවා: ඉංග්රීසි ව්යාපෘතිය වෙත සබැඳියක් එක් කිරීම.
238758
wikitext
text/x-wiki
{{auto cat}}
[[en:Category:Translingual terms spelled with ◌𑁅]]
r6ixzm36pd2gxw25nqy8ch7gxhzvjz3
ප්රවර්ගය:Translingual terms spelled with ◌𑁅
14
145764
238757
2026-11-11T12:30:09Z
Pinthura
2424
Pinthura විසින් [[ප්රවර්ගය:Translingual terms spelled with ◌𑁅]] සිට [[ප්රවර්ගය:සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද]] වෙත පිටුව ගෙන යන ලදී: සේවා: නව ප්රවර්ග නාමය වෙත ගෙනයාම.
238757
wikitext
text/x-wiki
#යළියොමුව [[:ප්රවර්ගය:සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද]]
fmdmvkdy3gvqmkpkt2s0vq7lvp0pbdt
238759
238757
2026-11-11T12:30:28Z
Pinthura
2424
සේවා: යළියොමුව, මෘදු ප්රවර්ග යළියොමුවක් බවට හැරවීම.
238759
wikitext
text/x-wiki
{{category redirect|සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද}}
cxgswhyt85y7khbw88f99585iz4ydpz
ප්රවර්ගය:Translingual යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද
14
145765
238760
2026-11-11T12:30:38Z
Pinthura
2424
සේවා: මෘදු ප්රවර්ග යළියොමුවක් නිර්මාණය.
238760
wikitext
text/x-wiki
{{category redirect|සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද}}
cxgswhyt85y7khbw88f99585iz4ydpz
ප්රවර්ගය:සර්ව භාෂාමය terms spelled with ◌𑁅
14
145766
238761
2026-11-11T12:30:48Z
Pinthura
2424
සේවා: මෘදු ප්රවර්ග යළියොමුවක් නිර්මාණය.
238761
wikitext
text/x-wiki
{{category redirect|සර්ව භාෂාමය යෙදුම්, ◌𑁅 භාවිතා කොට ලියන ලද}}
cxgswhyt85y7khbw88f99585iz4ydpz
ප්රවර්ගය:සර්ව භාෂාමය terms with redundant transliterations
14
145767
238762
2025-12-29T08:19:03Z
en>WingerBot
0
Created page with "{{auto cat}}"
238762
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238763
238762
2026-11-11T12:35:34Z
Lee
19
[[:en:Category:Translingual_terms_with_redundant_transliterations]] වෙතින් එක් සංශෝධනයක්
238762
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
238764
238763
2026-11-11T12:36:58Z
Lee
19
Lee විසින් [[ප්රවර්ගය:Translingual terms with redundant transliterations]] සිට [[ප්රවර්ගය:සර්ව භාෂාමය terms with redundant transliterations]] වෙත පිටුව ගෙන යන ලදී
238762
wikitext
text/x-wiki
{{auto cat}}
eomzlm5v4j7ond1phrju7cnue91g5qx
ප්රවර්ගය:Translingual terms with redundant transliterations
14
145768
238765
2026-11-11T12:36:59Z
Lee
19
Lee විසින් [[ප්රවර්ගය:Translingual terms with redundant transliterations]] සිට [[ප්රවර්ගය:සර්ව භාෂාමය terms with redundant transliterations]] වෙත පිටුව ගෙන යන ලදී
238765
wikitext
text/x-wiki
#යළියොමුව [[:ප්රවර්ගය:සර්ව භාෂාමය terms with redundant transliterations]]
6h1d7dmaknk8ietga7fg0ad1ma8kvxf
238790
238765
2026-11-12T04:29:45Z
Pinthura
2424
රොබෝ: යළියොමුව, මෘදු ප්රවර්ග යළියොමුවක් බවට හැරවීම
238790
wikitext
text/x-wiki
{{category redirect|සර්ව භාෂාමය terms with redundant transliterations}}
7i0elmf25ldxokg4pkk02k0x00kggkm
Module:category tree/topic/Sciences
828
145769
238774
2026-11-11T14:09:33Z
Lee
19
Lee විසින් [[Module:category tree/topic/Sciences]] සිට [[Module:category tree/topic/Science and technology]] වෙත පිටුව ගෙන යන ලදී
238774
Scribunto
text/plain
return require [[Module:category tree/topic/Science and technology]]
pzuu9gp2rt9gbbd4iib6w02a1fb92rd
Module talk:category tree/topic/Sciences
829
145770
238776
2026-11-11T14:09:33Z
Lee
19
Lee විසින් [[Module talk:category tree/topic/Sciences]] සිට [[Module talk:category tree/topic/Science and technology]] වෙත පිටුව ගෙන යන ලදී
238776
wikitext
text/x-wiki
#යළියොමුව [[Module talk:category tree/topic/Science and technology]]
czsf4uxptlt2hm75hj77ksozrtltkkj
වික්ෂනරි:Category and label treatment requests/ලේඛනාගාරය
4
145771
238780
2025-06-08T04:20:45Z
en>Benwing2
0
238780
wikitext
text/x-wiki
An archive of category and label treatment discussions from [[WT:CLTR|category and label treatment requests]] and its predecessor venues, [[WT:RFM]], [[WT:RFDO]] and [[WT:BP]].
Note that discussions are archived according to '''the date they were started'''.
<onlyinclude>{| class="wikitable" style="width: 40em;"
! Category and label treatment requests: Archive index
|-
| {{Special:PrefixIndex/Wiktionary:Category and label treatment requests/Archives/}}
|}</onlyinclude>
koim9j4s1aqqt5bgsu8jecs4ii1np3l
238781
238780
2026-11-11T14:20:50Z
Lee
19
[[:en:Wiktionary:Category_and_label_treatment_requests/Archives]] වෙතින් එක් සංශෝධනයක්
238780
wikitext
text/x-wiki
An archive of category and label treatment discussions from [[WT:CLTR|category and label treatment requests]] and its predecessor venues, [[WT:RFM]], [[WT:RFDO]] and [[WT:BP]].
Note that discussions are archived according to '''the date they were started'''.
<onlyinclude>{| class="wikitable" style="width: 40em;"
! Category and label treatment requests: Archive index
|-
| {{Special:PrefixIndex/Wiktionary:Category and label treatment requests/Archives/}}
|}</onlyinclude>
koim9j4s1aqqt5bgsu8jecs4ii1np3l
238782
238781
2026-11-11T14:22:09Z
Lee
19
Lee විසින් [[වික්ෂනරි:Category and label treatment requests/Archives]] සිට [[වික්ෂනරි:Category and label treatment requests/ලේඛනාගාරය]] වෙත පිටුව ගෙන යන ලදී
238780
wikitext
text/x-wiki
An archive of category and label treatment discussions from [[WT:CLTR|category and label treatment requests]] and its predecessor venues, [[WT:RFM]], [[WT:RFDO]] and [[WT:BP]].
Note that discussions are archived according to '''the date they were started'''.
<onlyinclude>{| class="wikitable" style="width: 40em;"
! Category and label treatment requests: Archive index
|-
| {{Special:PrefixIndex/Wiktionary:Category and label treatment requests/Archives/}}
|}</onlyinclude>
koim9j4s1aqqt5bgsu8jecs4ii1np3l
වික්ෂනරි:Category and label treatment requests/Archives
4
145772
238783
2026-11-11T14:22:09Z
Lee
19
Lee විසින් [[වික්ෂනරි:Category and label treatment requests/Archives]] සිට [[වික්ෂනරි:Category and label treatment requests/ලේඛනාගාරය]] වෙත පිටුව ගෙන යන ලදී
238783
wikitext
text/x-wiki
#යළියොමුව [[වික්ෂනරි:Category and label treatment requests/ලේඛනාගාරය]]
51xfo74xg4jry0iwdbx0xzrw9qfriht
ප්රවර්ගය:ja:Architecture
14
145773
238785
2026-11-11T14:23:54Z
Lee
19
Lee විසින් [[ප්රවර්ගය:ja:Architecture]] සිට [[ප්රවර්ගය:ja:ගෘහ නිර්මාණ ශිල්පය]] වෙත පිටුව ගෙන යන ලදී
238785
wikitext
text/x-wiki
#යළියොමුව [[:ප්රවර්ගය:ja:ගෘහ නිර්මාණ ශිල්පය]]
p9rvw8ofcvvxisob649dbl95o07kvlt
238791
238785
2026-11-12T04:29:55Z
Pinthura
2424
රොබෝ: යළියොමුව, මෘදු ප්රවර්ග යළියොමුවක් බවට හැරවීම
238791
wikitext
text/x-wiki
{{category redirect|ja:ගෘහ නිර්මාණ ශිල්පය}}
ik3zcgritqligx8c6boxcir0p3ia2c8
Great Attractor
0
145774
238840
2024-10-14T19:47:14Z
en>Box16
0
/* Proper noun */
238840
wikitext
text/x-wiki
==English==
===Proper noun===
{{en-proper noun|head=[[great|Great]] [[attractor|Attractor]]|def=1}}
# {{lb|en|astronomy}} A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].
===Further reading===
* {{pedia}}
2qavt9acbjgtbuopo2rzs4lgqlp7buk
238841
238840
2026-11-12T09:37:55Z
Lee
19
[[:en:Great_Attractor]] වෙතින් එක් සංශෝධනයක්
238840
wikitext
text/x-wiki
==English==
===Proper noun===
{{en-proper noun|head=[[great|Great]] [[attractor|Attractor]]|def=1}}
# {{lb|en|astronomy}} A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].
===Further reading===
* {{pedia}}
2qavt9acbjgtbuopo2rzs4lgqlp7buk
238842
238841
2026-11-12T09:38:25Z
Pinthura
2424
යොමු තොරතුරු පරිවර්තනය
238842
wikitext
text/x-wiki
== ඉංග්රීසි ==
=== සංඥා නාම පදය ===
{{en-proper noun|head=[[great|Great]] [[attractor|Attractor]]|def=1}}
# {{lb|en|astronomy}} A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].
=== වැඩිදුර් කියවීම සඳහා ===
* {{pedia}}
0c7jbu3ewyo57ezueq7ytypc54r7f9s
238843
238842
2026-11-12T09:41:32Z
Lee
19
238843
wikitext
text/x-wiki
== ඉංග්රීසි ==
=== සංඥා නාම පදය ===
{{en-proper noun|head=[[great|Great]] [[attractor|Attractor]]|def=1}}
# {{lb|en|astronomy}} [[මහා ආකර්ෂකය]].
21wy3rrh3sjgtuzyt138wig92gigp7i
මහා ආකර්ෂකය
0
145775
238844
2026-11-12T09:43:05Z
Lee
19
නිර්මාණය
238844
wikitext
text/x-wiki
== සිංහල ==
=== නිරුක්තිය ===
{{rfe|si}}
=== සංඥා නාම පදය ===
{{si-proper noun}}
# {{lb|si|astronomy}} A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].
==== පරිවර්තන ====
{{trans-top|පරිවර්තන}}
* ඉංග්රීසි: {{t|en|Great Attractor}}
{{trans-bottom}}
=== අමතර අවධානයට ===
* {{l|si|හිරු}}
=== වැඩිදුර් කියවීම සඳහා ===
* {{pedia}}
jcxgijf53qfrsojlpvqh7dtb1ldy80d
238845
238844
2026-11-12T09:43:52Z
Lee
19
/* අමතර අවධානයට */
238845
wikitext
text/x-wiki
== සිංහල ==
=== නිරුක්තිය ===
{{rfe|si}}
=== සංඥා නාම පදය ===
{{si-proper noun}}
# {{lb|si|astronomy}} A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].
==== පරිවර්තන ====
{{trans-top|පරිවර්තන}}
* ඉංග්රීසි: {{t|en|Great Attractor}}
{{trans-bottom}}
=== අමතර අවධානයට ===
* {{l|si|හිරු}}
* {{l|si|ක්ෂීරපථය}}
=== වැඩිදුර් කියවීම සඳහා ===
* {{pedia}}
p2pdeexsiuh87ys6xsimkhubqixwr0f
238846
238845
2026-11-12T09:48:06Z
Lee
19
/* සංඥා නාම පදය */
238846
wikitext
text/x-wiki
== සිංහල ==
=== නිරුක්තිය ===
{{rfe|si}}
=== සංඥා නාම පදය ===
{{si-proper noun}}
# {{lb|si|astronomy}} [[ලැනියාකියා]] [[චක්රාවාට]] [[සුපිරි පොකුර|සුපිරි පොකුරේ]] ගුරුත්ත්ව කේන්ද්රය පිහිටි ප්රදේශය. (A [[region]] of [[gravitational]] [[attraction]] in [[intergalactic]] [[space]] and the [[apparent]] [[central]] [[gravitational]] [[point]] of the [[Laniakea]] [[supercluster|Supercluster]] of [[galaxy|galaxies]].)
==== පරිවර්තන ====
{{trans-top|පරිවර්තන}}
* ඉංග්රීසි: {{t|en|Great Attractor}}
{{trans-bottom}}
=== අමතර අවධානයට ===
* {{l|si|හිරු}}
* {{l|si|ක්ෂීරපථය}}
=== වැඩිදුර් කියවීම සඳහා ===
* {{pedia}}
f5pun9e7vml8wlzky1mhvt51d9coswn