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|&nbsp;%1&nbsp;]]}} * [[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|&nbsp;%1&nbsp;]]}} * [[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|&nbsp;%1&nbsp;]]}} * [[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|&nbsp;%1&nbsp;]]}} * [[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&#39;a}}', '<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'nia|wa&#x27;a}}', '<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'ja|恵&#8204;美|恵&amp;#8204;美}}', '<span class="Jpan" lang="ja">[[恵‌美#Japanese|恵&amp;#8204;美]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'en|&amp;}}', '<span class="None" lang="en">[[Unsupported titles/Amp#English|&amp;]]</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&#x3a;Sindarin/mithril|mithril]]</span>' }, 'reconstructed terms', -- ([[Module:languages]]) { '{{' .. temp .. '|' .. lang .. 'ine-pro|*bʰréh₂tēr}}', '<span class="Latn" lang="ine-pro">[[Reconstruction&#x3a;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&#x3a;Proto-Slavic/dьnь|*dьnь]] [[Reconstruction&#x3a;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&#x3a;Latin/verbum|*verbum]] .. [[Reconstruction&#x3a;Latin/verbum|verbum]] .. [[Reconstruction&#x3a;Latin/verbum|*verba]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[serda]]}}', '<span class="Latn" lang="sla-pro">*[[Reconstruction&#x3a;Proto-Slavic/serda|serda]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[*serda]] .. [[*serda]] .. [[serda]] .. [[*serda|serda]] .. [[*serda|*serda]]}}', '<span class="Latn" lang="sla-pro">[[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]] .. [[Reconstruction&#x3a;Proto-Slavic/serda|serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[dьnь|alt1]] [[serda|alt2]]}}', '<span class="Latn" lang="sla-pro">*[[Reconstruction&#x3a;Proto-Slavic/dьnь|alt1]] [[Reconstruction&#x3a;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>&nbsp;<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>&nbsp;<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>&lrm; <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">[[&#x3a;/#Translingual|/]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'mul|//}}', '<span class="None" lang="mul">[[&#x3a;//#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 §&nbsp;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&#39;a}}', '<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'nia|wa&#x27;a}}', '<span class="Latn" lang="nia">[[wa\'a#Nias|wa\'a]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'ja|恵&#8204;美|恵&amp;#8204;美}}', '<span class="Jpan" lang="ja">[[恵‌美#Japanese|恵&amp;#8204;美]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'en|&amp;}}', '<span class="None" lang="en">[[Unsupported titles/Amp#English|&amp;]]</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&#x3a;Sindarin/mithril|mithril]]</span>' }, 'reconstructed terms', -- ([[Module:languages]]) { '{{' .. temp .. '|' .. lang .. 'ine-pro|*bʰréh₂tēr}}', '<span class="Latn" lang="ine-pro">[[Reconstruction&#x3a;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&#x3a;Proto-Slavic/dьnь|*dьnь]] [[Reconstruction&#x3a;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&#x3a;Latin/verbum|*verbum]] .. [[Reconstruction&#x3a;Latin/verbum|verbum]] .. [[Reconstruction&#x3a;Latin/verbum|*verba]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[serda]]}}', '<span class="Latn" lang="sla-pro">*[[Reconstruction&#x3a;Proto-Slavic/serda|serda]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[*serda]] .. [[*serda]] .. [[serda]] .. [[*serda|serda]] .. [[*serda|*serda]]}}', '<span class="Latn" lang="sla-pro">[[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]] .. [[Reconstruction&#x3a;Proto-Slavic/serda|serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|serda]] .. [[Reconstruction&#x3a;Proto-Slavic/*serda|*serda]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'sla-pro|*[[dьnь|alt1]] [[serda|alt2]]}}', '<span class="Latn" lang="sla-pro">*[[Reconstruction&#x3a;Proto-Slavic/dьnь|alt1]] [[Reconstruction&#x3a;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>&nbsp;<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>&nbsp;<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>&lrm; <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">[[&#x3a;/#Translingual|/]]</span>' }, { '{{' .. temp .. '|' .. lang .. 'mul|//}}', '<span class="None" lang="mul">[[&#x3a;//#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 §&nbsp;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 `&amp;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 `&amp;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 `&amp;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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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('"', "&quot;") -- & in attributes is automatically escaped. -- :gsub("&", "&amp;") :gsub("<", "&lt;") :gsub(">", "&gt;") 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`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`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 (&#39; → '), -- as they contain #, which causes the numeric character reference to be -- misparsed (wa'a → wa&#39;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 = "&#x5D;" .. link.display .. "&#x5B;" 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, "&nbsp;" .. 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 &lt; -- and &gt; 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), ["<"] = "&lt;", [">"] = "&gt;", } 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%;\">&nbsp;/ </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>` &rarr; `displayed text` * `<nowiki>[[page and displayed text]]</nowiki>` &rarr; `page and displayed text` * `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` &rarr; ''(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 .. " §&nbsp;" .. 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 (&#39; → '), -- as they contain #, which causes the numeric character reference to be -- misparsed (wa'a → wa&#39;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 = "&#x5D;" .. link.display .. "&#x5B;" 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, "&nbsp;" .. 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 &lt; -- and &gt; 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), ["<"] = "&lt;", [">"] = "&gt;", } 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%;\">&nbsp;/ </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>` &rarr; `displayed text` * `<nowiki>[[page and displayed text]]</nowiki>` &rarr; `page and displayed text` * `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` &rarr; ''(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 .. " §&nbsp;" .. 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 (&#39; → '), -- as they contain #, which causes the numeric character reference to be -- misparsed (wa'a → wa&#39;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 = "&#x5D;" .. link.display .. "&#x5B;" 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, "&nbsp;" .. 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 &lt; -- and &gt; 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), ["<"] = "&lt;", [">"] = "&gt;", } 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%;\">&nbsp;/ </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>` &rarr; `displayed text` * `<nowiki>[[page and displayed text]]</nowiki>` &rarr; `page and displayed text` * `<nowiki>[[Category:English lemmas|WORD]]</nowiki>` &rarr; ''(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 .. " §&nbsp;" .. 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) .. '&#xFE0E; || style="padding: 0;" | ' .. u(codepoint) .. '&#xFE0F;\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&amp;#xFE0E;⟩ and emoji style with ⟨&amp;#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|&amp;#" .. 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> &#91;U+%04X&#93;]]') :format(link_target, script, dotted_circle, nfdcp, nfdcp) or ('<span class="%s">%s&#%u;</span> &#91;U+%04X&#93;') :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) .. '&#xFE0E; || style="padding: 0;" | ' .. u(codepoint) .. '&#xFE0F;\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&amp;#xFE0E;⟩ and emoji style with ⟨&amp;#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|&amp;#" .. 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> &#91;U+%04X&#93;]]') :format(link_target, script, dotted_circle, nfdcp, nfdcp) or ('<span class="%s">%s&#%u;</span> &#91;U+%04X&#93;') :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) .. '&#xFE0E; || style="padding: 0;" | ' .. u(codepoint) .. '&#xFE0F;\n|- style="font-size: 80%;"\n| colspan="2" | Text style is [[variation selector|forced with]] ⟨&amp;#xFE0E;⟩ and emoji style with ⟨&amp;#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|&amp;#" .. 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> &#91;U+%04X&#93;]]') :format(link_target, script, dotted_circle, nfdcp, nfdcp) or ('<span class="%s">%s&#%u;</span> &#91;U+%04X&#93;') :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|}}}|&#32;or [[:Category:{{{2}}}|{{{alt2|{{{2}}}}}}]]}}{{#if:{{{3|}}}|&#32;or [[:Category:{{{3}}}|{{{alt3|{{{3}}}}}}]]}}{{#if:{{{4|}}}|&#32;or [[:Category:{{{4}}}|{{{alt4|{{{4}}}}}}]]}}{{#if:{{{5|}}}|&#32;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|}}}|&#32;or [[:Category:{{{2}}}|{{{alt2|{{{2}}}}}}]]}}{{#if:{{{3|}}}|&#32;or [[:Category:{{{3}}}|{{{alt3|{{{3}}}}}}]]}}{{#if:{{{4|}}}|&#32;or [[:Category:{{{4}}}|{{{alt4|{{{4}}}}}}]]}}{{#if:{{{5|}}}|&#32;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|,&amp;#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>[&#x5B;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|}}}|&#32;({{{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