Wiktionary gdwiktionary https://gd.wiktionary.org/wiki/Pr%C3%AComh-Dhuilleag MediaWiki 1.47.0-wmf.14 case-sensitive Meadhan Sònraichte Deasbaireachd Cleachdaiche Deasbaireachd a' chleachdaiche Wiktionary An deasbaireachd aig Wiktionary Faidhle Deasbaireachd an fhaidhle MediaWiki Deasbaireachd MediaWiki Teamplaid Deasbaireachd na teamplaid Cobhair Deasbaireachd na cobharach Roinn-seòrsa Deasbaireachd na roinn-seòrsa TimedText TimedText talk Mòideal Deasbaireachd mòideil Event Event talk Alba 0 4330 88843 86001 2026-08-06T21:43:42Z Altronic 4137 fix page 88843 wikitext text/x-wiki ==Gàidhlig== [[Faidhle:Scotland in the UK and Europe.svg|thumb|Suidheachadh na h-Alba]] ===Freumhachadh=== Bho {{inh|gd|sga|Albu|t=Breatainn Mhòr}}. ===Fuaimneachadh=== * {{IPA|gd|/ˈaˈl̪ˠa.pə/}} ===Ainmear sònrachaidh=== {{gd-proper noun|b|Alba|-}} # [[tìr|Tìr]] a th' ann an [[tuath]] na [[Breatainn Mhòr|Breatainne Mòire]]. ## Dùthaich a th' ann an [[Rìoghachd Aonaichte]]. ## {{lb|gd|eachdraidheil}} [[Rìoghachd na h-Alba]], [[rìoghachd]] gu robh anns a' Bhreatainn Mhòir gu ruige cruthachadh na [[Rìoghachd na Breatainne Mòire]]. ===Mùthadh=== {{gd-mut}} ===Barrachd fiosrachaidh=== * {{R:Dwelly}} oc7m48w0silpm78m6erwbwv00f2gxuf Mòideal:gd-conj 828 16619 88994 88704 2026-08-06T23:30:18Z Altronic 4137 88994 Scribunto text/plain local export = {} local wikitext = [=[ ! rowspan="2" | taisbeanach ! colspan="2" | neo-eisimeileach ! colspan="2" | eisimeileach |- class="secondary" ! class="secondary" | [[pearsanta]] ! class="secondary" | [[fulangach]] ! class="secondary" | [[pearsanta]] ! class="secondary" | [[fulangach]] |- ! caithte | {{{past-indep}}} | {{{past-indep-impersonal}}} | {{{past-dep}}} | {{{past-dep-impersonal}}} |- ! teachdail | {{{fut-indep}}} | {{{fut-indep-impersonal1}}}</br>{{{fut-indep-impersonal2}}} | {{{fut-dep}}} | {{{fut-dep-impersonal1}}}</br>{{{fut-indep-impersonal2}}} |- ! teachdail dàimheach | {{{relfut}}} | {{{relfut-impersonal}}} | — | — |- | class="separator" colspan=9 | |- class="inflection-table-cyan" ! rowspan="2" | conditional ! colspan="2" | neo-eisimeileach ! colspan="2" | eisimeileach |- class="inflection-table-cyan" ! class="secondary" | [[pearsanta]] ! class="secondary" | [[fulangach]] ! class="secondary" | [[pearsanta]] ! class="secondary" | [[fulangach]] |- class="inflection-table-cyan" ! a' chiad phearsa singilte | {{{cond-indep-first}}} | rowspan=3 | {{{cond-indep-first-impersonal}}}<br>{{{cond-indep-first-impersonal-l1}}}<sup>1</sup><br>{{{cond-indep-first-impersonal-l2}}}<sup>1</sup> | {{{cond-dep-first}}} | rowspan=3 | {{{cond-dep-first-impersonal}}}<br>{{{cond-dep-first-impersonal-l1}}}<sup>1</sup><br>{{{cond-dep-first-impersonal-l2}}}<sup>1</sup> |- class="inflection-table-cyan" ! a' chiad phearsa iolra | {{{cond-indep-first-pl}}}<br>{{{cond-indep-third}}} sinn | {{{cond-dep-first-pl}}}<br>{{{cond-dep-third}}} sinn |- class="inflection-table-cyan" ! an dàrna/treas pearsa | {{{cond-indep-third}}} | {{{cond-dep-third}}} |- | class="separator" colspan=4 | ! colspan=5 rowspan=6 class=blank-end-row | |- class="inflection-table-green" ! rowspan=2 | àithneach ! colspan=3 | neo-eisimeileach |- class="inflection-table-green" ! class="secondary" | singilte ! class="secondary" | iolra ! class="secondary" | [[fulangach]] |- class="inflection-table-green" ! a' chiad phearsa | {{{imper-first}}} | {{{imper-first-pl}}} | rowspan=3 | {{{imper-impersonal1}}}<br>{{{imper-impersonal2}}} |- class="inflection-table-green" ! an dàrna pearsa | {{{imper-second}}} | {{{imper-second-pl}}} |- class="inflection-table-green" ! an treas pearsa | colspan=2 | {{{imper-third}}} |- | class="separator" colspan=4 | ! colspan=5 rowspan=4 class=blank-end-row | |- class="inflection-table-amber" ! pàirtear caithte | colspan=3 | {{{participle}}} |- | class="separator" colspan=4 | |- class="inflection-table-yellow" ! ainmear gnìomhaireach | colspan=3 | {{{vn}}} ]=] local participle = nil local vn = nil local fut = nil local langcode = require("Module:languages").getByCode("gd") local m_links = require("Module:links") local function mutate(term) local lower = mw.ustring.lower(term) local out = term if mw.ustring.find(lower, "^[bsdfgmpst]h") then return out end if mw.ustring.find(lower, "^[bcdfgmpt]") then out = mw.ustring.gsub(term, "^(.)", "%1h") elseif mw.ustring.find(lower, "^s[aeiouàèìòùáéólnr]") then out = mw.ustring.gsub(term, "^(.)", "%1h") end if mw.ustring.find(lower, "^[k]") then out = mw.ustring.gsub(term, "^(.)", "ch") end if mw.ustring.find(lower, "^[aàeèiìoòuùáéó]") then out = mw.ustring.gsub(term, "^(.)", "dh'%1") elseif mw.ustring.find(out, "^fh[aeiouàèìòùáéó]") then out = mw.ustring.gsub(out, "^(.)", "dh'%1") end return out end local function ending(type, stem, broad, slender) local out if type == "broad" then out = stem .. broad else out = stem .. slender end return out end local function get_vowel_type(string) local function contains(table, entry) for _, value in ipairs(table) do if value == entry then return true end end return false end local len = mw.ustring.len(string) local broad = { 'a', 'à', 'á', 'o', 'ò', 'ó'} local slender = { 'e', 'è', 'é', 'i', 'ì' } for i = len, 1, -1 do local char = mw.ustring.sub(string, i, i) if contains(broad, char) then return "broad" elseif contains(slender, char) then return "slender" end end return "no-vowel" end local function conjugate(param, term) local conj = term local type = get_vowel_type(conj) if param == "participle" then if participle then return m_links.full_link({ lang = langcode, term = participle }, nil, true) else return m_links.full_link({ lang = langcode, term = ending(type, conj, "ta", "te") }) end end if param == "vn" then conj = m_links.full_link({ lang = langcode, term = vn }, nil, true) return conj end -- switch statement of all the possible conjugation types -- indicative if param == "past-indep" or param == "past-dep" then conj = mutate(conj) elseif param == "past-indep-impersonal" or param == "past-dep-impersonal" then conj = mutate(conj) conj = ending(type, conj, "adh", "eadh") elseif param == "fut-indep" then if fut ~= nil then conj = fut type = get_vowel_type(conj) end conj = ending(type, conj, "aidh", "idh") elseif param == "fut-indep-impersonal1" or param == "fut-dep-impersonal1" or param == "imper-impersonal1" then if fut ~= nil then conj = fut type = get_vowel_type(conj) end conj = ending(type, conj, "ar", "ear") elseif param == "fut-indep-impersonal2" or param == "fut-dep-impersonal2" or param == "imper-impersonal2" then if fut ~= nil then -- TODO: forms with syncope don't have the ~tar forms, see [[labhair]] as an example conj = fut type = get_vowel_type(conj) end conj = ending(type, conj, "tar", "tear") elseif param == "fut-dep" then return m_links.full_link({ term = conj, lang = langcode }, nil, true) elseif param == "relfut" then conj = mutate(conj) conj = ending(type, conj, "as", "eas") elseif param == "relfut-impersonal" then conj = mutate(conj) conj = ending(type, conj, "ar", "ear") -- conditional elseif param == "cond-indep-first" then conj = mutate(conj) conj = ending(type, conj, "ainn", "inn") elseif param == "cond-indep-first-impersonal" then conj = mutate(conj) conj = ending(type, conj, "tadh", "teadh") elseif param == "cond-indep-first-impersonal-l1" then conj = mutate(conj) conj = ending(type, conj, "aist", "ist") elseif param == "cond-indep-first-impersonal-l2" then conj = mutate(conj) conj = ending(type, conj, "aiste", "iste") elseif param == "cond-indep-first-pl" then conj = mutate(conj) conj = ending(type, conj, "amaid", "eamaid") elseif param == "cond-indep-third" then conj = mutate(conj) conj = ending(type, conj, "adh", "eadh") elseif param == "cond-dep-first" then conj = ending(type, conj, "ainn", "inn") elseif param == "cond-dep-first-impersonal" then conj = ending(type, conj, "tadh", "teadh") elseif param == "cond-dep-first-impersonal-l1" then conj = ending(type, conj, "aist", "ist") elseif param == "cond-dep-first-impersonal-l2" then conj = ending(type, conj, "aiste", "iste") elseif param == "cond-dep-first-pl" then conj = ending(type, conj, "amaid", "eamaid") elseif param == "cond-dep-third" then conj = ending(type, conj, "adh", "eadh") elseif param == "imper-first" then conj = ending(type, conj, "am", "eam") elseif param == "imper-first-pl" then conj = ending(type, conj, "amaid", "eamaid") elseif param == "imper-second" then return m_links.full_link({ term = conj, lang = langcode }, nil, true) elseif param == "imper-second-pl" then conj = ending(type, conj, "aibh", "ibh") elseif param == "imper-third" then conj = ending(type, conj, "adh", "eadh") end return m_links.full_link({ term = conj, lang = langcode }, nil, true) end function export.draw(frame) local parentargs = frame:getParent().args local params = { [1] = { required = true, type = "parameter" }, ["pp"] = true, ["fut"] = true } local args = require("Module:parameters").process(parentargs, params) local term = require("Module:headword/data").pagename vn = args[1] if args["pp"] ~= nil then participle = args["pp"] end if args["fut"] ~= nil then fut = args["fut"] end local result = frame:expandTemplate{ title = "inflection-table-top", args = { title = "Co-nasgadh dhe " .. m_links.full_link({ lang = langcode, alt = term }, 'term') .. " ([[Appendix:Gnìomhairean na Gàidhlig|riaghailteach]])", tall = "yes", palette = "blue" } } result = result .. '\n' result = result .. mw.ustring.gsub(wikitext, "{{{([a-z0-9_-]+)}}}", function(param) return conjugate(param, term) end) result = result .. frame:expandTemplate{ title = "inflection-table-bottom", args = { notes = "1. Ann an Leòdhas" } } return result end return export 7neup56n698nqfkjbse98iwl2bsok4i seo 0 16840 88846 87974 2026-08-06T21:56:51Z Altronic 4137 Fix entry 88846 wikitext text/x-wiki ==Gàidhlig na h-Èireann== ===Cruthan eile=== * {{alter|ga|so||Mumhain}} * {{alter|ga|seod|seobh||CF}}{{ref|{{R:ga:GCFD|349|page=161}}}} ===Freumhachadh=== Bho {{inh|ga|sga|so}}. ===Fuaimneachadh=== * {{IPA|ga|/ʃɔ(h)/|ref={{R:ga:SjPh|67|section=126}} !!! {{R:ga:Quiggin|120|351}} !!! {{R:ga:Ó Searcaigh|page=8|section=12}}}} ===Riochdair=== {{head|ga|riochdair}} # seo #: {{ux|ga|Seo mo theach.|Seo mo thaigh.|inline=1}} ===Cinntiche=== {{head|ga|cinntiche}} # seo {{gloss|leis {{m|ga|an}}}} #: {{ux|ga|An bhfuil tú ag iarraidh an leabhar seo a fháil ar iasacht?|A bheil thu ag iarraidh an leabhar seo a ghabhail air iasad?}} ===Co-ghnìomhair=== {{head|ga|co-ghnìomhair}} # [[an-seo]] {{gloss|a' filleadh gluasad}} #: {{ux|ga|Cuir é seo.|Cuir e (sìos) an-seo.}} ===Iomraidhean=== {{reflist|size=smaller}} ===Barrachd fiosrachaidh=== * {{R:ga:Ó Dónaill}} * {{R:ga:NEID}} * {{R:DIL|38191|so}} cbctx2bl3q8x9yj73tx9eqqi9bkdnyh Mòideal:quote 828 17507 88847 87915 2026-08-06T22:00:45Z Altronic 4137 change text 88847 Scribunto text/plain --[=[ This module contains functions to implement quote-* templates. Author: Benwing2; conversion into Lua of {{quote-meta/source}} template, written by Sgconlaw with some help from Erutuon and Benwing2. The main interface is quote_t(). Note that the source display is handled by source(), which reads both the arguments passed to it *and* the arguments passed to the parent template, with the former overriding the latter. ]=] local export = {} --[=[ FIXME: 1. Dates like `1 march 2025` with the day of the month being 1 and the month lowercased are treated as month-year-only. The relevant code checks for a capitalized word; it should probably instead check for the actual month names or abbrevs. ]=] -- Named constants for all modules used, to make it easier to swap out sandbox versions. local check_isxn_module = "Module:check isxn" local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local italics_module = "Module:italics" local labels_module = "Module:labels" local languages_module = "Module:languages" local languages_error_module = "Module:languages/error" local links_module = "Module:links" local number_utilities_module = "Module:number utilities" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local qualifier_module = "Module:qualifier" local roman_numerals_module = "Module:roman numerals" local scribunto_module = "Module:Scribunto" local script_utilities_module = "Module:script utilities" local scripts_module = "Module:scripts" 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 template_parser_module = "Module:template parser" local usex_module = "Module:usex" local usex_templates_module = "Module:usex/templates" local utilities_module = "Module:utilities" local yesno_module = "Module:yesno" local concat = table.concat local insert = table.insert local new_title = mw.title.new local remove = table.remove local require = require local sort = table.sort local u = mw.ustring.char local ugsub = mw.ustring.gsub local umatch = mw.ustring.match local unpack = unpack or table.unpack -- Lua 5.2 compatibility -- Use HTML entities here to avoid parsing issues (esp. with brackets) local SEMICOLON_SPACE = "&#59; " local SPACE_LBRAC = " &#91;" local RBRAC = "&#93;" local TEMP_LT = u(0xFFF1) local TEMP_GT = u(0xFFF2) local TEMP_LBRAC = u(0xFFF3) local TEMP_RBRAC = u(0xFFF4) local TEMP_SEMICOLON = u(0xFFF5) local function apply_subst(...) apply_subst = require(usex_module).apply_subst return apply_subst(...) end local function check_isbn(...) check_isbn = require(check_isxn_module).check_isbn return check_isbn(...) end local function check_issn(...) check_issn = require(check_isxn_module).check_issn return check_issn(...) 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 embedded_language_links(...) embedded_language_links = require(links_module).embedded_language_links return embedded_language_links(...) end local function escape_wikicode(...) escape_wikicode = require(parse_utilities_module).escape_wikicode return escape_wikicode(...) 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 find_parameters(...) find_parameters = require(template_parser_module).find_parameters return find_parameters(...) end local function format_categories(...) format_categories = require(utilities_module).format_categories return format_categories(...) end local function format_processed_labels(...) format_processed_labels = require(labels_module).format_processed_labels return format_processed_labels(...) end local function format_qualifier(...) format_qualifier = require(qualifier_module).format_qualifier return format_qualifier(...) end local function format_usex(...) format_usex = require(usex_module).format_usex return format_usex(...) end local function get_lang(...) get_lang = require(languages_module).getByCode return get_lang(...) end local function get_number(...) get_number = require(number_utilities_module).get_number return get_number(...) end local function get_script(...) get_script = require(scripts_module).getByCode return get_script(...) end local function gsplit(...) gsplit = require(string_utilities_module).gsplit return gsplit(...) end local function page_should_be_ignored(...) page_should_be_ignored = require(usex_templates_module).page_should_be_ignored return page_should_be_ignored(...) end local function parse_inline_modifiers(...) parse_inline_modifiers = require(parse_utilities_module).parse_inline_modifiers return parse_inline_modifiers(...) end local function parse_inline_modifiers_from_segments(...) parse_inline_modifiers_from_segments = require(parse_utilities_module).parse_inline_modifiers_from_segments return parse_inline_modifiers_from_segments(...) end local function parse_multi_delimiter_balanced_segment_run(...) parse_multi_delimiter_balanced_segment_run = require(parse_utilities_module).parse_multi_delimiter_balanced_segment_run return parse_multi_delimiter_balanced_segment_run(...) end local function parse_term_with_lang(...) parse_term_with_lang = require(parse_utilities_module).parse_term_with_lang return parse_term_with_lang(...) end local function pattern_escape(...) pattern_escape = require(string_pattern_escape_module) return pattern_escape(...) end local function pluralize(...) pluralize = require(en_utilities_module).pluralize return pluralize(...) end local function process_params(...) process_params = require(parameters_module).process return process_params(...) end local function remove_links(...) remove_links = require(links_module).remove_links return remove_links(...) end local function roman_to_arabic(...) roman_to_arabic = require(roman_numerals_module).roman_to_arabic return roman_to_arabic(...) end local function replacement_escape(...) replacement_escape = require(string_replacement_escape_module) return replacement_escape(...) end local function scribunto_parameter_key(...) scribunto_parameter_key = require(scribunto_module).scribunto_parameter_key return scribunto_parameter_key(...) end local function serial_comma_join(...) serial_comma_join = require(table_module).serialCommaJoin return serial_comma_join(...) 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 split_alternating_runs(...) split_alternating_runs = require(parse_utilities_module).split_alternating_runs return split_alternating_runs(...) end local function split_and_process_raw_labels(...) split_and_process_raw_labels = require(labels_module).split_and_process_raw_labels return split_and_process_raw_labels(...) end local function split_on_comma(...) split_on_comma = require(parse_utilities_module).split_on_comma return split_on_comma(...) end local function tag_text(...) tag_text = require(script_utilities_module).tag_text return tag_text(...) end local function tag_transcription(...) tag_transcription = require(script_utilities_module).tag_transcription return tag_transcription(...) end local function tag_translit(...) tag_translit = require(script_utilities_module).tag_translit return tag_translit(...) end local function ulen(...) ulen = require(string_utilities_module).len return ulen(...) end local function unitalicize_brackets(...) unitalicize_brackets = require(italics_module).unitalicize_brackets return unitalicize_brackets(...) end local function upper(...) upper = require(string_utilities_module).upper return upper(...) end local function usub(...) usub = require(string_utilities_module).sub return usub(...) end local function yesno(...) yesno = require(yesno_module) return yesno(...) end local function track(page) debug_track("quote/" .. page) end local function maintenance_line(text) return '<span class="maintenance-line">(' .. text .. ")</span>" end local function isbn(text) return "[[Special:BookSources/" .. text .. "|→ISBN]]" .. check_isbn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISBN</span>[[Category:Pages with ISBN errors]]' ) end local function issn(text) return "[https://www.worldcat.org/issn/" .. text .. " →ISSN]" .. check_issn( text, '&nbsp;<span class="error" style="font-size:88%">Invalid&nbsp;ISSN</span>[[Category:Pages with ISSN errors]]' ) end local function lccn(text) text = text:gsub(" ", "") if text:find("-") then -- old-style LCCN; reformat per request by [[User:The Editor's Apprentice]] local prefix, part1, part2 = text:match("^(.-)(%d+)%-(%d+)$") if prefix then if ulen(part2) < 6 then part2 = ("0"):rep(6 - ulen(part2)) .. part2 end text = prefix .. part1 .. part2 end end return "[https://lccn.loc.gov/" .. mw.uri.encode(text) .. " →LCCN]" end local function format_date(text) return mw.getCurrentFrame():callParserFunction("#formatdate", text, "dmy") end -- Parse a raw lb= param (or nil) to individual label info objects and then concatenate them appropriately into a -- qualifier input, respecting flags like `omit_preComma` and `omit_postSpace` in the label specs. local function parse_and_format_labels(raw_lb, lang) if not raw_lb then return nil end local labels = split_and_process_raw_labels{labels = raw_lb, lang = lang, nocat = true} labels = format_processed_labels{labels = labels, lang = lang, no_ib_content = true} if labels ~= "" then -- not sure labels can be an empty string but it seems possible in some circumstances return {labels} end end -- Convert a comma-separated list of language codes to a comma-separated list of language names. `fullname` is the -- name of the parameter from which the list of language codes was fetched. local function format_langs(langs) local names = {} for i, lang in ipairs(langs) do names[i] = lang:getCanonicalName() end if #names == 1 then return names[1] end return serial_comma_join(names) end local function get_first_lang(langs) return langs[1] or get_lang("und") end --[=[ Normally we parse off inline modifiers and language code prefixes in various places, e.g. he:מרים<tr:Miryem>. But we exclude HTML entries with <span ...>, <i ...>, <br/> or similar in it, caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Basically, all tags of the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the outer level is to allow generated HTML inside of e.g. qualifier modifiers, such as foo<q:similar to {{m|fr|bar}}> (if we end up supporting such modifiers). Also exclude things that look like URL's from being parsed as having language code prefixes. ]=] local function val_should_not_be_parsed_for_annotations(val) return val:find("^[^<]*<%l*[^%l:]") or val:find("^%l+://") end local param_mods = { t = { -- <t:...> and <gloss:...> are aliases. item_dest = "gloss", }, gloss = {}, alt = {}, tr = {}, ts = {}, subst = {}, sc = {type = "script"}, f = { convert = function(arg, parse_err) local prefix, val = arg:match("^(.-):([^ ].*)$") if not prefix then prefix = "" val = arg end local tags, sc_code, sc = prefix:match("^(.*)/(.-)$") if sc_code then sc = get_script(sc_code) or require(languages_error_module)(sc_code, parse_err, "script code", nil, "not real lang") else tags = prefix end local quals if tags ~= "" then quals = split_on_comma(tags) for i, qual in ipairs(quals) do local obj = get_lang(qual, nil, "allow etym") or get_script(qual) quals[i] = obj or qual end end return { quals = quals, sc = sc, val = val, } end, store = "insert", }, q = {}, qq = {}, } local function generate_obj_annotated_text(text, parse_err, paramname) local obj = {} if text:find(":[^ ]") or text:find("%[%[") then local display, is_wikipedia_wikisource obj.text, obj.lang, obj.link, display, is_wikipedia_wikisource = parse_term_with_lang { term = text, parse_err = parse_err, paramname = paramname } -- HACK: If object is a Wikipedia or Wikisource link, we need to convert it to a two-part link -- to avoid the w: or s: prefix showing. We should probably avoid this by calling -- language_link() (in [[Module:links]]) in format_annotated_text() instead of the hacky stuff -- that we currently do; but we need to test that carefully to make sure it doesn't do things like -- munge % signs. if is_wikipedia_wikisource and not obj.text:find("%[%[") and not obj.text:find("%]%]") then -- Don't directly set .alt, because then if the user specifies <alt:...>, it will cause an error in -- parse_inline_modifiers(). obj.display = display end else obj.text = text obj.link = text end return obj end --[=[ Parse a textual property that may be in a foreign language or script and may be annotated with a language prefix and/or inline modifiers. `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier. If `val` is nil, the return value of this function is nil. Otherwise it is parsed for a language prefix (e.g. 'ar:مُؤَلِّف') and inline modifiers (e.g. 'ar:مُؤَلِّف<t:Author>'), and the return value is an object with the following fields: `lang`: The language object corresponding to the language prefix, if specified, or nil if no language prefix is given. `text`: The text after stripping off any language prefix and inline modifiers. `link`: The link part of the text if it consists of a two-part link; otherwise, same as `text`. `alt`: Display text specified using the <alt:...> modifier, if given; otherwise, nil. `subst`: Substitutions used to generate the transliteration, in the same format as the subst= parameter. `sc`: The script object corresponding to the <sc:...> modifier, if given; otherwise nil. `tr`: The transliteration corresponding to the <tr:...> modifier, if given; otherwise nil. `ts`: The transcription corresponding to the <ts:...> modifier, if given; otherwise nil. `gloss`: The gloss/translation corresponding to the `explicit_gloss` parameter (if given and non-nil), otherwise the <t:...> or <gloss:...> modifiers if given, otherwise nil. `f`: Foreign versions of the text. `q`: Left qualifiers. `qq`: Right qualifiers. Note that as a special case, if `val` contains HTML tags at the top level (e.g. '<span class="Arab">...</span>', as might be generated by specifying {{lang|ar|مُؤَلِّف}}), no language prefix or inline modifiers are parsed, and the return value has the `noscript` field set to true, which tells format_annotated_text() not to try to identify the script of the text and CSS-tag the text accordingly, but to leave the text untagged. This object can be passed to format_annotated_text() to format a string displaying the text (appropriately script-tagged, unless `noscript` is set, as described above) and modifiers. ]=] local function parse_annotated_text(val, fullname, explicit_gloss) if not val then return nil end -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, caused -- by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed as having -- language code prefixes. See val_should_not_be_parsed_for_annotations() for more information. If we find a -- parameter value with top-level HTML in it, add 'noscript = true' to indicate that we should not try to do script -- inference and tagging. (Otherwise, e.g. if you specify {{lang|ar|مُؤَلِّف}} as the author, you'll get an extra big -- font coming from the fact that {{lang|...}} wraps the Arabic text in CSS that increases the size from the -- default, and then we do script detection and again wrap the text in the same CSS, which increases the size even -- more.) if val_should_not_be_parsed_for_annotations(val) then return {text = val, link = val, noscript = true, gloss = explicit_gloss} end local obj if val:find("<") then -- Check for inline modifier. obj = parse_inline_modifiers(val, { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_annotated_text, }) else obj = generate_obj_annotated_text(val, nil, fullname) end if explicit_gloss then obj.gloss = explicit_gloss end return obj end local html_entity_char_to_replacement = { ["<"] = TEMP_LT, [">"] = TEMP_GT, ["["] = TEMP_LBRAC, ["]"] = TEMP_RBRAC, } local function html_entity_replacement(entity, code_without_semicolon, hash, xcode, x, code) -- Try to decode the entity. If successful, Replace certain special HTML entities (those that are bracket-like) -- with single Unicode characters; otherwise, replace the semicolon with a special character so it won't get -- interpreted as a delimiter. local ch = decode_entities(entity) if ch ~= entity then return html_entity_char_to_replacement[ch] or code_without_semicolon .. TEMP_SEMICOLON end -- If the entity doesn't decode, escape it anyway iff it follows a valid format. if hash == "" then -- Any nonstandard MediaWiki-only entities have now been filtered off, so treat any non-ASCII characters as -- invalid. return xcode:match("^[^\128-\255]+$") and code_without_semicolon .. TEMP_SEMICOLON or entity elseif x == "" then return xcode:match("^%d+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end return code:match("^%x+$") and code_without_semicolon .. TEMP_SEMICOLON or entity end local html_entity_replacement_to_char = { [TEMP_LT] = "&lt;", [TEMP_GT] = "&gt;", [TEMP_LBRAC] = "&#91;", [TEMP_RBRAC] = "&#93;", [TEMP_SEMICOLON] = ";", } local function undo_html_entity_replacement(txt) -- Pattern covers everything in html_entity_replacement_to_char. return (txt:gsub("\239\191[\177-\181]", html_entity_replacement_to_char)) end -- NOTE: We try hard to optimize this function for the common cases and avoid loading [[Module:parse utilities]] -- in such cases. The cases we can handle without loading [[Module:parse utilities]] are single values (no -- semicolons present) without inline modifiers or language prefixes, and multi-entity values (semicolons present) -- without (a) brackets of any kind (including parens, braces and angle brackets; angle brackets typically indicate -- inline modifiers and other brackets may protect a semicolon from being interpreted as a delimiter); -- (b) ampersands (which may indicate HTML entities, which protect a semicolon from being interpreted as a -- delimiter); and (c) colons not followed by a space (which may indicate a language prefix). local function generate_obj_multivalued_annotated_text(text, parse_err, paramname, no_undo_html_entity_replacement) local obj = generate_obj_annotated_text(text, parse_err, paramname) if not no_undo_html_entity_replacement then obj.text = undo_html_entity_replacement(obj.text) obj.link = undo_html_entity_replacement(obj.link) end return obj end --[=[ Similar to parse_annotated_text() but the parameter value may contain multiple semicolon-separated entities, each with their own inline modifiers. Some examples: * mainauthor=Paula Pattengale; Terea Sonsthagen * author=Katie Brick; J. Cody Nielsen; Greg Jao; Eric Paul Rogers; John A. Monson * author=Suzanne Brockmann; Patrick G. Lawlor (Patrick Girard); Melanie Ewbank * author=G Ristori; et al. * author=Jason Scott; zh:王晰宁<t:Wang Xining> * editors=zh:包文俊; zh:金心雯 * quotee=zh:張福運<t:Chang Fu-yun>; zh:張景文<t:Chang Ching-wen> There may be embedded semicolons within brackets, braces or parens that should not be treated as delimiters, e.g.: * author=Oliver Optic [pseudonym; {{w|William Taylor Adams}}] * author=author=Shannon Drake (pen name; {{w|Heather Graham Pozzessere}}) * author=James (the Elder;) Humphrys There may also be HTML entities with semicolons in them: * author=&#91;{{w|Gilbert Clerke}}&#93; * 2ndauthor=Martin Biddle &amp; Sally Badham * author=Peter Christen Asbj&oslash;rnsen There may be both embedded semicolons and HTML entities with semicolons in them: * author=&#91;{{w|Voltaire}} [pseudonym; François-Marie Arouet]&#93; In general we want to treat &#91; like an opening bracket and &#93; like a closing bracket. Beware that they may be mismatched: * author=Anonymous &#91;{{w|Karl Maria Kertbeny}}] Here, `val` is the value of the parameter and `fullname` is the name of the parameter from which the value was retrieved. `explicit_gloss`, if specified and non-nil, overrides any gloss specified using the <t:...> or <gloss:...> inline modifier, and `explicit_gloss_fullname` is the name of the parameter from which this value was retrieved. (If `explicit_gloss` is specified and multiple values were seen, an error results.) Return value is a list of objects of the same sort as returned by parse_annotated_text(). ]=] local function parse_multivalued_annotated_text(val, fullname, explicit_gloss, explicit_gloss_fullname) if not val then return nil end -- NOTE: In the code that follows, we use `entity` most of the time to refer to one of the semicolon-separated -- values in the multivalued param. Entities are most commonly people (typically authors, editors, translators or -- the like), but may be the names of publishers, locations, or other entities. "Entity" can also refer to HTML -- entities; in the places where this occurs, the variable name contains 'html' in it. local splitchar, english_delim if val:find("^,") then splitchar = "," english_delim = "comma" val = val:gsub("^,", "") else splitchar = ";" english_delim = "semicolon" end -- Optimization #1: No semicolons/commas or angle brackets (indicating inline modifiers). if not val:find("[<" .. splitchar .. "]") then if val_should_not_be_parsed_for_annotations(val) then return {{text = val, link = val, noscript = true}} else return {generate_obj_multivalued_annotated_text(val, nil, fullname, "no undo html entity replacement")} end end -- Optimization #2: Semicolons/commas but no angle brackets (indicating inline modifiers), braces, brackets, or -- parens (any of which would protect the semicolon/comma from interpretation as a delimiter), and no ampersand -- (which might indicate an HTML entity with a terminating semicolon, which should not be interpreted as a -- delimiter). if not val:find("[<>%[%](){}&]") then local entity_objs = {} for entity in gsplit(val, "%s*" .. splitchar .. "%s*") do if val_should_not_be_parsed_for_annotations(entity) then insert(entity_objs, { text = entity, link = entity, noscript = true }) else insert(entity_objs, generate_obj_multivalued_annotated_text(entity, nil, fullname, "no undo html entity replacement")) end end return entity_objs end -- Escape HTML entities, and get rid of directionality markers. local amp = val:find("&", nil, true) if amp then -- The pattern is more permissive than the usual entity pattern, as MediaWiki has some nonstandard entities -- that have non-ASCII characters in their codes. val = val:gsub("((&(#?)(([xX]?)([%w\128-\255]+)));)", html_entity_replacement) end -- Pattern covers left-to-right (U+200E) and right-to-left (U+200F). val = val:gsub("\226\128[\142\143]", "") -- Parse balanced segment runs, treating HTML entities for left and right bracket and left and right angle bracket -- as matching literal versions of the same characters. local entity_runs = parse_multi_delimiter_balanced_segment_run( val, {{"[" .. TEMP_LBRAC, "]" .. TEMP_RBRAC}, {"(", ")"}, {"{", "}"}, {"<" .. TEMP_LT, ">" .. TEMP_GT}}, true ) if type(entity_runs) == "string" then local undo_val = undo_html_entity_replacement(val) -- Parse error due to unbalanced delimiters. Don't throw an error here; instead, don't attempt to parse off -- any annotations, but return the value directly, maybe allowing script tagging (not allowing it if it appears -- the text is already script-tagged). return {{text = undo_val, link = undo_val, noscript = not not val_should_not_be_parsed_for_annotations(val)}} end -- Split on semicolon (or comma), possibly surrounded by whitespace. local separated_groups = split_alternating_runs(entity_runs, "%s*" .. splitchar .. "%s*") -- Process each value. local entity_objs = {} for _, entity_group in ipairs(separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #entity_group do if not entity_group[j]:find("^<.*>$") then entity_group[j - 1] = entity_group[j - 1] .. entity_group[j] .. entity_group[j + 1] remove(entity_group, j) remove(entity_group, j) else j = j + 2 end end local oneval = undo_html_entity_replacement(concat(entity_group)) -- When checking for inline modifiers, exclude HTML entry with <span ...>, <i ...>, <br/> or similar in it, -- caused by wrapping an argument in {{l|...}}, {{lang|...}} or similar. Also exclude URL's from being parsed -- as having language code prefixes. This works analogously to parse_annotated_text(); see there for more. if val_should_not_be_parsed_for_annotations(oneval) then insert(entity_objs, { text = oneval, link = oneval, noscript = true }) else local obj if #entity_group > 1 then -- Check for inline modifier. obj = parse_inline_modifiers_from_segments({ group = entity_group, arg = oneval, props = { paramname = fullname, param_mods = param_mods, generate_obj = generate_obj_multivalued_annotated_text, }, }) else obj = generate_obj_multivalued_annotated_text(entity_group[1], nil, fullname) end insert(entity_objs, obj) end end if explicit_gloss then if #entity_objs > 1 then error( ( "Can't specify |%s= along with multiple %s-separated entities in |%s=; use the <t:...> " .. "inline modifier attached to the individual entities" ):format(explicit_gloss_fullname, english_delim, fullname) ) end entity_objs[1].gloss = explicit_gloss end return entity_objs end --[=[ Format a text property that may be in a foreign language or script, along with annotations. This is conceptually similar to the full_link() function in [[Module:links]], but displays the annotations in a different format that is more appropriate for bibliographic entries. The output looks like this: TEXT [TRANSLIT /TRANSCRIPTION/, GLOSS] `textobj` is as returned by parse_annotated_text(). `tag_text_func`, if supplied, is a function of one argument to further wrap the text after it has been processed and CSS-tagged appropriately, directly before insertion. `tag_gloss_func` is a similar function for the gloss. ]=] local function format_annotated_text(textobj, tag_text_func, tag_gloss_func) if not textobj then return nil end local text, link = textobj.text, textobj.link local subst, tr, ts, f, gloss = textobj.subst, textobj.tr, textobj.ts, textobj.f, textobj.gloss -- Retrieve the display text, either specified by the user (.alt) or by parse_annotated_text() (.display) when a -- Wikipedia link is given. local alt = textobj.alt or textobj.display if alt then if link:find("%[%[") or link:find("%]%]") then local errmsg = ("Can't currently handle embedded links in '%s', with <alt:...> text '%s'"):format(link, alt) error(escape_wikicode(errmsg)) end text = ("[[%s|%s]]"):format(link, alt) end -- See above for `noscript`, meaning HTML was found in the text value, probably generated using {{lang|...}}. -- {{lang}} already script-tags the text and processes embedded language links, so we don't want to do it again (in -- fact, the code below within the if-clause is similar to what {{lang}} does). In such a case, an explicit language -- won't be available and find_best_script_without_lang() may not be accurate, so we can't do automatic transliteration. if not textobj.noscript then local lang = textobj.lang -- As an optimization, don't do script detection on an argument that contains only ASCII. local sc = textobj.sc or lang and lang:findBestScript(text) or not text:find("^[ -~]$") and find_best_script_without_lang(text) or nil -- As an optimization, don't do any of the following if there's no language, script, translit or transcription, -- as will be the case with simple ASCII values. if lang or sc or tr or ts then if not lang then lang = get_lang("und") end if tr == "-" then tr = nil elseif not tr and sc and not sc:getCode():find("Lat") then -- Latn, Latf, Latg, pjt-Latn -- might return nil local text_for_tr = text if subst then text_for_tr = apply_subst(text_for_tr, subst) else text_for_tr = remove_links(text) end tr = (lang:transliterate(text_for_tr, sc)) end if text:find("%[%[") then -- FIXME: embedded_language_links() replaces % signs with their URL-encoded equivalents, -- which messes up URL's that may be present (e.g. if chapterurl= is given). IMO this -- should not happen, and embedded_language_links() should do nothing if no embedded links -- are present. To work around this, only call embedded_language_links() when there are -- embedded links present. text = embedded_language_links({ term = text, lang = lang, sc = sc, }) end if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then text = tag_text(text, lang, sc) end if tr then -- Should we link to the transliteration of languages with lang:link_tr()? Probably not because `text` is not -- likely to be a term that has an entry. tr = tag_translit(tr, lang, "usex") end if ts then ts = tag_transcription(ts, lang, "usex") end end end text = unitalicize_brackets(text) if tag_text_func then text = tag_text_func(text) end local parts = {} if textobj.q then insert(parts, format_qualifier(textobj.q) .. " ") end insert(parts, text) if tr or ts or f or gloss then insert(parts, SPACE_LBRAC) local subparts = {} if tr or ts then local tr_ts if ts then ts = "/" .. ts .. "/" end if tr and ts then tr_ts = tr .. " " .. ts else tr_ts = tr or ts end insert(subparts, tr_ts) end if f then for _, ff in ipairs(f) do local sc = ff.sc local lang if not sc and ff.quals then local qual = ff.quals[1] if type(qual) == "string" then -- do nothing; we'll do script detection farther down elseif qual:hasType("script") then sc = qual else -- language sc = qual:findBestScript(ff.val) lang = qual end end if not lang then lang = get_lang("und") end sc = sc or find_best_script_without_lang(ff.val) local val = embedded_language_links({ term = ff.val, lang = lang, sc = sc, }) if lang:getCode() ~= "und" or sc:getCode() ~= "Latn" then val = tag_text(val, lang, sc) end local qual_prefix if ff.quals then for i, qual in ipairs(ff.quals) do if type(qual) ~= "string" and (qual:hasType("script") or qual:hasType("language")) then ff.quals[i] = qual:getCanonicalName() end end qual_prefix = concat(ff.quals, "/") .. ": " else qual_prefix = "" end insert(subparts, qual_prefix .. val) end end if gloss then gloss = '<span class="e-translation">' .. gloss .. "</span>" gloss = unitalicize_brackets(gloss) if tag_gloss_func then gloss = tag_gloss_func(gloss) end insert(subparts, gloss) end insert(parts, concat(subparts, ", ")) insert(parts, RBRAC) end if textobj.qq then insert(parts, " " .. format_qualifier(textobj.qq)) end return concat(parts) end --[=[ Format a multivalued text property that may be in a foreign language or script, along with annotations. This is the multivalued analog to format_annotated_text(), and formats each individual entity using format_annotated_text(), joining the results with `delimiter`, which defaults to ", ". It `delimiter` is "and" or "or", join the results using serial_comma_join() with the specified conjunction. `textobjs` is as returned by parse_multivalued_annotated_text(). `tag_text_func` and `tag_gloss_func` are as in format_annotated_text(). ]=] local function format_multivalued_annotated_text(textobjs, delimiter, tag_text_func, tag_gloss_func) if not textobjs then return nil end if #textobjs == 1 then return format_annotated_text(textobjs[1], tag_text_func, tag_gloss_func) end local parts = {} for _, textobj in ipairs(textobjs) do insert(parts, format_annotated_text(textobj, tag_text_func, tag_gloss_func)) end -- Change delimiter to semicolon if the items themselves contain commas (e.g., in ", Jr.") local use_semicolon = false for _, obj in ipairs(textobjs) do -- Use remove_links to ignore commas in links if obj.text and remove_links(obj.text):find(", ") then use_semicolon = true break end end local n = #parts if n > 0 and parts[n]:match("^'*et al[.']*$") then -- Special handling for 'et al.' parts[n] = "''et al.''" if n == 2 then -- author et al. return concat(parts, " ") else -- author 1, author 2, et al. return concat(parts, (use_semicolon and "; ") or ", ") end if delimiter == "and" or delimiter == "or" then delimiter = ", " end return concat(parts, delimiter) end if delimiter == "and" or delimiter == "or" then return serial_comma_join(parts, {conj = delimiter}) end return concat(parts, delimiter or ((use_semicolon and "; ") or ", ")) 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 elseif type(arg) ~= "string" then return arg end arg = mw.text.trim(arg) if arg == "" then return nil end return arg end local abbrs = { ["a."] = {anchor = "a.", full = "ante"}, ["c."] = {anchor = "c.", full = "circa"}, ["p."] = {anchor = "p.", full = "post"}, } -- Process prefixes 'a.' (ante), 'c.' (circa) and 'p.' (post) at the beginning of an arbitrary date or year spec. -- Returns two values, the formatted version of the prefix and the date spec minus the prefix. If no prefix is found, -- returns an empty string and the full date. local function process_ante_circa_post(date) local prefix = usub(date, 1, 2) local abbr = abbrs[prefix] local abbr_prefix = "" if abbr then abbr_prefix = "''[[Appendix:Glossary#" .. abbr.anchor .. '|<abbr title="' .. abbr.full .. '">' .. abbr.anchor .. "</abbr>]]'' " -- Remove lowercase letter, period, and space from beginning of date parameter. date = ugsub(date, "^%l%.%s*", "") end return abbr_prefix, date end -- Format the arguments that specify the date of the quotation. These include the following: -- |date=: The date. If |start_date= is given, this is the end date. -- |year=, |month=: Year and month of quotation date or end of range, if |date= isn't given. -- |start_date=: The start date, to specify a range. -- |start_year=, |start_month=: Year and month of start of range, if |start_date= isn't given. -- |accessdate=: Date a website was accessed; processed if no other date was given. -- |nodate=: Indicate that no date is present; otherwise a maintenance line will be displayed if there is no date. -- -- If `parampref` and/or `paramsuf` are given, this modifies all the date arguments accordingly. For example, if -- `parampref` == "orig" and `paramsuf` is omitted, the date is specified using |origdate= or |origyear=/|origmonth=, -- and the start of the range is |origstart_date=, etc. Similarly, if `parampref` is omitted and `paramsuf` is -- "_published", the date is specified using |date_published= or |year_published=/|month_published=, and the start of -- the range is |start_date_published=, etc. -- -- `a` and `get_full_paramname` are functions with the same interpretation as the local functions of the same name in -- source(). These are used to fetch parameters and get their full names. Note that this may cause all arguments to -- have an index added to them (|date2=, |year2=, |month2=, etc.). -- -- `alias_map` is as in source() and is used to map canonical arguments to their aliases when aliases were used. -- -- If `bold_year` is given, displayed years are boldfaced unless boldface is present in the parameter value. -- -- If `maintenance_line_no_date` is specified, it should be a string that will be returned if no date is found (i.e. -- neither |date= nor |year=, or their appropriate equivalents per `parampref` and `paramsuf`, are specified, and -- neither |nodate= is given to indicate that there is no date, or |accessdate= is given). -- -- Returns two values: the formatted date and a boolean indicating whether to add a maintenance category -- [[:Category:Requests for date in LANG entries]]. The first return value will be nil if nothing is to be added -- (in which case the scond return value will always be nil). local function format_date_args( a, get_full_paramname, alias_map, parampref, paramsuf, bold_year, maintenance_line_no_date, year_last ) local output = {} parampref = parampref or "" paramsuf = paramsuf or "" local function getp(param) return a(parampref .. param .. paramsuf) end local function pname(param) local fullname = get_full_paramname(parampref .. param .. paramsuf) return alias_map[fullname] or fullname end -- Format `timestamp` (a timestamp referencing a date) according to the spec in `code`. `param` is the base name of -- the parameter from which the timestamp was fetched, for error messages. local function format_date_with_code(code, timestamp, param) local language = mw.getContentLanguage() local ok, date = pcall(language.formatDate, language, code, timestamp) if ok then return date else -- All the formats used in format_date_args() are fine, so the timestamp must be at fault. error( ( "Timestamp |%s=%s (possibly canonicalized from its original format) could not be parsed; see the " .. "[[mw:Help:Extension:ParserFunctions##time|documentation for the #time parser function]]" ):format(pname(param), tostring(timestamp)) ) end end -- Try to figure out if the given timestamp has the day of the month explicitly given. We use the following -- algorithm: -- 1. Format as year-month-day; if the day is not 1, the day was explicitly given, since if only the year/month are -- given, the day shows up as 1. -- 2. If the day shows up as 1 and there isn't a 1 or 01 in the timestamp, the day wasn't explicitly given. -- 3. Otherwise, if there are three separate numbers (e.g. 2022-07-01), or two separate numbers plus a capitalized -- letter (taken as an English month, e.g. 2022 July 1), the day was explicitly given, otherwise not. -- -- `param` is the base name of the parameter from which the timestamp was fetched. local function date_has_day_specified(timestamp, param) local day = format_date_with_code("j", timestamp, param) if day ~= "1" then return true end local english_month = timestamp:find("%u") local canon_timestamp = mw.text.trim((timestamp:gsub("%D+", " "))) local seen_nums = split(canon_timestamp, " ", true) local saw_one = false for _, num in ipairs(seen_nums) do if num == "1" or num == "01" then saw_one = true break end end if not saw_one then return false end return #seen_nums >= 3 or english_month and #seen_nums >= 2 end -- Format a date with boldfaced year, as e.g. '''2023''' August 3. `explicit_day_given` indicates whether to include -- the day; if false, the return value will be e.g. '''2023''' August. `date_param` is the base name of the param -- from which the date was fetched, for error messages. local function format_bold_date(date, explicit_day_given, date_param) local day_month_code = explicit_day_given and "j F" or "F" local month_day_code = explicit_day_given and "F j" or "F" if year_last then if bold_year then -- This formats like "3 August '''2023'''" (or "August '''2023'''" if day not explicitly given). return format_date_with_code(day_month_code .. " '''Y'''", date, date_param) else -- This formats like "3 August 2023" (or "August 2023" if day not explicitly given). return format_date_with_code(day_month_code .. " Y", date, date_param) end else if bold_year then -- This formats like "'''2023''' August 3" (or "'''2023''' August" if day not explicitly given). return format_date_with_code("'''Y''' " .. month_day_code, date, date_param) else -- This formats like "2023 August 3" (or "2023 August" if day not explicitly given). return format_date_with_code("Y " .. month_day_code, date, date_param) end end end -- The formatDate method of the mw.language object behaves like the {{#time:}} parser function, which doesn't -- accept the formats "monthday monthname, year" or "year monthname monthday", but outputs garbage when it receives -- them, behavior inherited from PHP. {{#formatdate:}} magic word is more forgiving. Fix dates so that, for -- instance, the |date= parameter of {{quote-journal}} (which uses this code) and the |accessdate= parameter (which -- uses {{#formatdate:}}) accept similar date formats. See: -- * [[mw:Extension:Scribunto/Lua_reference_manual#mw.language:formatDate]] -- * [[mw:Help:Extension:ParserFunctions##time]] -- * [[mw:Help:Magic_words#Formatting]] -- `date` is the date spec from the user, which is assumed to come from a parameter whose base name ends in "date"; -- `parampref` is the prefix added to "date" to get the parameter name. local function fix_date(date, param_pref) if tonumber(date) ~= nil then error( ("|%s= should contain a full date (year, month, day of month); use |%s= for year"):format( pname(param_pref .. "date"), pname(param_pref .. "year") ) ) elseif date and date:find("%s*%a+,%s*%d+%s*$") then error( ("|%s= should contain a full date (year, month, day of month); use |%s=, |%s= for month and year"):format( pname(param_pref .. "date"), pname(param_pref .. "month"), pname(param_pref .. "year") ) ) end if date then -- Commas are replaced with spaces to prevent parsing issues local fixed_date = ugsub(date, ", *", " ") return (ugsub(ugsub(fixed_date or date, "(%d+ %a+),", "%1"), "^(%d%d%d%d) (%a+ %d%d?)$", "%2 %1")) end end local start_date, date = fix_date(getp("start_date"), "start_"), fix_date(getp("date"), "") local year = getp("year") local month = getp("month") local start_year = getp("start_year") local start_month = getp("start_month") if date and year then error(("Only one of |%s= or |%s= should be specified"):format(pname("date"), pname("year"))) end if date and month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("month"), pname("year"), pname("date") ) ) end if start_date and start_year then error(("Only one of |%s= or |%s= should be specified"):format(pname("start_date"), pname("start_year"))) end if start_date and start_month then error( ("|%s= should only be specified in conjunction with |%s=, not with |%s="):format( pname("start_month"), pname("start_year"), pname("start_date") ) ) end if (start_date or start_year) and not (date or year) then error( ("|%s= or |%s=/|%s= cannot be specified without specifying |%s= or |%s=/|%s="):format( pname("start_date"), pname("start_year"), pname("start_month"), pname("date"), pname("year"), pname("month") ) ) end local dash = "&nbsp;– " local day_explicitly_given = date and date_has_day_specified(date, "date") local start_day_explicitly_given = start_date and date_has_day_specified(start_date, "start_date") -- Format a date with boldfaced year, as e.g. '''2023''' August 3 (if `explicit_day_given` specified) or -- '''2023''' August (if `explicit_day_given` not specified). If no date specified, fall back to formatting based -- on the year and (optionally) month params given in `yearobj` and `monthobj`, boldfacing the year if not already. -- `date_param` is the base name of the param from which the date was fetched, for error messages. local function format_date_or_year_month(date, yearobj, monthobj, explicit_day_given, date_param) if date then return format_bold_date(date, explicit_day_given, date_param) else -- Boldface a year spec if it's not already boldface. if bold_year and not yearobj.text:find("'''") then -- Clone the year object before modifying it because we may use it later to check against the current -- year (if we're dealing with start_year). yearobj = shallow_copy(yearobj) yearobj.text = "'''" .. yearobj.text .. "'''" if yearobj.alt then yearobj.alt = "'''" .. yearobj.alt .. "'''" end end if year_last then return (monthobj and format_annotated_text(monthobj) .. " " or "") .. format_annotated_text(yearobj) else return format_annotated_text(yearobj) .. (monthobj and " " .. format_annotated_text(monthobj) or "") end end end local yearobj = parse_annotated_text(year, pname("year")) local monthobj = parse_annotated_text(month, pname("month")) local start_yearobj = parse_annotated_text(start_year, pname("start_year")) local start_monthobj = parse_annotated_text(start_month, pname("start_month")) if start_yearobj then local abbr_prefix abbr_prefix, start_yearobj.text = process_ante_circa_post(start_yearobj.text) start_yearobj.link = select(2, process_ante_circa_post(start_yearobj.link)) insert(output, abbr_prefix) elseif yearobj then local abbr_prefix abbr_prefix, yearobj.text = process_ante_circa_post(yearobj.text) yearobj.link = select(2, process_ante_circa_post(yearobj.link)) insert(output, abbr_prefix) end if start_date or start_year then local cur_year = yearobj and yearobj.text or format_date_with_code("Y", date, "date") local cur_month = monthobj and monthobj.text or date and format_date_with_code("F", date, "date") or nil local cur_day = date and day_explicitly_given and format_date_with_code("j", date, "date") or nil local beg_year = start_yearobj and start_yearobj.text or format_date_with_code("Y", start_date, "start_date") local beg_month = start_monthobj and start_monthobj.text or start_date and format_date_with_code("F", start_date, "start_date") or nil local beg_day = start_date and start_day_explicitly_given and format_date_with_code("j", start_date, "start_date") or nil if year_last then if beg_day then insert(output, beg_day .. " " .. beg_month) else insert(output, beg_month) end if beg_year ~= cur_year then insert(output, " " .. beg_year) end else insert(output, format_date_or_year_month( start_date, start_yearobj, start_monthobj, start_day_explicitly_given, "start_date" )) end if cur_year ~= beg_year then -- Different years; insert current date in full. if beg_month or cur_month then insert(output, dash) else insert(output, "–") end insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif cur_month and cur_month ~= beg_month then local month_ins = monthobj and format_annotated_text(monthobj) or cur_month -- Same year but different months; insert current month and (if available) current day. if cur_day then insert(output, dash) if year_last then insert(output, cur_day .. " " .. month_ins) else insert(output, month_ins .. " " .. cur_day) end else if beg_day then insert(output, dash) else insert(output, "–") end insert(output, month_ins) end elseif cur_day and cur_day ~= beg_day then -- Same year and month but different days; insert current day. insert(output, "–") insert(output, cur_day) else -- Same year, month and day; or same year and month, and day not available; or same year, and month and -- day not available. Do nothing. FIXME: Should we throw an error? end if year_last and beg_year == cur_year then if cur_month then insert(output, " " .. cur_year) else insert(output, " " .. cur_year) end end elseif date or yearobj then insert(output, format_date_or_year_month(date, yearobj, monthobj, day_explicitly_given, "date")) elseif not maintenance_line_no_date then -- Not main quote date. Return nil, caller will handle. return nil, nil elseif not getp("nodate") then local accessdate = getp("accessdate") if accessdate then local explicit_day_given = date_has_day_specified(accessdate, "accessdate") insert(output, format_bold_date(accessdate, explicit_day_given, "accessdate") .. " (last accessed)") else if mw.title.getCurrentTitle().namespace ~= 10 then return maintenance_line(maintenance_line_no_date), true end return nil, nil end end return ine(concat(output)), nil end local function tag_with_cite(txt) return "<cite>" .. txt .. "</cite>" end -- Display the source line of the quote, above the actual quote text. This contains the majority of the logic of this -- module (formerly contained in {{quote-meta/source}}). function export.source(args, alias_map, format_as_cite, other_controls) local tracking_categories = {} local argslang = args[1] or args.lang if not argslang then -- For the moment, only trigger an error on mainspace pages and -- other pages that are not user pages or pages containing discussions. -- These are the same pages that appear in the appropriate tracking -- categories. User and discussion pages have not generally been -- fixed up to include a language code and so it's more helpful -- to use a maintenance line than signal an error. local current_title = mw.title.getCurrentTitle() if not (current_title.namespace == 10 or page_should_be_ignored(current_title.fullText)) then require(languages_error_module)(nil, 1) end end -- Given a canonical param, convert it to the original parameter specified by the user (which may have been an -- alias). local function alias(param) return alias_map[param] or param end local output, sep = {} local overrides = other_controls and other_controls.overrides or {} -- Add text to the output. The text goes into a list, and we concatenate all the list components together at the -- end. To make it easier to handle comma-separated items, we keep track (in `sep`) of the separator (if any) that -- needs to be inserted before the next item added. For example, if we're in the "newversion" code (ind ~= ""), and -- there's no title and no URL, then the first time we add anything after the title, we don't want to add a -- separating comma because the preceding text will say "republished " or "republished as " or "translated as " or -- similar. In all- other cases, we do want to add a separating comma. The bare add() function reset the separator -- to be nothing, while the add_with_sep() function resets the separator to be the value of `next_sep` (defaulting -- to ", "), so the next time around we do add a comma to separate `text` from the preceding piece of text. local function add(text) if sep then insert(output, sep) end insert(output, text) sep = nil end local function add_with_sep(text, next_sep) add(text) sep = next_sep or ", " end -- FIXME: This is all very over-engineered, which makes it slow and memory-inefficient. -- Return a function that generates the actual parameter name associated with a base param (e.g. "author", "last"). -- The actual parameter name may have an index added (an empty string for the first set of params, e.g. author=, -- last=, or a numeric index for further sets of params, e.g. author2=, last2=, etc.). local function make_get_full_paramname(ind) return function(param) return param .. ind end end -- Function to fetch the actual parameter name associated with a base param (see make_get_full_paramname() above). -- Assigned at various times below by calling make_get_full_paramname(). We do it this way so that we can have -- wrapper functions that access params and define them only once. local get_full_paramname -- Return two values: the value of a parameter given the base param name (which may have a numeric index added), -- and the parameter name from which the value was fetched (which may be an alias, i.e. you can't necessarily fetch -- the parameter value from args[] given this name). The base parameter can be a list of such base params, which -- are checked in turn, or nil, in which case nil is returned. local function a_with_name(param) if not param then return nil elseif type(param) ~= "table" then local fullname = get_full_paramname(param) return args[fullname], alias(fullname) end for _, par in ipairs(param) do local val, fullname = a_with_name(par) if val then return val, alias(fullname) end end return nil end -- Fetch the value of a parameter given the base param name (which may have a numeric index added). The base -- parameter can be a list of such base params, which are checked in turn, or nil, in which case nil is returned. local function a(param) return (a_with_name(param)) end -- Identical to a_with_name(param) except that it verifies that no space is present. Should be used for URL's. local function aurl_with_name(param) local value, fullname = a_with_name(param) if value and value:find(" ") and not value:find("%[") then error(("URL not allowed to contain a space, but saw |%s=%s"):format(fullname, value)) end return value, fullname end -- Identical to a(param) except that it verifies that no space is present. Should be used for URL's. local function aurl(param) return (aurl_with_name(param)) end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the annotations and convert the result into a formatted string. -- This is the same as parse_and_format_annotated_text() below but also returns the full param name as the second -- return value. local function parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local obj = parse_annotated_text(val, fullname) return format_annotated_text(obj, tag_text_func, tag_gloss_func), fullname end -- Convenience function to fetch a parameter that may be in a foreign language or text (and may consequently have -- a language prefix and/or inline modifiers), parse the modifiers and convert the result into a formatted string. -- This is a wrapper around parse_annotated_text() and format_annotated_text(). `param` is the base parameter name (see -- a_with_name()), `tag_text_func` is an optional function to tag the parameter text after all other processing (e.g. -- wrap in <cite>...</cite> tags), and `tag_gloss_func` is a similar function for the parameter translation/gloss. local function parse_and_format_annotated_text(param, tag_text_func, tag_gloss_func) return (parse_and_format_annotated_text_with_name(param, tag_text_func, tag_gloss_func)) end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text_with_name() and returns two -- values, the formatted string and the full name of the parameter fetched. `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func) local val, fullname = a_with_name(param) local objs = parse_multivalued_annotated_text(val, fullname) local num_objs = objs and #objs or 0 return format_multivalued_annotated_text(objs, delimiter, tag_text_func, tag_gloss_func), fullname, num_objs end -- Convenience function to fetch a multivalued parameter that may be in a foreign language or text (and may -- consequently have a language prefix and/or inline modifiers), parse the modifiers and convert the result into a -- formatted string. This is the multivalued analog to parse_and_format_annotated_text(). `delimiter` is as in -- format_multivalued_annotated_text(). local function parse_and_format_multivalued_annotated_text(param, delimiter, tag_text_func, tag_gloss_func) return (parse_and_format_multivalued_annotated_text_with_name(param, delimiter, tag_text_func, tag_gloss_func)) end -- This determines whether to display "Mary Bloggs, transl." (if there's no author preceding) or "translated by -- Mary Bloggs" (if there's an author preceding). local author_outputted = false -- When formatting as a citation, the priority is to display a name and a date before the book/chapter title -- this tracks whether or not the author/date has been displayed local date_outputted, formatted_date, formatted_origdate = false local function add_date(no_paren) if not date_outputted then if no_paren then sep = ", " else sep = " " end if formatted_date then if no_paren then add(formatted_date) else add("(" .. formatted_date .. ")") end end if formatted_origdate then add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end sep = ", " date_outputted = true end end local function is_anonymous(val) return val:match("^[Aa]nonymous$") or val:match("^[Aa]non%.?$") end -- Add a formatted author (whose values may be specified using `author` or, for compatibility purposes, split -- among various parameters): -- * `author` is the value of the author param (e.g. "author", "author2" or "2ndauthor"), and `author_fullname` is -- the full parameter name holding that value; -- * `trans_author` is the optional value of the param holding the gloss/translation of the author, and -- `trans_author_fullname` is the full parameter name holding that value (or nil for no such parameter); -- * `authorlink` is the value of the authorlink param, which holds the Wikipedia link of the author(s) in `author`, -- and `authorlink_fullname` is the full parameter name holding that value; -- * `trans_authorlink` is the optional value of the param holding the Wikipedia link of the gloss/translation of -- the author, and `trans_authorlink_fullname` is the full parameter name holding that value (or nil for no such -- parameter); -- * `first` is the value of the parameter holding the first name of the author, and `first_fullname` is the full -- parameter name holding that value; -- * `trans_first` is the value of the corresponding parameter holding the gloss/translation of the first name -- (e.g. "trans-first"), and `trans_first_fullname` is the full parameter name holding that value (or nil for -- no such parameter); -- * `last` is the value of the parameter holding the last name of the author, and `last_fullname` is the full -- parameter name holding that value; -- * `trans_last` is the value of the corresponding parameter holding the gloss/translation of the last name -- (e.g. "trans-last"), and `trans_last_fullname` is the full parameter name holding that value (or nil for -- no such parameter). -- * `last_first` if set, when parameters `first` and `last` are used, display the author name as "last, first" local function add_author( author, author_fullname, trans_author, trans_author_fullname, authorlink, authorlink_fullname, trans_authorlink, trans_authorlink_fullname, first, first_fullname, trans_first, trans_first_fullname, last, last_fullname, trans_last, trans_last_fullname, last_first ) local function make_author_with_url(txt, txtparam, authorlink, authorlink_param) if authorlink then if authorlink:find("%[%[") then error(("Can't specify links in |%s=%s"):format(authorlink_param, authorlink)) end if txt:find("%[%[") then error(("Can't specify links in %s=%s"):format(txtparam, txt)) end return "[[w:" .. authorlink .. "|" .. txt .. "]]" else return txt end end local num_authorobjs if author then local authorobjs = parse_multivalued_annotated_text(author, author_fullname, trans_author, trans_author_fullname) num_authorobjs = #authorobjs if num_authorobjs == 1 then if is_anonymous(authorobjs[1].text) then authorobjs[1].text = "anonymous author" authorobjs[1].link = "anonymous author" end if authorlink then authorobjs[1].text = make_author_with_url( authorobjs[1].text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) authorobjs[1].link = make_author_with_url( authorobjs[1].link, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end if authorobjs[1].gloss and trans_authorlink then authorobjs[1].gloss = make_author_with_url( authorobjs[1].gloss, ("<t:...> in |%s"):format(author_fullname), trans_authorlink, "|" .. trans_author_fullname ) end add(format_multivalued_annotated_text(authorobjs)) elseif trans_authorlink then error( ( "Can't specify |%s= along with multiple semicolon-separated entities in |%s=; use the " .. "<t:...> inline modifier attached to the individual entities and put the link directly " .. "in the value of the inline modifier" ):format(trans_authorlink_fullname, author_fullname) ) else -- Allow an authorlink with multiple authors, e.g. for use with |author=Max Mills; Harvey Mills -- with |authorlink=Max and Harvey. For this we have to generate the entire text and link it -- all. local formatted_text = format_multivalued_annotated_text(authorobjs) if authorlink then formatted_text = make_author_with_url( formatted_text, "|" .. author_fullname, authorlink, "|" .. authorlink_fullname ) end add(formatted_text) end else num_authorobjs = 1 -- Author separated into first name + last name. We don't currently support non-Latin-script -- authors separated this way and probably never will. if first then if last_first then author = last .. ", " .. first else author = first .. " " .. last end else author = last end if authorlink then local authorparam = first and ("|%s |%s"):format(first_fullname, last_fullname) or "|" .. last_fullname author = make_author_with_url(author, authorparam, authorlink, authorlink_fullname) end local trans_author if trans_last then if trans_first then trans_author = trans_first .. " " .. trans_last else trans_author = trans_last end if trans_authorlink then local trans_authorparam = trans_first and ("|%s |%s"):format(trans_first_fullname, trans_last_fullname) or "|" .. trans_last_fullname trans_author = make_author_with_url( trans_author, trans_authorparam, trans_authorlink, trans_authorlink_fullname ) end end add(author) if trans_author then add(SPACE_LBRAC) add(trans_author) add(RBRAC) end end author_outputted = true return num_authorobjs end local function add_authorlike( param, prefix_with_preceding_authors, suffix_without_preceding_authors, suffix_if_multiple, anonymous_suffix ) local delimiter = author_outputted and "and" or ", " local entities, _, num_entities = parse_and_format_multivalued_annotated_text_with_name(param, delimiter) if not entities then return end if is_anonymous(entities) then -- If tlr=anonymous or similar given, display as "anonymous translator" or similar. If a specific -- anonymous suffix not given, try to derive the anonymous suffix from the non-preceding-author suffix. if not anonymous_suffix then local cleaned_suffix = suffix_without_preceding_authors :gsub("&#32;", " ") :gsub("&nbsp;", " ") :gsub("&#160;", " ") :gsub("&#91;", "[") :gsub("&#93;", "]") cleaned_suffix = mw.text.trim(cleaned_suffix) if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^, (.*)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%((.*)%)$") end if not anonymous_suffix then anonymous_suffix = " " .. cleaned_suffix:match("^%[(.*)%]$") end if not anonymous_suffix then anonymous_suffix = suffix_without_preceding_authors end end add_with_sep("anonymous" .. anonymous_suffix) elseif prefix_with_preceding_authors and (author_outputted or not suffix_without_preceding_authors) then add_with_sep(prefix_with_preceding_authors .. entities) elseif suffix_if_multiple and num_entities > 1 then add_with_sep(entities .. suffix_if_multiple) else add_with_sep(entities .. suffix_without_preceding_authors) end author_outputted = true end local function add_authorlabel() local default_authorlabel = a("default-authorlabel") if default_authorlabel and yesno(a("authorlabel"), true) then sep = nil add_with_sep(" " .. default_authorlabel) end end local function has_new_title_or_author() return args["2ndauthor"] or args["2ndlast"] or args.chapter2 or args.title2 or args.tlr2 or args.mainauthor2 or args.editor2 or args.editors2 or args.compiler2 or args.compilers2 or args.director2 or args.directors2 end local function has_newversion() return args.newversion or args.location2 or has_new_title_or_author() end -- Handle chapter=, section=, etc. `param` is the base name of the parameter in question, e.g. "chapter" or -- "section". If numeric (either Arabic or Roman), add `numeric_prefix`; otherwise, parse as textual (allowing for -- language prefixes, inline modifiers, etc.), prefix with `textual_prefix` (if given) and suffix with -- `textual_suffix` (if given). Also checks for and handles the following (assuming param == "chapter"): -- * chapterurl=: URL of the chapter. -- * trans-chapter=: Chapter translation (can be given using an inline modifier <t:...>). -- * chapter_number=: Chapter number, when chapter= is also given (otherwise put the chapter number in chapter=). -- * chapter_plain=: Plain version of the chapter number; the "chapter " prefix isn't added. -- * chapter_series=: Series that the chapter is within (used e.g. for journal articles part of a series). -- * chapter_seriesvolume=: Volume of the series (compare seriesvolume=). -- -- Returns nil if no value specified for the main parameter, otherwise the formatted value. local function format_chapterlike(param, numeric_prefix, textual_prefix, textual_suffix) local chap, chap_fullname = a_with_name(param) local chap_num, chap_num_fullname = a_with_name(param .. "_number") local chap_plain, chap_plain_fullname = parse_and_format_annotated_text_with_name(param .. "_plain") if chap_num and chap_plain then error(("Specify only one of |%s= or %s="):format(chap_num_fullname, chap_plain_fullname)) end local chap_series, chap_series_fullname = parse_and_format_annotated_text_with_name(param .. "_series", tag_with_cite, tag_with_cite) local chap_seriesvolume, chap_seriesvolume_fullname = parse_and_format_annotated_text_with_name(param .. "_seriesvolume") if chap_series then chap_series = ", " .. chap_series end if chap_seriesvolume then if not chap_series then error(("Cannot specify |%s= without %s="):format(chap_series_fullname, chap_seriesvolume_fullname)) end chap_series = chap_series .. " (" .. chap_seriesvolume .. ")" end local chapterurl local function make_chapter_with_url(chap) if chapterurl then return "[" .. chapterurl .. " " .. chap .. "]" else return chap end end if not chap then if chap_num then error( ("Cannot specify |%s= without |%s=; put the numeric value in |%s= directly"):format( chap_num_fullname, chap_fullname, chap_fullname ) ) end if chap_plain then chapterurl = aurl(param .. "url") return make_chapter_with_url(chap_plain .. (chap_series or "")) end return nil end local cleaned_chap = chap:gsub("<sup>[^<>]*</sup>", ""):gsub("[*+#]", "") chapterurl = aurl(param .. "url") local formatted if numeric_prefix and get_number(cleaned_chap) then -- Arabic chapter number formatted = numeric_prefix .. make_chapter_with_url(chap) elseif numeric_prefix and cleaned_chap:match("^[mdclxviMDCLXVI]+$") and roman_to_arabic(cleaned_chap, true) and (not overrides[param] or not overrides[param].noroman) then -- Roman chapter number formatted = numeric_prefix .. make_chapter_with_url(upper(chap)) else -- strip leading ! (used to force text-mode for titles that look like Roman numerals like "mil" and "dill") if chap:find("^!") then chap = chap:gsub("^!", "") end -- Must be a chapter name local chapterobj = parse_annotated_text(chap, chap_fullname, a("trans-" .. param)) chapterobj.text = make_chapter_with_url(chapterobj.text) chapterobj.link = make_chapter_with_url(chapterobj.link) formatted = (textual_prefix or "") .. format_annotated_text(chapterobj) .. (textual_suffix or "") end if chap_num or chap_plain then -- NOTE: Up above we throw an error if both chap_num and chap_plain are specified. formatted = formatted .. " (" .. (chap_plain or numeric_prefix .. chap_num) .. ")" end if chap_series then formatted = formatted .. chap_series end return formatted end -- This handles everything after displaying the author, starting with the chapter and ending with page, column, -- line and then other=. It is currently called twice: Once to handle the main portion of the citation, and once to -- handle a "newversion" citation. `ind` is either "" for the main portion or a number (currently only 2) for a -- "newversion" citation. In a few places we conditionalize on `ind` to take actions depending on its value. local function postauthor(ind, num_authors, format_as_cite) get_full_paramname = make_get_full_paramname(ind) if author_outputted then add_authorlabel() end local coauthors = parse_and_format_multivalued_annotated_text("coauthors", "and") if coauthors then local with_prefix = "" if author_outputted then with_prefix = "with " if num_authors == 1 then sep = " " end end add_with_sep(with_prefix .. coauthors) author_outputted = true end add_authorlike("quotee", "quoting ", ", quotee", ", quotees") if format_as_cite and author_outputted and not date_outputted then add_date() sep = ", " end add_authorlike("chapter_tlr", "translated by ", ", transl.", nil, " translator") local function add_sg_and_pl_authorlike(noun, verbed) local sgparam = noun local plparam = noun .. "s" local sgval, sgval_fullname = a_with_name(sgparam) local plval, plval_fullname = a_with_name(plparam) if sgval and plval then error(("Can't specify both |%s= and |%s="):format(sgval_fullname, plval_fullname)) end if sgval or plval then local verbed_by = verbed .. " by " local comma_sgnoun = ", " .. noun local comma_plnoun = ", " .. noun .. "s" add_authorlike(sgparam, verbed_by, comma_sgnoun, comma_plnoun) add_authorlike(plparam, verbed_by, comma_plnoun) end end local formatted_entry = format_chapterlike("entry", nil, "“", "”") local formatted_chapter = format_chapterlike("chapter", "chapter ", "“", "”") local function add_entry() if formatted_entry then add_with_sep(formatted_entry) if not a("notitle") then add("ann an ") author_outputted = false else author_outputted = true end formatted_entry = nil end end local function add_chapter() add_entry() if formatted_chapter then add_with_sep(formatted_chapter) if not a("notitle") then add("ann an ") author_outputted = false end formatted_chapter = nil end end local function add_actor_role(format_as_cite) local role = parse_and_format_multivalued_annotated_text("role", "and") local actor_val, actor_fullname = a_with_name("actor") local actor_objs = parse_multivalued_annotated_text(actor_val, actor_fullname) local actor = format_multivalued_annotated_text(actor_objs, "and") if format_as_cite then if role then if actor then add_with_sep(actor .. " as ") end sep = nil add_with_sep(role) elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "actors" or "actor") .. ")") end else if role then add_with_sep("spoken by " .. role) if actor then sep = nil add_with_sep(" (" .. actor .. ")") end elseif actor then add_with_sep(actor .. " (" .. (#actor_objs > 1 and "actors" or "actor") .. ")") end end end if format_as_cite then if date_outputted then add_chapter() end local output_len = #output local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) end -- quote-* templates display "jobbed by name" after the author, controlled by the author_outputted flag author_outputted = false add_authorlike("tlr", "translated by ", ", transl.", nil, " translator") author_outputted = false add_sg_and_pl_authorlike("editor", "edited") add_sg_and_pl_authorlike("compiler", "compiled") add_sg_and_pl_authorlike("director", "directed") add_authorlike("lyricist", nil, " (lyrics)", nil, " lyricist") add_authorlike("lyrics-translator", nil, " (translation)", nil, " lyrics translator") add_authorlike("composer", nil, " (music)", nil, " composer") add_actor_role("format_as_cite") -- if the output length has changed, a credit name has been printed -- and we can print the date if output_len ~= #output then author_outputted = true add_date() end add_chapter() else add_chapter() local mainauthor = parse_and_format_multivalued_annotated_text("mainauthor") if mainauthor then add_with_sep(mainauthor) author_outputted = true end add_authorlike("tlr", "translated by ", ", transl.", nil, " translator") add_sg_and_pl_authorlike("editor", "edited") add_sg_and_pl_authorlike("compiler", "compiled") add_sg_and_pl_authorlike("director", "directed") add_authorlike("lyricist", nil, " (lyrics)", nil, " lyricist") add_authorlike("lyrics-translator", nil, " (translation)", nil, " lyrics translator") add_authorlike("composer", nil, " (music)", nil, " composer") end local title, title_fullname = a_with_name("title") local need_comma = false if title then local titleobj = parse_annotated_text(title, title_fullname, a("trans-title")) add(format_annotated_text(titleobj, tag_with_cite, tag_with_cite)) local series = parse_and_format_annotated_text("series") if series then add(" (" .. series) local seriesvolume = parse_and_format_annotated_text("seriesvolume") if seriesvolume then add(SEMICOLON_SPACE .. seriesvolume) end add(")") end need_comma = true elseif ind == "" then if not a("notitle") then add(maintenance_line("Please provide the book title or journal name")) need_comma = true end end local archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") local url, url_fullname = aurl_with_name("url") local urls, urls_fullname = aurl_with_name("urls") if url and urls then error(("Supply only one of |%s= and |%s="):format(url_fullname, urls_fullname)) end local function verify_title_supplied(url_name) -- There are too many cases of this to throw an error at this time. -- if not title then -- error(("If |%s= is given, |%s= must also be supplied"):format(url_name, title_fullname)) -- end end if archiveurl or url then verify_title_supplied(archiveurl and archiveurl_fullname or url_fullname) sep = nil add("&lrm;<sup>[" .. (archiveurl or url) .. "]</sup>") elseif urls then verify_title_supplied(urls_fullname) sep = nil add("&lrm;<sup>" .. urls .. "</sup>") end -- display (in Language) if language is provided and is not English and not overriden by termlang or worklang if format_as_cite and ind == "" and not (args.termlang or args.worklang) and (args[1] or args.lang) then local lang = get_first_lang(args[1] or args.lang) if lang then local langcode = lang:getCode() if not (langcode == "und" or langcode == "gd") then local langs = format_langs(args[1] or args.lang) if langs then add(" (ann an " .. langs .. ")") end end end end if need_comma then sep = ", " end local edition, edition_fullname = parse_and_format_annotated_text_with_name("edition") local edition_plain, edition_plain_fullname = parse_and_format_annotated_text_with_name("edition_plain") if edition and edition_plain then error(("Supply only one of |%s= and |%s="):format(edition_fullname, edition_plain_fullname)) end if edition then add_with_sep(edition .. " edition") end if edition_plain then add_with_sep(edition_plain) end -- Display a numeric param such as page=, volume=, column=. For each `paramname`, four params are actually -- recognized, e.g. for paramname == "page", the params page=, pages=, page_plain= and pageurl= are recognized -- and checked (or the same with an index, e.g. page2=, pages2=, page_plain2= and pageurl2= respectively if -- ind == "2"). Only one of the first three can be specified; an error results if more than one are given. -- If none are given, the return value is nil; otherwise it is a string. The numeric spec is taken directly -- from e.g. page_plain= if given; otherwise if e.g. pages= is given, or if page= is given and looks like a -- combination of numbers (i.e. it has a hyphen or dash in it, a comma, or the word " and "), it is prefixed -- by `singular_desc` + "s" (e.g. "pages "), otherwise it is prefixed by just `singular_desc` (e.g. "page "). -- (As a special case, if either e.g. page=unnumbered or pages=unnumbered is given, the numeric spec is -- "unnumbered page".) The resulting spec is returned directly unless e.g. pageurl= is given, in which case -- it is linked to the specified URL. Note that any of the specs can be foreign text, e.g. foreign numbers -- (including with optional inline modifiers), and such text is handled appropriately. local function format_numeric_param(paramname, singular_desc) local sgval = a_with_name(paramname) local sgobj = parse_annotated_text(sgval, paramname) local plparamname = paramname .. "s" local plval = a_with_name(plparamname) local plobj = parse_annotated_text(plval, plparamname) local plainval, plain_fullname = parse_and_format_annotated_text_with_name(paramname .. "_plain") local numspec if not sgval and not plval and not plainval then return elseif plainval and (sgval or plval) then error(("Can't specify " .. plain_fullname .. " with " .. paramname .. " or " .. plparamname)) elseif sgval and plval then -- if both singular and plural, display "page 1 of 1-10" numspec = singular_desc .. " " .. sgval .. " of " .. plval else -- Merge page= and pages= and treat alike because people often mix them up in both directions. if plainval then numspec = plainval else local val = sgobj and sgobj.text or plobj.text if val == "unnumbered" then numspec = "unnumbered " .. singular_desc else local desc if val:find("^!") then val = val:gsub("^!", "") desc = sgval and singular_desc or pluralize(singular_desc) else local check_val = val if check_val:find("%[") then check_val = remove_links(check_val) -- convert URL's of the form [URL DISPLAY] to the displayed value check_val = check_val:gsub("%[[^ %[%]]* ([^%[%]]*)%]", "%1") end -- in case of negative page numbers (do they exist?), don't treat as multiple pages check_val = check_val:gsub("^%-", "") -- replace HTML entity en-dashes and em-dashes with their literal codes check_val = check_val:gsub("&ndash;", "–") check_val = check_val:gsub("&#8211;", "–") check_val = check_val:gsub("&mdash;", "—") check_val = check_val:gsub("&#8212;", "—") -- Check for en-dash or em-dash, or two numbers (possibly with stuff after like 12a-15b) -- separated by a hyphen or by comma a followed by a space (to avoid firing on thousands separators). if umatch(check_val, "[–—]") or check_val:find(" and ") or check_val:match("%d+[^ ]* *%- *%d+") or check_val:match("%d+[^ ]* *, +%d+") then desc = pluralize(singular_desc) else desc = singular_desc end end local obj = sgobj or plobj obj.text = val if obj.link:find("^!") then obj.link = obj.link:gsub("^!", "") end val = format_annotated_text(obj) numspec = desc .. " " .. val end end end local url = a(paramname .. "url") if url then return "[" .. url .. " " .. numspec .. "]" else return numspec end end local volume = format_numeric_param("volume", a("volume_prefix") or "volume") if volume then add_with_sep(volume) end local issue = format_numeric_param("issue", a("issue_prefix") or "number") if issue then add_with_sep(issue) end -- number= is an alias for issue= (except in {{quote-av}}, where it is the episode number) local number = format_numeric_param("number", a("number_prefix") or "number") if number then add_with_sep(number) end local annotations = {} local genre = a("genre") if genre then insert(annotations, genre) end local format = a("format") if format then insert(annotations, format) end local medium = a("medium") if medium then insert(annotations, medium) end -- Now handle the display of language annotations like "(in French)" or -- "(quotation in Nauruan; overall work in German)". local quotelang = args[1] or args.lang if not quotelang then if ind == "" then -- This can only happen for certain non-mainspace pages, e.g. Talk pages; otherwise an error is thrown -- above. insert(annotations, maintenance_line("Please specify the language of the quote using |1=")) else -- do nothing in newversion= portion end elseif ind == "" then local worklang = a("worklang") local termlang = a("termlang") worklang = worklang or quotelang termlang = termlang or quotelang if worklang == quotelang then if worklang == termlang then -- do nothing else insert(annotations, "ann an " .. format_langs(quotelang)) end else if quotelang ~= termlang then insert(annotations, "quotation in " .. format_langs(quotelang)) end insert(annotations, "overall work in " .. format_langs(worklang)) end else local lang2 = a("lang2") if lang2 then insert(annotations, "ann an " .. format_langs(lang2)) end end if #annotations > 0 then sep = nil add_with_sep(" (" .. concat(annotations, SEMICOLON_SPACE) .. ")") end local artist = parse_and_format_multivalued_annotated_text("artist", "and") if artist then add_with_sep("performed by " .. artist) end local feat = parse_and_format_multivalued_annotated_text("feat", "and") if feat then sep = " " add_with_sep("ft. " .. feat) end if not format_as_cite then add_actor_role() end local others = parse_and_format_annotated_text("others") if others then add_with_sep(others) end local quoted_in = parse_and_format_annotated_text("quoted_in", tag_with_cite, tag_with_cite) if quoted_in then add_with_sep("quoted in " .. quoted_in) insert(tracking_categories, "Quotations using quoted-in parameter") end local location = parse_and_format_multivalued_annotated_text("location", "; ") local publisher = parse_and_format_multivalued_annotated_text("publisher", "; ") if publisher then if location then add_with_sep(location) -- colon sep = "&#58; " -- colon end add_with_sep(publisher) elseif location then add_with_sep(location) end if not date_outputted then add_date("no_paren") end local source = parse_and_format_multivalued_annotated_text("source", "and") if source then add_with_sep("sourced from " .. source) end local original = parse_and_format_annotated_text("original", tag_with_cite, tag_with_cite) local by = parse_and_format_multivalued_annotated_text("by", "and") local origtype = a("deriv") or "translation" if original or by then add_with_sep(origtype .. " of " .. (original or "original") .. (by and " by " .. by or "")) end -- Handle origlang=, origworklang=. How we handle them depends on whether the original title or author are explicitly -- given. local origlang = a("origlang") local origworklang = a("origworklang") local origlangtext, origworklangtext if origlang then origlangtext = "in " .. format_langs(origlang) end if origworklang then origworklangtext = "overall work in " .. format_langs(origworklang) end if origlang or origworklang then if original or by then local orig_annotations = {} if origlangtext then insert(orig_annotations, origlangtext) end if origworklangtext then insert(orig_annotations, origworklangtext) end sep = nil add_with_sep(" (" .. concat(orig_annotations, SEMICOLON_SPACE) .. ")") else add_with_sep(origtype .. " of original" .. (origlangtext and " " .. origlangtext or "")) if origworklangtext then sep = nil add_with_sep(" (" .. origworklangtext .. ")") end end end if ind ~= "" and has_newversion() then local formatted_new_date = format_date_args(a, get_full_paramname, alias_map, "", "", nil, "Please provide a date or year", true) if formatted_new_date then add_with_sep(formatted_new_date) end end -- Fetch date_published=/year_published=/month_published= and format appropriately. local formatted_date_published = format_date_args(a, get_full_paramname, alias_map, "", "_published", nil, nil, true) local platform = parse_and_format_multivalued_annotated_text("platform", "and") if formatted_date_published then add_with_sep("published " .. formatted_date_published .. (platform and " via " .. platform or "")) elseif platform then add_with_sep("via " .. platform) end -- From here on out, there should always be a preceding item, so we -- can dispense with add_with_sep() and always insert the comma. sep = nil local function small(txt) add(", <small>") add(txt) add("</small>") end -- Add an identifier to a book or article database such as DOI, ISBN, JSTOR, etc. `param_or_params` -- is a string identifying the base param, or a list of such strings to check in turn. If found, the value -- of the parameter is processed using `process` (a function of one argument, defaulting to mw.uri.encode()), -- and then the actual URL to insert is generated by preceding with `pretext`, following with `posttext`, -- and running the resulting string through small(), which first adds a comma and then the URL in small font. local function add_identifier(param_or_params, pretext, posttext, process) local val = a(param_or_params) if val then val = (process or mw.uri.encode)(val) small(pretext .. val .. posttext) end end add_identifier("bibcode", "[https://adsabs.harvard.edu/abs/", " →Bibcode]") add_identifier("doi", '<span class="neverexpand">[https://doi.org/', " →DOI]</span>") add_identifier("isbn", "", "", isbn) add_identifier("issn", "", "", issn) add_identifier("jstor", "[https://www.jstor.org/stable/", " →JSTOR]") add_identifier("lccn", "", "", lccn) add_identifier("oclc", "[https://search.worldcat.org/title/", " →OCLC]") add_identifier("ol", "[https://openlibrary.org/works/OL", "/ →OL]") add_identifier("pmid", "[https://www.ncbi.nlm.nih.gov/pubmed/", " →PMID]") add_identifier("pmcid", "[https://www.ncbi.nlm.nih.gov/pmc/articles/", "/ →PMCID]") add_identifier("ssrn", "[https://ssrn.com/abstract=", " →SSRN]") -- add_identifier("urn", "", "", urn) local id = a("id") if id then small(id) end archiveurl, archiveurl_fullname = aurl_with_name("archiveurl") if archiveurl then add(", archived from ") local url, url_fullname = aurl_with_name("url") if not url then -- attempt to infer original URL from archive URL; this works at -- least for Wayback Machine (web.archive.org) URL's url = archiveurl:match("/(https?:.*)$") if not url then error( ("When |%s= is specified, |%s= must also be included"):format(archiveurl_fullname, url_fullname) ) end end add("[" .. url .. " the original] on ") local archivedate, archivedate_fullname = a_with_name("archivedate") if archivedate then add(format_date(archivedate)) elseif string.sub(archiveurl, 1, 28) == "https://web.archive.org/web/" then -- If the archive is from the Wayback Machine, then it already contains the date -- Get the date and format it local wayback_date = string.sub(archiveurl, 29, 29 + 7) wayback_date = string.sub(wayback_date, 1, 4) .. "-" .. string.sub(wayback_date, 5, 6) .. "-" .. string.sub(wayback_date, 7, 8) add(format_date(wayback_date)) else error( ("When |%s= is specified, |%s= must also be included"):format( archiveurl_fullname, archivedate_fullname ) ) end end if a("accessdate") then --Otherwise do not display here, as already used as a fallback for missing date= or year= earlier. if (a("date") or a("nodate") or a("year")) and not a("archivedate") then add(", retrieved " .. format_date(a("accessdate"))) end end local formatted_section = format_chapterlike("section", "section ") if formatted_section then add(", ") add(formatted_section) end -- video game stuff local system = parse_and_format_annotated_text("system") if system then add(", " .. system) end local scene = parse_and_format_annotated_text("scene") if scene then add(", scene: " .. scene) end local level = parse_and_format_annotated_text("level") if level then add(", level/area: " .. level) end local note = parse_and_format_annotated_text("note") if note then add(", " .. note) end local note_plain = parse_and_format_annotated_text("note_plain") if note_plain then add(" " .. note_plain) end -- Wrapper around format_numeric_param that inserts the formatted text with optional preceding text. local function handle_numeric_param(paramname, singular_desc, pretext) local numspec = format_numeric_param(paramname, singular_desc) if numspec then add((pretext or "") .. numspec) end end handle_numeric_param("page", a("page_prefix") or "page", ", ") handle_numeric_param("column", a("column_prefix") or "column", ", ") handle_numeric_param("line", a("line_prefix") or "line", ", ") -- FIXME: Does this make sense? What is other=? local other = parse_and_format_annotated_text("other") if other then add(", " .. other) end end local function add_authors(args, last_first) -- Find maximum indexed author or last name. local maxind = math.max(args.author.maxindex, args.last.maxindex) -- Include max index of ancillary params so we get an error message about their use without the primary params. local ancillary_params = {"trans-author", "authorlink", "trans-authorlink", "first", "trans-first", "trans-last"} for _, ancillary in ipairs(ancillary_params) do maxind = math.max(maxind, args[ancillary].maxindex) end local num_authors = 0 for i = 1, maxind do local ind = i == 1 and "" or i local author, last = args.author[i], args.last[i] if author or last then local this_num_authors = add_author( author, "author" .. ind, args["trans-author"][i], "trans-author" .. ind, args.authorlink[i], "authorlink" .. ind, args["trans-authorlink"][i], "trans-authorlink" .. ind, args.first[i], "first" .. ind, args["trans-first"][i], "trans-first" .. ind, last, "last" .. ind, args["trans-last"][i], "trans-last" .. ind, last_first ) num_authors = num_authors + this_num_authors sep = last_first and "; " or ", " else for _, cant_have in ipairs(ancillary_params) do if args[cant_have][i] then error(("Can't have |%s%s= without |author%s= or |last%s="):format(cant_have, ind, ind, ind)) end end end end return num_authors end local function add_newversion() -- If there's a "newversion" section, add the new-version text. if has_newversion() then sep = nil --Test for new version of work. add(SEMICOLON_SPACE) if args.newversion then -- newversion= is intended for English text, e.g. "quoted in" or "republished as". add(args.newversion) elseif not args.edition2 then if has_new_title_or_author() then add("republished as") else add("republished") end end add(" ") return "" else return ", " end end ------------------- Now we start outputting text ---------------------- local need_comma = false -- Set this now so a() works just below. get_full_paramname = make_get_full_paramname("") if args.brackets then add("[") end bold_year = not format_as_cite year_last = format_as_cite formatted_date, need_date = format_date_args( a, get_full_paramname, alias_map, nil, nil, bold_year, "Can we [[:Category:Requests for date|date]] this quote?", year_last ) -- Fetch origdate=/origyear=/origmonth= and format appropriately. formatted_origdate = format_date_args(a, get_full_paramname, alias_map, "orig", nil, nil, nil, year_last) local num_authors, need_date if format_as_cite then num_authors = add_authors(args, "last_first") if author_outputted then sep = " " end -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors, "format_as_cite") author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil, "last_first" ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors, "format_as_cite") else if formatted_date then need_comma = true add(formatted_date) end if formatted_origdate then need_comma = true add(SPACE_LBRAC .. formatted_origdate .. RBRAC) end if need_comma then sep = ", " end date_outputted = true num_authors = add_authors(args) -- Display all the text that comes after the author, for the main portion. postauthor("", num_authors) author_outputted = false sep = add_newversion() -- Add the newversion author(s). if args["2ndauthor"] or args["2ndlast"] then num_authors = add_author( args["2ndauthor"], "2ndauthor", nil, nil, args["2ndauthorlink"], "2ndauthorlink", nil, nil, args["2ndfirst"], "2ndfirst", nil, nil, args["2ndlast"], "2ndlast", nil, nil ) sep = ", " else for _, cant_have in ipairs{"2ndauthorlink", "2ndfirst"} do if args[cant_have] then error(("Can't have |%s= without |2ndauthor= or |2ndlast="):format(cant_have)) end end end -- Display all the text that comes after the author, for the "newversion" section. postauthor(2, num_authors) end if not args.nocolon then sep = nil add(":") elseif args.usenodot and not args.nodot then add(".") end -- Concatenate output portions to form output text. local output_text = concat(output) -- Remainder of code handles adding categories. We add one or more of the following categories: -- -- 1. [[Category:LANG terms with quotations]], based on the first language code in termlang= or 1=. Added to -- mainspace, Reconstruction: and Appendix: pages as well as Citations: pages if the corresponding mainspace -- page exists. Not added if nocat= is given. Note that [[Module:usex]] adds the same category using the same -- logic, but we do it here too because we may not have a quotation to format. (We add in those circumstances -- because typically when there's no quotation to format, it's because it's formatted manually underneath the -- citation, or using {{ja-x}}, {{th-x}} or similar.) -- 2. [[Category:Requests for date in LANG entries]], based on the first language code in 1=. Added to mainspace, -- Reconstruction:, Appendix: and Citations: pages unless nocat= is given. -- 3. [[Category:Quotations using nocat parameter]], if nocat= is given. Added to mainspace, Reconstruction:, -- Appendix: and Citations: pages. local categories = {} local termlang = get_first_lang(args.termlang or argslang) if args.nocat then if format_as_cite then insert(tracking_categories, "Citations using nocat parameter") else insert(tracking_categories, "Quotations using nocat parameter") end else -- don't create language tracking categories for citations if not format_as_cite then local title if args.pagename then -- for testing, doc pages, etc. title = mw.title.new(args.pagename) if not title then error(("Bad value for `args.pagename`: '%s'"):format(args.pagename)) end else title = mw.title.getCurrentTitle() end -- Only add [[Citations:foo]] to [[:Category:LANG terms with quotations]] if [[foo]] exists. local ok_to_add_cat if title.nsText ~= "Citations" then ok_to_add_cat = true else local mainspace_title = mw.title.new(title.text) if mainspace_title and mainspace_title.exists then ok_to_add_cat = true end end if ok_to_add_cat then insert(categories, termlang:getFullName() .. " terms with quotations") end end if need_date then local argslangobj = get_first_lang(argslang) insert(categories, "Requests for date in " .. argslangobj:getCanonicalName() .. " entries") end end return output_text .. ( not lang and "" or (#categories > 0 and format_categories(categories, lang, args.sort) or "") .. ( #tracking_categories > 0 and format_categories( tracking_categories, lang, args.sort, nil, not page_should_be_ignored(mw.title.getCurrentTitle().fullText) ) or "" ) ) end -- Alias specs for type= and type2=. Each spec is `{canon, aliases, with_newversion}` where `canon` is the canonical -- parameter (with "2" added if type2= is being handled), `aliases` is a comma-separated string of aliases (with "2" -- added if type2= is being handled, except for numeric params), and `with_newversion` indicates whether we should -- process this spec if type2= is being handled. local type_alias_specs = { av = { {"author", "writer,writers", true}, {"chapter", "episode", true}, {"chapterurl", "episodeurl", true}, {"trans-chapter", "trans-episode", true}, {"chapter_tlr", "episode_tlr,episode_tlrs,episode_translator,episode_translators", true}, {"chapter_series", "episode_series", true}, {"chapter_seriesvolume", "episode_seriesvolume", true}, {"chapter_number", "episode_number", true}, {"chapter_plain", "episode_plain", true}, {"volume", "season", true}, {"volumes", "seasons", true}, {"volume_plain", "season_plain", true}, {"volumeurl", "seasonurl", true}, {"platform", "network", true}, }, book = { {"author", "3"}, {"title", "4"}, {"url", "5"}, {"year", "2"}, {"page", "6"}, {"text", "7"}, {"t", "8"}, }, journal = { {"year", "2"}, {"author", "3"}, {"chapter", "title,article,4", true}, {"chapterurl", "titleurl,articleurl", true}, {"trans-chapter", "trans-title,trans-article", true}, {"chapter_tlr", "title_tlr,title_tlrs,title_translator,title_translators,article_tlr,article_tlrs,article_translator,article_translators", true}, {"chapter_series", "title_series,article_series", true}, {"chapter_seriesvolume", "title_seriesvolume,article_seriesvolume", true}, {"chapter_number", "title_number,article_number", true}, {"chapter_plain", "title_plain,article_plain", true}, {"title", "journal,magazine,newspaper,work,5", true}, {"trans-title", "trans-journal,trans-magazine,trans-newspaper,trans-work", true}, {"tlr", "journal_tlr,journal_tlrs,journal_translator,journal_translators,magazine_tlr,magazine_tlrs,magazine_translator,magazine_translators,newspaper_tlr,newspaper_tlrs,newspaper_translator,newspaper_translators,work_tlr,work_tlrs,work_translator,work_translators", true}, {"url", "6,journalurl,magazineurl,newspaperurl,workurl", true}, {"page", "7"}, {"source", "newsagency,news_agency", true}, {"text", "8"}, {"t", "9"}, }, } -- Process interally-handled aliases related to type= or type2=. `args` is a table of arguments; `typ` is the value of -- type= or type2=; newversion=true if we're dealing with type2=; alias_map is used to keep track of alias mappings -- seen. local function process_type_aliases(args, typ, newversion, alias_map) local ind = newversion and "2" or "" local deprecated = ine(args.lang) if not type_alias_specs[typ] then local possible_values = {} for possible, _ in pairs(type_alias_specs) do insert(possible_values, possible) end sort(possible_values) error( ("Unrecognized value '%s' for type%s=; possible values are %s"):format( typ, ind, concat(possible_values, ",") ) ) end for _, alias_spec in ipairs(type_alias_specs[typ]) do local canon, aliases, with_newversion = unpack(alias_spec) if with_newversion or not newversion then canon = canon .. ind aliases = split(aliases, ",", true) local saw_alias = nil for _, alias in ipairs(aliases) do if alias:match("^%d+$") then alias = tonumber(alias) if deprecated then alias = alias - 1 end else alias = alias .. ind end if args[alias] then if saw_alias == nil then saw_alias = alias else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_alias, alias)) end end end if saw_alias and (not newversion or type(saw_alias) == "string") then if args[canon] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_alias, canon)) end args[canon] = args[saw_alias] -- Wipe out the original after copying. This is important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_alias] = nil alias_map[canon] = saw_alias end end end end -- Clone and combine frame's and parent's args while also assigning nil to empty strings. Handle aliases and ignores. local function clone_args(direct_args, parent_args) local args = {} -- Processing parent args must come first so that direct args override parent args. Note that if a direct arg is -- specified but is blank, it will still override the parent arg (with nil). for pname, param in pairs(parent_args) do -- [[Special:WhatLinksHere/Wiktionary:Tracking/quote/param/PARAM]] track("param/" .. pname) args[pname] = ine(param) end -- Process ignores. The value of `ignore` is a comma-separated list of parameter names to ignore (erase). We need to -- do this before aliases due to {{quote-song}}, which sets chapter= to the value of title= in the direct params and -- sets title= to the value of album= using an alias. If we do the ignores after aliases, we get an error during alias -- processing, saying that title= and its alias album= are both present. local ignores = ine(direct_args.ignore) if ignores then for ignore in gsplit(ignores, "%s*,%s*") do args[ignore] = nil end end local alias_map = {} local other_controls = {} -- noroman local noroman = ine(direct_args.noroman) if noroman then other_controls.overrides = other_controls.overrides or {} for param in gsplit(noroman, "%s*,%s*") do other_controls.overrides[param] = (other_controls.overrides[param] or {}) other_controls.overrides[param].noroman = true end end -- Process internally-specified aliases using type= or type2=. local typ = args.type or direct_args.type if typ then process_type_aliases(args, typ, false, alias_map) end local typ2 = args.type2 or direct_args.type2 if typ2 then process_type_aliases(args, typ2, true, alias_map) end -- Process externally-specified aliases. The value of `alias` is a list of semicolon-separated specs, each of which -- is of the form DEST:SOURCE,SOURCE,... where DEST is the canonical name of a parameter and SOURCE refers to an -- alias. Whitespace is allowed between all delimiters. The order of aliases may be important. For example, for -- {{quote-journal}}, title= contains the article name and is an alias of underlying chapter=, while journal= or -- work= contains the journal name and is an alias of underlying title=. As a result, the title -> chapter alias -- must be specified before the journal/work -> title alias. -- -- Whenever we copy a value from argument SOURCE to argument DEST, we record an entry for the pair in alias_map, so -- that when we would display an error message about DEST, we display SOURCE instead. -- -- Do alias processing (and ignore and error_if processing) before processing direct_args so that e.g. we can set up -- an alias of title -> chapter and then set title= to something else in the direct args ({{quote-hansard}} does -- this). -- -- FIXME: Delete this once we've converted all alias processing to internal. local aliases = ine(direct_args.alias) if aliases then -- Allow and discard a trailing semicolon, to make managing multiple aliases easier. aliases = ugsub(aliases, "%s*;$", "") for alias_spec in gsplit(aliases, "%s*;%s*") do local alias_spec_parts = split(alias_spec, "%s*:%s*") if #alias_spec_parts ~= 2 then error(("Alias spec '%s' should have one colon in it"):format(alias_spec)) end local dest, sources = unpack(alias_spec_parts) sources = split(sources, "%s*,%s*") local saw_source = nil for _, source in ipairs(sources) do if source:match("^%d+$") then source = tonumber(source) end if args[source] then if saw_source == nil then saw_source = source else error(("|%s= and |%s= are aliases; cannot specify a value for both"):format(saw_source, source)) end end end if saw_source then if args[dest] then error(("|%s= is an alias of |%s=; cannot specify a value for both"):format(saw_source, dest)) end args[dest] = args[saw_source] -- Wipe out the original after copying. This important in case of a param that has general significance -- but has been redefined (e.g. {{quote-av}} redefines number= for the episode number, and -- {{quote-journal}} redefines title= for the chapter= (article). It's also important due to unhandled -- parameter checking. args[saw_source] = nil alias_map[dest] = saw_source end end end -- Process error_if. The value of `error_if` is a comma-separated list of parameter names to throw an error if seen -- in parent_args (they are params we overwrite in the direct args). local error_ifs = ine(direct_args.error_if) if error_ifs then for error_if in gsplit(error_ifs, "%s*,%s*") do if ine(parent_args[error_if]) then error( ("Cannot specify a value |%s=%s as it would be overwritten or ignored"):format( error_if, ine(parent_args[error_if]) ) ) end end end for pname, param in pairs(direct_args) do -- ignore control params if pname ~= "ignore" and pname ~= "alias" and pname ~= "error_if" and pname ~= "noroman" then args[pname] = ine(param) end end return args, alias_map, other_controls end local function get_args(frame_args, parent_args, require_lang) -- FIXME: We are processing arguments twice, once in clone_args() and then again in [[Module:parameters]]. This is -- wasteful of memory. local cloned_args, alias_map, other_controls = clone_args(frame_args, parent_args) local deprecated = ine(parent_args.lang) local alias_of_t = {alias_of = "t"} local boolean = {type = "boolean"} local language_sublist = {type = "language", sublist = true} local list_allow_holes = {list = true, allow_holes = true} local script = {type = "script"} -- First, the "single" params that don't have FOO2 or FOOn versions. local params = { [deprecated and "lang" or 1] = {required = require_lang, type = "language", sublist = true, default = "und"}, ["lang2"] = language_sublist, ["newversion"] = true, ["author"] = list_allow_holes, ["2ndauthor"] = true, ["trans-author"] = list_allow_holes, ["authorlink"] = list_allow_holes, ["2ndauthorlink"] = true, ["trans-authorlink"] = list_allow_holes, ["first"] = list_allow_holes, ["2ndfirst"] = true, ["trans-first"] = list_allow_holes, ["last"] = list_allow_holes, ["2ndlast"] = true, ["trans-last"] = list_allow_holes, ["nocat"] = boolean, ["nocolon"] = boolean, -- quote params text = true, passage = {alias_of = "text"}, tr = true, transliteration = {alias_of = "tr"}, ts = true, transcription = {alias_of = "ts"}, norm = true, normalization = {alias_of = "norm"}, sc = script, normsc = script, sort = true, subst = true, footer = true, lit = true, t = true, translation = alias_of_t, gloss = alias_of_t, lb = true, brackets = boolean, -- original quote params origtext = true, origtr = true, origts = true, orignorm = true, origsc = script, orignormsc = script, origsubst = true, origlb = true, usenodot = boolean, nodot = boolean, inline = boolean, asquote = boolean, ascite = boolean, } -- Most params have PARAM2 variants for use with `newversion`. FIXME: We should generalize this to -- allow PARAMN variants for any N. local function add_with_2(param, value) params[param] = value params[param .. "2"] = value end local function alias_with_2(alias, canon) params[alias] = {alias_of = canon} params[alias .. "2"] = {alias_of = canon .. "2"} end for _, param12 in ipairs{ "worklang", "termlang", "origlang", "origworklang" } do add_with_2(param12, language_sublist) end -- Then the newversion params (which have FOO2 versions). for _, param12 in ipairs{ -- author-like params; author params themselves are either list params (author=, last=, etc.) or single params -- (2ndauthor=, 2ndlast=, etc.) "coauthors", "quotee", "tlr", "editor", "editors", "mainauthor", "compiler", "compilers", "director", "directors", "lyricist", "lyrics-translator", "composer", "role", "actor", "artist", "feat", -- author control params "default-authorlabel", "authorlabel", -- title "title", "trans-title", "series", "seriesvolume", "notitle", -- entry "entry", "entryurl", "trans-entry", -- chapter "chapter", "chapterurl", "chapter_number", "chapter_plain", "chapter_series", "chapter_seriesvolume", "trans-chapter", "chapter_tlr", -- section "section", "sectionurl", "section_number", "section_plain", "section_series", "section_seriesvolume", "trans-section", -- other video-game params "system", "scene", "level", -- URL "url", "urls", "archiveurl", -- edition "edition", "edition_plain", -- ID params "bibcode", "doi", "isbn", "issn", "jstor", "lccn", "oclc", "ol", "pmid", "pmcid", "ssrn", "urn", "id", -- misc date params; most date params handled below "archivedate", "accessdate", "nodate", -- numeric params handled below -- other params "type", "genre", "format", "medium", "others", "quoted_in", "location", "publisher", "original", "by", "deriv", "note", "note_plain", "other", "source", "platform", } do add_with_2(param12, true) end -- Then the aliases of newversion params (which have FOO2 versions). for _, param12_aliased in ipairs{ {"role", "roles"}, {"role", "speaker"}, {"tlr", "tlrs"}, {"tlr", "translator"}, {"tlr", "translators"}, {"chapter_tlr", "chapter_tlrs"}, {"chapter_tlr", "chapter_translator"}, {"chapter_tlr", "chapter_translators"}, {"doi", "DOI"}, {"isbn", "ISBN"}, {"issn", "ISSN"}, {"jstor", "JSTOR"}, {"lccn", "LCCN"}, {"oclc", "OCLC"}, {"ol", "OL"}, {"pmid", "PMID"}, {"pmcid", "PMCID"}, {"ssrn", "SSRN"}, {"urn", "URN"}, } do local canon, alias = unpack(param12_aliased) alias_with_2(alias, canon) end -- Then the date params. for _, datelike in ipairs{{"", ""}, {"orig", ""}, {"", "_published"}} do local pref, suf = unpack(datelike) for _, arg in ipairs{"date", "year", "month", "start_date", "start_year", "start_month"} do add_with_2(pref .. arg .. suf, true) end end local numeric_param_suffixes = {"", "s", "_plain", "url", "_prefix"} -- Then the numeric params. for _, numeric in ipairs{"volume", "issue", "number", "line", "page", "column"} do for _, suf in ipairs(numeric_param_suffixes) do add_with_2(numeric .. suf, true) end end -- And the aliases of numeric params. for _, numeric_aliased in ipairs{{"volume", "vol"}} do local canon, alias = unpack(numeric_aliased) for _, suf in ipairs(numeric_param_suffixes) do alias_with_2(alias .. suf, canon .. suf) end end return process_params(cloned_args, params), alias_map, other_controls end local function get_origtext_params(args) local origtext, origtextlang, origsc, orignormsc if args.origtext then -- Wiktionary language codes have at least two lowercase letters followed possibly by lowercase letters and/or -- hyphens (there are more restrictions but this is close enough). Also check for nonstandard Latin etymology -- language codes (e.g. VL. or LL.). (There used to be more nonstandard codes but they have all been -- eliminated.) origtextlang, origtext = args.origtext:match("^(%l%l[%l-]*):([^ ].*)$") if not origtextlang then -- Special hack for Latin variants, which can have nonstandard etym codes, e.g. VL., LL. origtextlang, origtext = args.origtext:match("^(%uL%.):([^ ].*)$") end if not origtextlang then error("origtext= should begin with a language code prefix") end origtextlang = get_lang(origtextlang, nil, "allow etym") or error("origtext= should begin with a language code prefix") origsc = args.origsc orignormsc = args.orignormsc else for _, noparam in ipairs{"origtr", "origts", "origsc", "orignorm", "orignormsc", "origsubst", "origlb"} do if args[noparam] then error(("Cannot specify %s= without origtext="):format(noparam)) end end end return origtext, origtextlang, origsc, orignormsc end local function get_quote(args, is_cite) local text = args.text local gloss = args.t local tr = args.tr local ts = args.ts local norm = args.norm local sc = args.sc local normsc = args.normsc -- Fetch original-text parameters. local origtext, origtextlang, origsc, orignormsc = get_origtext_params(args) -- If any quote-related args are present, display the actual quote; otherwise, display nothing. if text or gloss or tr or ts or norm or args.origtext then -- Pass "und" here rather than cause an error; there will be an error on mainspace, Citations, etc. pages -- in any case in source() if the language is omitted. local lang = get_first_lang(args[1] or args.lang) local termlang = args.termlang and get_first_lang(args.termlang) or lang local usex_data = { lang = lang, termlang = termlang, usex = text, sc = sc, translation = gloss, normalization = norm, normsc = normsc, transliteration = tr, transcription = ts, brackets = args.brackets, subst = args.subst, lit = args.lit, footer = args.footer, qq = parse_and_format_labels(args.lb, lang), quote = "quote-meta", orig = origtext, origlang = origtextlang, origsc = origsc, orignorm = args.orignorm, orignormsc = orignormsc, origtr = args.origtr, origts = args.origts, origsubst = args.origsubst, origqq = parse_and_format_labels(args.origlb, lang), noreq = args.noreq, nocat = is_cite or args.nocat, } if args.inline then -- don't let usex format the footer, otherwise it gets inlined with the rest of the quoted text usex_data.footer = nil usex_data.inline = 1 text = format_usex(usex_data) if text then text = " “" .. text .. "”" else text = "" end if args.footer then text = text .. "<dl><dd>" .. args.footer .. "</dd></dl>" end else text = "<dl><dd>" .. format_usex(usex_data) .. "</dd></dl>" end elseif args.footer then text = "<dl><dd>" .. args.footer .. "</dd></dl>" end return text end -- External interface, meant to be called from a template. Replaces {{quote-meta}} and meant to be the primary -- interface for {{quote-*}} templates. function export.quote_t(frame) local args, alias_map, other_controls = get_args(frame.args, frame:getParent().args, "require_lang") if args.ascite then return export.cite_t(frame) end return show_quote(args, alias_map, other_controls) end function show_quote(args, alias_map, other_controls) local parts = {} insert(parts, '<div class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, nil, other_controls)) insert(parts, "</span>") insert(parts, get_quote(args)) insert(parts, "</div>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. Replaces {{cite-meta}} and meant to be the primary -- interface for {{cite-*}} templates. function export.cite_t(frame) local parent_args = {} for k, v in pairs(frame:getParent().args) do parent_args[k] = v end -- use "und" as lang if none provided if parent_args[1] == nil then parent_args[1] = "und" end local args, alias_map, other_controls = get_args(frame.args, parent_args) if args.asquote then return show_quote(args, alias_map, other_controls) end return show_cite(args, alias_map, other_controls) end function show_cite(args, alias_map, other_controls) local parts = {} -- don't nag for translations if args.text and not args.t then args.noreq = 1 end local len_visible = args.text and ulen((args.text:gsub("<[^<>]+>", ""))) or 0 if len_visible == 0 then if not args.t or args.t == "-" then args.nocolon = true end elseif args.inline == nil then args.inline = not ( args.block_text or len_visible > 300 or (args.t and not args.t == "-" and len_visible < 80) or string.match(args.text, "<br>") ) end insert(parts, '<span class="citation-whole"><span class="cited-source">') insert(parts, export.source(args, alias_map, "format_as_cite", other_controls)) insert(parts, "</span>") insert(parts, get_quote(args, "is_cite")) insert(parts, "</span>") local retval = concat(parts) return deprecated and frame:expandTemplate({ title = "check deprecated lang param usage", args = {retval, lang = args.lang}, }) or retval end -- External interface, meant to be called from a template. function export.call_quote_template(frame) return export.call_template(frame) end -- External interface, for calling a template with overloaded parameters. function export.overload(frame) local iargs, overloaded_args = process_params(frame.args, { [1] = {required = true} }, true) local parent_args = frame:getParent().args for k, v in pairs(parent_args) do overloaded_args[k] = v end return frame:expandTemplate{title = iargs[1], args = overloaded_args} end -- External interface, meant to be called from a template. function export.call_template(frame) local parameter_sublist = {type = "parameter", sublist = true} local iargs, other_direct_args = process_params(frame.args, { ["template"] = true, ["textparam"] = parameter_sublist, ["pageparam"] = parameter_sublist, ["propagateparams"] = parameter_sublist, ["allowparams"] = {sublist = true}, -- Doesn't use type = "parameter", because any that end in :list get processed differently. }, true) local function fetch_param(source, params) for _, param in ipairs(params) do if source[param] then return source[param] end end return nil end local params = { ["text"] = true, ["passage"] = true, ["footer"] = true, -- always propagates, but gets special formatting } -- paramaters that can be used during template declaration or included in template calls -- if the template is called with param=- it will set any declared value to nil local always_propagate = { ["brackets"] = true, ["usenodot"] = true, ["nodot"] = true, ["ascite"] = true, ["asquote"] = true, } for k,v in pairs(always_propagate) do params[k] = v end local textparam = iargs.textparam or {} for _, param in ipairs(textparam) do params[param] = true end local pageparam = iargs.pageparam or {} local pageparam1 = pageparam[1] if pageparam1 ~= nil then params["page"], params["pages"] = true, true for _, param in ipairs(pageparam) do params[param] = true end end local allowparams, allow_all, list = iargs.allowparams, false if allowparams ~= nil then for _, allow in ipairs(allowparams) do local param = allow:match("^(.*):list$") if param then if list == nil then list = {list = true} end params[scribunto_parameter_key(param)] = list elseif allow == "*" then track("no parameter checking") allow_all = true else params[scribunto_parameter_key(allow)] = true end end else local parent = frame:getParent() local template_name = parent:getTitle() local template_title = new_title(template_name) local content = template_title:getContent() local allowed_params, seen = {}, {} -- Detect all params used by the parent template. param:get_name() takes the -- parent frame arg table as an argument so that preprocessing will take -- them into account, since it will matter if the name contains another -- parameter (e.g. the outer param in "{{{foo{{{bar}}}baz}}}" will change -- depending on the value for bar=). `seen` memoizes results based on the -- raw parameter text (which is stored as a string in the parameter object), -- which avoids unnecessary param:get_name() calls, which are non-trivial. for param in find_parameters(content) do local raw = param.raw if not seen[raw] then allow = param:get_name(template_args) params[scribunto_parameter_key(allow)] = true seen[raw] = true end end end local propagateparams = iargs.propagateparams or {} for _, param in ipairs(propagateparams) do params[param] = true end local parent_args = frame:getParent().args local args = process_params(parent_args, params, allow_all) parent_args = shallow_copy(parent_args) if textparam[1] ~= "-" then other_direct_args.passage = args.text or args.passage or fetch_param(args, textparam) end if not (pageparam1 == nil or pageparam1 == "-") then other_direct_args.page = fetch_param(args, pageparam) or args.page or other_direct_args.page or nil other_direct_args.pages = args.pages or other_direct_args.pages or nil if other_direct_args.page == "-" then other_direct_args.page = nil end if other_direct_args.pages == "-" then other_direct_args.pages = nil end end if args.footer then other_direct_args.footer = frame:expandTemplate{title = "small", args = {args.footer}} end for param, _ in pairs(always_propagate) do if args[param] == "-" then other_direct_args[param] = nil else other_direct_args[param] = args[param] or other_direct_args[param] or nil end end -- authorlink=- can be used to prevent copying of author= to authorlink= but we don't want to propagate this to -- the actual {{quote-*}} code. if other_direct_args.authorlink == "-" then other_direct_args.authorlink = nil end for _, param in ipairs(propagateparams) do if args[param] then other_direct_args[param] = args[param] end end return frame:expandTemplate{title = iargs.template or "quote-book", args = other_direct_args} end local paramdoc_param_replacements = { passage = { param_with_synonym = "<<synonym>>, {{para|text}}, or {{para|passage}}", param_no_synonym = "{{para|text}} or {{para|passage}}", text = [=[ * <<params>> – the passage to be quoted.]=], }, page = { param_with_synonym = "<<synonym>> or {{para|page}}, or {{para|pages}}", param_no_synonym = "{{para|page}} or {{para|pages}}", text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. 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 indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, page_with_roman_preface = { param_with_synonym = {"inherit", "page"}, param_no_synonym = {"inherit", "page"}, text = [=[ * <<params>> – '''mandatory in some cases''': the page number(s) quoted from. If quoting from the preface, specify the page number(s) in lowercase Roman numerals. When quoting a range of pages, note the following: ** Separate the first and last page number of the range with an [[en dash]], like this: {{para|pages|10–11}} or {{para|pages|iii–iv}}. ** You must also use {{para|pageref}} to indicate the page to be linked to (usually the page on which the Wiktionary entry appears). : This parameter must be specified to have the template link to the online version of the work.]=], }, chapter = { param_with_synonym = "<<synonym>> or {{para|chapter}}", param_no_synonym = "{{para|chapter}}", text = [=[ * <<params>> – the name of the chapter quoted from.]=], }, roman_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in uppercase Roman numerals.]=], }, arabic_chapter = { param_with_synonym = {"inherit", "chapter"}, param_no_synonym = {"inherit", "chapter"}, text = [=[ * <<params>> – the chapter number quoted from in Arabic numerals.]=], }, trailing_params = { text = [=[ * {{para|footer}} – a comment on the passage quoted. * {{para|brackets}} – use {{para|brackets|on}} to surround a quotation with [[bracket#Noun|brackets]]. This indicates that the quotation either contains a mere mention of a term (for example, “some people find the word '''''manoeuvre''''' hard to spell”) rather than an actual use of it (for example, “we need to '''manoeuvre''' carefully to avoid causing upset”), or does not provide an actual instance of a term but provides information about related terms.]=], }, } function export.paramdoc(frame) local parargs = frame:getParent().args local args = process_params(parargs, { [1] = true, }) local text = args[1] local function do_param_with_optional_synonym(param, text_to_sub, paramtext_synonym, paramtext_no_synonym) local function sub_param(synonym) local subbed_paramtext if synonym then subbed_paramtext = paramtext_synonym:gsub("<<synonym>>", "{{para|" .. replacement_escape(synonym) .. "}}") else subbed_paramtext = paramtext_no_synonym end return frame:preprocess((text_to_sub:gsub("<<params>>", replacement_escape(subbed_paramtext)))) end text = text:gsub("<<" .. pattern_escape(param) .. ">>", function() return sub_param() end) text = text:gsub("<<" .. pattern_escape(param) .. ":(.-)>>", sub_param) end local function fetch_text(param_to_replace, key) local spec = paramdoc_param_replacements[param_to_replace] local val = spec[key] if type(val) == "string" then return val end if type(val) == "table" and val[1] == "inherit" then return fetch_text(val[2], key) end error( "Internal error: Unrecognized value for param '" .. param_to_replace .. "', key '" .. key .. "': " .. mw.dumpObject(val) ) end for param_to_replace, spec in pairs(paramdoc_param_replacements) do if not spec.param_no_synonym then -- Text to substitute directly. text = text:gsub("<<" .. pattern_escape(param_to_replace) .. ">>", function() return frame:preprocess(fetch_text(param_to_replace, "text")) end) else do_param_with_optional_synonym( param_to_replace, fetch_text(param_to_replace, "text"), fetch_text(param_to_replace, "param_with_synonym"), fetch_text(param_to_replace, "param_no_synonym") ) end end -- Remove final newline so template code can add a newline after invocation text = text:gsub("\n$", "") return text end return export k5559jxnbddst687ypwonq9gixjxzt5 Mòideal:etymology/templates 828 17526 88842 87953 2026-08-06T21:41:00Z Altronic 4137 add argument 88842 Scribunto text/plain local export = {} local require_when_needed = require("Module:require when needed") local concat = table.concat local format_categories = require_when_needed("Module:utilities", "format_categories") local insert = table.insert local process_params = require_when_needed("Module:parameters", "process") local trim = mw.text.trim local lower = mw.ustring.lower local dump = mw.dumpObject local etymology_module = "Module:etymology" local etymology_specialized_module = "Module:etymology/specialized" local parameter_utilities_module = "Module:parameter utilities" -- For testing local force_cat = false local allowed_conjs = {"and", "or", ",", "/", "~", ";"} local function parse_etym_args(parent_args, base_params, has_dest_lang) local m_param_utils = require(parameter_utilities_module) local param_mods = m_param_utils.construct_param_mods { {group = {"link", "q", "l", "ref"}}, } local sourcearg, termarg if has_dest_lang then sourcearg, termarg = 2, 3 else sourcearg, termarg = 1, 2 end local terms, args = m_param_utils.parse_term_with_inline_modifiers_and_separate_params { params = base_params, param_mods = param_mods, raw_args = parent_args, termarg = termarg, track_module = "etymology", lang = function(args) return args[sourcearg][#args[sourcearg]] end, sc = "sc", -- Don't do this, doesn't seem to make sense. -- parse_lang_prefix = true, make_separate_g_into_list = true, splitchar = ",", subitem_param_handling = "last", } -- If term param 3= is empty, there will be no terms in terms.terms. To facilitate further code and for -- compatibility,, insert one. It will display as <small>[Term?]</small>. if not terms.terms[1] then terms.terms[1] = { lang = args[sourcearg][#args[sourcearg]], sc = args.sc, } end return terms.terms, args end function export.parse_2_lang_args(parent_args, has_text, no_family) local boolean = {type = "boolean"} local params = { [1] = { required = true, type = "language", default = "und" }, [2] = { required = true, sublist = true, type = "language", family = not no_family, default = "und" }, [3] = true, [4] = {alias_of = "alt"}, [5] = {alias_of = "t"}, ["senseid"] = true, ["nocat"] = boolean, ["sort"] = true, ["sourceconj"] = true, ["conj"] = {set = allowed_conjs, default = ","}, ["len"] = { type = "boolean" } } if has_text then params["notext"] = boolean params["nocap"] = boolean end return parse_etym_args(parent_args, params, "has dest lang") end -- Implementation of deprecated {{etyl}}. Provided to make histories more legible. function export.etyl(frame) local params = { [1] = {required = true, type = "language", default = "und"}, [2] = {type = "language", default = "en"}, ["sort"] = {}, } -- Empty language means English, but "-" means no language. Yes, confusing... local args = frame:getParent().args if args[2] and trim(args[2]) == "-" then params[2] = nil args = process_params({ [1] = args[1], ["sort"] = args.sort }, params) else args = process_params(args, params) end return require(etymology_module).format_source { lang = args[2], source = args[1], sort_key = args.sort, force_cat = force_cat, } end -- Implementation of {{derived}}/{{der}}. function export.derived(frame) local parent_args = frame:getParent().args local terms, args = export.parse_2_lang_args(parent_args) return require(etymology_module).format_derived { lang = args[1], sources = args[2], terms = terms, sort_key = args.sort, nocat = args.nocat, sourceconj = args.sourceconj, conj = args.conj, template_name = "derived", force_cat = force_cat, } end -- Implementation of {{borrowed}}/{{bor}}. function export.borrowed(frame) local parent_args = frame:getParent().args local terms, args = export.parse_2_lang_args(parent_args) return require(etymology_module).format_borrowed { lang = args[1], sources = args[2], terms = terms, sort_key = args.sort, nocat = args.nocat, sourceconj = args.sourceconj, conj = args.conj, force_cat = force_cat, } end function export.inherited(frame) local parent_args = frame:getParent().args local terms, args = export.parse_2_lang_args(parent_args) local sources = args[2] if sources[2] then -- Because this doesn't really make sense. error("[[Template:inherited]] doesn't support multiple comma-separated sources") end return require(etymology_module).format_inherited { lang = args[1], terms = terms, sort_key = args.sort, nocat = args.nocat, conj = args.conj, force_cat = force_cat, } end function export.cognate(frame) local params = { [1] = { required = true, sublist = true, type = "language", family = true, default = "und" }, [2] = true, [3] = {alias_of = "alt"}, [4] = {alias_of = "t"}, sourceconj = true, ["conj"] = {set = allowed_conjs, default = ","}, sort = true, } local parent_args = frame:getParent().args local terms, args = parse_etym_args(parent_args, params, false) return require(etymology_module).format_cognate { sources = args[1], terms = terms, sort_key = args.sort, sourceconj = args.sourceconj, conj = args.conj, force_cat = force_cat, } end function export.noncognate(frame) return export.cognate(frame) end -- Supports various specialized types of borrowings, according to `frame.args.bortype`: -- "learned" = {{lbor}}/{{learned borrowing}} -- "semi-learned" = {{slbor}}/{{semi-learned borrowing}} -- "orthographic" = {{obor}}/{{orthographic borrowing}} -- "unadapted" = {{ubor}}/{{unadapted borrowing}} -- "calque" = {{cal}}/{{calque}} -- "partial-calque" = {{pcal}}/{{partial calque}} -- "semantic-loan" = {{sl}}/{{semantic loan}} -- "transliteration" = {{translit}}/{{transliteration}} -- "phono-semantic-matching" = {{psm}}/{{phono-semantic matching}} function export.specialized_borrowing(frame) local parent_args = frame:getParent().args local terms, args = export.parse_2_lang_args(parent_args, "has text") local m_etymology_specialized = require(etymology_specialized_module) return m_etymology_specialized.specialized_borrowing { bortype = frame.args.bortype, lang = args[1], sources = args[2], terms = terms, sort_key = args.sort, nocap = args.nocap, notext = args.notext, nocat = args.nocat, sourceconj = args.sourceconj, conj = args.conj, senseid = args.senseid, force_cat = force_cat, } end -- Implementation of miscellaneous templates such as {{abbrev}}, {{back-formation}}, {{clipping}}, {{ellipsis}}, -- {{rebracketing}} and {{reduplication}} that have a single associated term. function export.misc_variant(frame) local iparams = { ["ignore-params"] = true, text = {required = true}, oftext = true, cat = {list = true}, -- allow and compress holes conj = true, } local iargs = process_params(frame.args, iparams) local boolean = {type = "boolean"} local params = { [1] = {required = true, type = "language", default = "und"}, [2] = true, [3] = {alias_of = "alt"}, [4] = {alias_of = "t"}, nocap = boolean, -- should be processed in the template itself notext = boolean, nocat = boolean, conj = {set = allowed_conjs}, sort = true, } -- |ignore-params= parameter to module invocation specifies -- additional parameter names to allow in template invocation, separated by -- commas. They must consist of ASCII letters or numbers or hyphens. local ignore_params = iargs["ignore-params"] if ignore_params then ignore_params = trim(ignore_params) if not ignore_params:match("^[%w%-,]+$") then error("Invalid characters in |ignore-params=: " .. ignore_params:gsub("[%w%-,]+", "")) end for param in ignore_params:gmatch("[%w%-]+") do if params[param] then error("Duplicate param |" .. param .. " in |ignore-params=: already specified in params") end params[param] = true end end local m_param_utils = require(parameter_utilities_module) local param_mods = m_param_utils.construct_param_mods { {group = {"link", "q", "l", "ref"}}, } local parent_args = frame:getParent().args local terms, args = m_param_utils.parse_term_with_inline_modifiers_and_separate_params { params = params, param_mods = param_mods, raw_args = parent_args, termarg = 2, track_module = "etymology", -- Don't set lang here as we want to know whether there was a lang prefix or not. sc = "sc", parse_lang_prefix = true, allow_multiple_lang_prefixes = true, make_separate_g_into_list = true, splitchar = ",", subitem_param_handling = "last", } return require(etymology_module).format_misc_variant { lang = args[1], notext = args.notext, text = iargs.text, oftext = iargs.oftext, terms = terms.terms, sort_key = args.sort, conj = args.conj or iargs.conj or "and", nocat = args.nocat, cats = iargs.cat, force_cat = force_cat, } end -- Implementation of miscellaneous templates such as {{doublet}} that can take multiple terms. Doesn't handle {{blend}} -- or {{univerbation}}, which display + signs between elements and use compound_like in [[Module:affix/templates]]. function export.misc_variant_multiple_terms(frame) local iparams = { text = {required = true}, oftext = true, cat = {list = true}, -- allow and compress holes conj = true, } local iargs = process_params(frame.args, iparams) local boolean = {type = "boolean"} local params = { [1] = {required = true, type = "language", template_default = "und"}, [2] = {list = true, allow_holes = true}, nocap = boolean, -- should be processed in the template itself notext = boolean, nocat = boolean, conj = {set = allowed_conjs}, sort = true, } local m_param_utils = require(parameter_utilities_module) local param_mods = m_param_utils.construct_param_mods { -- We want to require an index for all params. {default = true, require_index = true}, {group = {"link", "q", "l", "ref"}}, } local parent_args = frame:getParent().args local terms, args = m_param_utils.parse_list_with_inline_modifiers_and_separate_params { params = params, param_mods = param_mods, raw_args = parent_args, termarg = 2, parse_lang_prefix = true, allow_multiple_lang_prefixes = true, track_module = "etymology-templates-doublet", disallow_custom_separators = true, -- For compatibility, we need to not skip completely unspecified items. It is common, for example, to do -- {{suffix|lang||foo}} to generate "+ -foo". dont_skip_items = true, -- Don't set lang here as we want to know whether there was a lang prefix or not. sc = "sc.default", } return require(etymology_module).format_misc_variant { lang = args[1], notext = args.notext, text = iargs.text, oftext = iargs.oftext, terms = terms, sort_key = args.sort, conj = args.conj or iargs.conj or "and", nocat = args.nocat, cats = iargs.cat, force_cat = force_cat, } end -- Implementation of miscellaneous templates such as {{unknown}} that have no associated terms. do local function get_args(frame) local boolean = {type = "boolean"} local params = { [1] = {required = true, type = "language", default = "und"}, ["title"] = true, ["nocap"] = boolean, -- should be processed in the template itself ["notext"] = boolean, ["nocat"] = boolean, ["sort"] = true, } if frame.args.title2_alias then params[2] = {alias_of = "title"} end return process_params(frame:getParent().args, params) end function export.misc_variant_no_term(frame) local args = get_args(frame) return require(etymology_module).format_misc_variant_no_term { lang = args[1], notext = args.notext, title = args.title or frame.args.text, nocat = args.nocat, cat = frame.args.cat, sort_key = args.sort, force_cat = force_cat, } end -- This function works similarly to misc_variant_no_term(), but with some automatic linking to the glossary in -- `title`. function export.onomatopoeia(frame) local args = get_args(frame) local title = args.title if title and (lower(title) == "imitative" or lower(title) == "imitation") then title = "[[Appendix:Glossary#imitative|" .. title .. "]]" end return require(etymology_module).format_misc_variant_no_term { lang = args[1], notext = args.notext, title = title or frame.args.text, nocat = args.nocat, cat = frame.args.cat, sort_key = args.sort, force_cat = force_cat, } end end return export bbpkn5ag0kw0xf4gi06xeh7t1i3mqd5 Teamplaid:RQ:sga:Glosses 10 17886 88768 2026-03-08T20:33:56Z en>Mahagaja 0 88768 wikitext text/x-wiki {{#invoke:checkparams|error}}<!-- Validate template parameters -->{{#switch:{{{1|}}} |Acr={{circa|'''850'''}}, Carlsruhe Glosses on St Augustine’s ''Soliloquia'', published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;2, pp.&nbsp;1–9, [[oldwikisource:Thesaurus Palaeohibernicus/Glosses on S. Augustine's Soliloquia (Carlsruhe)#{{{2}}}{{{3}}}|Acr. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}]] |Ardm={{circa|'''810'''}}, Biblical Glosses in the Book of Armagh, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;494–98, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Bcr={{circa|'''850'''}} Glosses on the Carlsruhe Beda, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;10–30, [[oldwikisource:Thesaurus Palaeohibernicus/Glosses on Beda (Carlsruhe)#{{{2}}}{{{3}}}|Bcr. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}]] |Ml={{circa|'''800–825'''}}, Diarmait, Milan Glosses on the Psalms, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;7–483, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |PCr={{circa|'''825–850'''}} Karlsruhe Glosses on Priscian, published in ''Thesaurus Palaeohibernicus'' (reprinted 1975, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;225–230, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Sg={{circa|'''845'''}}, St Gall Glosses on Priscian, published in ''Thesaurus Palaeohibernicus'' (reprinted 1975, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;49–224, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Tur={{circa|'''850–875'''}}, Turin Glosses and Scholia on St Mark, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;484–94, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Wb={{circa|'''800'''}}, Würzburg Glosses on the Pauline Epistles, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;499–712, {{{1}}}. [https://wuerzburg.ie/index_Eng.html#folf.{{{2}}}{{{3}}}.1 {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}] |<includeonly>'''Error: please include a valid parameter'''[[Category:Requests for attention concerning Old Irish]]</includeonly> }}<noinclude> {{documentation}}</noinclude> 9r5aida8uu4iktbr6etl00yb96963k1 88769 88768 2026-08-06T17:45:44Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:RQ:sga:Glosses]] 88768 wikitext text/x-wiki {{#invoke:checkparams|error}}<!-- Validate template parameters -->{{#switch:{{{1|}}} |Acr={{circa|'''850'''}}, Carlsruhe Glosses on St Augustine’s ''Soliloquia'', published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;2, pp.&nbsp;1–9, [[oldwikisource:Thesaurus Palaeohibernicus/Glosses on S. Augustine's Soliloquia (Carlsruhe)#{{{2}}}{{{3}}}|Acr. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}]] |Ardm={{circa|'''810'''}}, Biblical Glosses in the Book of Armagh, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;494–98, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Bcr={{circa|'''850'''}} Glosses on the Carlsruhe Beda, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;10–30, [[oldwikisource:Thesaurus Palaeohibernicus/Glosses on Beda (Carlsruhe)#{{{2}}}{{{3}}}|Bcr. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}]] |Ml={{circa|'''800–825'''}}, Diarmait, Milan Glosses on the Psalms, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;7–483, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |PCr={{circa|'''825–850'''}} Karlsruhe Glosses on Priscian, published in ''Thesaurus Palaeohibernicus'' (reprinted 1975, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;225–230, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Sg={{circa|'''845'''}}, St Gall Glosses on Priscian, published in ''Thesaurus Palaeohibernicus'' (reprinted 1975, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;II, pp.&nbsp;49–224, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Tur={{circa|'''850–875'''}}, Turin Glosses and Scholia on St Mark, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;484–94, {{{1}}}. {{{2}}}{{sup|{{{3|}}}}}{{{4|}}} |Wb={{circa|'''800'''}}, Würzburg Glosses on the Pauline Epistles, published in ''Thesaurus Palaeohibernicus'' (reprinted 1987, Dublin Institute for Advanced Studies), edited and with translations by Whitley Stokes and John Strachan, vol.&nbsp;I, pp.&nbsp;499–712, {{{1}}}. [https://wuerzburg.ie/index_Eng.html#folf.{{{2}}}{{{3}}}.1 {{{2}}}{{sup|{{{3|}}}}}{{{4|}}}] |<includeonly>'''Error: please include a valid parameter'''[[Category:Requests for attention concerning Old Irish]]</includeonly> }}<noinclude> {{documentation}}</noinclude> 9r5aida8uu4iktbr6etl00yb96963k1 Teamplaid:circa 10 17887 88770 2026-08-04T19:13:00Z en>AutoDooz 0 no existing calls with bad parameters, throw error instead of warning to avoid future misuse 88770 wikitext text/x-wiki {{#invoke:checkparams|error|short}}<!-- Validate template parameters --><abbr title="circa">c.</abbr>{{#if:{{{1|}}} | <span style="white-space: nowrap;">&thinsp;{{trim|{{{1|}}}}}</span> }}{{#if: {{{2|}}} | &nbsp;– c.<span style="white-space: nowrap;">&thinsp;{{{2}}}</span> }}<!-- --><noinclude>{{documentation}}</noinclude> 3d10wbgim45bivvspu1zqlj2slxrv5m 88771 88770 2026-08-06T17:46:54Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:circa]] 88770 wikitext text/x-wiki {{#invoke:checkparams|error|short}}<!-- Validate template parameters --><abbr title="circa">c.</abbr>{{#if:{{{1|}}} | <span style="white-space: nowrap;">&thinsp;{{trim|{{{1|}}}}}</span> }}{{#if: {{{2|}}} | &nbsp;– c.<span style="white-space: nowrap;">&thinsp;{{{2}}}</span> }}<!-- --><noinclude>{{documentation}}</noinclude> 3d10wbgim45bivvspu1zqlj2slxrv5m Teamplaid:quote 10 17888 88772 2026-04-15T09:13:27Z en>Surjection 0 Changed protection settings for "[[Template:quote]]": Highly visible template/module ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88772 wikitext text/x-wiki <includeonly>{{#invoke:usex/templates|usex_t|quote=1}}</includeonly><noinclude>{{documentation}}</noinclude> j4a69ylf2bgejx9blqbs44xcom1x6si 88773 88772 2026-08-06T17:46:59Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:quote]] 88772 wikitext text/x-wiki <includeonly>{{#invoke:usex/templates|usex_t|quote=1}}</includeonly><noinclude>{{documentation}}</noinclude> j4a69ylf2bgejx9blqbs44xcom1x6si Teamplaid:hyph 10 17889 88774 2024-11-09T20:24:20Z en>Surjection 0 Changed protection settings for "[[Template:hyph]]" ([Edit=Allow only template editors and administrators] (indefinite) [Move=Allow only template editors and administrators] (indefinite)) 88774 wikitext text/x-wiki #REDIRECT [[Template:hyphenation]] 74ud0rq50ttrtn2x4qfwvh9jxuk3ezv 88775 88774 2026-08-06T17:59:19Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:hyph]] 88774 wikitext text/x-wiki #REDIRECT [[Template:hyphenation]] 74ud0rq50ttrtn2x4qfwvh9jxuk3ezv Teamplaid:hyphenation 10 17890 88776 2023-01-12T03:36:34Z en>Theknightwho 0 88776 wikitext text/x-wiki {{ {{#if:{{{lang|}}}|check deprecated lang param usage|no deprecated lang param usage}}|lang={{{lang|}}}|<!-- -->{{#invoke:hyphenation|hyphenation}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> 364pj5u4hseu4haqzv1fa5f8npchy0s 88777 88776 2026-08-06T17:59:25Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:hyphenation]] 88776 wikitext text/x-wiki {{ {{#if:{{{lang|}}}|check deprecated lang param usage|no deprecated lang param usage}}|lang={{{lang|}}}|<!-- -->{{#invoke:hyphenation|hyphenation}}<!-- -->}}<!-- --><noinclude>{{documentation}}</noinclude> 364pj5u4hseu4haqzv1fa5f8npchy0s 88778 88777 2026-08-06T17:59:42Z Altronic 4137 88778 wikitext text/x-wiki {{#invoke:hyphenation|hyphenation}}<!-- --><noinclude>{{documentation}}</noinclude> i50htcn4kctu70dozrb1ocm8dks5cza Mòideal:hyphenation 828 17891 88779 2025-11-04T04:08:30Z en>Benwing2 0 tracking for '.qualifiers' field 88779 Scribunto text/plain local export = {} local links_module = "Module:links" local parameters_module = "Module:parameters" local pron_qualifier_module = "Module:pron qualifier" local function track(page) require("Module:debug/track")("hyphenation/" .. page) return true end --[==[ Meant to be called from a module. `data` is a table containing the following fields: * `lang`: language object for the hyphenations or syllabifications; * `hyphs`: a list of hyphenations/syllabifications, each described by an object which can contain the following fields: ** `hyph`: list of syllables comprising the hyphenation or syllabification, each a string; ** `q`: {nil} or a list of left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; ** `qq`: {nil} or a list of right regular qualifier strings; ** `qualifiers`: {nil} or a list of left regular qualifier strings; for compatibility purposes only, do not use in new code; ** `a`: {nil} or a list of left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; ** `aa`: {nil} or a list of right accent qualifier strings; ** `refs`: {nil} or a list of references or reference specs to add after the pronunciation and any posttext and qualifiers; the value of a list item is either a string containing the reference text (typically a call to a citation template such as {{tl|cite-book}}, or a template wrapping such a call), or an object with fields `text` (the reference text), `name` (the name of the reference, as in {{cd|<nowiki><ref name="foo">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" /></nowiki>}}) and/or `group` (the group of the reference, as in {{cd|<nowiki><ref name="foo" group="bar">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" group="bar"/></nowiki>}}); this uses a parser function to format the reference appropriately and insert a footnote number that hyperlinks to the actual reference, located in the {{cd|<nowiki><references /></nowiki>}} section; ** `sc`: {nil} or script object for this particular hyphenation/syllabification; * `sc`: {nil} or script object for the hyphenations/syllabifications; * `q`: {nil} or a list of overall left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; * `qq`: {nil} or a list of overall right regular qualifier strings; * `a`: {nil} or a list of overall left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; * `aa`: {nil} or a list of overall right accent qualifier strings; * `caption`, {nil} or a string specifying the caption to use, in place of {"Hyphenation"}; e.g. use {"Syllabification"} if what is passed in is actually a syllabification, as is common; a colon and space is automatically added after the caption; * `nocaption`: if true, suppress the caption display. ]==] function export.format_hyphenations(data) local hyphtexts = {} for _, hyph in ipairs(data.hyphs) do if #hyph.hyph == 0 then error("Saw empty hyphenation; use || to separate hyphenations") end if hyph.qualifiers then track("old-qualifiers") end local text = require(links_module).full_link { lang = data.lang, sc = hyph.sc or data.sc, alt = table.concat(hyph.hyph, "‧"), tr = "-" } if hyph.q and hyph.q[1] or hyph.qq and hyph.qq[1] or hyph.qualifiers and hyph.qualifiers[1] or hyph.a and hyph.a[1] or hyph.aa and hyph.aa[1] or hyph.refs and hyph.refs[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = hyph.q, qq = hyph.qq, qualifiers = hyph.qualifiers, a = hyph.a, aa = hyph.aa, refs = hyph.refs, } end table.insert(hyphtexts, text) end local text = ((data.nocaption and "") or ((data.caption or "Hyphenation") .. ": ")) .. table.concat(hyphtexts, ", ") if data.q and data.q[1] or data.qq and data.qq[1] or data.a and data.a[1] or data.aa and data.aa[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = data.q, qq = data.qq, a = data.a, aa = data.aa, } end return text end --[==[ Entry point for {{tl|hyphenation}} template (also written {{tl|hyph}}). ]==] function export.hyphenation(frame) local parent_args = frame:getParent().args local compat = parent_args.lang local lang_param = compat and "lang" or 1 local offset = compat and 0 or 1 local params = { [lang_param] = {required = true, type = "language", default = "und"}, [1 + offset] = {list = true, required = true, allow_holes = true, default = "{{{2}}}"}, -- FIXME: For compatibility, q= and qq= refer to the first hyphenation rather than overall. Consider tracking and -- changing this. ["q"] = {list = true, allow_holes = true, type = "qualifier"}, ["qq"] = {list = true, allow_holes = true, type = "qualifier"}, ["a"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["aa"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["ref"] = {list = true, allow_holes = true, type = "references"}, ["caption"] = {}, ["nocaption"] = {type = "boolean"}, ["sc"] = {list = true, allow_holes = true, separate_no_index = true, type = "script"}, } local args = require(parameters_module).process(parent_args, params) local lang = args[lang_param] local sc = args.sc.default local data = { lang = lang, sc = sc, hyphs = {}, caption = args.caption, nocaption = args.nocaption, a = args.a.default, aa = args.aa.default, } local this_hyph = {hyph = {}} local maxindex = args[1 + offset].maxindex local function insert_hyph() local hyphnum = #data.hyphs + 1 this_hyph.q = args.q[hyphnum] this_hyph.qq = args.qq[hyphnum] this_hyph.a = args.a[hyphnum] this_hyph.aa = args.aa[hyphnum] this_hyph.refs = args.ref[hyphnum] table.insert(data.hyphs, this_hyph) end for i=1, maxindex do local syl = args[1 + offset][i] if not syl then insert_hyph() this_hyph = {hyph = {}} else table.insert(this_hyph.hyph, syl) end end insert_hyph() return export.format_hyphenations(data) end return export 5ifdc56czy0071cr4rwjvauyq6wq80t 88780 88779 2026-08-06T17:59:49Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:hyphenation]] 88779 Scribunto text/plain local export = {} local links_module = "Module:links" local parameters_module = "Module:parameters" local pron_qualifier_module = "Module:pron qualifier" local function track(page) require("Module:debug/track")("hyphenation/" .. page) return true end --[==[ Meant to be called from a module. `data` is a table containing the following fields: * `lang`: language object for the hyphenations or syllabifications; * `hyphs`: a list of hyphenations/syllabifications, each described by an object which can contain the following fields: ** `hyph`: list of syllables comprising the hyphenation or syllabification, each a string; ** `q`: {nil} or a list of left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; ** `qq`: {nil} or a list of right regular qualifier strings; ** `qualifiers`: {nil} or a list of left regular qualifier strings; for compatibility purposes only, do not use in new code; ** `a`: {nil} or a list of left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; ** `aa`: {nil} or a list of right accent qualifier strings; ** `refs`: {nil} or a list of references or reference specs to add after the pronunciation and any posttext and qualifiers; the value of a list item is either a string containing the reference text (typically a call to a citation template such as {{tl|cite-book}}, or a template wrapping such a call), or an object with fields `text` (the reference text), `name` (the name of the reference, as in {{cd|<nowiki><ref name="foo">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" /></nowiki>}}) and/or `group` (the group of the reference, as in {{cd|<nowiki><ref name="foo" group="bar">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" group="bar"/></nowiki>}}); this uses a parser function to format the reference appropriately and insert a footnote number that hyperlinks to the actual reference, located in the {{cd|<nowiki><references /></nowiki>}} section; ** `sc`: {nil} or script object for this particular hyphenation/syllabification; * `sc`: {nil} or script object for the hyphenations/syllabifications; * `q`: {nil} or a list of overall left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; * `qq`: {nil} or a list of overall right regular qualifier strings; * `a`: {nil} or a list of overall left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; * `aa`: {nil} or a list of overall right accent qualifier strings; * `caption`, {nil} or a string specifying the caption to use, in place of {"Hyphenation"}; e.g. use {"Syllabification"} if what is passed in is actually a syllabification, as is common; a colon and space is automatically added after the caption; * `nocaption`: if true, suppress the caption display. ]==] function export.format_hyphenations(data) local hyphtexts = {} for _, hyph in ipairs(data.hyphs) do if #hyph.hyph == 0 then error("Saw empty hyphenation; use || to separate hyphenations") end if hyph.qualifiers then track("old-qualifiers") end local text = require(links_module).full_link { lang = data.lang, sc = hyph.sc or data.sc, alt = table.concat(hyph.hyph, "‧"), tr = "-" } if hyph.q and hyph.q[1] or hyph.qq and hyph.qq[1] or hyph.qualifiers and hyph.qualifiers[1] or hyph.a and hyph.a[1] or hyph.aa and hyph.aa[1] or hyph.refs and hyph.refs[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = hyph.q, qq = hyph.qq, qualifiers = hyph.qualifiers, a = hyph.a, aa = hyph.aa, refs = hyph.refs, } end table.insert(hyphtexts, text) end local text = ((data.nocaption and "") or ((data.caption or "Hyphenation") .. ": ")) .. table.concat(hyphtexts, ", ") if data.q and data.q[1] or data.qq and data.qq[1] or data.a and data.a[1] or data.aa and data.aa[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = data.q, qq = data.qq, a = data.a, aa = data.aa, } end return text end --[==[ Entry point for {{tl|hyphenation}} template (also written {{tl|hyph}}). ]==] function export.hyphenation(frame) local parent_args = frame:getParent().args local compat = parent_args.lang local lang_param = compat and "lang" or 1 local offset = compat and 0 or 1 local params = { [lang_param] = {required = true, type = "language", default = "und"}, [1 + offset] = {list = true, required = true, allow_holes = true, default = "{{{2}}}"}, -- FIXME: For compatibility, q= and qq= refer to the first hyphenation rather than overall. Consider tracking and -- changing this. ["q"] = {list = true, allow_holes = true, type = "qualifier"}, ["qq"] = {list = true, allow_holes = true, type = "qualifier"}, ["a"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["aa"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["ref"] = {list = true, allow_holes = true, type = "references"}, ["caption"] = {}, ["nocaption"] = {type = "boolean"}, ["sc"] = {list = true, allow_holes = true, separate_no_index = true, type = "script"}, } local args = require(parameters_module).process(parent_args, params) local lang = args[lang_param] local sc = args.sc.default local data = { lang = lang, sc = sc, hyphs = {}, caption = args.caption, nocaption = args.nocaption, a = args.a.default, aa = args.aa.default, } local this_hyph = {hyph = {}} local maxindex = args[1 + offset].maxindex local function insert_hyph() local hyphnum = #data.hyphs + 1 this_hyph.q = args.q[hyphnum] this_hyph.qq = args.qq[hyphnum] this_hyph.a = args.a[hyphnum] this_hyph.aa = args.aa[hyphnum] this_hyph.refs = args.ref[hyphnum] table.insert(data.hyphs, this_hyph) end for i=1, maxindex do local syl = args[1 + offset][i] if not syl then insert_hyph() this_hyph = {hyph = {}} else table.insert(this_hyph.hyph, syl) end end insert_hyph() return export.format_hyphenations(data) end return export 5ifdc56czy0071cr4rwjvauyq6wq80t 88781 88780 2026-08-06T18:01:30Z Altronic 4137 change text 88781 Scribunto text/plain local export = {} local links_module = "Module:links" local parameters_module = "Module:parameters" local pron_qualifier_module = "Module:pron qualifier" local function track(page) require("Module:debug/track")("hyphenation/" .. page) return true end --[==[ Meant to be called from a module. `data` is a table containing the following fields: * `lang`: language object for the hyphenations or syllabifications; * `hyphs`: a list of hyphenations/syllabifications, each described by an object which can contain the following fields: ** `hyph`: list of syllables comprising the hyphenation or syllabification, each a string; ** `q`: {nil} or a list of left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; ** `qq`: {nil} or a list of right regular qualifier strings; ** `qualifiers`: {nil} or a list of left regular qualifier strings; for compatibility purposes only, do not use in new code; ** `a`: {nil} or a list of left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; ** `aa`: {nil} or a list of right accent qualifier strings; ** `refs`: {nil} or a list of references or reference specs to add after the pronunciation and any posttext and qualifiers; the value of a list item is either a string containing the reference text (typically a call to a citation template such as {{tl|cite-book}}, or a template wrapping such a call), or an object with fields `text` (the reference text), `name` (the name of the reference, as in {{cd|<nowiki><ref name="foo">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" /></nowiki>}}) and/or `group` (the group of the reference, as in {{cd|<nowiki><ref name="foo" group="bar">...</ref></nowiki>}} or {{cd|<nowiki><ref name="foo" group="bar"/></nowiki>}}); this uses a parser function to format the reference appropriately and insert a footnote number that hyperlinks to the actual reference, located in the {{cd|<nowiki><references /></nowiki>}} section; ** `sc`: {nil} or script object for this particular hyphenation/syllabification; * `sc`: {nil} or script object for the hyphenations/syllabifications; * `q`: {nil} or a list of overall left regular qualifier strings, formatted using {format_qualifier()} in [[Module:qualifier]]; * `qq`: {nil} or a list of overall right regular qualifier strings; * `a`: {nil} or a list of overall left accent qualifier strings, formatted using {format_qualifiers()} in [[Module:accent qualifier]]; * `aa`: {nil} or a list of overall right accent qualifier strings; * `caption`, {nil} or a string specifying the caption to use, in place of {"Hyphenation"}; e.g. use {"Syllabification"} if what is passed in is actually a syllabification, as is common; a colon and space is automatically added after the caption; * `nocaption`: if true, suppress the caption display. ]==] function export.format_hyphenations(data) local hyphtexts = {} for _, hyph in ipairs(data.hyphs) do if #hyph.hyph == 0 then error("Saw empty hyphenation; use || to separate hyphenations") end if hyph.qualifiers then track("old-qualifiers") end local text = require(links_module).full_link { lang = data.lang, sc = hyph.sc or data.sc, alt = table.concat(hyph.hyph, "‧"), tr = "-" } if hyph.q and hyph.q[1] or hyph.qq and hyph.qq[1] or hyph.qualifiers and hyph.qualifiers[1] or hyph.a and hyph.a[1] or hyph.aa and hyph.aa[1] or hyph.refs and hyph.refs[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = hyph.q, qq = hyph.qq, qualifiers = hyph.qualifiers, a = hyph.a, aa = hyph.aa, refs = hyph.refs, } end table.insert(hyphtexts, text) end local text = ((data.nocaption and "") or ((data.caption or "Tàthanachadh") .. ": ")) .. table.concat(hyphtexts, ", ") if data.q and data.q[1] or data.qq and data.qq[1] or data.a and data.a[1] or data.aa and data.aa[1] then text = require(pron_qualifier_module).format_qualifiers { lang = data.lang, text = text, q = data.q, qq = data.qq, a = data.a, aa = data.aa, } end return text end --[==[ Entry point for {{tl|hyphenation}} template (also written {{tl|hyph}}). ]==] function export.hyphenation(frame) local parent_args = frame:getParent().args local compat = parent_args.lang local lang_param = compat and "lang" or 1 local offset = compat and 0 or 1 local params = { [lang_param] = {required = true, type = "language", default = "und"}, [1 + offset] = {list = true, required = true, allow_holes = true, default = "{{{2}}}"}, -- FIXME: For compatibility, q= and qq= refer to the first hyphenation rather than overall. Consider tracking and -- changing this. ["q"] = {list = true, allow_holes = true, type = "qualifier"}, ["qq"] = {list = true, allow_holes = true, type = "qualifier"}, ["a"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["aa"] = {list = true, allow_holes = true, separate_no_index = true, type = "labels"}, ["ref"] = {list = true, allow_holes = true, type = "references"}, ["caption"] = {}, ["nocaption"] = {type = "boolean"}, ["sc"] = {list = true, allow_holes = true, separate_no_index = true, type = "script"}, } local args = require(parameters_module).process(parent_args, params) local lang = args[lang_param] local sc = args.sc.default local data = { lang = lang, sc = sc, hyphs = {}, caption = args.caption, nocaption = args.nocaption, a = args.a.default, aa = args.aa.default, } local this_hyph = {hyph = {}} local maxindex = args[1 + offset].maxindex local function insert_hyph() local hyphnum = #data.hyphs + 1 this_hyph.q = args.q[hyphnum] this_hyph.qq = args.qq[hyphnum] this_hyph.a = args.a[hyphnum] this_hyph.aa = args.aa[hyphnum] this_hyph.refs = args.ref[hyphnum] table.insert(data.hyphs, this_hyph) end for i=1, maxindex do local syl = args[1 + offset][i] if not syl then insert_hyph() this_hyph = {hyph = {}} else table.insert(this_hyph.hyph, syl) end end insert_hyph() return export.format_hyphenations(data) end return export t2bfdyvl8kp8jlw170va4rup8ulzziu Teamplaid:category tree data submodule documentation 10 17892 88782 2025-06-04T21:16:26Z en>Benwing2 0 Benwing2 moved page [[Template:poscatboiler data submodule documentation]] to [[Template:category tree data submodule documentation]] without leaving a redirect: 'poscatboiler' as term is going away, leaving just 'category tree' 88782 wikitext text/x-wiki This data submodule defines part of Wiktionary's category structure. For an introduction to the category tree system and a description of how to add or modify categories, see [[Module:category tree/documentation]].<noinclude>{{documentation}}</noinclude> mcxfpt90i6xr7t9uglu422x131ffdpn 88783 88782 2026-08-06T18:16:29Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:category_tree_data_submodule_documentation]] 88782 wikitext text/x-wiki This data submodule defines part of Wiktionary's category structure. For an introduction to the category tree system and a description of how to add or modify categories, see [[Module:category tree/documentation]].<noinclude>{{documentation}}</noinclude> mcxfpt90i6xr7t9uglu422x131ffdpn Mòideal:category tree/topic/Music 828 17893 88784 2026-07-23T19:36:34Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88784 Scribunto text/plain local labels = {} ------------------------------------ music base labels ------------------------------------ labels["music"] = { type = "related-to", parents = {"art", "sound"}, } labels["singing"] = { type = "related-to", parents = {"music", "talking"}, } ------------------------------------ music theory ------------------------------------ labels["musical voices and registers"] = { type = "type", parents = {"music", "singing"}, } labels["musical meters"] = { type = "type", parents = {"music"}, } labels["musical notes"] = { type = "type", parents = {"music"}, } ------------------------------------ musicians ------------------------------------ labels["musicians"] = { type = "type", parents = {"occupations", "music"}, } labels["Justin Bieber"] = { type = "related-to", description = "=Canadian singer {{w|Justin Bieber}}", parents = {"individuals", "musicians"}, } labels["Taylor Swift"] = { type = "related-to", description = "=American singer-songwriter {{w|Taylor Swift}}", parents = {"individuals", "musicians"}, } ------------------------------------ musical genres ------------------------------------ labels["musical genres"] = { type = "type", parents = {"music", "genres"}, } labels["blues music"] = { type = "related-to", wikidata = 9759, parents = {"musical genres"}, } labels["jazz"] = { type = "related-to", parents = {"musical genres"}, } labels["opera"] = { type = "related-to", parents = {"theater", "musical genres"}, } ------------------------------------ musical instruments ------------------------------------ labels["musical instruments"] = { type = "set", parents = {"music"}, } labels["brass instruments"] = { type = "type", parents = {"wind instruments"}, } labels["gongs"] = { type = "related-to", parents = {"percussion instruments"}, } labels["organ instruments"] = { type = "type", parents = {"wind instruments"}, } labels["percussion instruments"] = { type = "set", parents = {"musical instruments"}, } labels["singing voice synthesis"] = { type = "related-to", parents = {"musical instruments", "singing"}, } labels["string instruments"] = { type = "set", description = "{{{langname}}} names of [[string instrument]]s.", parents = {"musical instruments"}, } labels["wind instruments"] = { type = "type", parents = {"musical instruments"}, } labels["woodwind instruments"] = { type = "type", parents = {"wind instruments"}, } ------------------------------------ music misc ------------------------------------ labels["lutherie"] = { type = "related-to", parents = {"music", "crafts"}, } labels["music industry"] = { type = "related-to", description = "default with the", parents = {"industries", "music"}, } labels["national anthems"] = { type = "name", parents = {"artistic works", "music"}, } return labels 8yabl5xj151u3vejavycr34z2n77gdx 88785 88784 2026-08-06T18:20:12Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Music]] 88784 Scribunto text/plain local labels = {} ------------------------------------ music base labels ------------------------------------ labels["music"] = { type = "related-to", parents = {"art", "sound"}, } labels["singing"] = { type = "related-to", parents = {"music", "talking"}, } ------------------------------------ music theory ------------------------------------ labels["musical voices and registers"] = { type = "type", parents = {"music", "singing"}, } labels["musical meters"] = { type = "type", parents = {"music"}, } labels["musical notes"] = { type = "type", parents = {"music"}, } ------------------------------------ musicians ------------------------------------ labels["musicians"] = { type = "type", parents = {"occupations", "music"}, } labels["Justin Bieber"] = { type = "related-to", description = "=Canadian singer {{w|Justin Bieber}}", parents = {"individuals", "musicians"}, } labels["Taylor Swift"] = { type = "related-to", description = "=American singer-songwriter {{w|Taylor Swift}}", parents = {"individuals", "musicians"}, } ------------------------------------ musical genres ------------------------------------ labels["musical genres"] = { type = "type", parents = {"music", "genres"}, } labels["blues music"] = { type = "related-to", wikidata = 9759, parents = {"musical genres"}, } labels["jazz"] = { type = "related-to", parents = {"musical genres"}, } labels["opera"] = { type = "related-to", parents = {"theater", "musical genres"}, } ------------------------------------ musical instruments ------------------------------------ labels["musical instruments"] = { type = "set", parents = {"music"}, } labels["brass instruments"] = { type = "type", parents = {"wind instruments"}, } labels["gongs"] = { type = "related-to", parents = {"percussion instruments"}, } labels["organ instruments"] = { type = "type", parents = {"wind instruments"}, } labels["percussion instruments"] = { type = "set", parents = {"musical instruments"}, } labels["singing voice synthesis"] = { type = "related-to", parents = {"musical instruments", "singing"}, } labels["string instruments"] = { type = "set", description = "{{{langname}}} names of [[string instrument]]s.", parents = {"musical instruments"}, } labels["wind instruments"] = { type = "type", parents = {"musical instruments"}, } labels["woodwind instruments"] = { type = "type", parents = {"wind instruments"}, } ------------------------------------ music misc ------------------------------------ labels["lutherie"] = { type = "related-to", parents = {"music", "crafts"}, } labels["music industry"] = { type = "related-to", description = "default with the", parents = {"industries", "music"}, } labels["national anthems"] = { type = "name", parents = {"artistic works", "music"}, } return labels 8yabl5xj151u3vejavycr34z2n77gdx Mòideal:category tree/topic/Names 828 17894 88786 2026-07-23T19:36:35Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88786 Scribunto text/plain local labels = {} local handlers = {} labels["names"] = { type = "related-to", description = "{{{langname}}} names for a variety of things.", additional = "Given names and surnames can be found in [[:Category:Names by language]].", parents = {"all topics"}, } labels["letter names"] = { type = "name", description = "{{{langname}}} terms that are the names of letters.", additional = "Ideally entries should be in a subcategory for the names of letters in a particular script.", parents = {"names", "letters, symbols, and punctuation"}, } -- Handler for "SCRIPT letter names". table.insert(handlers, function(label) local script = label:match("^(.*) letter names$") if script then local sc = require("Module:scripts").getByCanonicalName(script) if sc then local script_page local appendix = ("Appendix: %s script"):format(script) local appendix_title = mw.title.new(appendix) if appendix_title and appendix_title.exists then script_page = appendix else script_page = "w:" .. sc:getWikipediaArticle() end local link = ("[[%s|%s script]]"):format(script_page, script) return { type = "name", description = ("{{{langname}}} terms that serve as names for letters and symbols directly based on letters, " .. "such as [[ligature]]s and letters with [[diacritic]]s, of the %s."):format(link), parents = {"letter names"}, } end end end) labels["couple nicknames"] = { type = "name", description = "{{{langname}}} informal names for pairs of people, especially [[celebrity]] [[couple]]s.", additional = "For fictional relationships, see [[:Category:Ships (fandom)]].", parents = {"nicknames", "people"}, } labels["named prayers"] = { type = "name", description = "=[[specific]] [[prayer]]s", parents = {"names", "prayer"}, } labels["nicknames"] = { type = "name", description = "{{{langname}}} terms that are informal names or diminutives of specific entities (people, places, etc.)", parents = {"names"}, } labels["nicknames for individuals"] = { type = "name", description = "{{{langname}}} terms that are informal names for specific individuals (e.g. [[J-Lo]] for singer {{w|Jennifer Lopez}}).", parents = {"individuals", "nicknames"}, } labels["sports nicknames"] = { type = "name", description = "{{{langname}}} informal names for people or teams involved in sports.", parents = {"nicknames", "sports"}, } labels["taxonomic names"] = { type = "name", parents = {"names", "taxonomy"}, } return {LABELS = labels, HANDLERS = handlers} 5knyjw34nmc268rm5tk8ub80kdq7mo9 88787 88786 2026-08-06T18:21:09Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Names]] 88786 Scribunto text/plain local labels = {} local handlers = {} labels["names"] = { type = "related-to", description = "{{{langname}}} names for a variety of things.", additional = "Given names and surnames can be found in [[:Category:Names by language]].", parents = {"all topics"}, } labels["letter names"] = { type = "name", description = "{{{langname}}} terms that are the names of letters.", additional = "Ideally entries should be in a subcategory for the names of letters in a particular script.", parents = {"names", "letters, symbols, and punctuation"}, } -- Handler for "SCRIPT letter names". table.insert(handlers, function(label) local script = label:match("^(.*) letter names$") if script then local sc = require("Module:scripts").getByCanonicalName(script) if sc then local script_page local appendix = ("Appendix: %s script"):format(script) local appendix_title = mw.title.new(appendix) if appendix_title and appendix_title.exists then script_page = appendix else script_page = "w:" .. sc:getWikipediaArticle() end local link = ("[[%s|%s script]]"):format(script_page, script) return { type = "name", description = ("{{{langname}}} terms that serve as names for letters and symbols directly based on letters, " .. "such as [[ligature]]s and letters with [[diacritic]]s, of the %s."):format(link), parents = {"letter names"}, } end end end) labels["couple nicknames"] = { type = "name", description = "{{{langname}}} informal names for pairs of people, especially [[celebrity]] [[couple]]s.", additional = "For fictional relationships, see [[:Category:Ships (fandom)]].", parents = {"nicknames", "people"}, } labels["named prayers"] = { type = "name", description = "=[[specific]] [[prayer]]s", parents = {"names", "prayer"}, } labels["nicknames"] = { type = "name", description = "{{{langname}}} terms that are informal names or diminutives of specific entities (people, places, etc.)", parents = {"names"}, } labels["nicknames for individuals"] = { type = "name", description = "{{{langname}}} terms that are informal names for specific individuals (e.g. [[J-Lo]] for singer {{w|Jennifer Lopez}}).", parents = {"individuals", "nicknames"}, } labels["sports nicknames"] = { type = "name", description = "{{{langname}}} informal names for people or teams involved in sports.", parents = {"nicknames", "sports"}, } labels["taxonomic names"] = { type = "name", parents = {"names", "taxonomy"}, } return {LABELS = labels, HANDLERS = handlers} 5knyjw34nmc268rm5tk8ub80kdq7mo9 Mòideal:category tree/topic/Places 828 17895 88788 2026-07-23T19:36:43Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88788 Scribunto text/plain local labels = {} local handlers = {} local m_table = require("Module:table") local en_utilities_module = "Module:en-utilities" local string_utilities_module = "Module:string utilities" local m_locations = require("Module:place/locations") local m_placetypes = require("Module:place/placetypes") local placetype_data = m_placetypes.placetype_data local internal_error = m_locations.internal_error local dump = mw.dumpObject local insert = table.insert local concat = table.concat local is_callable = require("Module:fun").is_callable --[==[ intro: This module is part of the category tree code and contains code to generate the descriptions of place-related categories such as [[Category:de:Hokkaido Prefecture, Japan]], [[Category:es:Cities in France]], [[Category:pt:Municipalities of Tocantins, Brazil]], etc.). Note that this module doesn't actually create the categories; that must be done separately, with the text "{{tl|auto cat}}" as the definition of the category. (This process should automatically happen periodically for non-empty categories, because they will appear in [[Special:WantedCategories]] and a bot will periodically examine that list and create any needed category.) There are two ways that category descriptions are specified: (1) by manually adding an entry to the `labels` table, keyed by the label (the category minus the language code) with a value consisting of a Lua table specifying the description text and the category's parents; (2) through handlers (pieces of Lua code) added to the `handlers` list, which recognize labels of a specific type (e.g. `Cities in France`) and generate the appropriate specification for that label on-the-fly. See [[Module:place]] for an introduction to the terminology associated with places along with a list of all the relevant modules, along with for more specific information on types of toponyms and placetypes and how their categorization works. ]==] local function lcfirst(label) return mw.getContentLanguage():lcfirst(label) end local function gsub_literally(str, from, to) local m_strutils = require(string_utilities_module) return (str:gsub(m_strutils.pattern_escape(from), m_strutils.replacement_escape(to))) end local class_to_bare_category_parent = { ["polity"] = "polities", ["subpolity"] = "political divisions", ["settlement"] = "settlements", ["non-admin settlement"] = "settlements", ["capital"] = "capital cities", ["natural feature"] = "natural features", ["man-made structure"] = "man-made structures", ["geographic region"] = "geographic and cultural areas", } local class_is_political_division = { ["polity"] = true, -- strictly false but there are placetypes ambiguous between polity and subpolity ["subpolity"] = true, ["settlement"] = true, ["non-admin settlement"] = false, ["capital"] = true, ["natural feature"] = false, ["man-made structure"] = false, ["geographic region"] = false, ["generic place"] = false, } local capital_cat_to_placetype = {} for placetype, capital_cat in pairs(m_placetypes.placetype_to_capital_cat) do capital_cat_to_placetype[capital_cat] = placetype end -- Handler for bare categories for all types of capitals. This needs to precede the handler for bare placetype -- categories as some of the types of capitals exist as placetypes as well. insert(handlers, function(label) label = lcfirst(label) local capital_placetype = capital_cat_to_placetype[label] if capital_placetype then local pl_placetype = m_placetypes.pluralize_placetype(capital_placetype) local linkdesc = m_placetypes.get_placetype_display_form(pl_placetype, "top-level") if linkdesc == nil then internal_error("Unrecognized placetype %s when processing label %s", capital_placetype, label) end if linkdesc == false then mw.log(("Display form for pl_placetype %s is false, can't categorize"):format(dump(pl_placetype))) return nil end return { type = "name", topic = label, description = "{{{langname}}} names of [[capital]]s of " .. linkdesc .. ".", parents = {"capital cities"}, } end end) -- Handler for bare placetype categories. FIXME: Add wpcat= and commonscat= info. Previously we had it for various -- so-called "generic" placetypes, but sometimes the categories were wrong. insert(handlers, function(label) for _, canon_label in ipairs { lcfirst(label), label } do local ptdesc, ptdata = m_placetypes.get_placetype_display_form(canon_label, "top-level", "return full") if ptdesc then local from_category_props = { from_category = true, no_split_qualifiers = true, } local bare_category_parent = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) local bare_category_parent = m_placetypes.get_placetype_prop(pt, "bare_category_parent") if bare_category_parent then return bare_category_parent end local class = m_placetypes.get_placetype_prop(pt, "class") if class then if class_to_bare_category_parent[class] == nil then internal_error("Saw unknown category class %s derived from placetype %s", class, canon_label) end return class_to_bare_category_parent[class] end end, from_category_props) if not bare_category_parent then internal_error("Saw placetype %s without a `class` or `bare_category_parent` setting, either " .. "directly or through a fallback", canon_label) end local addl_bare_category_parents = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) return m_placetypes.get_placetype_prop(pt, "addl_bare_category_parents") end, from_category_props) local bare_category_breadcrumb = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) return m_placetypes.get_placetype_prop(pt, "bare_category_breadcrumb") end, from_category_props) if type(bare_category_parent) == "string" and bare_category_breadcrumb then bare_category_parent = {name = bare_category_parent, sort = bare_category_breadcrumb} end local parents = {bare_category_parent} if addl_bare_category_parents then m_table.extend(parents, addl_bare_category_parents) end return { type = "name", topic = canon_label, description = "{{{langname}}} " .. ptdesc .. ".", breadcrumb = bare_category_breadcrumb, parents = parents, } elseif ptdesc == false then mw.log(("Display form for canon_label %s is false, can't categorize"):format(dump(canon_label))) end end end) local function fetch_primary_placetype(key, spec) local placetype = spec.placetype if type(placetype) == "table" then placetype = placetype[1] end if not placetype then internal_error("No placetype specified or defaulted for key %s, spec %s", key, spec) end return placetype end --[==[ Construct an appropriately linked location based on the full or elliptical placename, preceded by `"the "`` if appropriate. Specifically: Fetch the full and elliptical_placenames. If they are the same, just link to the placename directly. Otherwise, check if the full placename exists; if so link to it. Otherwise, if the elliptical placename exists, link to it but display it as the full placename. Finally, if neither full placename nor elliptical placename exists, fall back to linking to the full placename. That way, we prefer full placenames to elliptical placenames if both or neither exist as Wiktionary entries, but if only one exists, we link to that one rather than have a red link. ]==] local function construct_linked_location(group, key, spec) local full_placename, elliptical_placename = m_locations.key_to_placename(group, key) local linked_placename if elliptical_placename ~= full_placename then local full_placename_title = mw.title.new(full_placename) if full_placename_title and full_placename_title.exists then linked_placename = m_locations.construct_linked_placename(spec, full_placename) else local elliptical_placename_title = mw.title.new(elliptical_placename) if elliptical_placename_title and elliptical_placename_title.exists then linked_placename = m_locations.construct_linked_placename(spec, elliptical_placename, full_placename) end end end return linked_placename or m_locations.construct_linked_placename(spec, full_placename) end --[==[ Construct the description of a location, including its container trail either to the end or until we encounter a `no_include_container_in_desc` setting. For example, for the city of [[Birmingham]], the description will read `"[[Birmingham]], a [[city]] in the [[West Midlands]] (which is a [[county]] of [[England]], which is a [[constituent country]] of the [[United Kingdom]], which is a [[country]] in [[Europe]])"`. FIXME: Possibly we should adopt the way city descriptions used to read, which was similar to `"the city of [[Birmingham]], in the county of the [[West Midlands]], in the [[constituent country]] of [[England]], in the [[country]] of the [[United Kingdom]], in [[Europe]]"`. ]==] local function construct_location_desc(group, key, spec) local parts = {} local function ins(txt) insert(parts, txt) end ins(construct_linked_location(group, key, spec)) local iteration = 0 local need_closing_paren = false local containers = {{group = group, key = key, spec = spec}} local container_iterator = m_locations.iterate_containers(group, key, spec) while true do iteration = iteration + 1 local include_container_in_desc = false for _, container in ipairs(containers) do if not container.spec.no_include_container_in_desc then include_container_in_desc = true break end end if not include_container_in_desc then break end local next_containers = container_iterator() if not next_containers then break end local is_former = nil for _, container in ipairs(containers) do local this_is_former = container.spec.is_former_place if is_former == nil then is_former = this_is_former elseif is_former ~= this_is_former then internal_error("When processing container trail of key %s, found a mixture of former and non-former " .. "containers: %s", key, containers) end end if #containers > 1 then local placetypes = {} local prepositions = {} for _, container in ipairs(containers) do local container_type = fetch_primary_placetype(container.key, container.spec) m_table.insertIfNot(placetypes, m_placetypes.pluralize_placetype(container_type)) m_table.insertIfNot(prepositions, m_placetypes.get_placetype_entry_preposition(container_type)) end if iteration == 1 then ins(", ") elseif iteration == 2 then ins(" (which are ") need_closing_paren = true else ins(", which are ") end if is_former then ins("former ") end ins(m_table.serialCommaJoin(placetypes)) ins(" ") ins(concat(prepositions, "/")) else if iteration == 1 then ins(", ") elseif iteration == 2 then ins(" (which is ") need_closing_paren = true else ins(", which is ") end local container_type = fetch_primary_placetype(containers[1].key, containers[1].spec) if is_former then ins("a former ") else ins(m_placetypes.get_placetype_article(container_type)) ins(" ") end ins(container_type) ins(" ") ins(m_placetypes.get_placetype_entry_preposition(container_type)) end ins(" ") first_container = false containers = next_containers local container_locations = {} for _, container in ipairs(containers) do insert(container_locations, construct_linked_location(container.group, container.key, container.spec)) end ins(m_table.serialCommaJoin(container_locations)) end if need_closing_paren then ins(")") end return concat(parts) end -- Fetch or construct the description of the location specified by `key`. If the `keydesc` property is specified, -- use it directly but substitute any occurrence of `+++` with the auto-constructed location description, which -- mentions the placename corresponding to the key, its placetype and container, and repeats the description up -- the container trail until either there are no more containers or (more usually) the `no_include_container_in_desc` -- setting is found (which is set on all continents and continent-level regions). local function fetch_or_construct_location_desc(group, key, spec) local val = spec.keydesc if is_callable(val) then val = val(group, key, spec) spec.keydesc = val end val = val or "+++" if val:find("%+%+%+") then val = gsub_literally(val, "+++", construct_location_desc(group, key, spec)) end return val end local function normalize_cat_as(cat_as, div) if type(cat_as) ~= "table" or cat_as.type then cat_as = {cat_as} end local ret_cat_as = {} for _, pt_cat_as in ipairs(cat_as) do if type(pt_cat_as) == "string" then pt_cat_as = {type = pt_cat_as} end insert(ret_cat_as, {type = pt_cat_as.type, prep = pt_cat_as.prep or div.prep or "of"}) end return ret_cat_as end -- Find the specified plural placetype among the divs for a given known location. Return a list of cat_as specs, where -- each spec is of the form {type = "PLURAL_PLACETYPE", prep = "PREP"} indicating the plural placetype to use when -- categorizing and the preposition to follow. local function find_placetype_cat_as(divs, pl_placetype) if divs then if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) == "string" then div = {type = div} end if div.type == pl_placetype then local cat_as = div.cat_as or div.type return normalize_cat_as(cat_as, div) end end end return nil end -- Handler for bare placename categories for known locations in `locations` in [[Module:place/locations]]. insert(handlers, function(label) for _, canon_label in ipairs { label, lcfirst(label) } do local group, spec = m_locations.find_canonical_key(canon_label) if group then -- wp= defaults to true (Wikipedia article matches location's full placename) local wp = spec.wp if wp == nil then wp = true end -- wpcat= defaults to wp= (if Wikipedia article has its own name, Wikipedia category and Commons category -- generally follow) local wpcat = spec.wpcat if wpcat == nil then wpcat = wp end -- commonscat= defaults to wpcat= (if Wikipedia category has its own name, Commons category generally -- follows) local commonscat = spec.commonscat if commonscat == nil then commonscat = wpcat end local parents = {} local bare_label_parents = spec.overriding_bare_label_parents local container_iterator = m_locations.iterate_containers(group, canon_label, spec) local containers = container_iterator() if not bare_label_parents then bare_label_parents = {"+++"} end local full_location_placename, elliptical_location_placename = m_locations.key_to_placename(group, canon_label) local full_container_placename if containers then full_container_placename, _ = m_locations.key_to_placename(containers[1].group, containers[1].key) end local inserted_containers = false for _, parent in ipairs(bare_label_parents) do if parent == "+++" then parent = "PL_PLACETYPE PREP CONTAINER" end if parent:find("CONTAINER") then if not containers then internal_error("Parent category %s needs the container of %s but no containers specified: %s", parent, canon_label, spec) end local location_type = fetch_primary_placetype(canon_label, spec) local pl_location_type = m_placetypes.pluralize_placetype(location_type) for _, container in ipairs(containers) do local per_container_parent = parent local cat_as_list if per_container_parent:find("PL_PLACETYPE") then if spec.bare_category_parent_type then cat_as_list = normalize_cat_as(spec.bare_category_parent_type, spec) else cat_as_list = find_placetype_cat_as(container.spec.divs, pl_location_type) or find_placetype_cat_as(container.spec.addl_divs, pl_location_type) end end if not cat_as_list then local canon_placetype, ptdata, ptmatch = m_placetypes.get_placetype_data(location_type, "from category") if not canon_placetype or not (ptdata.generic_before_non_cities or ptdata.generic_before_cities) then internal_error("Unable to locate plural location type %s among the divs or addl_divs " .. "for container key %s spec %s, and the location type is either not in placetype_data or " .. "not identified as a generic placetype", pl_location_type, container.key, container.spec) end cat_as_list = {{type = pl_location_type, prep = m_placetypes.get_placetype_entry_preposition(location_type)}} end local prefixed_key = m_placetypes.get_prefixed_key(container.key, container.spec) per_container_parent = gsub_literally(per_container_parent, "CONTAINER", prefixed_key) for _, cat_as in ipairs(cat_as_list) do local per_container_per_placetype_parent = per_container_parent per_container_per_placetype_parent = gsub_literally(per_container_per_placetype_parent, "PL_PLACETYPE", cat_as.type) per_container_per_placetype_parent = gsub_literally(per_container_per_placetype_parent, "PREP", cat_as.prep) m_table.insertIfNot(parents, per_container_per_placetype_parent) end end inserted_containers = true else m_table.insertIfNot(parents, parent) end end if not inserted_containers and containers then -- If we didn't insert the containers above in some form, insert them now as bare categories. Note that -- this may be different categories from the container categories inserted above. for _, container in ipairs(containers) do m_table.insertIfNot(parents, container.key) end end if spec.addl_parents then for _, parent in ipairs(spec.addl_parents) do m_table.insertIfNot(parents, parent) end end local function format_boxval(val, specname) if val == true then val = "%l" end if type(val) == "string" then val = gsub_literally(val, "%l", full_location_placename) val = gsub_literally(val, "%e", elliptical_location_placename) if val:find("%%c") then if not full_container_placename then internal_error("Wikipedia/Commons spec %s = %s has %%c in it but key %s has no " .. "containers: %s", specname, val, canon_label, spec) end val = gsub_literally(val, "%c", full_container_placename) end end return val end local description = spec.fulldesc or ( "{{{langname}}} terms related to the people, culture, or territory of " .. fetch_or_construct_location_desc(group, canon_label, spec) .. ".") local full_placename, _ = m_locations.key_to_placename(group, canon_label) return { type = "topic", description = description, breadcrumb = full_placename, parents = parents, wp = format_boxval(wp, "wp"), wpcat = format_boxval(wpcat, "wpcat"), commonscat = format_boxval(commonscat, "commonscat"), } end end end) local function find_canonical_key_from_place(place, canon_label) local has_the = false local key if place:find("^the ") then key = place:gsub("^the ", "") has_the = true else key = place end local group, spec = m_locations.find_canonical_key(key) if group then local requires_the = spec.the or false if has_the ~= requires_the then if has_the then mw.log(("Mismatch in category name '%s', has 'the' in the category when it should not"):format( canon_label)) else mw.log(("Mismatch in category name '%s', should have 'the' in the category but does not"): format(canon_label)) end return nil end return group, key, spec end return nil end -- Handler for generic placetypes (those whose categories are added through category generation handlers or through -- explicit category specs in the placetype data) for known locations in [[Module:place/locations]]. All such -- placetypes have either a `generic_before_non_cities` setting (meaning they can occur before non-city locations) or -- `generic_before_cities` setting (meaning they can occur before cities), or both. Examples of such categories are -- "cities in the Bahamas" or "rivers in Western Australia, Australia", or (for city locations) -- "neighbourhoods of Hong Kong" or "places in Melbourne". insert(handlers, function(label) for _, canon_label in ipairs { lcfirst(label), label } do local placetype, in_of, place = canon_label:match("^([A-Za-z%- ]-) (in) (.*)$") if not placetype then placetype, in_of, place = canon_label:match("^([A-Za-z%- ]-) (of) (.*)$") end if placetype then local normalized_placetype = placetype == "neighbourhoods" and "neighborhoods" or placetype local canon_placetype, ptdata, ptmatch = m_placetypes.get_placetype_data(normalized_placetype, "from category") if canon_placetype and (ptdata.generic_before_non_cities or ptdata.generic_before_cities) then local group, key, spec = find_canonical_key_from_place(place, canon_label) if group then -- Check whether the location uses British spelling, but also check all containers, because -- it's too hard to keep in sync the `british_spelling` setting for locations at all different -- levels (e.g. cities of various countries, first and second level administrative division, etc.), -- so we just set it at top level on the country. local uses_british_spelling = spec.british_spelling if uses_british_spelling == nil then for containers in m_locations.iterate_containers(group, key, spec) do local must_outer_break = false for _, container in ipairs(containers) do if container.spec.british_spelling ~= nil then uses_british_spelling = container.spec.british_spelling must_outer_break = true break end end if must_outer_break then break end end end local allow_cat = true if placetype == "neighborhoods" and uses_british_spelling or placetype == "neighbourhoods" and not uses_british_spelling then mw.log(("Mismatch in spelling of placetype '%s' in category '%s', should be '%s'"):format( placetype, canon_label, uses_british_spelling and "neighbourhoods" or "neighborhoods")) allow_cat = false end if spec.is_former_place and placetype ~= "places" then allow_cat = false end local expected_prep if spec.is_city then expected_prep = ptdata.generic_before_cities else expected_prep = ptdata.generic_before_non_cities end if not expected_prep then allow_cat = false end if allow_cat then if expected_prep ~= in_of then mw.log(("Mismatch in category name '%s', has '%s' when it should have '%s'"):format( canon_label, in_of, expected_prep)) return nil end local linkdesc = m_placetypes.get_placetype_display_form(placetype, spec.is_city and "city" or "noncity", "return full") if linkdesc == false then mw.log(("Display form for placetype %s is false, can't categorize"):format(dump(placetype))) return nil end if not linkdesc then internal_error("Unrecognized placetype %s when processing key %s, data %s, label %s", placetype, key, spec, canon_label) end desc = linkdesc .. " " .. in_of .. " " .. fetch_or_construct_location_desc(group, key, spec) desc = "{{{langname}}} " .. desc .. "." local parents = {} insert(parents, key) if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = normalized_placetype, sort = key}) if spec.placetype == "country" or m_table.contains(spec.placetype, "country") then local category_class = m_placetypes.get_equiv_placetype_prop(normalized_placetype, function(pt) return m_placetypes.get_placetype_prop(pt, "class") end, { from_category = true, no_split_qualifiers = true, }) if not category_class then internal_error("Saw placetype %s that is either unknown or has no `class` " .. "setting in `placetype_data`", normalized_placetype) end if class_is_political_division[category_class] == nil then internal_error("Saw unknown category class %s derived from placetype %s", category_class, normalized_placetype) end if class_is_political_division[category_class] then insert(parents, "political divisions of specific countries") end end else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do local container_prep if container.spec.is_city then container_prep = ptdata.generic_before_cities else container_prep = ptdata.generic_before_non_cities end if not container_prep then internal_error("For container key %s spec %s defines is_city = %s but " .. "there is no corresponding `generic_before_*` setting in the " .. "placedata for placetype %s", container.key, container.spec, container.spec.is_city, placetype) end insert(parents, { name = placetype .. " " .. container_prep .. " " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = normalized_placetype, sort = key}) end end return { type = "name", topic = canon_label, description = desc, breadcrumb = placetype, parents = parents, } end end end end end end) -- Handler for "state capitals of the United States", "provincial capitals of Canada", etc. This must precede the next -- handler for specific political and misc (non-political) divisions of polities and subpolities, such as -- "provinces of the Philippines", because "departmental capitals" is listed in cat_as for French prefectures and so -- will trigger an error if that handler runs before this one. insert(handlers, function(label) label = lcfirst(label) local capital_cat, place = label:match("^([a-z%- ]- capitals) of (.*)$") -- Make sure we recognize the type of capital. if place and capital_cat_to_placetype[capital_cat] then local placetype = capital_cat_to_placetype[capital_cat] local pl_placetype = m_placetypes.pluralize_placetype(placetype) -- Locate the container, fetch its known political divisions, and make sure the placetype corresponding to the -- type of capital is among the list. local group, key, spec = find_canonical_key_from_place(place, canon_label) if group and (spec.divs or spec.addl_divs) then local saw_match = false local variant_matches = {} local divlists = {} if spec.divs then insert(divlists, spec.divs) end if spec.addl_divs then insert(divlists, spec.addl_divs) end for _, divlist in ipairs(divlists) do if type(divlist) ~= "table" then divlist = {divlist} end for _, div in ipairs(divlist) do if type(div) == "string" then div = {type = div} end -- HACK. Currently if we don't find a match for the placetype, we map e.g. 'autonomous region' -- -> 'regional capitals' and 'union territory' -> 'territorial capitals'. When encountering a -- political division like 'autonomous region' or 'union territory', chop off everything up -- through a space to make things match. To make this clearer, we record all such -- "variant match" cases, and down below we insert a note into the category text indicating that -- such "variant matches" are included among the category. if pl_placetype == div.type or pl_placetype == div.type:gsub("^.* ", "") then saw_match = true if pl_placetype ~= div.type then insert(variant_matches, div.type) end end end end if saw_match then -- Everything checks out, construct the category description. local placetype_desc = m_placetypes.get_placetype_display_form(pl_placetype, placetype.is_city and "city" or "noncity") if placetype_desc == false then mw.log(("Display form for pl_placetype %s is false, can't categorize"):format(dump(pl_placetype))) return nil end if not placetype_desc then internal_error("Unrecognized plural placetype %s, generated as the plural of %s, which " .. "was found as the placetype of capital placetype %s in label %s", pl_placetype, placetype, capital_cat, label) end local variant_match_text = "" if variant_matches[1] then local real_variant_match_descs = {} for i, variant_match in ipairs(variant_matches) do local variant_match_desc = m_placetypes.get_placetype_display_form(variant_match, placetype.is_city and "city" or "noncity") if variant_match_desc == nil then internal_error("Unrecognized variant match plural placetype %s, coming from " .. "place key %s, data %s in label %s", variant_match, key, spec, label) end if variant_match_desc then -- skip those for which the description is `false`, like `ABBREVIATION_OF states` -- in the United States divs. insert(real_variant_match_descs, variant_match_desc) end end if real_variant_match_descs[1] then variant_match_text = " (including " .. m_table.serialCommaJoin(real_variant_match_descs) .. ")" end end local desc = "{{{langname}}} names of [[capital]]s of " .. placetype_desc .. variant_match_text .. " of " .. fetch_or_construct_location_desc(group, key, spec) .. "." local full_placename, _ = m_locations.key_to_placename(group, key) local parents = {} if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = capital_cat, sort = key}) else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do insert(parents, { name = capital_cat .. " of " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = capital_cat, sort = key}) end end insert(parents, key) return { type = "name", topic = label, description = desc, breadcrumb = full_placename, parents = parents, } end end end end) local overriding_category_descriptions = { ["autonomous cities of Spain"] = "the [[w:Autonomous communities of Spain#Autonomous_cities|autonomous cities of Spain]]", ["regions of Greece"] = "the regions ([[periphery|peripheries]]) of [[Greece]]", ["regions of North Macedonia"] = "the regions ([[periphery|peripheries]]) of [[North Macedonia]]", ["subprefectures of Japan"] = "[[subprefecture]]s of [[Japan]]ese [[prefecture]]s", } -- Handler for specific political and misc (non-political) divisions of locations (polities, subpolities, cities, etc.), -- such as "provinces of the Philippines", "counties of Wales", "municipalities of Tocantins, Brazil", -- "boroughs of New York City", etc. This does not handle categories for generic placetypes (cities, rivers, etc.) of -- locations, which are handled by different handlers above. insert(handlers, function(label) -- The label comes with an initial capitalization but we have to check both lowercase-initial and capital-initial -- versions of the placetype to handle e.g. [[:Category:en:Indian reserves of Canada]]. for _, canon_label in ipairs { label, lcfirst(label) } do for _, minimal_placetype in ipairs { true, false } do local match_quantifier = minimal_placetype and "-" or "+" -- Some categories have two "of"s in them, and depending on the category, it's correct to do either a greedy -- ([[:Category:en:Abbreviations of states of the United States]], with placetype `abbreviations of states`) -- or non-greedy ([[:Category:en:Provinces of the Democratic Republic of the Congo]], with placetype -- `provinces`) match. We can't know in advance which is correct so we try both possibilities, doing the -- non-greedy one first as it seems more common (there are many locations with "of" in them, but currently -- only `abbreviations of states` occurs with a following location). local placetype, in_of, place = canon_label:match("^([A-Za-z%- ]" .. match_quantifier .. ") (of) (.*)$") if not placetype then placetype, in_of, place = canon_label:match("^([A-Za-z%- ]" .. match_quantifier .. ") (in) (.*)$") end if placetype then local group, key, spec = find_canonical_key_from_place(place, canon_label) if group then local function find_placetype(divs) if divs then if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) == "string" then div = {type = div} end local cat_as = div.cat_as or div.type if type(cat_as) ~= "table" then cat_as = {cat_as} end for _, pt_cat_as in ipairs(cat_as) do if type(pt_cat_as) == "string" then pt_cat_as = {type = pt_cat_as} end if placetype == pt_cat_as.type then local div_parent = pt_cat_as.container_parent_type if div_parent == nil then -- allow false div_parent = div.container_parent_type end if div_parent == nil then div_parent = placetype end return div_parent, pt_cat_as.prep or div.prep or "of" end end end end return nil end local div_parent, div_prep = find_placetype(spec.divs) if div_parent == nil then -- allow false div_parent, div_prep = find_placetype(spec.addl_divs) end if div_parent == nil then -- allow false div_parent, div_prep = find_placetype(spec.addl_divs_for_categorization) end if div_parent ~= nil then if div_prep ~= in_of then mw.log(("Mismatch in category name '%s', has '%s' when it should have '%s'"):format( canon_label, in_of, div_prep)) return nil end local linkdesc = m_placetypes.get_placetype_display_form(placetype, spec.is_city and "city" or "noncity", "return full") if linkdesc == false then mw.log(("Display form for placetype %s is false, can't categorize"):format(dump(placetype))) return nil end if not linkdesc then internal_error("Unrecognized placetype %s when processing key %s, data %s, label %s", placetype, key, spec, canon_label) end local desc = overriding_category_descriptions[canon_label] if not desc then desc = linkdesc .. " " .. in_of .. " " .. fetch_or_construct_location_desc(group, key, spec) end desc = "{{{langname}}} " .. desc .. "." local parents = {} insert(parents, key) if div_parent then -- div_parent may be `false` if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = placetype, sort = " " .. key}) if spec.placetype == "country" or m_table.contains(spec.placetype, "country") then insert(parents, "political divisions of specific countries") end else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do insert(parents, { name = div_parent .. " " .. in_of .. " " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = placetype, sort = " " .. key}) end end end return { type = "name", topic = canon_label, description = desc, breadcrumb = placetype, parents = parents, } end end end end end end) labels["exonyms"] = { type = "name", -- special-cased description description = "{{{langname}}} [[exonym]]s.", parents = {"places"}, } labels["political divisions of specific countries"] = { type = "grouping", description = "{{{langname}}} categories for political divisions of specific countries.", parents = {"places"}, } -- Misc. FIXME: Remove the need for this. labels["nomes of Ancient Egypt"] = { type = "name", -- special-cased description description = "{{{langname}}} names of the [[nome]]s of [[Ancient Egypt]].", breadcrumb = "nomes", parents = {"Ancient Egypt"}, } -- Sui generis place categories (mostly cross-jurisdictional subcontinental/transcontinental regions) -- FIXME: Everything here has been moved from [[Module:category tree/topic/Earth]]. Most should be removed. labels["Atlantic Ocean"] = { type = "related-to", description = "default with the", parents = {"Earth"}, } labels["British Isles"] = { type = "related-to", description = "=the people, culture, or territory of [[Great Britain]], [[Ireland]], and other nearby islands", parents = {"Europe", "islands"}, } labels["European Union"] = { type = "related-to", description = "default with the", parents = {"Europe"}, } labels["Gascony"] = { type = "related-to", parents = {"Occitania, France"}, } labels["Indian subcontinent"] = { type = "related-to", description = "default with the", parents = {"South Asia"}, } labels["Bengal"] = { type = "related-to", description = "{{{langname}}} terms related to the people, culture, or territory of [[Bengal]].", parents = {"Indian subcontinent"}, } labels["Kashmir"] = { type = "related-to", description = "{{{langname}}} terms related to the people, culture, or territory of [[Kashmir]].", parents = {"Indian subcontinent"}, } labels["Kashmir, India"] = { type = "related-to", description = "{{{langname}}} names of places in {{w|Kashmir, India}}.", parents = {"India", "Kashmir"}, } labels["Korea"] = { type = "related-to", description = "=the people, culture, or territory of [[Korea]]", parents = {"Asia"}, } labels["Languedoc"] = { type = "related-to", parents = {"Occitania, France"}, } labels["Lapland"] = { type = "related-to", description = "=[[Lapland]], a region in northernmost Europe", parents = {"Europe", "Finland", "Norway", "Russia", "Sweden"}, } labels["Middle East"] = { type = "related-to", description = "default with the", parents = {"Africa", "Asia"}, } labels["Netherlands Antilles"] = { type = "related-to", description = "=the people, culture, or territory of the [[Netherlands Antilles]]", parents = {"Netherlands", "North America"}, } labels["Overseas France"] = { type = "related-to", description = "={{w|Overseas France}} ({{m|fr||France d'outre-mer}})", parents = {"France"}, } labels["Provence"] = { type = "related-to", parents = {"Provence-Alpes-Côte d'Azur, France"}, } labels["Polish People's Republic"] = { type = "related-to", parents = {"Poland"}, } labels["South Asia"] = { type = "related-to", parents = {"Eurasia", "Asia"}, } return {LABELS = labels, HANDLERS = handlers} d3765m11xpzqpaf3g1rpd7tkzgydkgp 88789 88788 2026-08-06T18:21:36Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Places]] 88788 Scribunto text/plain local labels = {} local handlers = {} local m_table = require("Module:table") local en_utilities_module = "Module:en-utilities" local string_utilities_module = "Module:string utilities" local m_locations = require("Module:place/locations") local m_placetypes = require("Module:place/placetypes") local placetype_data = m_placetypes.placetype_data local internal_error = m_locations.internal_error local dump = mw.dumpObject local insert = table.insert local concat = table.concat local is_callable = require("Module:fun").is_callable --[==[ intro: This module is part of the category tree code and contains code to generate the descriptions of place-related categories such as [[Category:de:Hokkaido Prefecture, Japan]], [[Category:es:Cities in France]], [[Category:pt:Municipalities of Tocantins, Brazil]], etc.). Note that this module doesn't actually create the categories; that must be done separately, with the text "{{tl|auto cat}}" as the definition of the category. (This process should automatically happen periodically for non-empty categories, because they will appear in [[Special:WantedCategories]] and a bot will periodically examine that list and create any needed category.) There are two ways that category descriptions are specified: (1) by manually adding an entry to the `labels` table, keyed by the label (the category minus the language code) with a value consisting of a Lua table specifying the description text and the category's parents; (2) through handlers (pieces of Lua code) added to the `handlers` list, which recognize labels of a specific type (e.g. `Cities in France`) and generate the appropriate specification for that label on-the-fly. See [[Module:place]] for an introduction to the terminology associated with places along with a list of all the relevant modules, along with for more specific information on types of toponyms and placetypes and how their categorization works. ]==] local function lcfirst(label) return mw.getContentLanguage():lcfirst(label) end local function gsub_literally(str, from, to) local m_strutils = require(string_utilities_module) return (str:gsub(m_strutils.pattern_escape(from), m_strutils.replacement_escape(to))) end local class_to_bare_category_parent = { ["polity"] = "polities", ["subpolity"] = "political divisions", ["settlement"] = "settlements", ["non-admin settlement"] = "settlements", ["capital"] = "capital cities", ["natural feature"] = "natural features", ["man-made structure"] = "man-made structures", ["geographic region"] = "geographic and cultural areas", } local class_is_political_division = { ["polity"] = true, -- strictly false but there are placetypes ambiguous between polity and subpolity ["subpolity"] = true, ["settlement"] = true, ["non-admin settlement"] = false, ["capital"] = true, ["natural feature"] = false, ["man-made structure"] = false, ["geographic region"] = false, ["generic place"] = false, } local capital_cat_to_placetype = {} for placetype, capital_cat in pairs(m_placetypes.placetype_to_capital_cat) do capital_cat_to_placetype[capital_cat] = placetype end -- Handler for bare categories for all types of capitals. This needs to precede the handler for bare placetype -- categories as some of the types of capitals exist as placetypes as well. insert(handlers, function(label) label = lcfirst(label) local capital_placetype = capital_cat_to_placetype[label] if capital_placetype then local pl_placetype = m_placetypes.pluralize_placetype(capital_placetype) local linkdesc = m_placetypes.get_placetype_display_form(pl_placetype, "top-level") if linkdesc == nil then internal_error("Unrecognized placetype %s when processing label %s", capital_placetype, label) end if linkdesc == false then mw.log(("Display form for pl_placetype %s is false, can't categorize"):format(dump(pl_placetype))) return nil end return { type = "name", topic = label, description = "{{{langname}}} names of [[capital]]s of " .. linkdesc .. ".", parents = {"capital cities"}, } end end) -- Handler for bare placetype categories. FIXME: Add wpcat= and commonscat= info. Previously we had it for various -- so-called "generic" placetypes, but sometimes the categories were wrong. insert(handlers, function(label) for _, canon_label in ipairs { lcfirst(label), label } do local ptdesc, ptdata = m_placetypes.get_placetype_display_form(canon_label, "top-level", "return full") if ptdesc then local from_category_props = { from_category = true, no_split_qualifiers = true, } local bare_category_parent = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) local bare_category_parent = m_placetypes.get_placetype_prop(pt, "bare_category_parent") if bare_category_parent then return bare_category_parent end local class = m_placetypes.get_placetype_prop(pt, "class") if class then if class_to_bare_category_parent[class] == nil then internal_error("Saw unknown category class %s derived from placetype %s", class, canon_label) end return class_to_bare_category_parent[class] end end, from_category_props) if not bare_category_parent then internal_error("Saw placetype %s without a `class` or `bare_category_parent` setting, either " .. "directly or through a fallback", canon_label) end local addl_bare_category_parents = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) return m_placetypes.get_placetype_prop(pt, "addl_bare_category_parents") end, from_category_props) local bare_category_breadcrumb = m_placetypes.get_equiv_placetype_prop(canon_label, function(pt) return m_placetypes.get_placetype_prop(pt, "bare_category_breadcrumb") end, from_category_props) if type(bare_category_parent) == "string" and bare_category_breadcrumb then bare_category_parent = {name = bare_category_parent, sort = bare_category_breadcrumb} end local parents = {bare_category_parent} if addl_bare_category_parents then m_table.extend(parents, addl_bare_category_parents) end return { type = "name", topic = canon_label, description = "{{{langname}}} " .. ptdesc .. ".", breadcrumb = bare_category_breadcrumb, parents = parents, } elseif ptdesc == false then mw.log(("Display form for canon_label %s is false, can't categorize"):format(dump(canon_label))) end end end) local function fetch_primary_placetype(key, spec) local placetype = spec.placetype if type(placetype) == "table" then placetype = placetype[1] end if not placetype then internal_error("No placetype specified or defaulted for key %s, spec %s", key, spec) end return placetype end --[==[ Construct an appropriately linked location based on the full or elliptical placename, preceded by `"the "`` if appropriate. Specifically: Fetch the full and elliptical_placenames. If they are the same, just link to the placename directly. Otherwise, check if the full placename exists; if so link to it. Otherwise, if the elliptical placename exists, link to it but display it as the full placename. Finally, if neither full placename nor elliptical placename exists, fall back to linking to the full placename. That way, we prefer full placenames to elliptical placenames if both or neither exist as Wiktionary entries, but if only one exists, we link to that one rather than have a red link. ]==] local function construct_linked_location(group, key, spec) local full_placename, elliptical_placename = m_locations.key_to_placename(group, key) local linked_placename if elliptical_placename ~= full_placename then local full_placename_title = mw.title.new(full_placename) if full_placename_title and full_placename_title.exists then linked_placename = m_locations.construct_linked_placename(spec, full_placename) else local elliptical_placename_title = mw.title.new(elliptical_placename) if elliptical_placename_title and elliptical_placename_title.exists then linked_placename = m_locations.construct_linked_placename(spec, elliptical_placename, full_placename) end end end return linked_placename or m_locations.construct_linked_placename(spec, full_placename) end --[==[ Construct the description of a location, including its container trail either to the end or until we encounter a `no_include_container_in_desc` setting. For example, for the city of [[Birmingham]], the description will read `"[[Birmingham]], a [[city]] in the [[West Midlands]] (which is a [[county]] of [[England]], which is a [[constituent country]] of the [[United Kingdom]], which is a [[country]] in [[Europe]])"`. FIXME: Possibly we should adopt the way city descriptions used to read, which was similar to `"the city of [[Birmingham]], in the county of the [[West Midlands]], in the [[constituent country]] of [[England]], in the [[country]] of the [[United Kingdom]], in [[Europe]]"`. ]==] local function construct_location_desc(group, key, spec) local parts = {} local function ins(txt) insert(parts, txt) end ins(construct_linked_location(group, key, spec)) local iteration = 0 local need_closing_paren = false local containers = {{group = group, key = key, spec = spec}} local container_iterator = m_locations.iterate_containers(group, key, spec) while true do iteration = iteration + 1 local include_container_in_desc = false for _, container in ipairs(containers) do if not container.spec.no_include_container_in_desc then include_container_in_desc = true break end end if not include_container_in_desc then break end local next_containers = container_iterator() if not next_containers then break end local is_former = nil for _, container in ipairs(containers) do local this_is_former = container.spec.is_former_place if is_former == nil then is_former = this_is_former elseif is_former ~= this_is_former then internal_error("When processing container trail of key %s, found a mixture of former and non-former " .. "containers: %s", key, containers) end end if #containers > 1 then local placetypes = {} local prepositions = {} for _, container in ipairs(containers) do local container_type = fetch_primary_placetype(container.key, container.spec) m_table.insertIfNot(placetypes, m_placetypes.pluralize_placetype(container_type)) m_table.insertIfNot(prepositions, m_placetypes.get_placetype_entry_preposition(container_type)) end if iteration == 1 then ins(", ") elseif iteration == 2 then ins(" (which are ") need_closing_paren = true else ins(", which are ") end if is_former then ins("former ") end ins(m_table.serialCommaJoin(placetypes)) ins(" ") ins(concat(prepositions, "/")) else if iteration == 1 then ins(", ") elseif iteration == 2 then ins(" (which is ") need_closing_paren = true else ins(", which is ") end local container_type = fetch_primary_placetype(containers[1].key, containers[1].spec) if is_former then ins("a former ") else ins(m_placetypes.get_placetype_article(container_type)) ins(" ") end ins(container_type) ins(" ") ins(m_placetypes.get_placetype_entry_preposition(container_type)) end ins(" ") first_container = false containers = next_containers local container_locations = {} for _, container in ipairs(containers) do insert(container_locations, construct_linked_location(container.group, container.key, container.spec)) end ins(m_table.serialCommaJoin(container_locations)) end if need_closing_paren then ins(")") end return concat(parts) end -- Fetch or construct the description of the location specified by `key`. If the `keydesc` property is specified, -- use it directly but substitute any occurrence of `+++` with the auto-constructed location description, which -- mentions the placename corresponding to the key, its placetype and container, and repeats the description up -- the container trail until either there are no more containers or (more usually) the `no_include_container_in_desc` -- setting is found (which is set on all continents and continent-level regions). local function fetch_or_construct_location_desc(group, key, spec) local val = spec.keydesc if is_callable(val) then val = val(group, key, spec) spec.keydesc = val end val = val or "+++" if val:find("%+%+%+") then val = gsub_literally(val, "+++", construct_location_desc(group, key, spec)) end return val end local function normalize_cat_as(cat_as, div) if type(cat_as) ~= "table" or cat_as.type then cat_as = {cat_as} end local ret_cat_as = {} for _, pt_cat_as in ipairs(cat_as) do if type(pt_cat_as) == "string" then pt_cat_as = {type = pt_cat_as} end insert(ret_cat_as, {type = pt_cat_as.type, prep = pt_cat_as.prep or div.prep or "of"}) end return ret_cat_as end -- Find the specified plural placetype among the divs for a given known location. Return a list of cat_as specs, where -- each spec is of the form {type = "PLURAL_PLACETYPE", prep = "PREP"} indicating the plural placetype to use when -- categorizing and the preposition to follow. local function find_placetype_cat_as(divs, pl_placetype) if divs then if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) == "string" then div = {type = div} end if div.type == pl_placetype then local cat_as = div.cat_as or div.type return normalize_cat_as(cat_as, div) end end end return nil end -- Handler for bare placename categories for known locations in `locations` in [[Module:place/locations]]. insert(handlers, function(label) for _, canon_label in ipairs { label, lcfirst(label) } do local group, spec = m_locations.find_canonical_key(canon_label) if group then -- wp= defaults to true (Wikipedia article matches location's full placename) local wp = spec.wp if wp == nil then wp = true end -- wpcat= defaults to wp= (if Wikipedia article has its own name, Wikipedia category and Commons category -- generally follow) local wpcat = spec.wpcat if wpcat == nil then wpcat = wp end -- commonscat= defaults to wpcat= (if Wikipedia category has its own name, Commons category generally -- follows) local commonscat = spec.commonscat if commonscat == nil then commonscat = wpcat end local parents = {} local bare_label_parents = spec.overriding_bare_label_parents local container_iterator = m_locations.iterate_containers(group, canon_label, spec) local containers = container_iterator() if not bare_label_parents then bare_label_parents = {"+++"} end local full_location_placename, elliptical_location_placename = m_locations.key_to_placename(group, canon_label) local full_container_placename if containers then full_container_placename, _ = m_locations.key_to_placename(containers[1].group, containers[1].key) end local inserted_containers = false for _, parent in ipairs(bare_label_parents) do if parent == "+++" then parent = "PL_PLACETYPE PREP CONTAINER" end if parent:find("CONTAINER") then if not containers then internal_error("Parent category %s needs the container of %s but no containers specified: %s", parent, canon_label, spec) end local location_type = fetch_primary_placetype(canon_label, spec) local pl_location_type = m_placetypes.pluralize_placetype(location_type) for _, container in ipairs(containers) do local per_container_parent = parent local cat_as_list if per_container_parent:find("PL_PLACETYPE") then if spec.bare_category_parent_type then cat_as_list = normalize_cat_as(spec.bare_category_parent_type, spec) else cat_as_list = find_placetype_cat_as(container.spec.divs, pl_location_type) or find_placetype_cat_as(container.spec.addl_divs, pl_location_type) end end if not cat_as_list then local canon_placetype, ptdata, ptmatch = m_placetypes.get_placetype_data(location_type, "from category") if not canon_placetype or not (ptdata.generic_before_non_cities or ptdata.generic_before_cities) then internal_error("Unable to locate plural location type %s among the divs or addl_divs " .. "for container key %s spec %s, and the location type is either not in placetype_data or " .. "not identified as a generic placetype", pl_location_type, container.key, container.spec) end cat_as_list = {{type = pl_location_type, prep = m_placetypes.get_placetype_entry_preposition(location_type)}} end local prefixed_key = m_placetypes.get_prefixed_key(container.key, container.spec) per_container_parent = gsub_literally(per_container_parent, "CONTAINER", prefixed_key) for _, cat_as in ipairs(cat_as_list) do local per_container_per_placetype_parent = per_container_parent per_container_per_placetype_parent = gsub_literally(per_container_per_placetype_parent, "PL_PLACETYPE", cat_as.type) per_container_per_placetype_parent = gsub_literally(per_container_per_placetype_parent, "PREP", cat_as.prep) m_table.insertIfNot(parents, per_container_per_placetype_parent) end end inserted_containers = true else m_table.insertIfNot(parents, parent) end end if not inserted_containers and containers then -- If we didn't insert the containers above in some form, insert them now as bare categories. Note that -- this may be different categories from the container categories inserted above. for _, container in ipairs(containers) do m_table.insertIfNot(parents, container.key) end end if spec.addl_parents then for _, parent in ipairs(spec.addl_parents) do m_table.insertIfNot(parents, parent) end end local function format_boxval(val, specname) if val == true then val = "%l" end if type(val) == "string" then val = gsub_literally(val, "%l", full_location_placename) val = gsub_literally(val, "%e", elliptical_location_placename) if val:find("%%c") then if not full_container_placename then internal_error("Wikipedia/Commons spec %s = %s has %%c in it but key %s has no " .. "containers: %s", specname, val, canon_label, spec) end val = gsub_literally(val, "%c", full_container_placename) end end return val end local description = spec.fulldesc or ( "{{{langname}}} terms related to the people, culture, or territory of " .. fetch_or_construct_location_desc(group, canon_label, spec) .. ".") local full_placename, _ = m_locations.key_to_placename(group, canon_label) return { type = "topic", description = description, breadcrumb = full_placename, parents = parents, wp = format_boxval(wp, "wp"), wpcat = format_boxval(wpcat, "wpcat"), commonscat = format_boxval(commonscat, "commonscat"), } end end end) local function find_canonical_key_from_place(place, canon_label) local has_the = false local key if place:find("^the ") then key = place:gsub("^the ", "") has_the = true else key = place end local group, spec = m_locations.find_canonical_key(key) if group then local requires_the = spec.the or false if has_the ~= requires_the then if has_the then mw.log(("Mismatch in category name '%s', has 'the' in the category when it should not"):format( canon_label)) else mw.log(("Mismatch in category name '%s', should have 'the' in the category but does not"): format(canon_label)) end return nil end return group, key, spec end return nil end -- Handler for generic placetypes (those whose categories are added through category generation handlers or through -- explicit category specs in the placetype data) for known locations in [[Module:place/locations]]. All such -- placetypes have either a `generic_before_non_cities` setting (meaning they can occur before non-city locations) or -- `generic_before_cities` setting (meaning they can occur before cities), or both. Examples of such categories are -- "cities in the Bahamas" or "rivers in Western Australia, Australia", or (for city locations) -- "neighbourhoods of Hong Kong" or "places in Melbourne". insert(handlers, function(label) for _, canon_label in ipairs { lcfirst(label), label } do local placetype, in_of, place = canon_label:match("^([A-Za-z%- ]-) (in) (.*)$") if not placetype then placetype, in_of, place = canon_label:match("^([A-Za-z%- ]-) (of) (.*)$") end if placetype then local normalized_placetype = placetype == "neighbourhoods" and "neighborhoods" or placetype local canon_placetype, ptdata, ptmatch = m_placetypes.get_placetype_data(normalized_placetype, "from category") if canon_placetype and (ptdata.generic_before_non_cities or ptdata.generic_before_cities) then local group, key, spec = find_canonical_key_from_place(place, canon_label) if group then -- Check whether the location uses British spelling, but also check all containers, because -- it's too hard to keep in sync the `british_spelling` setting for locations at all different -- levels (e.g. cities of various countries, first and second level administrative division, etc.), -- so we just set it at top level on the country. local uses_british_spelling = spec.british_spelling if uses_british_spelling == nil then for containers in m_locations.iterate_containers(group, key, spec) do local must_outer_break = false for _, container in ipairs(containers) do if container.spec.british_spelling ~= nil then uses_british_spelling = container.spec.british_spelling must_outer_break = true break end end if must_outer_break then break end end end local allow_cat = true if placetype == "neighborhoods" and uses_british_spelling or placetype == "neighbourhoods" and not uses_british_spelling then mw.log(("Mismatch in spelling of placetype '%s' in category '%s', should be '%s'"):format( placetype, canon_label, uses_british_spelling and "neighbourhoods" or "neighborhoods")) allow_cat = false end if spec.is_former_place and placetype ~= "places" then allow_cat = false end local expected_prep if spec.is_city then expected_prep = ptdata.generic_before_cities else expected_prep = ptdata.generic_before_non_cities end if not expected_prep then allow_cat = false end if allow_cat then if expected_prep ~= in_of then mw.log(("Mismatch in category name '%s', has '%s' when it should have '%s'"):format( canon_label, in_of, expected_prep)) return nil end local linkdesc = m_placetypes.get_placetype_display_form(placetype, spec.is_city and "city" or "noncity", "return full") if linkdesc == false then mw.log(("Display form for placetype %s is false, can't categorize"):format(dump(placetype))) return nil end if not linkdesc then internal_error("Unrecognized placetype %s when processing key %s, data %s, label %s", placetype, key, spec, canon_label) end desc = linkdesc .. " " .. in_of .. " " .. fetch_or_construct_location_desc(group, key, spec) desc = "{{{langname}}} " .. desc .. "." local parents = {} insert(parents, key) if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = normalized_placetype, sort = key}) if spec.placetype == "country" or m_table.contains(spec.placetype, "country") then local category_class = m_placetypes.get_equiv_placetype_prop(normalized_placetype, function(pt) return m_placetypes.get_placetype_prop(pt, "class") end, { from_category = true, no_split_qualifiers = true, }) if not category_class then internal_error("Saw placetype %s that is either unknown or has no `class` " .. "setting in `placetype_data`", normalized_placetype) end if class_is_political_division[category_class] == nil then internal_error("Saw unknown category class %s derived from placetype %s", category_class, normalized_placetype) end if class_is_political_division[category_class] then insert(parents, "political divisions of specific countries") end end else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do local container_prep if container.spec.is_city then container_prep = ptdata.generic_before_cities else container_prep = ptdata.generic_before_non_cities end if not container_prep then internal_error("For container key %s spec %s defines is_city = %s but " .. "there is no corresponding `generic_before_*` setting in the " .. "placedata for placetype %s", container.key, container.spec, container.spec.is_city, placetype) end insert(parents, { name = placetype .. " " .. container_prep .. " " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = normalized_placetype, sort = key}) end end return { type = "name", topic = canon_label, description = desc, breadcrumb = placetype, parents = parents, } end end end end end end) -- Handler for "state capitals of the United States", "provincial capitals of Canada", etc. This must precede the next -- handler for specific political and misc (non-political) divisions of polities and subpolities, such as -- "provinces of the Philippines", because "departmental capitals" is listed in cat_as for French prefectures and so -- will trigger an error if that handler runs before this one. insert(handlers, function(label) label = lcfirst(label) local capital_cat, place = label:match("^([a-z%- ]- capitals) of (.*)$") -- Make sure we recognize the type of capital. if place and capital_cat_to_placetype[capital_cat] then local placetype = capital_cat_to_placetype[capital_cat] local pl_placetype = m_placetypes.pluralize_placetype(placetype) -- Locate the container, fetch its known political divisions, and make sure the placetype corresponding to the -- type of capital is among the list. local group, key, spec = find_canonical_key_from_place(place, canon_label) if group and (spec.divs or spec.addl_divs) then local saw_match = false local variant_matches = {} local divlists = {} if spec.divs then insert(divlists, spec.divs) end if spec.addl_divs then insert(divlists, spec.addl_divs) end for _, divlist in ipairs(divlists) do if type(divlist) ~= "table" then divlist = {divlist} end for _, div in ipairs(divlist) do if type(div) == "string" then div = {type = div} end -- HACK. Currently if we don't find a match for the placetype, we map e.g. 'autonomous region' -- -> 'regional capitals' and 'union territory' -> 'territorial capitals'. When encountering a -- political division like 'autonomous region' or 'union territory', chop off everything up -- through a space to make things match. To make this clearer, we record all such -- "variant match" cases, and down below we insert a note into the category text indicating that -- such "variant matches" are included among the category. if pl_placetype == div.type or pl_placetype == div.type:gsub("^.* ", "") then saw_match = true if pl_placetype ~= div.type then insert(variant_matches, div.type) end end end end if saw_match then -- Everything checks out, construct the category description. local placetype_desc = m_placetypes.get_placetype_display_form(pl_placetype, placetype.is_city and "city" or "noncity") if placetype_desc == false then mw.log(("Display form for pl_placetype %s is false, can't categorize"):format(dump(pl_placetype))) return nil end if not placetype_desc then internal_error("Unrecognized plural placetype %s, generated as the plural of %s, which " .. "was found as the placetype of capital placetype %s in label %s", pl_placetype, placetype, capital_cat, label) end local variant_match_text = "" if variant_matches[1] then local real_variant_match_descs = {} for i, variant_match in ipairs(variant_matches) do local variant_match_desc = m_placetypes.get_placetype_display_form(variant_match, placetype.is_city and "city" or "noncity") if variant_match_desc == nil then internal_error("Unrecognized variant match plural placetype %s, coming from " .. "place key %s, data %s in label %s", variant_match, key, spec, label) end if variant_match_desc then -- skip those for which the description is `false`, like `ABBREVIATION_OF states` -- in the United States divs. insert(real_variant_match_descs, variant_match_desc) end end if real_variant_match_descs[1] then variant_match_text = " (including " .. m_table.serialCommaJoin(real_variant_match_descs) .. ")" end end local desc = "{{{langname}}} names of [[capital]]s of " .. placetype_desc .. variant_match_text .. " of " .. fetch_or_construct_location_desc(group, key, spec) .. "." local full_placename, _ = m_locations.key_to_placename(group, key) local parents = {} if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = capital_cat, sort = key}) else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do insert(parents, { name = capital_cat .. " of " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = capital_cat, sort = key}) end end insert(parents, key) return { type = "name", topic = label, description = desc, breadcrumb = full_placename, parents = parents, } end end end end) local overriding_category_descriptions = { ["autonomous cities of Spain"] = "the [[w:Autonomous communities of Spain#Autonomous_cities|autonomous cities of Spain]]", ["regions of Greece"] = "the regions ([[periphery|peripheries]]) of [[Greece]]", ["regions of North Macedonia"] = "the regions ([[periphery|peripheries]]) of [[North Macedonia]]", ["subprefectures of Japan"] = "[[subprefecture]]s of [[Japan]]ese [[prefecture]]s", } -- Handler for specific political and misc (non-political) divisions of locations (polities, subpolities, cities, etc.), -- such as "provinces of the Philippines", "counties of Wales", "municipalities of Tocantins, Brazil", -- "boroughs of New York City", etc. This does not handle categories for generic placetypes (cities, rivers, etc.) of -- locations, which are handled by different handlers above. insert(handlers, function(label) -- The label comes with an initial capitalization but we have to check both lowercase-initial and capital-initial -- versions of the placetype to handle e.g. [[:Category:en:Indian reserves of Canada]]. for _, canon_label in ipairs { label, lcfirst(label) } do for _, minimal_placetype in ipairs { true, false } do local match_quantifier = minimal_placetype and "-" or "+" -- Some categories have two "of"s in them, and depending on the category, it's correct to do either a greedy -- ([[:Category:en:Abbreviations of states of the United States]], with placetype `abbreviations of states`) -- or non-greedy ([[:Category:en:Provinces of the Democratic Republic of the Congo]], with placetype -- `provinces`) match. We can't know in advance which is correct so we try both possibilities, doing the -- non-greedy one first as it seems more common (there are many locations with "of" in them, but currently -- only `abbreviations of states` occurs with a following location). local placetype, in_of, place = canon_label:match("^([A-Za-z%- ]" .. match_quantifier .. ") (of) (.*)$") if not placetype then placetype, in_of, place = canon_label:match("^([A-Za-z%- ]" .. match_quantifier .. ") (in) (.*)$") end if placetype then local group, key, spec = find_canonical_key_from_place(place, canon_label) if group then local function find_placetype(divs) if divs then if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) == "string" then div = {type = div} end local cat_as = div.cat_as or div.type if type(cat_as) ~= "table" then cat_as = {cat_as} end for _, pt_cat_as in ipairs(cat_as) do if type(pt_cat_as) == "string" then pt_cat_as = {type = pt_cat_as} end if placetype == pt_cat_as.type then local div_parent = pt_cat_as.container_parent_type if div_parent == nil then -- allow false div_parent = div.container_parent_type end if div_parent == nil then div_parent = placetype end return div_parent, pt_cat_as.prep or div.prep or "of" end end end end return nil end local div_parent, div_prep = find_placetype(spec.divs) if div_parent == nil then -- allow false div_parent, div_prep = find_placetype(spec.addl_divs) end if div_parent == nil then -- allow false div_parent, div_prep = find_placetype(spec.addl_divs_for_categorization) end if div_parent ~= nil then if div_prep ~= in_of then mw.log(("Mismatch in category name '%s', has '%s' when it should have '%s'"):format( canon_label, in_of, div_prep)) return nil end local linkdesc = m_placetypes.get_placetype_display_form(placetype, spec.is_city and "city" or "noncity", "return full") if linkdesc == false then mw.log(("Display form for placetype %s is false, can't categorize"):format(dump(placetype))) return nil end if not linkdesc then internal_error("Unrecognized placetype %s when processing key %s, data %s, label %s", placetype, key, spec, canon_label) end local desc = overriding_category_descriptions[canon_label] if not desc then desc = linkdesc .. " " .. in_of .. " " .. fetch_or_construct_location_desc(group, key, spec) end desc = "{{{langname}}} " .. desc .. "." local parents = {} insert(parents, key) if div_parent then -- div_parent may be `false` if spec.no_container_parent then -- top-level country, constituent country, continent or the like insert(parents, {name = placetype, sort = " " .. key}) if spec.placetype == "country" or m_table.contains(spec.placetype, "country") then insert(parents, "political divisions of specific countries") end else local container_iterator = m_locations.iterate_containers(group, key, spec) local next_containers = container_iterator() if next_containers then for _, container in ipairs(next_containers) do insert(parents, { name = div_parent .. " " .. in_of .. " " .. m_placetypes.get_prefixed_key( container.key, container.spec), sort = key }) end else -- unrecognized countries or the like insert(parents, {name = placetype, sort = " " .. key}) end end end return { type = "name", topic = canon_label, description = desc, breadcrumb = placetype, parents = parents, } end end end end end end) labels["exonyms"] = { type = "name", -- special-cased description description = "{{{langname}}} [[exonym]]s.", parents = {"places"}, } labels["political divisions of specific countries"] = { type = "grouping", description = "{{{langname}}} categories for political divisions of specific countries.", parents = {"places"}, } -- Misc. FIXME: Remove the need for this. labels["nomes of Ancient Egypt"] = { type = "name", -- special-cased description description = "{{{langname}}} names of the [[nome]]s of [[Ancient Egypt]].", breadcrumb = "nomes", parents = {"Ancient Egypt"}, } -- Sui generis place categories (mostly cross-jurisdictional subcontinental/transcontinental regions) -- FIXME: Everything here has been moved from [[Module:category tree/topic/Earth]]. Most should be removed. labels["Atlantic Ocean"] = { type = "related-to", description = "default with the", parents = {"Earth"}, } labels["British Isles"] = { type = "related-to", description = "=the people, culture, or territory of [[Great Britain]], [[Ireland]], and other nearby islands", parents = {"Europe", "islands"}, } labels["European Union"] = { type = "related-to", description = "default with the", parents = {"Europe"}, } labels["Gascony"] = { type = "related-to", parents = {"Occitania, France"}, } labels["Indian subcontinent"] = { type = "related-to", description = "default with the", parents = {"South Asia"}, } labels["Bengal"] = { type = "related-to", description = "{{{langname}}} terms related to the people, culture, or territory of [[Bengal]].", parents = {"Indian subcontinent"}, } labels["Kashmir"] = { type = "related-to", description = "{{{langname}}} terms related to the people, culture, or territory of [[Kashmir]].", parents = {"Indian subcontinent"}, } labels["Kashmir, India"] = { type = "related-to", description = "{{{langname}}} names of places in {{w|Kashmir, India}}.", parents = {"India", "Kashmir"}, } labels["Korea"] = { type = "related-to", description = "=the people, culture, or territory of [[Korea]]", parents = {"Asia"}, } labels["Languedoc"] = { type = "related-to", parents = {"Occitania, France"}, } labels["Lapland"] = { type = "related-to", description = "=[[Lapland]], a region in northernmost Europe", parents = {"Europe", "Finland", "Norway", "Russia", "Sweden"}, } labels["Middle East"] = { type = "related-to", description = "default with the", parents = {"Africa", "Asia"}, } labels["Netherlands Antilles"] = { type = "related-to", description = "=the people, culture, or territory of the [[Netherlands Antilles]]", parents = {"Netherlands", "North America"}, } labels["Overseas France"] = { type = "related-to", description = "={{w|Overseas France}} ({{m|fr||France d'outre-mer}})", parents = {"France"}, } labels["Provence"] = { type = "related-to", parents = {"Provence-Alpes-Côte d'Azur, France"}, } labels["Polish People's Republic"] = { type = "related-to", parents = {"Poland"}, } labels["South Asia"] = { type = "related-to", parents = {"Eurasia", "Asia"}, } return {LABELS = labels, HANDLERS = handlers} d3765m11xpzqpaf3g1rpd7tkzgydkgp Mòideal:place/locations 828 17896 88790 2026-07-14T10:46:44Z en>Juwan 0 [[Template talk:Bhutan - chiwogs]] 88790 Scribunto text/plain local export = {} export.force_cat = false -- set to true to force category generation even on non-mainspace pages local m_table = require("Module:table") local string_utilities_module = "Module:string utilities" local en_utilities_module = "Module:en-utilities" local insert = table.insert local concat = table.concat local dump = mw.dumpObject local unpack = unpack or table.unpack -- Lua 5.2 compatibility --[==[ intro: This module contains data on all known locations, along with some lower-level code to process them (higher-level known-location code is in [[Module:place/placetypes]]). You must load this module using require(), not using mw.loadData(). ===Location data=== '''NOTE: In order to understand the following better, first read the introductory documentation in [[Module:place]], especially the section `More about known locations`.''' The bulk of the code in this module (after some helper functions and placetype tables) describes the known locations and their relationships. Locations are grouped into ''location groups'' that share some common properties (examples are states of the United States and cities in Brazil). Each location group is associated with two tables, a ''data table'' that lists the locations and their individual properties, and a ''metadata table'' that lists group-level properties and defaults for the location properties. Each metadata table points to the associated data table (i.e. contains the data table as its `data` field), and the global `locations` variable holds a list of all group metadata tables. A given location is generally described by three values: (a) the group metadata table for the group the location is part of; (b) the location's canonical ''key'', which is the actual key in the group's data table and is globally unique across all locations; and (c) the location's ''spec'', which is the initialized object describing the properties of the location and comes from the value in the data table corresponding to the canonical key, transformed by the `initialize_spec()` function. These are typically named `group`, `key` and `spec`, respectively and in that order, and are found in the arguments to many functions. In a per-group data table, the keys are either ''canonical keys'' describing locations (which, as mentioned above, must be globally unique) or ''alias keys'' specifying an allowed alias for a given location. There may be multiple aliases for a given location and the alias keys only need to be unique within a particular group data table, not across all groups. It is also possible for the same string to serve as an alias key in one group and a canonical key in another group. (For example, `Newcastle` appears as an alias key in two different groups, referring to two different locations, canonically known as `Newcastle upon Tyne`, for the city in England, and `Newcastle, New South Wales`, for the city in New South Wales, Australia; and `Birmingham` appears both as a canonical key in the group of English cities and an alias key for canonical `Birmingham, Alabama` in the group of US cities.) The corresponding value objects are different for canonical and alias keys. Corresponding to canonical keys are ''location specs'', describing the properies of the location that cannot be derived from default properties of the group or global defaults. Corresponding to alias keys are ''alias specs'', which are highly restricted in the properties they can contain, and whose properties do not have per-group defaults, but only global defaults. The canonical key is always the same as the bare category corresponding to the location, which is one of the reasons it must be globally unique. For example, the country of Georgia uses the canonical key `Georgia` and corresponding bare category [[:Category:Georgia]], while the US state of Georgia uses the canonical key `Georgia, USA` and corresponding bare category [[:Category:Georgia, USA]]. The following conventions are followed in naming keys: * Countries, ''country-like entities'' (which are a mixture of unrecognized de-facto states and dependent territories) and ''former countries'' (which also includes other types of polities, such as the Roman Empire) use their unqualified placename as the canonical key. (See the documentation for [[Module:place]] for the distinction between keys and placenames, which is critical to understand when working with location data.) This also applies to constituent countries (such as England, Aruba and the Faroe Islands) and constituent parts of grouped dependent territories (such as the island of Saint Helena, which is administratively part of the British overseas territory of Saint Helena, Ascension and Tristan da Cunha). * Cities (including prefecture-level cities in China, which behave in most respects more like non-city administrative divisions) also normally use their unqualified placename as the canonical key, but if this causes name conflicts or ambiguities, they use a ''qualified key'' containing either the country name or immediate containing division (if different) following a comma, such as the case of `Newcastle, New South Wales` and `Birmingham, Alabama` above. Examples of name conflicts are the two cities just given; examples of ambiguities are the major cities of León and Mérida in Mexico and city of Cartagena, Colombia, which are given the respective canonical keys of `León, Guanajuato`, `Mérida, Yucatán` and `Cartagena, Colombia` to avoid ambiguity with the well-known respective cities of the same name in Spain, even though none of those cities are large enough to be included as known locations in this module. (The cutoff is generally having a metro area of at least 1,000,000 inhabitants, although there are exceptions.) * Administrative divisions of countries, other than the exceptions noted above for constituent countries and dependent territories, use a qualified key that contains the name of the country or constituent country in it, e.g. `Normandy, France` (a region), `Calvados, France` (a department in the region of Normandy), `Herefordshire, England` (a ceremonial county), `Northwest Territories, Canada` (a territory), `Central Finland, Finland` (a region), `Antalya Province, Turkey` (a province), `Cluj County, Romania` (a county), `County Cork, Ireland` (a county) and `New York, USA` (a state). As shown in these various examples, (a) first and second-level divisions are sometimes both included (as in France, the United Kingdom and China); (b) the qualifier after the comma is sometimes a constituent country (England) instead of a country (United Kingdom), and is sometimes abbreviated (USA rather than United States or Unites States of America); (c) the word `the` is not normally included in the key even if the location is normally preceded by `the` when following a preposition (there is a property in the location and alias specs to indicate this), except in a very few cases (most notably `The Hague`); (d) the country is included as a qualifier even if it creates an apparent redundancy, as with `Central Finland, Finland`; and (e) sometimes the placetype is included in the key, as with provinces in Turkey and several other countries; states in Nigeria; and counties in Ireland, Romania and several other countries. Whether the placetype is included, and whether it follows or precedes the placename, depends on per-country conventions. For example, provinces in Turkey, Iran and several other countries (likewise for states in Nigeria, oblasts in Russia, etc.) conventionally include the word "Province", "State", "Oblast" etc. in their name because they are normally named after the largest city in the division, which would otherwise lead to ambiguity; and counties in Ireland and Northern Ireland (and likewise County Durham, England) normally have the word "County" preceding rather than following them in their conventional name, so we follow this practice. The Wikipedia article naming scheme for a given administrative division is a strong clue as to how the division is normally referred to, and we usually follow this practice. (A minor exception is that the Wikipedia articles for provinces in Iran, Laos and Thailand include the word `province` with an initial lowercase letter while provinces elsewhere, e.g. North and South Korea, Saudi Arabia and Turkey, use uppercase `Province`; we normalize to uppercase `Province` in all cases.) As mentioned above, associated with canonical keys in the group data table are location specs, which are objects containing properties. It is important here to distinguish ''initialized specs'' from ''uninitialized specs''. Unininitialized specs are as directly specified in [[Module:place/locations]], containing only those properties that differ from the per-group or global defaults. Initialized specs result from calling `initialize_spec()` on an uninitialized spec (it is idempotent in that it will do nothing if encountering an already-initialized spec). This copies all group-level defaults that are not overridden in the location spec itself from the group-level metadata table into the location spec, so that in general, no more reference need be made to the group to fetch the correct value of a given location property. (The initialization process also does more transformations in a few cases, noted below.) Note that the default value of a given property is stored under a key in the group metadata table that is preceded by the string `default_`; for example, the default value corresponding to the `placetype` property of a given location is specified in the `default_placetype` key in the group metadata table. The following are the properties of the location spec. * `placetype`: String specifying the placetype of the location (e.g. "country", "state", province"). This can also be a table of such types; in this case, the first listed type is the canonical type that will be used in descriptions, but the location will be recognized (e.g. in a holonym, or for categorizing into the bare category) when tagged with any of the specified types. The placetype '''must''' be either specified on an individual location or defaulted at the group level, or an error occurs. * `container`: Either a string, a ''canonicalized container'' structure or a list of either type, specifying the immediate ''container'' (or containers) of the given location. A container is another location which this location is considered to be directly part of, either politically or (above the country level) geographically. Some locations belong to multiple immediate containers; this applies especially to transcontinental countries such as Russia and Turkey. Containers can themselves have containers, forming a tree (or more correctly, a [[w:directed acyclic graph]]) of locations. The list of immediate container(s), followed by the container(s) of the container(s), etc., is termed the ''container trail'', and some functions compute and return this trail as part of their operation. When a location spec is initialized, the given container spec is canonicalized into ''canonical container form'', which consists of a list of canonicalized container structures, each of which is of the form `{key = "``container_key``", placetype = "``container_placetype``"}`, where ``container_key`` is a canonical location key and ``container_placetype`` should be the listed placetype for the location, or the first listed placetype if there are multiple. (FIXME: Since the key uniquely identifies the container location, we should eliminate the placetype from the container structure.) The list of canonicalized container structures is stored into the `.containers` field of the location spec (this happens even if the container value is unset in its uninitialized spec form, causing it to default to the corresponding group-level value), and the `.container` field is set to {nil}. The canonicalization process is described in more detail below under [[#Container spec canonicalization]]. * `divs`: List of recognized political divisions; e.g. for the Netherlands, a specification of the form `divs = {"provinces", "municipalities"}` will allow categories such as [[:Category:de:Provinces of the Netherlands]] and [[:Category:pt:Municipalities of the Netherlands]] to be created. Any division that appears here must also be found in `placetype_data`, or an error occurs. The entities appearing in the `divs` list can be structures as well as just strings; this is explained more below under [[#Location divisions]]. Additional political divisions that apply to all locations in a group can be specified at the group level using the group-only property `addl_divs`, which has the same format as `divs`. This is intended to be used in the situation where some division types are shared among all locations in the group and others differ from location to location. An example where this is used is the United States, where `census-designated places` is specified in the group-level `addl_divs` so that all 50 states have census-designated places categorized as e.g. [[:Category:Census-designated places in Arizona, USA]], but `counties` and `county seats` are specified in the group-level `default_divs` because not all states have counties and county seats (Alaska has boroughs and borough seats and Louisiana has parishes and parish seats), and some states have additional divisions (New Jersey and Pennsylvania also have boroughs, while Colorado and Connecticut have municipalities). Note that under most circumstances (particularly, if `container_parent_type` is not set as a property associated with the division type), any division type specified on a sub-country-level location must also be specified on all containers up through the country. For example, since French departments specify `communes` and `municipalities` in `default_divs`, the same division types must be (and are) specified on French regions and for France itself. * `keydesc`: String directly specifying a description of the location, for use in generating the contents of category pages related to the location. In place of a string, a function of three arguments (`group`, `key`, `spec`, as is normal for locations) that computes the location description can also be given. This is used, for example, for Russian federal subjects; see `construct_russia_federal_subject_keydesc`. The special string `+++` contained in the keydesc is replaced with the default value of the location description, which specifies the location's placename, placetype, and the corresponding values for each container in the container trail, generally up through (but not beyond) the country level; see `no_include_container_in_desc` below. The location description is used to construct the full description of various categories, such as bare location categories, whose description generally reads `"{{(((}}langname}}} terms related to the people, culture, or territory of ``keydesc``."` where ``keydesc`` is the specified or auto-constructed location description. * `fulldesc`: String overriding the full description for the bare location category (but not for any other category). This is currently used only for the location `Earth`, at the very top of the tree (because the standard `people, culture or territory of ...` text doesn't make sense here), and for `Antarctica` (because it has no permanent inhabitants). FIXME: This should be renamed `bare_category_fulldesc`. * `addl_parents`: Specify additional parents for the bare location category, in addition to the category or categories generated based on the immediate container(s). For example, `Hawaii, USA` specifies `Polynesia` as an additional parent category; both `North Korea` and `South Korea` specify `Korea` (which is a specially handled location category) as an additional parent; and `Earth` specifies `nature` (not a location category, but still a topic category) as an additional parent (which in this case becomes the first parent, as `Earth` has no container). The only restriction on the categories in `addl_parents` is that they must be topic categories, because each language-specific version of the bare location category gets the corresponding language-specific versions of the categories in `addl_parents`. FIXME: This shoudl be renamed `bare_category_addl_parents`. * `wp`: Spec describing how to construct the Wikipedia article for the location. Each spec is either `true` (equivalent to `"%l"`, i.e. use the full location placename directly) or a string containing formatting directives, indicating how to construct the article name. The allowed formatting directives are `%l` (the full location placename), `%e` (the elliptical location placename) and `%c` (the full placename of the first immediate container). For example, the default value of `wp` for the group of United States cities is `"%l, %c"` since the city articles tend to be named e.g. `Austin, Texas` (but with many exceptions, specified using `wp` fields at the city level). Another example is Thai provinces, which specify a group-level default of `"%e province"` as the Wikipedia articles have lowercase `province` in their name but the Thai province keys specified in this module have uppercase `Province`. Here we have to use `%e` to get the placename without the word `Province` in it. The default is `true`, which simply uses the full location placename as the article name. Note that the Wikipedia article, along with the Wikipedia and Commons category pages, are shown in the upper right of bare category pages. * `wpcat`: Spec describing how to construct the Wikipedia category page for the location (i.e. the page listing articles and categories relevant to the location). The format is the same as with `wp`, and it defaults to the value of `wp`. It rarely needs to be specified because the category page and the article page almost always follow the same format. * `commonscat`: Spec describing how to construct the Commons category page for the location (i.e. the page on the MediaWiki Commons site listing articles and categories relevant to the location). It has the same format as `wp` and `wpcat` and defaults to `wpcat`, which is usually (but not always) correct. * `the`: Boolean specifying whether a location should be preceded by `the` when following a preposition, e.g. in category names such as [[:Category:Cities in the Northern Territory, Australia]] and in old-style place descriptions when the location occurs as the first holonym, such as the city [[Darwin]] described using {{tl|place|city|terr/Northern Territory|c/Australia}}. Note that the global default for this and all Boolean properties is {nil}, which amounts to the same as {false}. * `british_spelling`: Boolean indicating whether the location in question uses British spelling. Currently this only affects whether the spelling `neighborhoods` or `neighbourhoods` is used in categories such as [[:Category:Neighborhoods of New York City]] and [[:Category:Neighbourhoods of Sydney]]. This usually needs to be set only at the top level (i.e. country or country-like entity), because lower-level entities look up the container trail for any container that has `british_spelling = true` set, and if found, assume that British spelling applies. The general principle used in setting this is that all countries in Europe, all dependent territories of any such country, all former British colonies, and any dependent territories of these former colonies, are assumed to use British spelling, while all other countries and associated dependent territories are assumed to use American spelling. This can potentially be modified on a case-by-case basis. * `is_city`: Boolean indicating whether the location in question is a city. This is explicitly set to `true` for city-states (e.g. Monaco and Vatican City), dependent territories that are cities (e.g. Hong Kong, Macau, Bonaire, Gibraltar, etc.), certain city-level administrative divisions (such as `City of Belfast, Northern Ireland`) and (through a group-levell setting) New York boroughs. In addition, it is set to `true` in initialize_spec() whenever the group-level `default_placetype == "city"`, so that all cities get it set without explicitly needing to add a group-level setting for this. Note that the condition `default_placetype == "city"` intentionally excludes Chinese prefecture-level cities, which aren't really cities in that (for example) they don't directly contain neighborhoods, but do contain cities within them. This setting is used in various places: (a) to add cities, rivers, etc. to categories like [[:Category:Rivers in Osaka Prefecture, Japan]] and [[:Category:Cities in Wuhan]] for holonyms that are ''not'' cities; (b) to add districts, neighborhoods, and the like to categories like [[:Category:Neighborhoods of Brooklyn]] and [[:Category:Neighborhoods of Monaco]] for holoynms that ''are'' cities; (c) generally, to determine which "generic" placetypes (cities, rivers, neighborhoods, etc.) apply to the location. (Those that can occur with cities have a `generic_before_cities` setting in [[Module:place/placetypes]], and those that can occur with non-cities have a `generic_before_non_cities` setting.) * `is_former_place`: Boolean that should be set on former places such as the Soviet Union and the Roman Empire. For such places, categories such as [[:Category:fr:Rivers in the Soviet Union]] are neither generated nor recognized (more generally, no "generic" placetypes apply except for `places`), and category descriptions include the word `former`. * `overriding_bare_label_parents`: Document me! * `bare_category_parent_type`: Document me! * `no_container_cat`: Document me! * `no_container_parent`: Document me! * `no_generic_place_cat`: Document me! * `no_check_holonym_mismatch`: Document me! * `no_auto_augment_container`: Document me! * `no_include_container_in_desc`: Document me! ====Location divisions==== The `divs` field of a location describes the recognized political division types of that location. Specifying a given division type will cause places defined as being of the specified division type and with the location as a holonym will cause the place to be categorized as ` ``placetypes`` in/of ``location`` `; for example, specifying that the United States has `"states"` as a division will cause anything defined as {{tl|place|fr|state|c/US}} to be categorized under [[:Category:fr:States of the United States]]. Note that you do not have to explicitly specify division types for "generic" placetypes (those that have a `generic_before_non_cities` field if the location is not a city, or that have a `generic_before_cities` field if the location is a city); this includes things like cities, towns, villages, neighbo(u)rhoods and rivers. A given element in the `divs` list is usually a string naming a plural placetype; the placetype is automatically converted to the singular for recognizing the placetype in a {{tl|place}} spec, and irregular plurals such as `kibbutzim` are handled correctly as long as the placetype specifies an appropriate `plural` field (if the `plural` isn't explicitly given, the default singularization algorithm in [[Module:en-utilities]] is run, which gets most things correctly but has problems with `passes` and `fortresses`, which are singularized to `passe` and `fortresse`; for this reason, an explicit plural entry is added to terms in ''-ss''). In place of a string, an object can be given with the plural placetype in the `type` field; this allows additional properties to be specified along with the placetype. An example of this is the `divs` list for Canada: { ["Canada"] = {divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, "counties", "districts", "municipalities", "regional municipalities", "rural municipalities", "parishes", "Indian reserves", "census divisions", {type = "townships", prep = "in"}, }, ...}, } Here, both provinces and territories are set to categorize as `provinces and territories`, meaning that there is a single category [[:Category:Provinces and territories of Canada]] rather than separate categories for provinces and territories. Similar things are done for other countries that have more than one type of first-level administrative division (e.g. Australia, China, India and Pakistan). Note that any placetype listed under `cat_as` must exist in the table of placetypes in [[Module:place/placetypes]], and in fact there is a category-only entry there for `provinces and territories!` (the use of exclamation point following a plural placetype means that the placetype is present only for use in categories and won't be recognized as the placetype field in a {{tl|place}} description). In addition, townships are declared to use `in` rather than `of` as the preposition in the category; hence the category name will be [[:Category:Townships in Canada]] rather than [[:Category:Townships of Canada]]. (The use of `in` vs. `of` is somewhat related to whether a given placetype is an official administrative or statistical division of the location in question and comes in a defined list, in which case `of` should be used, or is more ill-defined, in which case `in` should be used; the default is `of`, and the use of `in` with `townships` is probably by analogy with the use of `in` with cities and towns.) Another more complex example is the divisions given for Quebec: { ["Quebec, Canada"] = {divs = { "counties", {type = "regional county municipalities", container_parent_type = "regional municipalities"}, {type = "regions", container_parent_type = false}, {type = "townships", prep = "in"}, {type = "parish municipalities", cat_as = {{type = "parishes", container_parent_type = "counties"}, "municipalities"}}, {type = "township municipalities", cat_as = {{type = "townships", prep = "in"}, "municipalities"}}, {type = "village municipalities", cat_as = {{type = "villages", prep = "in"}, "municipalities"}}, }, ...}, } Here, `container_parent_type` controls the second parent category of the placetype/location category associated with the entry. In this case, for example, [[:Category:Counties of Quebec, Canada]] will have [[:Category:Counties of Canada]] as its second or ''container-level'' parent. However, this doesn't make sense for `regional county municipalities`, which exist only in Quebec (so the parent category [[:Category:Regional county municipalities of Canada]] would have only one subcategory); but they are similar to regional municipalities in British Columbia, Nova Scotia and Ontario, so the `container_parent_type = "regional municipalities"` spec causes the container-level parent of this category to be [[:Category:Regional municipalities of Canada]]. Likewise, `regions` as administrative divisions (as opposed to mere geographic regions) exist only in Quebec; they have no equivalent elsewhere, so we disable the container-level parent using `container_parent_type = false`. The specs for `parish municipalities`, `township municipalities` and `village municipalities` show both that multiple types can be specified under `cat_as` (here, for example, we categorize `parish municipalities` as both `parishes` and `municipalities`) and that these types can themselves have properties, just as for entries directly under `divs`. Specifically, `{type = "parishes", container_parent_type = "counties"}` means that any place defined as a parish municipality in Quebec will be categorized under both [[:Category:Parishes of Quebec, Canada]] and [[:Category:Municipalities of Quebec, Canada]], and that the former will have a container-level parent of [[:Category:Counties of Canada]] (rather than the default of [[:Category:Parishes of Canada]]). Similarly, `township municipalities` will be categorized under both [[:Category:Townships in Quebec, Canada]] (''not'' [[:Category:Townships of Quebec, Canada]]) and [[:Category:Municipalities of Quebec, Canada]]. ====Container spec canonicalization==== A fully canonicalized container spec for a given location consists of a list of ''canonicalized container objects'', each with a `key` and `placetype` field. The `key` field should name the canonical key of some other location at a higher level (e.g. French cities are contained in French departments, which are contained in French regions, which are contained in France, which is contained in Europe, which is contained in Eurasia, which is contained in the Earth). The `placetype` field should correspond to the first (canonical) placetype listed for the key in question. The process of initializing a locaion spec converts the container spec in `.container` into a canonicalized spec in `.containers` and removes the spec from `.container`. It works as follows: # If the `container` field is missing, and there is a group-level `default_container` field, it is used in its place. For example, none of the Brazilian states listed in `brazil_states` specifies a container, but the group specifies `default_container = "Brazil"`. # A single string or canonicalized container object is allowed and made into a one-element list. # If a list element is a string that did ''not'' come from `default_container`, and there is a group-level `canonicalize_key_container` field, it is assumed to be a one-argument function and is called on the string to get a canonicalized container object. # Any remaining strings are assumed to be countries and are used directly as the `key`, with `placetype` set to `"country"`. ====Alias keys==== Aliases can be provided for canonical keys using ''alias keys''. Alias keys have a very different location spec structure from canonical keys. This structure does not, in general, have defaults at the group level and is not initialized using `initialize_spec()`, but is used as-is. The following properties are recognized in an alias location spec: * `alias_of`: The canonical key of which this key is an alias. Required. * `the`: If true, this alias key is preceded by `the` following a preposition. Defaults to the group-level `default_the` but does not pay attention to the value of `the` for the corresponding canonical key. * `display`: This is a display alias, meaning that holonyms using the placename corresponding to this alias will be converted to the placename corresponding to the canonical key when formatting the holonym for display. (Otherwise, the aliasing applies only to categorization.) If the value is true, the display canonicalization is to the placename of the canonical key; otherwise, the value should be a key whose corresponding placename is used when display canonicalizing. * `placetype`: The placetype of the alias. Rarely needs to be specified as it defaults to the canonical key's placetype, and if that is unspecified, to the group-level default placetype. ====Location group metadata tables==== As mentioned above, associated with each location group is a ''metadata table'' listing group-level properties. The metadata table contains two types of keys: group-level defaults (named like the corresponding location-level keys but preceded by `default_`, e.g. `default_placetype` corresponding to the location-level `placetype` key) and group-only keys, which are mostly functions. The following are the possible group-only keys: * `data`: This points to the group data table for the group, as described above. * `key_to_placename`: This is a function of one argument to transform the location's key (whether canonical or alias) into the full and elliptical placenames. The difference between full and elliptical placenames is described in the documentation for [[Module:place]], but in essence, it applies for keys that include the placetype in them (e.g. `Phuket Province, Thailand` or `County Mayo, Ireland`), in which case the full placename includes the placetype and the elliptical placename does not. For keys that do not include the placetype in them (e.g. `Arizona, USA` or `Gloucestershire, England`), the full and elliptical placenames are identical. Note that neither the full nor the elliptical placename includes the container in it; hence, for `Phuket Province, Thailand`, the full placename is `Phuket Province` and the elliptical placename is just `Phuket`. (Note that the full vs. elliptical placename distinction is intended only for handling cases where the placetype follows or precedes the raw placename and there is no difference between the two in whether they are normally preceded by `the`. More complex situations, such as `State of Mexico` (which normally takes `the`) vs. just `Mexico` (which doesn't), or `Islamabad Capital Territory` vs. just `Islamabad`, should be handled instead by aliases.) The `key_to_placename` function takes one argument, the key, and returns two arguments, the full and elliptical placenames, respectively. If left undefined, the default is to chop off anything starting with a comma and return the result as both full and elliptical placename, and if specifically set to `false`, the key is used directly as both full and elliptical placename. If it needs to be defined, it is best to use the helper function `make_key_to_placename`, if possible (or `make_irish_type_key_to_placename` in the case of Ireland and Northern Ireland, where `County` precedes), rather than rolling your own. In addition, you should use the global `key_to_placename` function (which takes care of the default implementation and such) rather than directly calling the function in the `key_to_placename` field. * `placename_to_key`: This is approximately the inverse of `key_to_placename`, transforming a placename (which can be either in full or elliptical form) into the corresponding key. As with `key_to_placename`, if you need to define this (generally, when the full and elliptical placenames are different), prefer using `make_placename_to_key` (or `make_irish_type_placename_to_key` for Ireland and Northern Ireland) to rolling your own. In addition, similarly to `key_to_placename`, use the global `placename_to_key` function to convert placenames to keys rather than directly invoking the function in the `placename_to_key` field. If the field is set to `false`, the placename is used unchanged as the key. Otherwise, the default algorithm works as follows: *# If the group-level `default_placetype == "city"`, use the placename unchanged as the key. *# Otherwise, if the group-level `default_container` exists and is a string, append it to the placename after a comma + space and use the result as the key. *# Otherwise, if the group-level `default_container` is a canonical container object (an object with `key` and `placetype` fields), and the `placetype` field is either `country` or `constituent country`, append the `key` field to the placename after a comma + space and use the result as the key. *# Otherwise, use the placename unchanged as the key. * `canonicalize_key_container`: A function of one argument to convert the specified `container` field, when a string, to canonical form. Described in more detail above under [[#Container spec canonicalization]]. It is preferable to construct the function using `make_canonicalize_key_container`, if possible, rather than rolling your own. * `addl_divs`: Additional political divisions appended, for all locations in the group, to the list of divisions derived from the location-level `divs` or group-level `default_divs` fields to get the final list of divisions for the location. See [[#Location divisions]] for more details. ]==] ----------------------------------------------------------------------------------- -- Helper functions -- ----------------------------------------------------------------------------------- --[==[ Throw an error. `fmt` is a format string and the remaining arguments are passed through `mw.dumpObject` and then used to format the format string as if `fmt:format(...)` were called. In general, callers should use `internal_error` unless the error was due to bad user input rather than a logic error (which usually isn't the case in deep back-end code like this). ]==] function export.process_error(fmt, ...) local args = {...} for i = 1, select("#", ...) do args[i] = dump(args[i]) end return error(string.format(fmt, unpack(args))) end --[==[ Throw an internal error (a logic error that should never happen unless there is a bug in the code, as opposed to a user error triggered by bad input or a system error due to something like running out of memory or hitting a time limit). `fmt` is a format string and the remaining arguments are passed through `mw.dumpObject` and then used to format the format string as if `fmt:format(...)` were called. ]==] function export.internal_error(fmt, ...) export.process_error("Internal error: " .. fmt, ...) end local internal_error = export.internal_error -- Return whether `list_or_element` (a list of strings, or a single string) "contains" `item` (a string). If -- `list_or_element` is a list, this returns true if `item` is in the list; otherwise it returns true if `item` -- equals `list_or_element`. local function list_or_element_contains(list_or_element, item) if type(list_or_element) == "table" then return m_table.contains(list_or_element, item) and true or false end return list_or_element == item end --[==[ Call the location group's `key_to_placename` function if it exists (see the comment at the top of [[Module:place]] for the distinction between keys and placenames). Two values are returned, the full and elliptical placenames (e.g. full `"County Durham"` vs. elliptical `"Durham"`). If the group does not define `key_to_placename`, both full and elliptical placenames are computed by chopping off anything starting with a comma. ]==] function export.key_to_placename(group, key) if group.key_to_placename == false then return key, key end if group.key_to_placename then local full_placename, elliptical_placename = group.key_to_placename(key) if type(full_placename) ~= "string" then internal_error("Key %s returned a non-string full placename: %s", key, full_placename) end if type(elliptical_placename) ~= "string" then internal_error("Key %s returned a non-string elliptical placename: %s", key, elliptical_placename) end return full_placename, elliptical_placename end key = key:gsub(",.*", "") return key, key end --[==[ Call the location group's `placename_to_key` function if it exists (see the comment at the top of [[Module:place]] for the distinction between keys and placenames) and return the result. If `placename_to_key` exists with the value `false`, return the placename unchanged. If the group does not define `placename_to_key`, and it defines a `default_container` whose placetype is either `country` or `constituent country`, the container name is appended to the placename after a comma and a space. Otherwise the placename is returned unchanged. ]==] function export.placename_to_key(group, placename) if group.placename_to_key == false then return placename elseif group.placename_to_key then local key = group.placename_to_key(placename) if type(key) ~= "string" then internal_error("Placename %s returned a non-string key: %s", placename, key) end return key elseif group.default_placetype == "city" then return placename else local defcon = group.default_container if not defcon then return placename elseif type(defcon) == "string" then return placename .. ", " .. defcon elseif type(defcon) == "table" and (defcon.placetype == "country" or defcon.placetype == "constituent country") then return placename .. ", " .. defcon.key else return placename end end end --[==[ Initialize the location spec `spec`, augmenting it with default values taken from `group` if the spec itself doesn't specify values for the properties. This sets `containers` to a canonicalized list of objects, each with `key` and `placetype` keys, describing the immediate containers of the location, and erases (sets to nil) the original non-canonicalized `container` field. (Most locations have only one immediate container but some, e.g. Russia, have more than one. Containers should be carefully distinguished from category parents. Generally the container is the first category parent, or the first ``n`` parents if there are ``n`` containers, but there may be additional category parents, which indicate some sort of relation between the category parent and the location but not necessarily one of containment.) This function is idempotent in that nothing happens if called more than once on the same spec. FIXME: Consider reimplementing this in a more standardly object-oriented way using metatables. ]==] function export.initialize_spec(group, key, spec) if spec.initialized then return end local container = spec.container local containers local container_from_default if not container then container = group.default_container container_from_default = true end if container then if type(container) == "string" or container.key then container = {container} end containers = {} for _, cont in ipairs(container) do if type(cont) == "string" then if group.canonicalize_key_container and not container_from_default then cont = group.canonicalize_key_container(cont) else cont = {key = cont, placetype = "country"} end end insert(containers, cont) end end spec.containers = containers spec.container = nil local function value_with_default(val, default_val) if val == nil then return default_val else return val end end local function set_or_default(prop) spec[prop] = value_with_default(spec[prop], group["default_" .. prop]) end set_or_default("placetype") if not spec.placetype then internal_error("No placetype found in key %s for spec %s or in group `default_placetype`", key, spec) end set_or_default("divs") spec.addl_divs = group.addl_divs for _, prop in ipairs { "keydesc", "fulldesc", "addl_parents", "overriding_bare_label_parents", "bare_category_parent_type", "wp", "wpcat", "commonscat", "british_spelling", "the", "no_container_cat", "no_container_parent", "no_generic_place_cat", "no_check_holonym_mismatch", "no_auto_augment_container", "no_include_container_in_desc", "is_city", "is_former_place", } do set_or_default(prop) end -- `default_placetype == "city"` is correct; if `default_placetype` has something else like `prefecture-level city` -- as the canonical placetype but also lists `city` (as Chinese prefecture-level cities do), don't mark as -- is_city. spec.is_city = value_with_default(spec.is_city, group.default_placetype == "city") spec.initialized = true end --[=[ Given a location group, key and possible placetypes that the placename must match, check if the key exists in the group with at least one of the group's key's placetypes matching one of the passed-in placetypes. If so, return two values: the group key (which potentially could differ from the passed-in key due to aliases) and the corresponding spec object, which (as with all functions that return spec objects) has been initialized using `initialize_spec()` (i.e. default property values have been copied from the group into the spec, if the spec doesn't itself specify a value for the property in question). `alias_resolution` controls how aliases are resolved. Normally, both display and category aliases are followed, and the returned key will reflect the canonical location key. However, if `alias_resolution` is {"none"}, no alias following happens. In that case, if the key specifies an alias, the spec for the alias rather than the spec for the canonical location is returned, and importantly, it is returned uninitialized, meaning that properties from the group are not copied into the spec. (If the key specifies a canonical location, its spec is returned initialized, as in the normal case where `alias_resolution` is unspecified.) The caller needs to check whether the returned spec is an alias by looking for an `alias_of` property. If `alias_resolution` is {"display"}, the behavior is the same as for {"none"} except that if the alias contains a setting `display = true`, the returned key will reflect the canonical location key, and if the alias contains a setting `display = ``string`` `, the returned key will reflect that string. This is a low-level function meant for internal use; external callers should generally use `get_matching_location` (for internally-derived locations), `find_matching_holonym_location` (for externally-derived locations) or `find_canonical_key` (for known-canonical locations where the placetype isn't known). ]=] local function find_matching_key_in_group(group, placetypes, key, alias_resolution) if alias_resolution ~= nil and alias_resolution ~= "none" and alias_resolution ~= "display" and alias_resolution ~= "all" then internal_error("Bad value for 'alias_resolution': %s", alias_resolution) end local spec = group.data[key] if not spec then return nil end local function check_correct_placetype(placetype) if type(placetype) == "table" then for _, pt in ipairs(placetype) do if list_or_element_contains(placetypes, pt) then return true end end return false else return list_or_element_contains(placetypes, placetype) end end if spec.alias_of then local resolved_key = spec.alias_of local resolved_spec = group.data[resolved_key] if not resolved_spec then internal_error("Key %s is an alias of %s, which doesn't exist", key, resolved_key) elseif resolved_spec.alias_of then internal_error("Key %s is an alias of %s, which is itself an alias; indirect aliasing not allowed", key, resolved_key) end if alias_resolution == "none" or alias_resolution == "display" then -- We could be working with non-initialized/defaulted spec, since we're pulling it directly from the group. local placetype = spec.placetype or resolved_spec.placetype or group.default_placetype if not placetype then internal_error("No placetype found for key %s in any of spec %s, alias-resolved spec %s or in group " .. "`default_placetype`", key, spec, resolved_spec) end if not check_correct_placetype(placetype) then return nil end if alias_resolution == "display" then if spec.display == true then key = resolved_key elseif spec.display then key = spec.display end end return key, spec end key = resolved_key spec = resolved_spec end -- We could be working with non-initialized/defaulted spec, since we're pulling it directly from the group. local placetype = spec.placetype or group.default_placetype if not placetype then internal_error("No placetype found for key %s in spec %s or group `default_placetype`", key, spec) end if not check_correct_placetype(placetype) then return nil end export.initialize_spec(group, key, spec) return key, spec end --[=[ Given a location group, placename and possible placetypes that the placename must match, check if the placename exists in the group with at least one of the placetypes of the key in the group that corresponds to the placename matching one of the passed-in placetypes. If so, return two values: the key corrsponding to the passed-in placename and the corresponding spec object. This is similar to `find_matching_key_in_group()` but works with placenames rather than keys. `alias_resolution` is as in `find_matching_key_in_group()`. This is a low-level function meant for internal use; external callers should generally use `get_matching_location` (for internally-derived locations), `find_matching_holonym_location` (for externally-derived locations) or `find_canonical_key` (for known-canonical locations where the placetype isn't known). ]=] local function find_matching_placename_in_group(group, placetypes, placename, alias_resolution) local key = export.placename_to_key(group, placename) return find_matching_key_in_group(group, placetypes, key, alias_resolution) end --[==[ If `key` is a canonical known location key (i.e. not an alias), return the corresponding group and initialized spec. If no such key exists, return {nil}. This throws an internal error if two locations with the same key are found. ]==] function export.find_canonical_key(key) local found_locations = {} for _, group in ipairs(export.locations) do local spec = group.data[key] if not spec then -- do nothing elseif spec.alias_of then mw.log(("Skipping alias '%s' of canonical '%s'"):format(key, spec.alias_of)) else insert(found_locations, {group, spec}) end end if not found_locations[1] then return nil elseif found_locations[2] then internal_error("Found multiple matching locations for canonical key %s: %s", key, found_locations) else local group, spec = unpack(found_locations[1]) export.initialize_spec(group, key, spec) return group, spec end end --[==[ Iterator that returns all locations matching a given description, where the description consists of either a placename or a key along with a list of possible placetypes. Usually there will be at most one such location. The iterator returns three values at each iteration: the location group, canonical key by which the location is known and the spec object describing the location. `data` contains the following possible fields: * `placetypes`: A list of possible placetypes, one of which must match one of the location's placetypes; or a string specifying a placetype, which must match one of the location's placetypes. This must be specified. * `placename`: The placename of the location. Either this or `key` must be specified. * `key`: The key of the location. Either this or `placename` must be specified. * `alias_resolution`: If specified, it behaves the same as for `find_matching_key_in_group`. The spec is normally initialized using `initialize_spec()` prior to it being returned (but may not be if `alias_resolution` is given and the specified key or placename is an alias; see the documentation for `find_matching_key_in_group`). ]==] function export.iterate_matching_location(data) local i = 0 local n = #export.locations return function() while true do i = i + 1 if i > n then break end local group = export.locations[i] local key, spec if data.placename then key, spec = find_matching_placename_in_group(group, data.placetypes, data.placename, data.alias_resolution) else if not data.key then internal_error("'.placename' or '.key' must be defined: %s", data) end key, spec = find_matching_key_in_group(group, data.placetypes, data.key, data.alias_resolution) end if key then return group, key, spec end end end end --[==[ Return the location matching a given description, where the description consists of either a placename or a key along with a list of possible placetypes. This is similar to `iterate_matching_location()` but throws an internal error if there is not exactly one location found; as such, it is for use with internally specified locations (such as the containers of known locations) rather than externally specified locations, which may not match a known location and in some cases may match multiple known locations. For finding an externally specified location, consider using `find_matching_holonym_location`, which returns {nil} rather than throwing an error if the location isn't found, but also (more importantly) checks to make sure there are no conflicting holonyms among the user-specified holonyms (e.g. {{tl|place|city|s/Delaware|c/USA|t=Newark}} will not match the known location `Newark` (in New Jersey, not Delaware). ]==] function export.get_matching_location(data) local all_found = {} for group, key, spec in export.iterate_matching_location(data) do insert(all_found, {group, key, spec}) end if not all_found[1] then internal_error("Couldn't find matching location for data %s", data) elseif all_found[2] then internal_error("Found multiple matching locations for data %s: %s", data, all_found) else return unpack(all_found[1]) end end --[==[ Successively iterate over a location's containers, and then the containers of those containers, etc. Keep in mind that locations may have multiple containers (e.g. Russia has both Europe and Asia as containers, and both Europe and Asia have Eurasia as their container). A given container will never be returned twice (e.g. in the case where a specific location A has locations B and C as containers, and B has C as its container, C will not be returned twice). An internal error happens if a container loop is detected. The return value is a list of location objects, each of which contains `group`, `key` and `spec` fields. ]==] function export.iterate_containers(group, key, spec) local keys_seen = {} keys_seen[key] = true local iterations = 0 local last_iteration_containers = {{group = group, key = key, spec = spec}} return function() iterations = iterations + 1 if iterations > 10 then internal_error("Probable loop in containers when processing key %s", key) end local next_iteration_containers = {} for _, location in ipairs(last_iteration_containers) do local containers = location.spec.containers if containers then for _, container in ipairs(containers) do local container_group, container_key, container_spec = export.get_matching_location { placetypes = container.placetype, key = container.key, } if not keys_seen[container_key] then insert(next_iteration_containers, { group = container_group, key = container_key, spec = container_spec }) keys_seen[container_key] = true end end end end if not next_iteration_containers[1] then return nil end last_iteration_containers = next_iteration_containers return next_iteration_containers end end --[==[ Given a placename, convert it into a link (two-part if `display_form` is given and differs from `placename`) and add `"the "` to the beginning if called for in `spec`. ]==] function export.construct_linked_placename(spec, placename, display_form) local linked_placename = display_form and placename ~= display_form and ("[[%s|%s]]"):format(placename, display_form) or ("[[%s]]"):format(placename) if spec.the then linked_placename = "the " .. linked_placename end return linked_placename end --[=[ This is typically used to define `key_to_placename`. It generates a function that chops off parts of a string (a location key), typically at the end, in order to get the full and elliptical versions of a placename. (See the documentation above for `key_to_placename` under "Location group tables" for the difference between full and elliptical placenames.) `container_patterns` is a Lua pattern or a list of possible patterns matching the container at the end of the key, which will be used to remove that container. If multiple patterns are specified, each one is tried until one matches. If `container_patterns` is omitted, this part of the process is skipped. The reulting string becomes the full placename. If `divtype_patterns` is specified, it is likewise either a Lua pattern or list of possible patterns to match and remove the political division affixed onto the end (or possibly the beginning) of the key in the keys of certain countries (such as South Korean and North Korean counties, which include the word "County" in the key). The resulting chopped string becomes the elliptical placename. If `divtype_patterns` is omitted, this part of the process is skipped and the full and elliptical placenames are the same. Typical usage is as follows: ``` key_to_placename = make_key_to_placename(", England$"), ``` or (when the political division is part of the key) ``` key_to_placename = make_key_to_placename(", South Korea$", " County$") ``` ]=] local function make_key_to_placename(container_patterns, divtype_patterns) if type(container_patterns) == "string" then container_patterns = {container_patterns} end if type(divtype_patterns) == "string" then divtype_patterns = {divtype_patterns} end return function(key) local full_placename = key if container_patterns then for _, container_pattern in ipairs(container_patterns) do local nsubs full_placename, nsubs = full_placename:gsub(container_pattern, "") if nsubs > 0 then break end end end local elliptical_placename = full_placename if divtype_patterns then for _, divtype_pattern in ipairs(divtype_patterns) do local nsubs elliptical_placename, nsubs = elliptical_placename:gsub(divtype_pattern, "") if nsubs > 0 then break end end end return full_placename, elliptical_placename end end --[=[ This is typically used to define `placename_to_key`. It generates a function that appends a string to the end of a given placename to get the key (see the definition of `placename_to_key` above in the documentation under "Location group tables"). Optional `divtype_suffix` is a raw string (which should not contain hyphens or other characters that have special meaning in Lua patterns) to be appended first to the placename; if already present at the end, it is not appended. `container_suffix` is then added in the same fashion if given. Typical usage is like this: ``` placename_to_key = make_placename_to_key(", England") ``` (which will convert e.g. `"Hampshire"` into `"Hampshire, England"`) or ``` placename_to_key = make_placename_to_key(", South Korea", " County") ``` (which will convert e.g. `"Gangwon"` or `"Gangwon County"` into `"Gangwon County, South Korea"`). ]=] local function make_placename_to_key(container_suffix, divtype_suffix) return function(placename) local key = placename if divtype_suffix then if not key:find(divtype_suffix .. "$") then key = key .. divtype_suffix end end if container_suffix then key = key .. container_suffix end return key end end --[=[ This is typically used to define `canonicalize_key_container`, which converts a container as specified in the location data into the canonical form containing both the full container key and its placetype. It generates a function to do the canonicalization of a given container. If the container is a string, `suffix` is appended onto the string (use {nil} or {""} if there is no suffix to append), and the placetype is set to `placetype`. Otherwise the container is left as-is. Typical usage is like this: ``` canonicalize_key_container = make_canonicalize_key_container(", Canada", "province") ``` which will convert e.g. `"Ontario"` into `{key = "Ontario, Canada", placetype = "province"}`. ]=] local function make_canonicalize_key_container(suffix, placetype) return function(container) if type(container) == "string" then return {key = container .. (suffix or ""), placetype = placetype} else return container end end end ----------------------------------------------------------------------------------- -- Top-level tables -- ----------------------------------------------------------------------------------- export.continents = { ["Earth"] = {the = true, placetype = "planet", addl_parents = {"nature"}, fulldesc = "=the planet [[Earth]] and the features found on it"}, ["Africa"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}}, ["America"] = {placetype = {"supercontinent", "continent"}, container = {key = "Earth", placetype = "planet"}, keydesc = "[[America]], in the sense of [[North America]] and [[South America]] combined", wp = "Americas"}, ["Americas"] = {alias_of = "America", the = true}, ["North America"] = {placetype = "continent", container = {key = "America", placetype = "supercontinent"}}, ["Caribbean"] = {the = true, placetype = {"continental region", "region"}, container = {key = "North America", placetype = "continent"}}, ["Central America"] = {placetype = {"continental region", "region"}, container = {key = "North America", placetype = "continent"}}, ["South America"] = {placetype = "continent", container = {key = "America", placetype = "supercontinent"}}, ["Antarctica"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}, fulldesc = "=the territory of [[Antarctica]]"}, ["Eurasia"] = {placetype = {"supercontinent", "continent"}, container = {key = "Earth", placetype = "planet"}, keydesc = "[[Eurasia]], i.e. [[Europe]] and [[Asia]] together"}, ["Asia"] = {placetype = "continent", container = {key = "Eurasia", placetype = "supercontinent"}}, ["Europe"] = {placetype = "continent", container = {key = "Eurasia", placetype = "supercontinent"}}, ["Oceania"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}}, ["Melanesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, ["Micronesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, ["Polynesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, } export.continents_group = { default_overriding_bare_label_parents = {}, -- container parents should be used default_divs = {{type = "countries", prep = "in"}}, -- It's enough to mention the first-level continent or continent group. It seems excessive to write e.g. -- "El Salvador, a country in Central America, a continental region in North America, a continent in America, ...". default_no_include_container_in_desc = true, default_no_container_cat = true, default_no_container_parent = true, default_no_auto_augment_container = true, default_no_generic_place_cat = true, -- French Guyana is in France but not in Europe, which should not be an issue, so don't check holonym mismatches at -- this level. We also run into problems with supercontinents, which have "continent" as the fallback and cause -- mismatches. default_no_check_holonym_mismatch = true, data = export.continents, } -- Countries: including those with partial recognition that are normally considered countries (e.g. Kosovo, Taiwan). export.countries = { ["Afghanistan"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Albania"] = {container = "Europe", divs = {"counties", "municipalities", "communes", {type = "administrative units", cat_as = "communes"}, }, british_spelling = true}, ["Algeria"] = {container = "Africa", divs = {"provinces", "communes", "districts", "municipalities"}}, ["Andorra"] = {container = "Europe", divs = {"parishes"}, british_spelling = true}, ["Angola"] = {container = "Africa", divs = {"provinces", "municipalities"}}, ["Antigua and Barbuda"] = {container = "Caribbean", divs = {"provinces"}, british_spelling = true}, ["Argentina"] = {container = "South America", divs = {"provinces", "departments", "municipalities"}}, ["Armenia"] = {container = {"Europe", "Asia"}, divs = {"provinces", "districts", "municipalities"}, british_spelling = true}, ["Republic of Armenia"] = {alias_of = "Armenia", the = true}, -- differs in "the" -- Both a country and continent ["Australia"] = {container = "Oceania", divs = { {type = "states", cat_as = "states and territories"}, {type = "territories", cat_as = "states and territories"}, {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states and territories"}, {type = "ABBREVIATION_OF territories", cat_as = "abbreviations of states and territories"}, "local government areas", "dependent territories", }, british_spelling = true}, ["Austria"] = {container = "Europe", divs = {"states", "districts", "municipalities"}, british_spelling = true}, ["Azerbaijan"] = {container = {"Europe", "Asia"}, divs = {"districts", "municipalities"}, british_spelling = true}, ["Bahamas"] = {the = true, container = "Caribbean", divs = {"districts"}, british_spelling = true, wp = "The %l"}, ["Bahrain"] = {container = "Asia", divs = {"governorates"}}, ["Bangladesh"] = {container = "Asia", divs = {"divisions", "districts", "municipalities"}, british_spelling = true}, ["Barbados"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Belarus"] = {container = "Europe", divs = {"regions", "districts"}, british_spelling = true}, ["Belgium"] = {container = "Europe", divs = {"regions", "provinces", "municipalities"}, british_spelling = true}, ["Belize"] = {container = "Central America", divs = {"districts"}, british_spelling = true}, ["Benin"] = {container = "Africa", divs = {"departments", "communes"}}, ["Bhutan"] = {container = "Asia", divs = {"districts", "gewogs", "chiwogs"}}, ["Bolivia"] = {container = "South America", divs = {"provinces", "departments", "municipalities"}}, ["Bosnia and Herzegovina"] = {container = "Europe", divs = {"entities", "cantons", "municipalities"}, british_spelling = true}, ["Bosnia and Hercegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia-Herzegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia-Hercegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Botswana"] = {container = "Africa", divs = {"districts", "subdistricts"}, british_spelling = true}, ["Brazil"] = {container = "South America", divs = { "states", "municipalities", "macroregions", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, }}, ["Brunei"] = {container = "Asia", divs = {"districts", "mukims"}, british_spelling = true}, ["Bulgaria"] = {container = "Europe", divs = {"provinces", "municipalities"}, british_spelling = true}, ["Burkina Faso"] = {container = "Africa", divs = {"regions", "departments", "provinces"}}, ["Burundi"] = {container = "Africa", divs = {"provinces", "communes"}}, ["Cambodia"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Cameroon"] = {container = "Africa", divs = {"regions", "departments"}}, ["Canada"] = {container = "North America", divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, {type = "ABBREVIATION_OF provinces", cat_as = "abbreviations of provinces and territories"}, {type = "ABBREVIATION_OF territories", cat_as = "abbreviations of provinces and territories"}, "counties", "districts", "municipalities", "regional municipalities", "rural municipalities", "parishes", -- Don't change the following to something more politically correct (e.g. "First Nations reserves") until/unless -- the Canadian government makes a similar switch (and note that as of Apr 18 2025, the Wikipedia article is -- still at [[w:Indian reserves]]). "Indian reserves", "census divisions", {type = "townships", prep = "in"}, }, british_spelling = true}, ["Cape Verde"] = {container = "Africa", divs = {"municipalities", "parishes"}}, ["Cabo Verde"] = {alias_of = "Cape Verde", display = true}, ["Central African Republic"] = {the = true, container = "Africa", divs = {"prefectures", "subprefectures"}}, ["CAR"] = {alias_of = "Central African Republic", display = true, the = true}, ["C.A.R"] = {alias_of = "Central African Republic", display = true, the = true}, ["Chad"] = {container = "Africa", divs = {"regions", "departments"}}, ["Chile"] = {container = "South America", divs = {"regions", "provinces", "communes"}}, ["China"] = {container = "Asia", divs = { {type = "provinces", cat_as = "provinces and autonomous regions"}, {type = "autonomous regions", cat_as = "provinces and autonomous regions"}, {type = "FORMER provinces", cat_as = "former provinces"}, "special administrative regions", "prefectures", {type = "FORMER prefectures", cat_as = "former prefectures"}, "prefecture-level cities", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, {type = "FORMER counties", cat_as = "former counties and county-level cities"}, {type = "FORMER county-level cities", cat_as = "former counties and county-level cities"}, -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities. "districts", {type = "FORMER districts", cat_as = "former districts"}, "subdistricts", "townships", "municipalities", {type = "direct-administered municipalities", cat_as = "municipalities"}, }}, ["People's Republic of China"] = {alias_of = "China", the = true}, -- differs in "the" ["Colombia"] = {container = "South America", divs = {"departments", "municipalities"}}, ["Comoros"] = {the = true, container = "Africa", divs = {"autonomous islands"}}, ["Costa Rica"] = {container = "Central America", divs = {"provinces", "cantons"}}, ["Croatia"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Cuba"] = {container = "Caribbean", divs = {"provinces", "municipalities"}}, ["Cyprus"] = {container = {"Europe", "Asia"}, divs = {"districts"}, british_spelling = true}, ["Czech Republic"] = {the = true, container = "Europe", divs = {"regions", "districts", "municipalities"}, british_spelling = true}, ["Czechia"] = {alias_of = "Czech Republic"}, -- differs in "the" ["Democratic Republic of the Congo"] = {the = true, container = "Africa", divs = {"provinces", "territories"}}, ["Congo"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["DRC"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["D.R.C"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["Denmark"] = {container = "Europe", divs = {"regions", "municipalities", "dependent territories"}, british_spelling = true, -- Wikipedia separates [[w:Denmark]] (constituent country) from [[w:Danish Realm]] (country) }, ["Djibouti"] = {container = "Africa", divs = {"regions", "districts"}}, ["Dominica"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Dominican Republic"] = {the = true, container = "Caribbean", divs = {"provinces", "municipalities"}, keydesc = "the [[Dominican Republic]], the country that shares the [[Caribbean]] island of [[Hispaniola]] with [[Haiti]]"}, ["East Timor"] = {container = "Asia", divs = {"municipalities"}, wp = "Timor-Leste"}, ["Timor-Leste"] = {alias_of = "East Timor", display = true}, ["Ecuador"] = {container = "South America", divs = {"provinces", "cantons"}}, ["Egypt"] = {container = "Africa", divs = {"governorates", "regions"}, british_spelling = true}, ["El Salvador"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Equatorial Guinea"] = {container = "Africa", divs = {"provinces"}}, ["Eritrea"] = {container = "Africa", divs = {"regions", "subregions"}}, ["Estonia"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Eswatini"] = {container = "Africa", british_spelling = true}, ["Swaziland"] = {alias_of = "Eswatini", display = true}, ["Ethiopia"] = {container = "Africa", divs = {"regions", "zones"}}, ["Federated States of Micronesia"] = {the = true, container = "Micronesia", divs = {"states"}}, ["Micronesia"] = {alias_of = "Federated States of Micronesia"}, ["Fiji"] = {container = "Melanesia", divs = {"divisions", "provinces"}, british_spelling = true}, ["Finland"] = {container = "Europe", divs = {"regions", "municipalities"}, british_spelling = true}, ["France"] = {container = "Europe", divs = {"regions", "cantons", "collectivities", "communes", {type = "municipalities", cat_as = "communes"}, "departments", {type = "prefectures", cat_as = {"prefectures", "departmental capitals"}}, {type = "French prefectures", cat_as = {"prefectures", "departmental capitals"}}, "dependent territories", "territories", "provinces", }, british_spelling = true}, ["Gabon"] = {container = "Africa", divs = {"provinces", "departments"}}, ["Gambia"] = {the = true, container = "Africa", divs = {"divisions", "districts"}, british_spelling = true, wp = "The %l"}, ["Georgia"] = {container = {"Europe", "Asia"}, divs = {"regions", "districts"}, keydesc = "the country of [[Georgia]], in [[Eurasia]]", british_spelling = true, wp = "%l (country)"}, ["Germany"] = {container = "Europe", divs = { "states", -- Bavaria, Baden-Württemberg, Hesse and North Rhine-Westphalia have administrative regions as divisions, but -- there aren't really enough of them to categorize per state. "regions", "municipalities", "districts"}, british_spelling = true}, ["Ghana"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Greece"] = {container = "Europe", divs = {"regions", "regional units", "municipalities", {type = "peripheries", cat_as = {"regions"}}, }, british_spelling = true}, ["Grenada"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Guatemala"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Guinea"] = {container = "Africa", divs = {"regions", "prefectures"}}, ["Guinea-Bissau"] = {container = "Africa", divs = {"regions"}}, ["Guyana"] = {container = "South America", divs = {"regions"}, british_spelling = true}, ["Haiti"] = {container = "Caribbean", divs = {"departments", "arrondissements"}}, ["Honduras"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Hungary"] = {container = "Europe", divs = {"counties", "districts"}, british_spelling = true}, ["Iceland"] = {container = "Europe", divs = {"regions", "municipalities", "counties"}, british_spelling = true}, ["India"] = {container = "Asia", divs = { {type = "states", cat_as = "states and union territories"}, {type = "union territories", cat_as = "states and union territories"}, {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states and union territories"}, {type = "ABBREVIATION_OF union territories", cat_as = "abbreviations of states and union territories"}, "divisions", "districts", "municipalities", }, british_spelling = true}, ["Indonesia"] = {container = "Asia", divs = {"regencies", "provinces", {type = "ABBREVIATION_OF provinces", cat_as = "abbreviations of provinces"}, }}, ["Iran"] = {container = "Asia", divs = {"provinces", "counties"}}, ["Iraq"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Ireland"] = {container = "Europe", addl_parents = {"British Isles"}, divs = {"counties", "districts", "provinces"}, british_spelling = true, wp = "Republic of %l"}, ["Republic of Ireland"] = {alias_of = "Ireland", the = true}, -- differs in "the" ["Israel"] = {container = "Asia", divs = {"districts"}}, ["Italy"] = {container = "Europe", divs = { "regions", "provinces", "metropolitan cities", "municipalities", {type = "autonomous regions", cat_as = "regions"}, }, british_spelling = true}, ["Ivory Coast"] = {container = "Africa", divs = {"districts", "regions"}}, -- We should really be using Ivory Coast (common name) but there are political ramifications to the use of -- Côte d'Ivoire so don't make it a display alias. ["Côte d'Ivoire"] = {alias_of = "Ivory Coast"}, ["Jamaica"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Japan"] = {container = "Asia", divs = {"prefectures", "subprefectures", "municipalities"}}, ["Jordan"] = {container = "Asia", divs = {"governorates"}}, ["Kazakhstan"] = {container = {"Asia", "Europe"}, divs = {"regions", "districts"}}, ["Kenya"] = {container = "Africa", divs = {"counties"}, british_spelling = true}, ["Kiribati"] = {container = "Micronesia", british_spelling = true}, ["Kosovo"] = {container = "Europe", divs = {"districts", "municipalities"}, british_spelling = true}, ["Kuwait"] = {container = "Asia", divs = {"governorates", "areas"}}, ["Kyrgyzstan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Laos"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Latvia"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["Lebanon"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Lesotho"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Liberia"] = {container = "Africa", divs = {"counties", "districts"}}, ["Libya"] = {container = "Africa", divs = {"districts", "municipalities"}}, ["Liechtenstein"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["Lithuania"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Luxembourg"] = {container = "Europe", divs = {"cantons", "districts"}, british_spelling = true}, ["Madagascar"] = {container = "Africa", divs = {"regions", "districts"}}, ["Malawi"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Malaysia"] = {container = "Asia", divs = {"states", "federal territories", "districts"}, british_spelling = true}, ["Maldives"] = {the = true, container = "Asia", divs = {"provinces", "administrative atolls"}, british_spelling = true}, ["Mali"] = {container = "Africa", divs = {"regions", "cercles"}}, ["Malta"] = {container = "Europe", divs = {"regions", "local councils"}, british_spelling = true}, ["Marshall Islands"] = {the = true, container = "Micronesia", divs = {"municipalities"}}, ["Mauritania"] = {container = "Africa", divs = {"regions", "departments"}}, ["Mauritius"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Mexico"] = {container = "North America", addl_parents = {"Central America"}, divs = { "states", "municipalities", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, }}, ["Moldova"] = {container = "Europe", divs = { {type = "districts", cat_as = "districts and autonomous territorial units"}, {type = "autonomous territorial units", cat_as = "districts and autonomous territorial units"}, "communes", "municipalities", }, british_spelling = true}, ["Monaco"] = {placetype = {"city-state", "country"}, container = "Europe", -- We want the first placetype to be 'city-state' so the description of Monaco says it's a city-state, but we -- want its parent to be "countries in Europe". bare_category_parent_type = {type = "countries", prep = "in"}, is_city = true, british_spelling = true}, ["Mongolia"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Montenegro"] = {container = "Europe", divs = {"municipalities"}}, ["Morocco"] = {container = "Africa", divs = {"regions", "prefectures", "provinces"}}, ["Mozambique"] = {container = "Africa", divs = {"provinces", "districts"}}, ["Myanmar"] = {container = "Asia", divs = {"regions", "states", "union territories", {type = "self-administered zones", cat_as = "self-administered areas"}, {type = "self-administered divisions", cat_as = "self-administered areas"}, "districts"}}, ["Burma"] = {alias_of = "Myanmar"}, -- not display-canonicalizing; has political connotations ["Namibia"] = {container = "Africa", divs = {"regions", "constituencies"}, british_spelling = true}, ["Nauru"] = {container = "Micronesia", divs = {"districts"}, british_spelling = true}, ["Nepal"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Netherlands"] = {the = true, placetype = {"country", "constituent country"}, container = "Europe", divs = {"provinces", "municipalities", {type = "FORMER municipalities", cat_as = "former municipalities"}, "dependent territories", "constituent countries"}, british_spelling = true, -- Wikipedia separates [[w:Netherlands]] (constituent country) from [[w:Kingdom of the Netherlands]] -- (country) }, ["New Zealand"] = {container = "Polynesia", divs = { "regions", "dependent territories", "territorial authorities", {type = "districts", cat_as = "territorial authorities"}, }, british_spelling = true}, ["Nicaragua"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Niger"] = {container = "Africa", divs = {"regions", "departments"}}, ["Nigeria"] = {container = "Africa", divs = { "states", -- Categorize the Federal Capital Territory as a state because there's only one of it; we could categorize -- everything under 'states and territories' but that seems a bit pointless. {type = "federal territories", cat_as = "states"}, "local government areas", }, british_spelling = true}, ["North Korea"] = {container = "Asia", addl_parents = {"Korea"}, divs = {"provinces", "counties"}}, ["North Macedonia"] = {container = "Europe", divs = {"regions", "municipalities"}, british_spelling = true}, ["Macedonia"] = {alias_of = "North Macedonia", display = true}, ["Republic of North Macedonia"] = {alias_of = "North Macedonia", the = true}, -- differs in "the" ["Republic of Macedonia"] = {alias_of = "North Macedonia", the = true}, -- differs in "the" ["Norway"] = {container = "Europe", divs = {"counties", "municipalities", "dependent territories", "districts", "unincorporated areas"}, british_spelling = true}, ["Oman"] = {container = "Asia", divs = {"governorates", "provinces"}}, ["Pakistan"] = {container = "Asia", divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "administrative territories", cat_as = "provinces and territories"}, {type = "federal territories", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, "divisions", "districts", }, british_spelling = true}, ["Palau"] = {container = "Micronesia", divs = {"states"}}, ["Palestine"] = {container = "Asia", divs = {"governorates"}}, ["State of Palestine"] = {alias_of = "Palestine", the = true}, -- differs in "the" ["Panama"] = {container = "Central America", divs = {"provinces", "districts"}}, ["Papua New Guinea"] = {container = "Melanesia", divs = {"provinces", "districts"}, british_spelling = true}, ["Paraguay"] = {container = "South America", divs = {"departments", "districts"}}, ["Peru"] = {container = "South America", divs = {"regions", "provinces", "districts"}}, ["Philippines"] = {the = true, container = "Asia", divs = {"regions", "provinces", "districts", "municipalities", "barangays"}}, ["Poland"] = {divs = {"voivodeships", "counties", {type = "Polish colonies", cat_as = {{type = "villages", prep = "in"}}}, }, container = "Europe", british_spelling = true}, ["Portugal"] = {container = "Europe", divs = { {type = "autonomous regions", cat_as = "districts and autonomous regions"}, {type = "districts", cat_as = "districts and autonomous regions"}, "provinces", "municipalities"}, british_spelling = true}, ["Qatar"] = {container = "Asia", divs = {"municipalities", "zones"}}, ["Republic of the Congo"] = {the = true, container = "Africa", divs = {"departments", "districts"}}, ["Congo Republic"] = {alias_of = "Republic of the Congo", display = true, the = true}, ["Romania"] = {container = "Europe", divs = { "regions", "counties", "communes", {type = "ABBREVIATION_OF counties", cat_as = "abbreviations of counties"}, }, british_spelling = true}, ["Russia"] = {container = {"Europe", "Asia"}, divs = { "federal subjects", "republics", "autonomous oblasts", "autonomous okrugs", "oblasts", "krais", "federal cities", "districts", "federal districts"}, british_spelling = true}, ["Rwanda"] = {container = "Africa", divs = {"provinces", "districts"}}, ["Saint Kitts and Nevis"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Saint Kitts"] = {alias_of = "Saint Kitts and Nevis", display = true}, ["Saint Lucia"] = {container = "Caribbean", divs = {"districts"}, british_spelling = true}, ["Saint Vincent and the Grenadines"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Saint Vincent"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["SVG"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["S.V.G"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["Samoa"] = {container = "Polynesia", divs = {"districts"}, british_spelling = true}, ["San Marino"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["São Tomé and Príncipe"] = {container = "Africa", divs = {"districts"}}, ["São Tome and Principe"] = {alias_of = "São Tomé and Príncipe", display = true}, ["São Tomé"] = {alias_of = "São Tomé and Príncipe", display = true}, ["São Tome"] = {alias_of = "São Tomé and Príncipe", display = true}, ["Saudi Arabia"] = {container = "Asia", divs = {"provinces", "governorates"}}, ["Senegal"] = {container = "Africa", divs = {"regions", "departments"}}, ["Serbia"] = {container = "Europe", divs = {"districts", "municipalities", "autonomous provinces"}}, ["Seychelles"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Sierra Leone"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, ["Singapore"] = {container = "Asia", divs = {"districts", "regions"}, british_spelling = true}, ["Slovakia"] = {container = "Europe", divs = {"regions", "districts"}, british_spelling = true}, ["Slovenia"] = {container = "Europe", divs = {"statistical regions", "municipalities"}, british_spelling = true}, -- Note: While the official name does not include "the" at the beginning, -- it sounds strange in English to leave it out and it's commonly included. ["Solomon Islands"] = {the = true, container = "Melanesia", divs = {"provinces"}, british_spelling = true}, ["Somalia"] = {container = "Africa", divs = {"regions", "districts"}}, ["South Africa"] = {container = "Africa", divs = { "provinces", "districts", {type = "district municipalities", cat_as = "districts"}, {type = "metropolitan municipalities", cat_as = "districts"}, "municipalities", }, british_spelling = true}, ["South Korea"] = {container = "Asia", addl_parents = {"Korea"}, divs = {"provinces", "counties", "districts"}}, ["South Sudan"] = {container = "Africa", divs = {"regions", "states", "counties"}, british_spelling = true}, ["Spain"] = {container = "Europe", divs = {"autonomous communities", "provinces", "municipalities", "comarcas", "autonomous cities"}, british_spelling = true}, ["Sri Lanka"] = {container = "Asia", divs = {"provinces", "districts"}, british_spelling = true}, ["Sudan"] = {container = "Africa", divs = {"states", "districts"}, british_spelling = true}, ["Suriname"] = {container = "South America", divs = {"districts"}}, ["Sweden"] = {container = "Europe", divs = {"provinces", "counties", "municipalities"}, british_spelling = true}, ["Switzerland"] = {container = "Europe", divs = {"cantons", "municipalities", "districts"}, british_spelling = true}, ["Syria"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Taiwan"] = {container = "Asia", divs = {"counties", "districts", "townships", "special municipalities"}}, ["Republic of China"] = {alias_of = "Taiwan", the = true}, -- differs in "the", different political connotations ["Tajikistan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Tanzania"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Thailand"] = {container = "Asia", divs = {"provinces", "districts", "subdistricts"}}, ["Togo"] = {container = "Africa", divs = {"provinces", "prefectures"}}, ["Tonga"] = {container = "Polynesia", divs = {"divisions"}, british_spelling = true}, ["Trinidad and Tobago"] = {container = "Caribbean", divs = {"regions", "municipalities"}, british_spelling = true}, ["Tunisia"] = {container = "Africa", divs = {"governorates", "delegations"}}, ["Turkey"] = {container = {"Europe", "Asia"}, divs = {"provinces", "districts"}}, -- Foreign names generally get display-canonicalized. ["Türkiye"] = {alias_of = "Turkey", display = true}, ["Turkmenistan"] = {container = "Asia", divs = { -- The 5 regions are often also called provinces "regions", {type = "provinces", cat_as = "regions"}, "districts"}, }, ["Tuvalu"] = {container = "Polynesia", divs = {"atolls"}, british_spelling = true}, ["Uganda"] = {container = "Africa", divs = {"districts", "counties"}, british_spelling = true}, ["Ukraine"] = {container = "Europe", divs = { {type = "oblasts", cat_as = "oblasts and autonomous republics"}, {type = "autonomous republics", cat_as = "oblasts and autonomous republics"}, "raions", "hromadas", }, british_spelling = true}, ["United Arab Emirates"] = {the = true, container = "Asia", divs = {"emirates"}}, -- Abbreviations get display-canonicalized. ["UAE"] = {alias_of = "United Arab Emirates", display = true, the = true}, ["U.A.E."] = {alias_of = "United Arab Emirates", display = true, the = true}, ["United Kingdom"] = {the = true, container = "Europe", addl_parents = {"British Isles"}, divs = {"constituent countries", "counties", "districts", "boroughs", "territories", "dependent territories", "traditional counties"}, keydesc = "the [[United Kingdom]] of Great Britain and Northern Ireland", british_spelling = true}, -- Abbreviations get display-canonicalized. ["UK"] = {alias_of = "United Kingdom", display = true, the = true}, ["U.K."] = {alias_of = "United Kingdom", display = true, the = true}, ["United States"] = {the = true, container = "North America", divs = {"counties", "county seats", "states", "territories", "dependent territories", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, {type = "DEROGATORY_NAME_FOR states", cat_as = "derogatory names for states"}, {type = "NICKNAME_FOR states", cat_as = "nicknames for states"}, {type = "OFFICIAL_NICKNAME_FOR states", cat_as = "official nicknames for states"}, {type = "boroughs", prep = "in"}, -- exist in Pennsylvania and New Jersey "municipalities", -- these exist politically at least in Colorado and Connecticut {type = "census-designated places", prep = "in"}, {type = "unincorporated communities", prep = "in"}, -- Don't change the following to something more politically correct until/unless the US government makes a -- similar switch (and note that as of Apr 18 2025, the Wikipedia article is still at -- [[w:Indian reservations]]). "Indian reservations", }}, -- Abbreviations and long forms (when possible) get display-canonicalized. ["US"] = {alias_of = "United States", display = true, the = true}, ["U.S."] = {alias_of = "United States", display = true, the = true}, ["USA"] = {alias_of = "United States", display = true, the = true}, ["U.S.A."] = {alias_of = "United States", display = true, the = true}, ["United States of America"] = {alias_of = "United States", display = true, the = true}, ["Uruguay"] = {container = "South America", divs = {"departments", "municipalities"}}, ["Uzbekistan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Vanuatu"] = {container = "Melanesia", divs = {"provinces"}, british_spelling = true}, ["Vatican City"] = {placetype = {"city-state", "country"}, container = "Europe", -- First placetype should be 'city-state' for to shown up in its description, -- Its parent should still be "countries in Europe". bare_category_parent_type = {type = "countries", prep = "in"}, addl_parents = {"Rome"}, is_city = true, british_spelling = true}, ["Vatican"] = {alias_of = "Vatican City", the = true}, -- differs in "the" ["Venezuela"] = {container = "South America", divs = {"states", "municipalities"}}, ["Vietnam"] = {container = "Asia", divs = {"provinces", "districts", "municipalities"}}, ["Western Sahara"] = {placetype = {"territory", "country"}, container = "Africa", bare_category_parent_type = {type = "countries", prep = "in"}, }, -- Not display-canonicalizable both due to differences in 'the' and the sovereignty dispute over Western Sahara ["Sahrawi Arab Democratic Republic"] = {alias_of = "Western Sahara", the = true}, ["SADR"] = {alias_of = "Sahrawi Arab Democratic Republic", display = true, the = true}, ["Yemen"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Zambia"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, ["Zimbabwe"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, } local function canonicalize_continent_container(key) if type(key) ~= "string" then return key end if export.continents[key] then return {key = key, placetype = export.continents[key].placetype} end internal_error("Unrecognized key %s in `canonicalize_continent_like`", key) end export.countries_group = { canonicalize_key_container = canonicalize_continent_container, default_overriding_bare_label_parents = {"+++", "countries"}, default_placetype = "country", default_no_container_cat = true, default_no_container_parent = true, -- No need to augment country holonyms with continents; not needed for disambiguation. default_no_auto_augment_container = true, data = export.countries, } -- Country-like entities: typically overseas territories or de-facto independent countries, which in both cases -- are not internationally recognized as sovereign nations but which we treat similarly to countries. export.country_like_entities = { -- British Overseas Territory ["Akrotiri and Dhekelia"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Cyprus", "Europe", "Asia"}, british_spelling = true, }, -- Åland: Listed as a region of Finland. Wikipedia lists this under "dependent territories" in -- [[w:List of sovereign states and dependent territories by continent]]. -- unincorporated territory of the United States ["American Samoa"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Polynesia"}, }, -- British Overseas Territory ["Anguilla"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Georgia ["Abkhazia"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Georgia", "Europe", "Asia"}, divs = {"districts"}, keydesc = "the de-facto independent state of [[Abkhazia]], internationally recognized as part of the country of [[Georgia]]", british_spelling = true, }, -- Australian external territory ["Ashmore and Cartier Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, }, -- constituent country of the Netherlands ["Aruba"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- British Overseas Territory ["Bermuda"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"North America"}, british_spelling = true, }, -- special municipality of the Netherlands ["Bonaire"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- British Overseas Territory ["British Indian Ocean Territory"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Asia"}, british_spelling = true, }, -- British Overseas Territory ["British Virgin Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- Norwegian dependent territory ["Bouvet Island"] = { placetype = {"dependent territory", "territory"}, container = "Norway", addl_parents = {"Africa"}, british_spelling = true, }, -- British Overseas Territory ["Cayman Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- Australian external territory ["Christmas Island"] = { placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, british_spelling = true, }, -- Sui generis French "state private property" per Wikipedia; classify as overseas territory like the -- French Southern and Antarctic Lands. ["Clipperton Island"] = { placetype = {"overseas territory", "territory"}, container = "France", addl_parents = {"North America"}, }, -- Australian external territory; also called the Keeling Islands or (officially) the Cocos (Keeling) Islands ["Cocos Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, wp = "Cocos (Keeling) Islands", british_spelling = true, }, ["Cocos (Keeling) Islands"] = {alias_of = "Cocos Islands", display = true, the = true}, ["Keeling Islands"] = {alias_of = "Cocos Islands", display = true, the = true}, -- self-governing but in free association with New Zealand ["Cook Islands"] = { the = true, placetype = {"country"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- constituent country of the Netherlands ["Curaçao"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- special territory of Chile ["Easter Island"] = { placetype = {"special territory", "territory"}, container = "Chile", addl_parents = {"Polynesia"}, }, -- British Overseas Territory ["Falkland Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"South America"}, british_spelling = true, }, -- autonomous territory of Denmark ["Faroe Islands"] = { the = true, placetype = {"autonomous territory", "territory"}, container = "Denmark", addl_parents = {"Europe"}, british_spelling = true, }, -- overseas department and region of France ["French Guiana"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"South America"}, british_spelling = true, }, -- overseas collectivity of France ["French Polynesia"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Polynesia"}, british_spelling = true, }, -- French overseas territory ["French Southern and Antarctic Lands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "France", addl_parents = {"Africa"}, }, -- British Overseas Territory ["Gibraltar"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Europe"}, is_city = true, british_spelling = true, }, -- autonomous territory of Denmark ["Greenland"] = { placetype = {"autonomous territory", "territory"}, container = "Denmark", addl_parents = {"North America"}, divs = {"municipalities"}, british_spelling = true, }, -- overseas department and region of France ["Guadeloupe"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", addl_parents = {"Caribbean"}, divs = {"communes"}, british_spelling = true, }, -- unincorporated territory of the United States ["Guam"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- self-governing British Crown dependency; technically called the Bailiwick of Guernsey ["Guernsey"] = { placetype = {"crown dependency", "dependency", "dependent territory", "bailiwick", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, wp = "Bailiwick of %l", }, ["Bailiwick of Guernsey"] = {alias_of = "Guernsey", the = true}, -- Australian external territory ["Heard Island and McDonald Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Africa"}, }, -- special administrative region of China ["Hong Kong"] = { placetype = {"special administrative region", "city"}, container = "China", is_city = true, british_spelling = true, }, -- self-governing British Crown dependency ["Isle of Man"] = { the = true, placetype = {"crown dependency", "dependency", "dependent territory", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, }, -- Norwegian unincorporated area ["Jan Mayen"] = { placetype = {"unincorporated area", "dependent territory", "territory", "island"}, container = "Norway", addl_parents = {"Europe"}, british_spelling = true, }, -- self-governing British Crown dependency; technically called the Bailiwick of Jersey ["Jersey"] = { placetype = {"crown dependency", "dependency", "dependent territory", "bailiwick", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, }, ["Bailiwick of Jersey"] = {alias_of = "Jersey", the = true}, -- special administrative region of China ["Macau"] = { placetype = {"special administrative region", "city"}, container = "China", is_city = true, british_spelling = true, }, -- overseas department and region of France ["Martinique"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Caribbean"}, british_spelling = true, }, -- overseas department and region of France ["Mayotte"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Africa"}, british_spelling = true, }, -- British Overseas Territory ["Montserrat"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- special collectivity of France ["New Caledonia"] = { placetype = {"special collectivity", "collectivity"}, container = "France", addl_parents = {"Melanesia"}, british_spelling = true, }, -- dependent territory of New Zealand ["New Zealand Subantarctic Islands"] = { the = true, placetype = {"dependent territory", "territory"}, container = "New Zealand", addl_parents = {"Antarctica"}, british_spelling = true, }, -- self-governing but in free association with New Zealand ["Niue"] = { placetype = {"country"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- Australian external territory ["Norfolk Island"] = { placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Polynesia"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Cyprus ["Northern Cyprus"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Cyprus", "Turkey", "Europe", "Asia"}, divs = {"districts"}, keydesc = "the de-facto independent state of [[Northern Cyprus]], internationally recognized as part of the country of [[Cyprus]]", british_spelling = true, }, -- commonwealth, unincorporated territory of the United States ["Northern Mariana Islands"] = { the = true, placetype = {"commonwealth", "unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- British Overseas Territory ["Pitcairn Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Polynesia"}, british_spelling = true, }, -- commonwealth of the United States ["Puerto Rico"] = { placetype = {"commonwealth", "overseas territory", "territory"}, container = "United States", addl_parents = {"Caribbean"}, divs = {"municipalities"}, }, -- overseas department and region of France ["Réunion"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Africa"}, british_spelling = true, }, -- special municipality of the Netherlands ["Saba"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- overseas collectivity of France ["Saint Barthélemy"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Caribbean"}, british_spelling = true, }, -- British Overseas Territory ["Saint Helena, Ascension and Tristan da Cunha"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", divs = {{type = "constituent parts", container_parent_type = false}}, addl_parents = {"Atlantic Ocean", "Africa"}, british_spelling = true, }, -- constituent parts of the combined oveseas territory ["Ascension Island"] = { placetype = {"constituent part", "territory", "island"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, ["Saint Helena"] = { placetype = {"constituent part", "territory", "island"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, ["Tristan da Cunha"] = { placetype = {"constituent part", "territory", "archipelago"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, -- overseas collectivity of France ["Saint Martin"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Caribbean"}, british_spelling = true, }, -- overseas collectivity of France ["Saint Pierre and Miquelon"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", divs = {"communes"}, addl_parents = {"North America"}, british_spelling = true, }, -- special municipality of the Netherlands ["Sint Eustatius"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- constituent country of the Netherlands ["Sint Maarten"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Somalia ["Somaliland"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Somalia", "Africa"}, keydesc = "the de-facto independent state of [[Somaliland]], internationally recognized as part of the country of [[Somalia]]", british_spelling = true, }, -- British Overseas Territory -- FIXME: We should form the group "South Georgia and the South Sandwich Islands" like we did for -- "Saint Helena, Ascension and Tristan da Cunha". ["South Georgia"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Atlantic Ocean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Georgia ["South Ossetia"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Georgia", "Europe", "Asia"}, keydesc = "the de-facto independent state of [[South Ossetia]], internationally recognized as part of the country of [[Georgia]]", british_spelling = true, }, -- British Overseas Territory ["South Sandwich Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Atlantic Ocean"}, wp = true, wpcat = "South Georgia and the South Sandwich Islands", british_spelling = true, }, -- Norwegian unincorporated area ["Svalbard"] = { placetype = {"unincorporated area", "dependent territory", "territory", "archipelago"}, container = "Norway", addl_parents = {"Europe"}, british_spelling = true, }, -- dependent territory of New Zealand ["Tokelau"] = { placetype = {"dependent territory", "territory"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Moldova ["Transnistria"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Moldova", "Europe"}, keydesc = "the de-facto independent state of [[Transnistria]], internationally recognized as part of [[Moldova]]", british_spelling = true, }, -- British Overseas Territory ["Turks and Caicos Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- unincorporated territory of the United States ["United States Minor Outlying Islands"] = { the = true, placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Islands", "Micronesia", "Polynesia", "Caribbean"}, }, -- FIXME: We should add entries for the other minor outlying islands. -- Baker Island (Oceania) -- Howland Island (Oceania) -- Jarvis Island (Oceania) -- Johnston Atoll (Oceania) -- Kingman Reef (Oceania) -- Midway Atoll (Oceania) -- Navassa Island (Caribbean) -- Palmyra Atoll (Oceania) -- Wake Island (Oceania) ["Wake Island"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- unincorporated territory of the United States ["United States Virgin Islands"] = { the = true, placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Caribbean"}, }, ["U.S. Virgin Islands"] = {alias_of = "United States Virgin Islands", display = true, the = true}, ["US Virgin Islands"] = {alias_of = "United States Virgin Islands", display = true, the = true}, -- overseas collectivity of France ["Wallis and Futuna"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Polynesia"}, british_spelling = true, }, } export.country_like_entities_group = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Saint Helena, Ascension and Tristan da Cunha". key_to_placename = false, placename_to_key = false, canonicalize_key_container = make_canonicalize_key_container(nil, "country"), default_overriding_bare_label_parents = {"country-like entities"}, default_no_container_cat = true, default_no_container_parent = true, -- These entities often aren't really part of their container; a village in Wallis and Futuna (an overseas -- collectivity of France in Polynesia), for example, shouldn't be treated as a village in France, nor as a village -- in Europe. default_no_auto_augment_container = true, data = export.country_like_entities, } -- Former countries and such; we don't create "Cities in ..." categories because they don't exist anymore export.former_countries = { -- de-facto independent state of Armenian ethnicity, internationally recognized as part of Azerbaijan -- (also known as Nagorno-Karabakh) -- NOTE: Formerly listed Armenia as a parent; this seems politically non-neutral so I've taken it out. ["Artsakh"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Azerbaijan", "Europe", "Asia"}, keydesc = "the former de-facto independent state of [[Artsakh]], internationally recognized as part of [[Azerbaijan]]", british_spelling = true, }, ["Nagorno-Karabakh"] = {alias_of = "Artsakh"}, ["Czechoslovakia"] = {container = "Europe", british_spelling = true}, ["East Germany"] = {container = "Europe", addl_parents = {"Germany"}, british_spelling = true}, ["North Vietnam"] = {container = "Asia", addl_parents = {"Vietnam"}}, ["Persia"] = {placetype = {"empire", "country"}, container = "Asia", divs = {"provinces"}}, ["Byzantine Empire"] = { the = true, placetype = {"empire", "country"}, container = {"Europe", "Africa", "Asia"}, addl_parents = {"Ancient Europe", "Ancient Near East"}, divs = { "provinces", "themes", }}, ["Roman Empire"] = { the = true, placetype = {"empire", "country"}, container = {"Europe", "Africa", "Asia"}, addl_parents = {"Rome"}, divs = { "provinces", {type = "FORMER provinces", cat_as = "provinces"}, }}, ["South Vietnam"] = {container = "Asia", addl_parents = {"Vietnam"}}, ["Soviet Union"] = { the = true, container = {"Europe", "Asia"}, divs = {"republics", "autonomous republics"}, british_spelling = true}, ["West Germany"] = {container = "Europe", addl_parents = {"Germany"}, british_spelling = true}, ["Yugoslavia"] = {container = "Europe", divs = {"districts"}, keydesc = "the former [[Kingdom of Yugoslavia]] (1918–1943) or the former [[Socialist Federal Republic of Yugoslavia]] (1943–1992)", british_spelling = true}, } export.former_countries_group = { canonicalize_key_container = canonicalize_continent_container, default_overriding_bare_label_parents = {"former countries and country-like entities"}, default_is_former_place = true, default_placetype = "country", default_no_container_cat = true, default_no_container_parent = true, -- No need to augment country holonyms with continents; not needed for disambiguation. default_no_auto_augment_container = true, data = export.former_countries, } ----------------------------------------------------------------------------------- -- Subpolity tables -- ----------------------------------------------------------------------------------- export.australia_states_and_territories = { ["Australian Capital Territory, Australia"] = {the = true, placetype = "territory"}, ["Jervis Bay Territory, Australia"] = {the = true, placetype = "territory"}, ["New South Wales, Australia"] = {}, ["Northern Territory, Australia"] = {the = true, placetype = "territory"}, ["Queensland, Australia"] = {}, ["South Australia, Australia"] = {}, ["Tasmania, Australia"] = {}, ["Victoria, Australia"] = {}, ["Western Australia, Australia"] = {}, } -- states and territories of Australia export.australia_group = { default_container = "Australia", default_placetype = "state", default_divs = "local government areas", data = export.australia_states_and_territories, } export.austria_states = { ["Vienna, Austria"] = {}, ["Lower Austria, Austria"] = {}, ["Upper Austria, Austria"] = {}, ["Styria, Austria"] = {}, ["Tyrol, Austria"] = {wp = "Tyrol (state)"}, ["Carinthia, Austria"] = {}, ["Salzburg, Austria"] = {wp = "Salzburg (state)"}, ["Vorarlberg, Austria"] = {}, ["Burgenland, Austria"] = {}, } -- states of Austria export.austria_group = { default_container = "Austria", default_placetype = "state", default_divs = "municipalities", data = export.austria_states, } export.bangladesh_divisions = { ["Barisal Division, Bangladesh"] = {}, ["Chittagong Division, Bangladesh"] = {}, ["Dhaka Division, Bangladesh"] = {}, ["Khulna Division, Bangladesh"] = {}, ["Mymensingh Division, Bangladesh"] = {}, ["Rajshahi Division, Bangladesh"] = {}, ["Rangpur Division, Bangladesh"] = {}, ["Sylhet Division, Bangladesh"] = {}, } -- divisions of Bangladesh export.bangladesh_group = { key_to_placename = make_key_to_placename(", Bangladesh$", " Division$"), placename_to_key = make_placename_to_key(", Bangladesh", " Division"), default_container = "Bangladesh", default_placetype = "division", default_divs = "districts", data = export.bangladesh_divisions, } export.brazil_states = { ["Acre, Brazil"] = {wp = "%l (state)"}, ["Alagoas, Brazil"] = {}, ["Amapá, Brazil"] = {}, ["Amazonas, Brazil"] = {wp = "%l (Brazilian state)"}, ["Bahia, Brazil"] = {}, ["Ceará, Brazil"] = {}, ["Distrito Federal, Brazil"] = {wp = "Federal District (Brazil)"}, ["Espírito Santo, Brazil"] = {}, ["Goiás, Brazil"] = {}, ["Maranhão, Brazil"] = {}, ["Mato Grosso, Brazil"] = {}, ["Mato Grosso do Sul, Brazil"] = {}, ["Minas Gerais, Brazil"] = {}, ["Pará, Brazil"] = {}, ["Paraíba, Brazil"] = {}, ["Paraná, Brazil"] = {wp = "%l (state)"}, ["Pernambuco, Brazil"] = {}, ["Piauí, Brazil"] = {}, ["Rio de Janeiro, Brazil"] = {wp = "%l (state)"}, ["Rio Grande do Norte, Brazil"] = {}, ["Rio Grande do Sul, Brazil"] = {}, ["Rondônia, Brazil"] = {}, ["Roraima, Brazil"] = {}, ["Santa Catarina, Brazil"] = {wp = "%l (state)"}, ["São Paulo, Brazil"] = {wp = "%l (state)"}, ["Sergipe, Brazil"] = {}, ["Tocantins, Brazil"] = {}, } -- states of Brazil export.brazil_group = { default_container = "Brazil", default_placetype = "state", default_divs = "municipalities", data = export.brazil_states, } -- provinces (a.k.a. oblasts) of Bulgaria export.bulgaria_provinces = { ["Blagoevgrad Province, Bulgaria"] = {}, ["Burgas Province, Bulgaria"] = {}, ["Dobrich Province, Bulgaria"] = {}, ["Gabrovo Province, Bulgaria"] = {}, ["Haskovo Province, Bulgaria"] = {}, ["Kardzhali Province, Bulgaria"] = {}, ["Kyustendil Province, Bulgaria"] = {}, ["Lovech Province, Bulgaria"] = {}, ["Montana Province, Bulgaria"] = {}, ["Pazardzhik Province, Bulgaria"] = {}, ["Pernik Province, Bulgaria"] = {}, ["Pleven Province, Bulgaria"] = {}, ["Plovdiv Province, Bulgaria"] = {}, ["Razgrad Province, Bulgaria"] = {}, ["Ruse Province, Bulgaria"] = {}, ["Shumen Province, Bulgaria"] = {}, ["Silistra Province, Bulgaria"] = {}, ["Sliven Province, Bulgaria"] = {}, ["Smolyan Province, Bulgaria"] = {}, ["Sofia City Province, Bulgaria"] = {}, ["Sofia Province, Bulgaria"] = {}, ["Stara Zagora Province, Bulgaria"] = {}, ["Targovishte Province, Bulgaria"] = {}, ["Varna Province, Bulgaria"] = {}, ["Veliko Tarnovo Province, Bulgaria"] = {}, ["Vidin Province, Bulgaria"] = {}, ["Vratsa Province, Bulgaria"] = {}, ["Yambol Province, Bulgaria"] = {}, } export.bulgaria_group = { key_to_placename = make_key_to_placename(", Bulgaria$", " Province$"), placename_to_key = make_placename_to_key(", Bulgaria", " Province"), default_container = "Bulgaria", --== source: https://en.wikipedia.org/wiki/NUTS_statistical_regions_of_Bulgaria == divs = {"regions", "planning regions", "provinces", "municipalities", "settlements"}, default_placetype = "province", data = export.bulgaria_provinces, } export.canada_provinces_and_territories = { ["Alberta, Canada"] = {divs = { {type = "municipal districts", container_parent_type = "rural municipalities"}, }}, ["British Columbia, Canada"] = {divs = {type = "regional districts", container_parent_type = false}, "regional municipalities", }, ["Manitoba, Canada"] = {divs = {"rural municipalities"}}, ["New Brunswick, Canada"] = {divs = {"counties", "parishes", {type = "civil parishes", cat_as = "parishes"}}}, ["Newfoundland and Labrador, Canada"] = {}, ["Northwest Territories, Canada"] = {the = true, placetype = "territory"}, ["Nova Scotia, Canada"] = {divs = {"counties", "regional municipalities"}}, ["Nunavut, Canada"] = {placetype = "territory"}, ["Ontario, Canada"] = {divs = {"counties", "regional municipalities", {type = "townships", prep = "in"}}}, ["Prince Edward Island, Canada"] = {divs = {"counties", "parishes", "rural municipalities"}}, ["Saskatchewan, Canada"] = {divs = {"rural municipalities"}}, ["Quebec, Canada"] = {divs = { "counties", {type = "regional county municipalities", container_parent_type = "regional municipalities"}, -- administrative regions have an official (but non-governmental) function but there don't appear to be any -- equivalent regions elsewhere in Canada, so disable the [[Category:Regions of Canada]] grouping {type = "regions", container_parent_type = false}, {type = "townships", prep = "in"}, {type = "parish municipalities", cat_as = {{type = "parishes", container_parent_type = "counties"}, "municipalities"}}, {type = "township municipalities", cat_as = {{type = "townships", prep = "in"}, "municipalities"}}, {type = "village municipalities", cat_as = {{type = "villages", prep = "in"}, "municipalities"}}, }}, ["Yukon, Canada"] = {placetype = "territory"}, ["Yukon Territory, Canada"] = {alias_of = "Yukon, Canada", the = true}, } -- provinces and territories of Canada export.canada_group = { default_container = "Canada", default_placetype = "province", data = export.canada_provinces_and_territories, } export.china_provinces_and_autonomous_regions = { -- direct-administered municipalities are not here but below under prefecture-level cities ["Anhui, China"] = {}, ["Fujian, China"] = {}, ["Fuchien, China"] = {alias_of = "Fujian, China", display = true}, ["Gansu, China"] = {}, ["Guangdong, China"] = {}, ["Guangxi, China"] = {placetype = "autonomous region"}, ["Guizhou, China"] = {}, ["Hainan, China"] = {}, ["Hebei, China"] = {}, ["Heilongjiang, China"] = {}, ["Henan, China"] = {}, ["Hubei, China"] = {}, ["Hunan, China"] = {}, ["Inner Mongolia, China"] = {placetype = "autonomous region"}, ["Jiangsu, China"] = {}, ["Jiangxi, China"] = {}, ["Jilin, China"] = {}, ["Liaoning, China"] = {}, ["Ningxia, China"] = {placetype = "autonomous region"}, ["Qinghai, China"] = {}, ["Shaanxi, China"] = {}, ["Shandong, China"] = {}, ["Shanxi, China"] = {}, ["Sichuan, China"] = {}, ["Tibet, China"] = {placetype = "autonomous region", wp = "Tibet Autonomous Region"}, ["Xinjiang, China"] = {placetype = "autonomous region"}, ["Yunnan, China"] = {}, ["Zhejiang, China"] = {}, } -- provinces and autonomous regions of China export.china_group = { default_container = "China", default_placetype = "province", default_divs = { "prefectures", "prefecture-level cities", "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_provinces_and_autonomous_regions, } export.china_prefecture_level_cities = { -- In China, a "prefecture-level city" is not a city in any real sense. It is rather a prefecture, which is an -- administrative unit smaller than a province but bigger than a county, which is administratively controlled by -- the chief city of the prefecture (which bears the same name as the prefecture), in a unified government. Prior -- to the mid-1980's, in fact, prefecture-level cities *were* prefectures, and a few of them (especially in the -- western portion of China) have not yet been converted. Generally a given province is entirely tiled by -- prefecture-level cities, another indication that they should be treated as prefectures and not cities per se. -- Yet another indication is that prefecture-level cities can contain counties and county-level cities (which, much -- like prefecture-level cities, are effectively counties surrounding a chief city of the county, again which bears -- the same name as the county-level city). -- -- For this reason, we treat prefecture-level cities as non-city political divisions, and separately enumerate the -- most populous so we can separately categorize districts and counties under them instead of lumping them at the -- province level. -- -- Note also that China separately distinguishes "urban area" from "metro area". Sometimes the two figures are -- identical but sometimes the metro area is larger (and very occasionally smaller, which I assume is an error). I'm -- guessing that the "urban area" is the contiguous urban area over a certain density while the metro area includes -- all urban areas above a certain density; when the latter is greater, it's because of satellite cities in the -- metro area separated by suburban/exurban or rural land. -- At first I chose all prefecture/province-level cities with a total prefecture/province-level population of at -- least 6,000,000 per the 2020 census with data taken from https://www.citypopulation.de/en/china/admin/ (a total -- of 67, including the four direct-administered municipalities), and also chose all prefecture/province-level -- cities whose "urban population" was at least 2,000,000 per the 2020 census with data taken from Wikipedia -- [[w:List of cities in China by population#Cities and towns by population]] (a total of 61 cities; if we cut off -- at 1.5 million we'd have 84 cities, and if we cut off at 1 million we'd have 105 cities). Merging them produces -- 87 cities. Note that this leaves off a few well-known cities (Guilin, Qiqihar, Kashgar, Lhasa, ...) but includes -- a lot of obscure cities. -- -- At a later date I added all cities from citypopulation.de whose "urban" population per the 2020 China census was -- >= 1 million, and then finally added all urban agglomerations from citypopulation.de whose 2025-01-01 estimate -- was >= 1 million. These are sorted below by the urban agglomeration value (which is generally of the "adm-urb" = -- "administrative area (urban population)" type) and sometimes groups nearby cities into a single agglomeration -- (most notably in the case of the Pearl River Delta, grouped under Guangzhou with an agglomeration population of -- 72,700,000 but including a large number of nearby large cities in the agglomeration (although for some reason not -- Hong Kong, maybe due to the administrative issues involved). In addition, citypopulation.de includes divisions -- under a prefecture-level city if they are city-like and have an agglomeration population of at least 1 million; -- this includes several county-level cities, one county and one district (Wanzhou, a "district" of Chongqing -- despite being 142 miles away). None of the county-level cities or counties have districts under them, only -- subdistricts, towns and townships. ["Guangzhou"] = {container = "Guangdong"}, -- 18.7 prefectural, 18.8 urban; sub-provincial city; 16.097 urban (72.700 adm-urb including Dongguan, Foshan, Huizhou, Jiangmen, Shenzhen, Zhongshan) per citypopulation.de ["Dongguan"] = {container = "Guangdong"}, -- 10.5 prefectural, 10.5 urban; 9.645 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Foshan"] = {container = "Guangdong"}, -- 9.5 prefectural, 9.5 urban; 9.043 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Huizhou"] = {container = "Guangdong"}, -- 6.0 prefectural, 2.5 urban; 2.900 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Jiangmen"] = {container = "Guangdong"}, -- 4.798 prefectural, 2.7 urban; 1.795 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Shenzhen"] = {container = "Guangdong"}, -- 17.5 prefectural, 14.7 urban; sub-provincial city; 17.445 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Zhongshan"] = {container = "Guangdong"}, -- 4.418 prefectural, 4.4 urban; 3.842 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Shanghai"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 24.9 prefectural, 29.9 urban; 21.910 urban (41.600 adm-urb including Changshu, Changzhou, Suzhou, Wuxi) per citypopulation.de ["Changshu"] = {container = "Jiangsu"}, -- 1.231 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration -- NOTE: Not to be confused with Cangzhou in Hebei ["Changzhou"] = {container = "Jiangsu"}, -- 5.278 prefectural, 3.6 urban; 3.187 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration -- NOTE: There is also a prefecture-level city Suzhou in Anhui with 5.3 million prefectural inhabitants ["Suzhou"] = {container = "Jiangsu"}, -- 12.8 prefectural, 4.3 urban; 5.893 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration ["Wuxi"] = {container = "Jiangsu"}, -- 7.5 prefectural, 3.3 urban; 3.957 per citypopulation.de; included by citypopulation.de in Shanghai agglomeration ["Beijing"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 21.9 prefectural, 21.9 urban; 18.961 urban (21.500 adm-urb) per citypopulation.de ["Chengdu"] = {container = "Sichuan"}, -- 20.9 prefectural, 16.9 urban; sub-provincial city; 13.568 urban (18.100 adm-urb) per citypopulation.de ["Xiamen"] = {container = "Fujian"}, -- 5.163 prefectural, 5.2 urban; sub-provincial city; 4.617 urban (15.400 adm-urb including Jinjiang, Quanzhou, Putian) per citypopulation.de ["Jinjiang"] = {container = "Fujian"}, -- 1.416 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Quanzhou"] = {container = "Fujian"}, -- 8.8 prefectural, 1.7 urban (6.7 metro); 1.469 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Putian"] = {container = "Fujian"}, -- 3.210 prefectural, 2.0 urban; 1.539 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Hangzhou"] = {container = "Zhejiang"}, -- 11.9 prefectural, 10.7 urban; sub-provincial city; 9.236 urban (14.600 adm-urb including Shaoxing) per citypopulation.de ["Shaoxing"] = {container = "Zhejiang"}, -- 5.270 prefectural, 2.5 urban; 2.333 urban per citypopulation.de; included by citypopulation.de in Hangzhou agglomeration ["Xi'an"] = {container = "Shaanxi"}, -- 12.1 prefectural, 11.9 urban; sub-provincial city; 9.393 urban (13.400 adm-urb including Xianyang) per citypopulation.de ["Xianyang"] = {container = "Shaanxi"}, -- 1.193 urban per citypopulation.de; included by citypopulation.de in Xi'an agglomeration ["Chongqing"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 32.1 prefectural, 16.9 urban; 9.581 urban (12.900 adm-urb) per citypopulation.de ["Wuhan"] = {container = "Hubei"}, -- 12.4 prefectural, 12.3 urban; sub-provincial city; 10.495 urban (12.600 adm-urb) per citypopulation.de ["Tianjin"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 13.9 prefectural, 13.9 urban; 11.052 urban (11.700 adm-urb) per citypopulation.de ["Changsha"] = {container = "Hunan"}, -- 10.0 prefectural, 6.0 urban; 5.630 urban (11.500 adm-urb including Xiangtan, Zhuzhou) per citypopulation.de -- Changsha County -- 1.024 urban per citypopulation.de ["Zhuzhou"] = {container = "Hunan"}, -- 1.510 urban per citypopulation.de; included by citypopulation.de in Changsha agglomeration ["Zhengzhou"] = {container = "Henan"}, -- 12.6 prefectural, 6.7 urban; 6.461 urban (10.300 adm-urb) per citypopulation.de ["Nanjing"] = {container = "Jiangsu"}, -- 9.3 prefectural, 9.3 urban; sub-provincial city; 7.520 urban (9.500 adm-urb including Ma'anshan) per citypopulation.de ["Shenyang"] = {container = "Liaoning"}, -- 9.1 prefectural, 7.9 urban; sub-provincial city; 7.026 urban (8.800 adm-urb including Fushun) per citypopulation.de ["Fushun"] = {container = "Liaoning"}, -- 1.229 urban per citypopulation.de; included by citypopulation.de in Shenyang agglomeration ["Hefei"] = {container = "Anhui"}, -- 9.4 prefectural, 4.2 urban; 5.056 urban (8.200 adm-urb) per citypopulation.de ["Shantou"] = {container = "Guangdong"}, -- 5.502 prefectural, 4.3 urban; 3.839 urban (8.050 adm-urb including Chaozhou, Jieyang, Puning) per citypopulation.de ["Chaozhou"] = {container = "Guangdong"}, -- 1.254 urban per citypopulation.de; included by citypopulation.de in Shantou agglomeration ["Jieyang"] = {container = "Guangdong"}, -- 1.243 urban per citypopulation.de; included by citypopulation.de in Shantou agglomeration ["Qingdao"] = {container = "Shandong"}, -- 10.1 prefectural, 7.1 urban; sub-provincial city; 6.165 urban (7.700 adm-urb) per citypopulation.de ["Ningbo"] = {container = "Zhejiang"}, -- 9.4 prefectural, 5.1 urban; sub-provincial city; 3.731 urban (7.600 adm-urb including Cixi, Yuyao) per citypopulation.de ["Cixi"] = {container = "Zhejiang"}, -- 1.458 urban per citypopulation.de; included by citypopulation.de in Ningbo agglomeration ["Yuyao"] = {container = "Zhejiang"}, -- 1.014 urban per citypopulation.de; included by citypopulation.de in Ningbo agglomeration -- Hong Kong 7.500 agglomeration per citypopulation.de 2025-01-01 estimate including Kowloon, Victoria ["Wenzhou"] = {container = "Zhejiang"}, -- 9.6 prefectural, 3.6 urban; 2.582 urban (7.000 adm-urb including Rui'an, Cangnan, Pingyang) per citypopulation.de -- Rui'an is a "county-level city" of the "prefecture-level city" of Wenzhou but in fact is 19 miles away from Wenzhou city proper (urban core to urban core). ["Rui'an"] = {placetype = "county-level city", container = {key = "Wenzhou", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 1.013 urban per citypopulation.de; included by citypopulation.de in Wenzhou agglomeration ["Kunming"] = {container = "Yunnan"}, -- 8.5 prefectural, 6.0 urban; 5.273 urban (6.800 adm-urb) per citypopulation.de -- includes Láiwú city ["Jinan"] = {container = "Shandong", wp = "%l, %c"}, -- 9.2 prefectural, 8.4 urban; sub-provincial city; 5.648 urban (6.750 adm-urb) per citypopulation.de -- includes Xīnjí city ["Shijiazhuang"] = {container = "Hebei"}, -- 11.2 prefectural, 4.1 urban; 5.090 urban (6.450 adm-urb) per citypopulation.de ["Taiyuan"] = {container = "Shanxi"}, -- 5.304 prefectural, 4.5 urban; 4.304 urban (6.150 adm-urb) per citypopulation.de ["Harbin"] = {container = "Heilongjiang"}, -- 10.0 prefectural, 7.0 urban; sub-provincial city; 5.243 urban (5.550 adm-urb) per citypopulation.de ["Nanning"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 8.7 prefectural, 3.8 urban; 4.583 urban (5.550 adm-urb) per citypopulation.de ["Dalian"] = {container = "Liaoning"}, -- 7.5 prefectural, 5.7 urban; sub-provincial city; 4.914 urban (5.400 adm-urb) per citypopulation.de ["Guiyang"] = {container = "Guizhou"}, -- 5.987 prefectural, 3.5 urban; 4.021 urban (5.300 adm-urb) per citypopulation.de ["Changchun"] = {container = "Jilin"}, -- 9.1 prefectural, 5.7 urban; sub-provincial city; 4.557 urban (5.200 adm-urb) per citypopulation.de ["Nanchang"] = {container = "Jiangxi"}, -- 6.3 prefectural, 3.6 (3.9?) urban, 5.3 metro; 3.519 urban (5.150 adm-urb) per citypopulation.de ["Ürümqi"] = {container = {key = "Xinjiang, China", placetype = "autonomous region"}}, -- 4.054 prefectural, 4.3 urban; 3.843 urban (5.000 adm-urb) per citypopulation.de ["Urumqi"] = {alias_of = "Ürümqi", display = true}, ["Fuzhou"] = {container = "Fujian"}, -- 8.3 prefectural, 4.1 urban; 3.723 urban (4.775 adm-urb) per citypopulation.de ["Linyi"] = {container = "Shandong"}, -- 11.0 prefectural, 2.3 urban; 2.744 urban (4.650 adm-urb) per citypopulation.de ["Zibo"] = {container = "Shandong"}, -- 4.704 prefectural, 2.6 urban; 2.750 urban (3.975 adm-urb) per citypopulation.de ["Luoyang"] = {container = "Henan"}, -- 7.1 prefectural, 2.4 urban; 2.231 urban (3.750 adm-urb) per citypopulation.de ["Lanzhou"] = {container = "Gansu"}, -- 4.359 prefectural, 3.1 urban; 3.013 urban (3.575 adm-urb) per citypopulation.de ["Nantong"] = {container = "Jiangsu"}, -- 7.7 prefectural, 2.3 urban; 2.988 urban (3.475 adm-urb) citypopulation.de ["Weifang"] = {container = "Shandong"}, -- 9.4 prefectural, 2.7 urban; 1.998 urban (3.325 adm-urb) per citypopulation.de ["Jiangyin"] = {container = "Jiangsu"}, -- 1.331 urban (3.200 adm-urb including Zhangjiagang) per citypopulation.de ["Zhangjiagang"] = {container = "Jiangsu"}, -- 1.056 urban per citypopulation.de; included in Jiangyin figures ["Xuzhou"] = {container = "Jiangsu"}, -- 9.1 prefectural, 2.6 urban; 2.846 urban (3.150 adm-urb) per citypopulation.de ["Handan"] = {container = "Hebei"}, -- 9.4 prefectural, 2.8 urban; 2.095 urban (2.925 adm-urb) per citypopulation.de ["Hohhot"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 3.446 prefectural, 2.7 urban; 2.373 urban (2.850 adm-urb) per citypopulation.de ["Haikou"] = {container = "Hainan"}, -- 2.873 prefectural, 2.3 urban; 2.349 urban (2.800 adm-urb) per citypopulation.de ["Tangshan"] = {container = "Hebei"}, -- 7.7 prefectural, 3.4 urban; 2.550 urban (2.750 adm-urb) per citypopulation.de ["Xinxiang"] = {container = "Henan"}, -- 6.3 prefectural, 1.2 urban, 2.7 metro; 1.271 urban (2.700 adm-urb) per citypopulation.de ["Yiwu"] = {container = "Zhejiang"}, -- 1.481 urban (2.700 adm-urb) per citypopulation.de ["Zhuhai"] = {container = "Guangdong"}, -- 2.439 prefectural, 2.4 urban; 2.207 urban (2.675 adm-urb) per citypopulation.de ["Taizhou, Zhejiang"] = {container = "Zhejiang"}, -- 6.6 prefectural, 1.6 urban; 1.486 urban (2.625 adm-urb) per citypopulation.de ["Taizhou"] = {alias_of = "Taizhou, Zhejiang"}, ["Yantai"] = {container = "Shandong"}, -- 7.1 prefectural, 2.5 urban; 2.312 urban (2.550 adm-urb) per citypopulation.de ["Yinchuan"] = {container = {key = "Ningxia, China", placetype = "autonomous region"}}, -- 1.663 urban (2.525 adm-urb) per citypopulation.de ["Liuzhou"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 4.157 prefectural, 2.2 urban; 2.205 urban (2.500 adm-urb) per citypopulation.de ["Anshan"] = {container = "Liaoning"}, -- 1.480 urban (2.350 adm-urb including Liáoyáng) per citypopulation.de ["Yangzhou"] = {container = "Jiangsu"}, -- 2.067 urban (2.300 adm-urb) per citypopulation.de ["Jiaxing"] = {container = "Zhejiang"}, -- 1.188 urban (2.275 adm-urb) per citypopulation.de ["Xining"] = {container = "Qinghai"}, -- 1.677 urban (2.250 adm-urb) per citypopulation.de -- includes Dìngzhōu city and Xióngān Xīnqū ["Baoding"] = {container = "Hebei"}, -- 11.5 prefectural, 2.0 urban; 1.940 urban (2.225 adm-urb) per citypopulation.de ["Baotou"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 2.709 prefectural, 2.2 urban; 2.104 urban (2.200 adm-urb) per citypopulation.de ["Ganzhou"] = {container = "Jiangxi"}, -- 9.0 prefectural, 1.6 urban; 1.778 urban (2.150 adm-urb) per citypopulation.de ["Pingdingshan"] = {container = "Henan"}, -- 1.046 urban (2.100 adm-urb) per citypopulation.de ["Zunyi"] = {container = "Guizhou"}, -- 6.6 prefectural, 2.4 urban/metro; 1.675 urban (2.025 adm-urb) per citypopulation.de ["Bengbu"] = {container = "Anhui"}, -- 1.078 urban (2.000 adm-urb) per citypopulation.de ["Datong"] = {container = "Shanxi"}, -- 3.105 prefectural, 2.0 urban; 1.810 urban (2.000 adm-urb) per citypopulation.de ["Anyang"] = {container = "Henan"}, -- 1.188 urban (1.960 adm-urb) per citypopulation.de ["Huai'an"] = {container = "Jiangsu"}, -- 4.556 prefectural, 2.6 urban; 1.805 urban (1.940 adm-urb) per citypopulation.de ["Zaozhuang"] = {container = "Shandong"}, -- 1.350 urban (1.900 adm-urb) per citypopulation.de ["Zhanjiang"] = {container = "Guangdong"}, -- 7.0 prefectural, 1.9 urban; 1.401 urban (1.890 adm-urb) per citypopulation.de ["Huainan"] = {container = "Anhui"}, -- 1.256 urban (1.880 adm-urb) per citypopulation.de ["Jining"] = {container = "Shandong"}, -- 8.4 prefectural, 1.5 urban; 1.700 urban (1.880 adm-urb) per citypopulation.de ["Daqing"] = {container = "Heilongjiang"}, -- 1.604 urban (1.860 adm-urb) per citypopulation.de ["Wuhu"] = {container = "Anhui"}, -- 1.598 urban (1.850 adm-urb) per citypopulation.de ["Guilin"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 1.361 urban (1.830 adm-urb) per citypopulation.de ["Mianyang"] = {container = "Sichuan"}, -- 1.549 urban (1.800 adm-urb) per citypopulation.de ["Xiangyang"] = {container = "Hubei"}, -- 1.686 urban (1.800 adm-urb) per citypopulation.de ["Huzhou"] = {container = "Zhejiang"}, -- 1.084 urban (1.750 adm-urb) per citypopulation.de ["Puyang"] = {container = "Henan"}, -- 0.824 urban (1.750 adm-urb) per citypopulation.de ["Shangqiu"] = {container = "Henan"}, -- 7.8 prefectural, 1.9 urban (2.8 metro); 1.031 urban (1.750 adm-urb) per citypopulation.de ["Qinhuangdao"] = {container = "Hebei"}, -- 1.520 urban (1.740 adm-urb) per citypopulation.de ["Xingtai"] = {container = "Hebei"}, -- 7.1 prefectural, 971,000 urban; 1.5 urban (1.700 adm-urb) per citypopulation.de ["Nanyang"] = {container = "Henan", wp = "%l, %c"}, -- 9.7 prefectural, 2.1 urban/metro; 1.481 urban (1.680 adm-urb) per citypopulation.de ["Jiaozuo"] = {container = "Henan"}, -- 0.875 urban (1.640 adm-urb) per citypopulation.de ["Jilin City"] = {container = "Jilin"}, -- 1.509 urban (1.610 adm-urb) per citypopulation.de ["Jilin"] = {alias_of = "Jilin City"}, ["Jinhua"] = {container = "Zhejiang"}, -- 7.1 prefectural, 1.5 urban; 1.041 urban (1.590 adm-urb) per citypopulation.de ["Shangrao"] = {container = "Jiangxi"}, -- 6.5 prefectural, 2.1 urban, 1.3 metro [sic]; 1.342 urban (1.580 adm-urb) per citypopulation.de ["Heze"] = {container = "Shandong"}, -- 8.8 prefectural, 1.3 urban; 1.294 urban (1.570 adm-urb) per citypopulation.de ["Yulin"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}, wp = "%l, %c"}, -- 0.878 urban (1.570 adm-urb) per citypopulation.de ["Tai'an"] = {container = "Shandong"}, -- 1.417 urban (1.560 adm-urb) per citypopulation.de ["Weihai"] = {container = "Shandong"}, -- 1.340 urban (1.510 adm-urb) per citypopulation.de -- Taizhou, Jiangsu would be here (1.490 adm-urb) but moved to china_prefecture_level_cities_2 to avoid clash ["Yancheng"] = {container = "Jiangsu"}, -- 6.7 prefectural, 1.6 urban; 1.353 urban (1.460 adm-urb) per citypopulation.de ["Zhangjiakou"] = {container = "Hebei"}, -- 1.339 urban (1.450 adm-urb) per citypopulation.de ["Maoming"] = {container = "Guangdong"}, -- 6.2 prefectural, 2.5 urban; 1.308 urban (1.440 adm-urb) per citypopulation.de ["Nanchong"] = {container = "Sichuan"}, -- 1.254 urban (1.440 adm-urb) per citypopulation.de ["Fuyang"] = {container = "Anhui", wp = "%l, %c"}, -- 8.2 prefectural, 2.1 urban; 1.191 urban (1.410 adm-urb) per citypopulation.de ["Xuchang"] = {container = "Henan"}, -- 0.850 urban (1.390 adm-urb) per citypopulation.de ["Yichang"] = {container = "Hubei"}, -- 1.284 urban (1.390 adm-urb) per citypopulation.de ["Dazhou"] = {container = "Sichuan"}, -- 1.136 urban (1.380 adm-urb) per citypopulation.de ["Kaifeng"] = {container = "Henan"}, -- 1.194 urban (1.340 adm-urb) per citypopulation.de ["Luzhou"] = {container = "Sichuan"}, -- 1.128 urban (1.340 adm-urb) per citypopulation.de ["Qingyuan"] = {container = "Guangdong"}, -- 1.198 urban (1.340 adm-urb) per citypopulation.de ["Huaibei"] = {container = "Anhui"}, -- 0.831 urban (1.330 adm-urb) per citypopulation.de ["Yibin"] = {container = "Sichuan"}, -- 1.101 urban (1.310 adm-urb) per citypopulation.de ["Lu'an"] = {container = "Anhui"}, -- 1.070 urban (1.300 adm-urb) per citypopulation.de ["Dezhou"] = {container = "Shandong"}, -- 0.843 urban (1.290 adm-urb) per citypopulation.de ["Rizhao"] = {container = "Shandong"}, -- 1.147 urban (1.270 adm-urb) per citypopulation.de ["Changzhi"] = {container = "Shanxi"}, -- 1.047 urban (1.250 adm-urb) per citypopulation.de ["Hengyang"] = {container = "Hunan"}, -- 6.6 prefectural, 1.5 urban; 1.185 urban (1.250 adm-urb) per citypopulation.de ["Jinzhou"] = {container = "Liaoning"}, -- 1.021 urban (1.240 adm-urb) per citypopulation.de ["Liaocheng"] = {container = "Shandong"}, -- 1.020 urban (1.240 adm-urb) per citypopulation.de ["Changde"] = {container = "Hunan"}, -- 1.101 urban (1.230 adm-urb) per citypopulation.de ["Suqian"] = {container = "Jiangsu"}, -- 1.082 urban (1.230 adm-urb) per citypopulation.de ["Xinyang"] = {container = "Henan"}, -- 6.2 prefectural, 1.4 urban/metro; 1.015 urban (1.230 adm-urb) per citypopulation.de ["Baoji"] = {container = "Shaanxi"}, -- 1.108 urban (1.220 adm-urb) per citypopulation.de ["Yueyang"] = {container = "Hunan"}, -- 1.125 urban (1.220 adm-urb) per citypopulation.de ["Zhenjiang"] = {container = "Jiangsu"}, -- 1.124 urban (1.210 adm-urb) per citypopulation.de -- Wanzhou is a "district" of the "direct-administered municipality" of Chongqing but in fact is 142 miles away from Chongqing city proper. ["Wanzhou"] = {placetype = "district", container = {key = "Chongqing", placetype = "direct-administered municipality"}, divs = {"subdistricts", "townships"}, wp = "%l, %c"}, -- 1.078 urban (1.190 adm-urb) per citypopulation.de ["Ulanhad"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 1.093 urban (1.180 adm-urb) per citypopulation.de ["Chifeng"] = {alias_of = "Ulanhad"}, ["Ulankhad"] = {alias_of = "Ulanhad", display = true}, ["Ezhou"] = {container = "Hubei"}, -- < 0.750 urban (1.180 adm-urb) per citypopulation.de ["Zhaoqing"] = {container = "Guangdong"}, -- 1.036 urban (1.160 adm-urb) per citypopulation.de ["Lianyungang"] = {container = "Jiangsu"}, -- 4.599 prefectural, 2.0 urban; 1.071 urban (1.150 adm-urb) per citypopulation.de ["Qujing"] = {container = "Yunnan"}, -- 0.976 urban (1.150 adm-urb) per citypopulation.de -- Shuyang is a "county" of the "prefecture-level city" of Suqian but in fact is 38 miles away from Suqian city proper (urban core to urban core). -- The county itself is 37 miles by 34 miles. ["Shuyang"] = {placetype = "county", container = {key = "Suqian", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}, wp = "%l County"}, -- 0.986 urban (1.120 adm-urb) per citypopulation.de -- Yongkang is a "county-level city" of the "prefecture-level city" of Jinhua but in fact is 32 miles away from Jinhua city proper (urban core to urban core). ["Yongkang"] = {placetype = "county-level city", container = {key = "Jinhua", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}, wp = "%l, Zhejiang"}, -- < 0.750 urban (1.110 adm-urb) per citypopulation.de ["Zhoukou"] = {container = "Henan"}, -- 9.0 prefectural, 721,000 urban (1.6 metro); < 0.750 urban (1.100 adm-urb) per citypopulation.de ["Beihai"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- < 1 urban (1.090 adm-urb) per citypopulation.de ["Jiujiang"] = {container = "Jiangxi"}, -- < 0.750 urban (1.080 adm-urb) per citypopulation.de ["Shaoyang"] = {container = "Hunan"}, -- 6.6 prefectural, 802,000 urban, 1.4 metro; < 1 urban (1.080 adm-urb) per citypopulation.de ["Chuzhou"] = {container = "Anhui"}, -- < 0.750 urban (1.070 adm-urb) per citypopulation.de ["Hengshui"] = {container = "Hebei"}, -- 0.885 urban (1.070 adm-urb) per citypopulation.de ["Shiyan"] = {container = "Hubei"}, -- 0.955 urban (1.070 adm-urb) per citypopulation.de ["Huludao"] = {container = "Liaoning"}, -- 0.764 urban (1.060 adm-urb) per citypopulation.de ["Dongying"] = {container = "Shandong"}, -- 0.961 urban (1.050 adm-urb) per citypopulation.de ["Guigang"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 0.921 urban (1.050 adm-urb) per citypopulation.de -- Liuyang is a "county-level city" of the "prefecture-level city" of Changsha but in fact is 47 miles away from Changsha city proper (urban core to urban core). ["Liuyang"] = {placetype = "county-level city", container = {key = "Changsha", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 0.886 urban (1.040 adm-urb) per citypopulation.de -- NOTE: Not to be confused with Changzhou in Jiangsu ["Cangzhou"] = {container = "Hebei"}, -- 7.3 prefectural, 621,000 urban; 0.759 urban (1.030 adm-urb) per citypopulation.de ["Liupanshui"] = {container = "Guizhou"}, -- < 0.750 urban (1.030 adm-urb) per citypopulation.de ["Panjin"] = {container = "Liaoning"}, -- 0.980 urban (1.030 adm-urb) per citypopulation.de ["Qiqihar"] = {container = "Heilongjiang"}, -- 1.030 urban (1.030 adm-urb) per citypopulation.de ["Linfen"] = {container = "Shanxi"}, -- < 0.750 urban (1.010 adm-urb) per citypopulation.de -- Tengzhou is a "county-level city" of the "prefecture-level city" of Zaozhuang but in fact is 30 miles away from Zaozhuang city proper (urban core to urban core). ["Tengzhou"] = {placetype = "county-level city", container = {key = "Zaozhuang", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 0.937 urban (1.010 adm-urb) per citypopulation.de -- 3 extra that got added in earlier incarnations and aren't found in the "major agglomerations of the world" page https://citypopulation.de/en/world/agglomerations/ reference date 2025-01-01 ["Kunshan"] = {container = "Jiangsu"}, -- 1.652 urban (2020 China census) per citypopulation.de ["Zhumadian"] = {container = "Henan"}, -- 7.0 prefectural, 722,000 urban per Wikipedia; 0.754 urban per citypopulation.de ["Bijie"] = {container = "Guizhou"}, -- 6.9 prefectural, ? urban, ? metro (not listed in Wikipedia); < 0.750 urban per citypopulation.de } export.china_prefecture_level_cities_group = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Taizhou, Zhejiang" or "Suzhou, Anhui". key_to_placename = false, placename_to_key = false, -- don't add ", China" to make the key default_container = "China", canonicalize_key_container = make_canonicalize_key_container(", China", "province"), -- Prefecture-level cities aren't really cities but allow them to be identified that way, as many people -- don't understand how Chinese administrative divisions work. default_placetype = {"prefecture-level city", "city"}, default_divs = { -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities, -- and prefecture-level cities (as well as county-level cities) are considered non-cities. "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_prefecture_level_cities, } -- Needed to avoid problems with two cities called Taizhou and Suzhou. export.china_prefecture_level_cities_2 = { -- NOTE: There is also a larger and better-known prefecture-level city Taizhou in Zhejiang. ["Taizhou, Jiangsu"] = {container = "Jiangsu"}, -- 1.3 urban (1.490 adm-urb) per citypopulation.de 2020 census ["Taizhou"] = {alias_of = "Taizhou, Jiangsu"}, -- NOTE: There is also a larger and better-known prefecture-level city Suzhou in Jiangsu. ["Suzhou, Anhui"] = {container = "Anhui"}, -- 5.3 prefectural, 1.766 metro and "urban"; < 1 urban (1.010 adm-urb) per citypopulation.de 2020 census -- hopefully this will work because we also have Suzhou as a key by itself for the larger, more-well-known Suzhou in Jiangsu ["Suzhou"] = {alias_of = "Suzhou, Anhui"}, } export.china_prefecture_level_cities_group_2 = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Taizhou, Jiangsu". placename_to_key = false, -- don't add ", China" to make the key default_container = "China", canonicalize_key_container = make_canonicalize_key_container(", China", "province"), -- Prefecture-level cities aren't really cities but allow them to be identified that way, as many people -- don't understand how Chinese administrative divisions work. default_placetype = {"prefecture-level city", "city"}, default_divs = { -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities, -- and prefecture-level cities (as well as county-level cities) are considered non-cities. "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_prefecture_level_cities_2, } export.finland_regions = { ["Lapland, Finland"] = {wp = "%l (%c)"}, ["North Ostrobothnia, Finland"] = {}, ["Northern Ostrobothnia, Finland"] = {alias_of = "North Ostrobothnia, Finland", display = true}, ["Kainuu, Finland"] = {}, ["North Karelia, Finland"] = {}, ["Northern Savonia, Finland"] = {}, ["North Savo, Finland"] = {alias_of = "Northern Savonia, Finland", display = true}, ["Southern Savonia, Finland"] = {}, ["South Savo, Finland"] = {alias_of = "Southern Savonia, Finland", display = true}, ["South Karelia, Finland"] = {}, ["Central Finland, Finland"] = {}, ["South Ostrobothnia, Finland"] = {}, ["Southern Ostrobothnia, Finland"] = {alias_of = "South Ostrobothnia, Finland", display = true}, ["Ostrobothnia, Finland"] = {wp = "%l (region)"}, ["Central Ostrobothnia, Finland"] = {}, ["Pirkanmaa, Finland"] = {}, ["Satakunta, Finland"] = {}, ["Päijänne Tavastia, Finland"] = {}, ["Päijät-Häme, Finland"] = {alias_of = "Päijänne Tavastia, Finland", display = true}, ["Tavastia Proper, Finland"] = {}, ["Kanta-Häme, Finland"] = {alias_of = "Tavastia Proper, Finland", display = true}, ["Kymenlaakso, Finland"] = {}, ["Uusimaa, Finland"] = {}, ["Southwest Finland, Finland"] = {}, ["Åland Islands, Finland"] = {the = true, wp = "Åland"}, ["Åland, Finland"] = {alias_of = "Åland Islands, Finland"}, -- differs in "the" } -- regions of Finland export.finland_group = { default_container = "Finland", default_placetype = "region", default_divs = "municipalities", data = export.finland_regions, } export.france_administrative_regions = { ["Auvergne-Rhône-Alpes, France"] = {}, ["Bourgogne-Franche-Comté, France"] = {}, ["Brittany, France"] = {wp = "%l (administrative region)"}, ["Centre-Val de Loire, France"] = {}, ["Corsica, France"] = {}, -- overseas departments are handled in `export.country_like_entities` -- ["French Guiana"] = {}, ["Grand Est, France"] = {}, -- ["Guadeloupe"] = {}, ["Hauts-de-France, France"] = {}, ["Île-de-France, France"] = {}, -- ["Martinique"] = {}, -- ["Mayotte"] = {}, ["Normandy, France"] = {wp = "%l (administrative region)"}, ["Nouvelle-Aquitaine, France"] = {}, ["Occitania, France"] = {wp = "%l (administrative region)"}, ["Occitanie, France"] = {alias_of = "Occitania, France", display = true}, ["Pays de la Loire, France"] = {}, ["Provence-Alpes-Côte d'Azur, France"] = {}, -- ["Réunion"] = {}, } -- administrative regions of France export.france_group = { default_container = "France", -- Canonically these are 'administrative regions' but also treat as 'region' ('administrative region' falls back -- to 'region'). default_placetype = "region", default_divs = { "communes", {type = "municipalities", cat_as = "communes"}, "departments", {type = "prefectures", cat_as = {"prefectures", "departmental capitals"}}, {type = "French prefectures", cat_as = {"prefectures", "departmental capitals"}}, }, data = export.france_administrative_regions, } export.france_departments = { ["Ain, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 01 ["Aisne, France"] = {container = "Hauts-de-France"}, -- 02 ["Allier, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 03 ["Alpes-de-Haute-Provence, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 04 ["Hautes-Alpes, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 05 ["Alpes-Maritimes, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 06 ["Ardèche, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 07 ["Ardennes, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 08 ["Ariège, France"] = {container = "Occitania", wp = "%l (department)"}, -- 09 ["Aube, France"] = {container = "Grand Est"}, -- 10 ["Aude, France"] = {container = "Occitania"}, -- 11 ["Aveyron, France"] = {container = "Occitania"}, -- 12 ["Bouches-du-Rhône, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 13 ["Calvados, France"] = {container = "Normandy", wp = "%l (department)"}, -- 14 ["Cantal, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 15 ["Charente, France"] = {container = "Nouvelle-Aquitaine"}, -- 16 ["Charente-Maritime, France"] = {container = "Nouvelle-Aquitaine"}, -- 17 ["Cher, France"] = {container = "Centre-Val de Loire", wp = "%l (department)"}, -- 18 ["Corrèze, France"] = {container = "Nouvelle-Aquitaine"}, -- 19 ["Corse-du-Sud, France"] = {container = "Corsica"}, -- 2A ["Haute-Corse, France"] = {container = "Corsica"}, -- 2B ["Côte-d'Or, France"] = {container = "Bourgogne-Franche-Comté"}, -- 21 ["Côte d'Or, France"] = {alias_of = "Côte-d'Or, France", display = true}, ["Côtes-d'Armor, France"] = {container = "Brittany"}, -- 22 ["Côtes d'Armor, France"] = {alias_of = "Côtes-d'Armor, France", display = true}, ["Creuse, France"] = {container = "Nouvelle-Aquitaine"}, -- 23 ["Dordogne, France"] = {container = "Nouvelle-Aquitaine"}, -- 24 ["Doubs, France"] = {container = "Bourgogne-Franche-Comté"}, -- 25 ["Drôme, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 26 ["Eure, France"] = {container = "Normandy"}, -- 27 ["Eure-et-Loir, France"] = {container = "Centre-Val de Loire"}, -- 28 ["Finistère, France"] = {container = "Brittany"}, -- 29 ["Gard, France"] = {container = "Occitania"}, -- 30 ["Haute-Garonne, France"] = {container = "Occitania"}, -- 31 ["Gers, France"] = {container = "Occitania"}, -- 32 ["Gironde, France"] = {container = "Nouvelle-Aquitaine"}, -- 33 ["Hérault, France"] = {container = "Occitania"}, -- 34 ["Ille-et-Vilaine, France"] = {container = "Brittany"}, -- 35 ["Indre, France"] = {container = "Centre-Val de Loire"}, -- 36 ["Indre-et-Loire, France"] = {container = "Centre-Val de Loire"}, -- 37 ["Isère, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 38 ["Jura, France"] = {container = "Bourgogne-Franche-Comté", wp = "%l (department)"}, -- 39 ["Landes, France"] = {container = "Nouvelle-Aquitaine", wp = "%l (department)"}, -- 40 ["Loir-et-Cher, France"] = {container = "Centre-Val de Loire"}, -- 41 ["Loire, France"] = {container = "Auvergne-Rhône-Alpes", wp = "%l (department)"}, -- 42 ["Haute-Loire, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 43 ["Loire-Atlantique, France"] = {container = "Pays de la Loire"}, -- 44 ["Loiret, France"] = {container = "Centre-Val de Loire"}, -- 45 ["Lot, France"] = {container = "Occitania", wp = "%l (department)"}, -- 46 ["Lot-et-Garonne, France"] = {container = "Nouvelle-Aquitaine"}, -- 47 ["Lozère, France"] = {container = "Occitania"}, -- 48 ["Maine-et-Loire, France"] = {container = "Pays de la Loire"}, -- 49 ["Manche, France"] = {container = "Normandy"}, -- 50 ["Marne, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 51 ["Haute-Marne, France"] = {container = "Grand Est"}, -- 52 ["Mayenne, France"] = {container = "Pays de la Loire"}, -- 53 ["Meurthe-et-Moselle, France"] = {container = "Grand Est"}, -- 54 ["Meuse, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 55 ["Morbihan, France"] = {container = "Brittany"}, -- 56 ["Moselle, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 57 ["Nièvre, France"] = {container = "Bourgogne-Franche-Comté"}, -- 58 ["Nord, France"] = {container = "Hauts-de-France", wp = "%l (French department)"}, -- 59 ["Oise, France"] = {container = "Hauts-de-France"}, -- 60 ["Orne, France"] = {container = "Normandy"}, -- 61 ["Pas-de-Calais, France"] = {container = "Hauts-de-France"}, -- 62 ["Puy-de-Dôme, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 63 ["Pyrénées-Atlantiques, France"] = {container = "Nouvelle-Aquitaine"}, -- 64 ["Hautes-Pyrénées, France"] = {container = "Occitania"}, -- 65 ["Pyrénées-Orientales, France"] = {container = "Occitania"}, -- 66 ["Bas-Rhin, France"] = {container = "Grand Est"}, -- 67 ["Haut-Rhin, France"] = {container = "Grand Est"}, -- 68 ["Rhône, France"] = {container = "Auvergne-Rhône-Alpes", wp = "%l (department)"}, -- 69D ["Metropolis of Lyon, France"] = {container = "Auvergne-Rhône-Alpes", the = true}, -- 69M ["Lyon Metropolis, France"] = {alias_of = "Metropolis of Lyon, France"}, ["Lyon, France"] = {alias_of = "Metropolis of Lyon, France"}, ["Haute-Saône, France"] = {container = "Bourgogne-Franche-Comté"}, -- 70 ["Saône-et-Loire, France"] = {container = "Bourgogne-Franche-Comté"}, -- 71 ["Sarthe, France"] = {container = "Pays de la Loire"}, -- 72 ["Savoie, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 73 ["Haute-Savoie, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 74 ["Paris, France"] = {container = "Île-de-France"}, -- 75 ["Seine-Maritime, France"] = {container = "Normandy"}, -- 76 ["Seine-et-Marne, France"] = {container = "Île-de-France"}, -- 77 ["Yvelines, France"] = {container = "Île-de-France"}, -- 78 ["Deux-Sèvres, France"] = {container = "Nouvelle-Aquitaine"}, -- 79 ["Somme, France"] = {container = "Hauts-de-France", wp = "%l (department)"}, -- 80 ["Tarn, France"] = {container = "Occitania", wp = "%l (department)"}, -- 81 ["Tarn-et-Garonne, France"] = {container = "Occitania"}, -- 82 ["Var, France"] = {container = "Provence-Alpes-Côte d'Azur", wp = "%l (department)"}, -- 83 ["Vaucluse, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 84 ["Vendée, France"] = {container = "Pays de la Loire"}, -- 85 ["Vienne, France"] = {container = "Nouvelle-Aquitaine", wp = "%l (department)"}, -- 86 ["Haute-Vienne, France"] = {container = "Nouvelle-Aquitaine"}, -- 87 ["Vosges, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 88 ["Yonne, France"] = {container = "Bourgogne-Franche-Comté"}, -- 89 ["Territoire de Belfort, France"] = {container = "Bourgogne-Franche-Comté"}, -- 90 ["Essonne, France"] = {container = "Île-de-France"}, -- 91 ["Hauts-de-Seine, France"] = {container = "Île-de-France"}, -- 92 ["Seine-Saint-Denis, France"] = {container = "Île-de-France"}, -- 93 ["Val-de-Marne, France"] = {container = "Île-de-France"}, -- 94 ["Val-d'Oise, France"] = {container = "Île-de-France"}, -- 95 --["Guadeloupe"] = {container = "Guadeloupe"}, -- 971 --["Martinique"] = {container = "Martinique"}, -- 972 --["Guyane"] = {container = "French Guiana", wp = "French Guiana"}, -- 973 --["La Réunion"] = {container = "Réunion", wp = "Réunion"}, -- 974 --["Mayotte"] = {container = "Mayotte"}, -- 976 } export.france_departments_group = { placename_to_key = make_placename_to_key(", France"), canonicalize_key_container = make_canonicalize_key_container(", France", "region"), default_placetype = "department", default_divs = { "communes", {type = "municipalities", cat_as = "communes"}, }, data = export.france_departments, } export.germany_states = { ["Baden-Württemberg, Germany"] = {}, ["Bavaria, Germany"] = {}, -- Berlin, Bremen and Hamburg are effectively city-states and don't have districts ([[Kreise]]), so override -- the default_divs setting. Better not to include them at all since they're included as cities down below. -- ["Berlin"] = {divs = {}}, ["Brandenburg, Germany"] = {}, -- ["Bremen"] = {divs = {}}, -- ["Hamburg"] = {divs = {}}, ["Hesse, Germany"] = {}, ["Lower Saxony, Germany"] = {}, ["Mecklenburg-Vorpommern, Germany"] = {}, ["Mecklenburg-Western Pomerania, Germany"] = {alias_of = "Mecklenburg-Vorpommern, Germany", display = true}, ["North Rhine-Westphalia, Germany"] = {}, ["Rhineland-Palatinate, Germany"] = {}, ["Saarland, Germany"] = {}, ["Saxony, Germany"] = {}, ["Saxony-Anhalt, Germany"] = {}, ["Schleswig-Holstein, Germany"] = {}, ["Thuringia, Germany"] = {}, } -- states of Germany export.germany_group = { default_container = "Germany", default_placetype = "state", default_divs = {"districts", "municipalities"}, data = export.germany_states, } export.greece_regions = { ["Attica, Greece"] = {wp = "%l (region)"}, ["Central Greece, Greece"] = {wp = "%l (administrative region)"}, ["Central Macedonia, Greece"] = {}, ["Crete, Greece"] = {}, ["Eastern Macedonia and Thrace, Greece"] = {}, ["Epirus, Greece"] = {wp = "%l (region)"}, ["Ionian Islands, Greece"] = {the = true, wp = "%l (region)"}, ["North Aegean, Greece"] = {the = true}, -- I would expect 'the Peloponnese' but Wikipedia mostly has categories like [[w:Category:Geography of Peloponnese (region)]] -- and [[w:Category:Buildings and structures in Peloponnese (region)]]; only [[w:Category:People from the Peloponnese (region)]] -- has "the" in it. ["Peloponnese, Greece"] = {wp = "%l (region)"}, ["South Aegean, Greece"] = {the = true}, ["Thessaly, Greece"] = {}, ["Western Greece, Greece"] = {}, ["Western Macedonia, Greece"] = {}, ["Mount Athos, Greece"] = {placetype = {"autonomous region", "region"}, wp = "Monastic community of Mount Athos"}, } -- regions of Greece export.greece_group = { default_container = "Greece", default_placetype = "region", data = export.greece_regions, } local india_polity_with_divisions = {"divisions", "districts"} local india_polity_without_divisions = {"districts"} -- States and union territories of India. Only some of them are divided into divisions. export.india_states_and_union_territories = { ["Andaman and Nicobar Islands, India"] = {the = true, placetype = "union territory", divs = india_polity_without_divisions}, ["Andhra Pradesh, India"] = {divs = india_polity_without_divisions}, ["Arunachal Pradesh, India"] = {divs = india_polity_with_divisions}, ["Assam, India"] = {divs = india_polity_with_divisions}, ["Bihar, India"] = {divs = india_polity_with_divisions}, ["Chandigarh, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Chhattisgarh, India"] = {divs = india_polity_with_divisions}, ["Dadra and Nagar Haveli and Daman and Diu, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Delhi, India"] = {placetype = "union territory", divs = india_polity_with_divisions}, ["Goa, India"] = {divs = india_polity_without_divisions}, ["Gujarat, India"] = {divs = india_polity_without_divisions}, ["Haryana, India"] = {divs = india_polity_with_divisions}, ["Himachal Pradesh, India"] = {divs = india_polity_with_divisions}, ["Jammu and Kashmir, India"] = {placetype = "union territory", divs = india_polity_with_divisions, wp = "%l (union territory)"}, ["Jharkhand, India"] = {divs = india_polity_with_divisions}, ["Karnataka, India"] = {divs = india_polity_with_divisions}, ["Kerala, India"] = {divs = india_polity_without_divisions}, ["Ladakh, India"] = {placetype = "union territory", divs = india_polity_with_divisions}, ["Lakshadweep, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Madhya Pradesh, India"] = {divs = india_polity_with_divisions}, ["Maharashtra, India"] = {divs = india_polity_with_divisions}, ["Manipur, India"] = {divs = india_polity_without_divisions}, ["Meghalaya, India"] = {divs = india_polity_with_divisions}, ["Mizoram, India"] = {divs = india_polity_without_divisions}, ["Nagaland, India"] = {divs = india_polity_with_divisions}, ["Odisha, India"] = {divs = india_polity_with_divisions}, ["Puducherry, India"] = {placetype = "union territory", divs = india_polity_without_divisions, wp = "%l (union territory)"}, ["Pondicherry, India"] = {alias_of = "Puducherry, India", display = true}, ["Punjab, India"] = {divs = india_polity_with_divisions, wp = "%l, %c"}, ["Rajasthan, India"] = {divs = india_polity_with_divisions}, ["Sikkim, India"] = {divs = india_polity_without_divisions}, ["Tamil Nadu, India"] = {divs = india_polity_without_divisions}, ["Telangana, India"] = {divs = india_polity_without_divisions}, ["Tripura, India"] = {divs = india_polity_without_divisions}, ["Uttar Pradesh, India"] = {divs = india_polity_with_divisions}, ["Uttarakhand, India"] = {divs = india_polity_with_divisions}, ["West Bengal, India"] = {divs = india_polity_with_divisions}, } -- states and union territories of India export.india_group = { default_container = "India", default_placetype = "state", data = export.india_states_and_union_territories, } export.indonesia_provinces = { ["Aceh, Indonesia"] = {}, ["Bali, Indonesia"] = {}, ["Bangka Belitung Islands, Indonesia"] = {the = true}, ["Banten, Indonesia"] = {}, ["Bengkulu, Indonesia"] = {}, ["Central Java, Indonesia"] = {}, ["Central Kalimantan, Indonesia"] = {}, ["Central Papua, Indonesia"] = {}, ["Central Sulawesi, Indonesia"] = {}, ["East Java, Indonesia"] = {}, ["East Kalimantan, Indonesia"] = {}, ["East Nusa Tenggara, Indonesia"] = {}, ["Gorontalo, Indonesia"] = {}, ["Highland Papua, Indonesia"] = {wp = "%l"}, ["Special Capital Region of Jakarta, Indonesia"] = {the = true, wp = "Jakarta"}, ["Jakarta, Indonesia"] = {alias_of = "Special Capital Region of Jakarta, Indonesia"}, ["Jambi, Indonesia"] = {}, ["Lampung, Indonesia"] = {}, ["Maluku, Indonesia"] = {}, ["North Kalimantan, Indonesia"] = {}, ["North Maluku, Indonesia"] = {}, ["North Sulawesi, Indonesia"] = {}, ["North Papua, Indonesia"] = {}, ["North Sumatra, Indonesia"] = {}, ["Papua, Indonesia"] = {wp = "%l (province)"}, ["Riau, Indonesia"] = {}, ["Riau Islands, Indonesia"] = {the = true}, ["Southeast Sulawesi, Indonesia"] = {}, ["South Kalimantan, Indonesia"] = {}, ["South Papua, Indonesia"] = {}, ["South Sulawesi, Indonesia"] = {}, ["South Sumatra, Indonesia"] = {}, ["Southwest Papua, Indonesia"] = {}, ["West Java, Indonesia"] = {}, ["West Kalimantan, Indonesia"] = {}, ["West Nusa Tenggara, Indonesia"] = {}, ["West Papua, Indonesia"] = {wp = "%l (province)"}, ["West Sulawesi, Indonesia"] = {}, ["West Sumatra, Indonesia"] = {}, ["Special Region of Yogyakarta, Indonesia"] = {the = true}, ["Yogyakarta, Indonesia"] = {alias_of = "Special Region of Yogyakarta, Indonesia"}, } -- provinces of Indonesia export.indonesia_group = { default_container = "Indonesia", default_placetype = "province", -- per https://www.quora.com/Does-Indonesia-use-British-or-American-English, Indonesia tends to use American -- spellings. data = export.indonesia_provinces, } export.iran_provinces = { ["Alborz Province, Iran"] = {}, -- abbreviation AL, capital [[w:Karaj]] ["Ardabil Province, Iran"] = {}, -- abbreviation AR, capital [[w:Ardabil]] ["Bushehr Province, Iran"] = {}, -- abbreviation BU, capital [[w:Bushehr]] ["Chaharmahal and Bakhtiari Province, Iran"] = {}, -- abbreviation CB, capital [[w:Shahr-e Kord]] ["East Azerbaijan Province, Iran"] = {}, -- abbreviation EA, capital [[w:Tabriz]] ["Fars Province, Iran"] = {}, -- abbreviation FA, capital [[w:Shiraz]] ["Pars Province, Iran"] = {alias_of = "Fars Province, Iran", display = true}, ["Gilan Province, Iran"] = {}, -- abbreviation GN, capital [[w:Rasht]] ["Golestan Province, Iran"] = {}, -- abbreviation GO, capital [[w:Gorgan]] ["Hamadan Province, Iran"] = {}, -- abbreviation HA, capital [[w:Hamadan]] ["Hormozgan Province, Iran"] = {}, -- abbreviation HO, capital [[w:Bandar Abbas]] ["Ilam Province, Iran"] = {}, -- abbreviation IL, capital [[w:Ilam, Iran|Ilam]] ["Isfahan Province, Iran"] = {}, -- abbreviation IS, capital [[w:Isfahan]] ["Kerman Province, Iran"] = {}, -- abbreviation KN, capital [[w:Kerman]] ["Kermanshah Province, Iran"] = {}, -- abbreviation KE, capital [[w:Kermanshah]] ["Khuzestan Province, Iran"] = {}, -- abbreviation KH, capital [[w:Ahvaz]] ["Kohgiluyeh and Boyer-Ahmad Province, Iran"] = {}, -- abbreviation KB, capital [[w:Yasuj]] ["Kurdistan Province, Iran"] = {}, -- abbreviation KU, capital [[w:Sanandaj]] ["Lorestan Province, Iran"] = {}, -- abbreviation LO, capital [[w:Khorramabad]] ["Markazi Province, Iran"] = {}, -- abbreviation MA, capital [[w:Arak, Iran|Arak]] ["Mazandaran Province, Iran"] = {}, -- abbreviation MN, capital [[w:Sari, Iran|Sari]] ["North Khorasan Province, Iran"] = {}, -- abbreviation NK, capital [[w:Bojnord]] ["Qazvin Province, Iran"] = {}, -- abbreviation QA, capital [[w:Qazvin]] ["Qom Province, Iran"] = {}, -- abbreviation QM, capital [[w:Qom]] ["Razavi Khorasan Province, Iran"] = {}, -- abbreviation RK, capital [[w:Mashhad]] ["Semnan Province, Iran"] = {}, -- abbreviation SE, capital [[w:Semnan, Iran|Semnan]] ["Sistan and Baluchestan Province, Iran"] = {}, -- abbreviation SB, capital [[w:Zahedan]] ["South Khorasan Province, Iran"] = {}, -- abbreviation SK, capital [[w:Birjand]] ["Tehran Province, Iran"] = {}, -- abbreviation TE, capital [[w:Tehran]] ["West Azerbaijan Province, Iran"] = {}, -- abbreviation WA, capital [[w:Urmia]] ["Yazd Province, Iran"] = {}, -- abbreviation YA, capital [[w:Yazd]] ["Zanjan Province, Iran"] = {}, -- abbreviation ZA, capital [[w:Zanjan, Iran|Zanjan]] } -- provinces of Iran export.iran_group = { key_to_placename = make_key_to_placename(", Iran", " Province$"), placename_to_key = make_placename_to_key(", Iran", " Province"), default_container = "Iran", default_placetype = "province", -- There aren't nearly enough counties of Iran currently entered in any language to allow for categorizing them -- per-province. (As of 2025-05-09, there are only 6 counties in each of [[Category:en:Counties of Iran]], -- [[Category:fa:Counties of Iran]] and [[Category:ar:Counties of Iran]].) -- default_divs = "counties", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.iran_provinces, } export.ireland_counties = { ["County Carlow, Ireland"] = {}, ["County Cavan, Ireland"] = {}, ["County Clare, Ireland"] = {}, ["County Cork, Ireland"] = {}, ["County Donegal, Ireland"] = {}, ["County Dublin, Ireland"] = {}, ["County Galway, Ireland"] = {}, ["County Kerry, Ireland"] = {}, ["County Kildare, Ireland"] = {}, ["County Kilkenny, Ireland"] = {}, ["County Laois, Ireland"] = {}, ["County Leitrim, Ireland"] = {}, ["County Limerick, Ireland"] = {}, ["County Longford, Ireland"] = {}, ["County Louth, Ireland"] = {}, ["County Mayo, Ireland"] = {}, ["County Meath, Ireland"] = {}, ["County Monaghan, Ireland"] = {}, ["County Offaly, Ireland"] = {}, ["County Roscommon, Ireland"] = {}, ["County Sligo, Ireland"] = {}, ["County Tipperary, Ireland"] = {}, ["County Waterford, Ireland"] = {}, ["County Westmeath, Ireland"] = {}, ["County Wexford, Ireland"] = {}, ["County Wicklow, Ireland"] = {}, } local function make_irish_type_key_to_placename(container_pattern) return function(key) key = key:gsub(container_pattern, "") local elliptical_key = key:gsub("^County ", "") return key, elliptical_key end end local function make_irish_type_placename_to_key(container_suffix) return function(placename) if not placename:find("^County ") and not placename:find("^City ") then placename = "County " .. placename end return placename .. container_suffix end end -- counties of Ireland export.ireland_group = { key_to_placename = make_irish_type_key_to_placename(", Ireland$"), placename_to_key = make_irish_type_placename_to_key(", Ireland"), default_container = "Ireland", default_placetype = "county", data = export.ireland_counties, } export.italy_administrative_regions = { ["Abruzzo, Italy"] = {}, ["Aosta Valley, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Apulia, Italy"] = {}, ["Basilicata, Italy"] = {}, ["Calabria, Italy"] = {}, ["Campania, Italy"] = {}, ["Emilia-Romagna, Italy"] = {}, ["Friuli-Venezia Giulia, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Lazio, Italy"] = {}, ["Liguria, Italy"] = {}, ["Lombardy, Italy"] = {}, ["Marche, Italy"] = {}, ["Molise, Italy"] = {}, ["Piedmont, Italy"] = {}, ["Sardinia, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Sicily, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Trentino-Alto Adige, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Tuscany, Italy"] = {}, ["Umbria, Italy"] = {}, ["Veneto, Italy"] = {}, } -- administrative regions of Italy export.italy_group = { default_container = "Italy", default_placetype = "region", data = export.italy_administrative_regions, } -- table of Japanese prefectures; interpolated into the main 'places' table, but also needed separately export.japan_prefectures = { ["Aichi Prefecture, Japan"] = {}, ["Akita Prefecture, Japan"] = {}, ["Aomori Prefecture, Japan"] = {}, ["Chiba Prefecture, Japan"] = {}, ["Ehime Prefecture, Japan"] = {}, ["Fukui Prefecture, Japan"] = {}, ["Fukuoka Prefecture, Japan"] = {}, ["Fukushima Prefecture, Japan"] = {}, ["Gifu Prefecture, Japan"] = {}, ["Gunma Prefecture, Japan"] = {}, ["Hiroshima Prefecture, Japan"] = {}, ["Hokkaido Prefecture, Japan"] = {divs = "subprefectures", wp = "Hokkaido"}, ["Hyōgo Prefecture, Japan"] = {}, ["Hyogo Prefecture, Japan"] = {alias_of = "Hyōgo Prefecture, Japan", display = true}, ["Ibaraki Prefecture, Japan"] = {}, ["Ishikawa Prefecture, Japan"] = {}, ["Iwate Prefecture, Japan"] = {}, ["Kagawa Prefecture, Japan"] = {}, ["Kagoshima Prefecture, Japan"] = {}, ["Kanagawa Prefecture, Japan"] = {}, ["Kōchi Prefecture, Japan"] = {}, ["Kochi Prefecture, Japan"] = {alias_of = "Kōchi Prefecture, Japan", display = true}, ["Kumamoto Prefecture, Japan"] = {}, ["Kyoto Prefecture, Japan"] = {}, ["Mie Prefecture, Japan"] = {}, ["Miyagi Prefecture, Japan"] = {}, ["Miyazaki Prefecture, Japan"] = {}, ["Nagano Prefecture, Japan"] = {}, ["Nagasaki Prefecture, Japan"] = {}, ["Nara Prefecture, Japan"] = {}, ["Niigata Prefecture, Japan"] = {}, ["Ōita Prefecture, Japan"] = {}, ["Oita Prefecture, Japan"] = {alias_of = "Ōita Prefecture, Japan", display = true}, ["Okayama Prefecture, Japan"] = {}, ["Okinawa Prefecture, Japan"] = {}, ["Osaka Prefecture, Japan"] = {}, ["Saga Prefecture, Japan"] = {}, ["Saitama Prefecture, Japan"] = {}, ["Shiga Prefecture, Japan"] = {}, ["Shimane Prefecture, Japan"] = {}, ["Shizuoka Prefecture, Japan"] = {}, ["Tochigi Prefecture, Japan"] = {}, ["Tokushima Prefecture, Japan"] = {}, ["Tottori Prefecture, Japan"] = {}, ["Toyama Prefecture, Japan"] = {}, ["Wakayama Prefecture, Japan"] = {}, ["Yamagata Prefecture, Japan"] = {}, ["Yamaguchi Prefecture, Japan"] = {}, ["Yamanashi Prefecture, Japan"] = {}, } -- prefectures of Japan export.japan_group = { key_to_placename = make_key_to_placename(", Japan$", " Prefecture$"), placename_to_key = make_placename_to_key(", Japan", " Prefecture"), default_container = "Japan", default_placetype = "prefecture", data = export.japan_prefectures, } export.laos_provinces = { ["Attapeu Province, Laos"] = {}, ["Bokeo Province, Laos"] = {}, ["Bolikhamxai Province, Laos"] = {}, ["Champasak Province, Laos"] = {}, ["Houaphanh Province, Laos"] = {}, ["Khammouane Province, Laos"] = {}, ["Luang Namtha Province, Laos"] = {}, ["Luang Prabang Province, Laos"] = {}, ["Oudomxay Province, Laos"] = {}, ["Phongsaly Province, Laos"] = {}, ["Salavan Province, Laos"] = {}, ["Savannakhet Province, Laos"] = {}, ["Vientiane Province, Laos"] = {}, ["Vientiane Prefecture, Laos"] = {placetype = "prefecture", wp = "%l"}, ["Sainyabuli Province, Laos"] = {}, ["Sekong Province, Laos"] = {}, ["Xaisomboun Province, Laos"] = {}, ["Xiangkhouang Province, Laos"] = {}, } local function laos_placename_to_key(placename) if placename == "Vientiane Prefecture" then return placename .. ", Laos" end if placename:find(" Province$") then return placename .. ", Laos" end return placename .. " Province, Laos" end -- provinces of Laos export.laos_group = { key_to_placename = make_key_to_placename(", Laos$", {" Province$", " Prefecture$"}), placename_to_key = laos_placename_to_key, default_container = "Laos", default_placetype = "province", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.laos_provinces, } export.lebanon_governorates = { ["Akkar Governorate, Lebanon"] = {}, ["Baalbek-Hermel Governorate, Lebanon"] = {}, ["Beirut Governorate, Lebanon"] = {}, ["Beqaa Governorate, Lebanon"] = {}, ["Keserwan-Jbeil Governorate, Lebanon"] = {}, ["Mount Lebanon Governorate, Lebanon"] = {}, ["Nabatieh Governorate, Lebanon"] = {}, -- These two are generic enough that we don't want to automatically augment a use of `gov/North Governorate` or -- `gov/South Governorate` with `c/Lebanon`. ["North Governorate, Lebanon"] = {no_auto_augment_container = true}, ["South Governorate, Lebanon"] = {no_auto_augment_container = true}, } -- governorates of Lebanon export.lebanon_group = { key_to_placename = make_key_to_placename(", Lebanon$", " Governorate$"), placename_to_key = make_placename_to_key(", Lebanon", " Governorate"), default_container = "Lebanon", default_placetype = "governorate", data = export.lebanon_governorates, } export.malaysia_states = { ["Johor, Malaysia"] = {}, ["Kedah, Malaysia"] = {}, ["Kelantan, Malaysia"] = {}, ["Malacca, Malaysia"] = {}, ["Negeri Sembilan, Malaysia"] = {}, ["Pahang, Malaysia"] = {}, ["Penang, Malaysia"] = {}, ["Perak, Malaysia"] = {}, ["Perlis, Malaysia"] = {}, ["Sabah, Malaysia"] = {}, ["Sarawak, Malaysia"] = {}, ["Selangor, Malaysia"] = {}, ["Terengganu, Malaysia"] = {}, } -- states of Malaysia export.malaysia_group = { default_container = "Malaysia", default_placetype = "state", default_wp = "%l, %c", data = export.malaysia_states, } export.malta_regions = { -- Some of the regions are generic enough that we don't want to automatically augment a use of e.g. -- `r/Northern Region` with `c/Malta`. In particular; -- * "Eastern Region" also occurs at least in Ghana, Uganda, Iceland, Nigeria, Venezuela, North Macedonia and -- El Salvador; -- * "Northern Region" also occurs at least in Ghana, Uganda, Malawi, Nigeria, Canada and South Africa; -- * "Western Region" also occurs at least in Abu Dhabi, Bahrain, South Africa, Ghana, Iceland, Nepal, Nigeria, -- Serbia and Uganda; -- * "Southern Region" also occurs at least in Nigeria, Eritrea, Iceland, Ireland, Malawi and Serbia. ["Eastern Region, Malta"] = {no_auto_augment_container = true}, ["Gozo Region, Malta"] = {wp = "%l"}, ["Northern Region, Malta"] = {no_auto_augment_container = true}, ["Port Region, Malta"] = {}, ["Southern Region, Malta"] = {no_auto_augment_container = true}, ["Western Region, Malta"] = {no_auto_augment_container = true}, } -- regions of Malta export.malta_group = { key_to_placename = make_key_to_placename(", Malta$", " Region"), placename_to_key = make_placename_to_key(", Malta", " Region"), default_container = "Malta", default_placetype = "region", default_wp = "%l, %c", default_the = true, data = export.malta_regions, } export.mexico_states = { ["Aguascalientes, Mexico"] = {}, ["Baja California, Mexico"] = {}, -- not display-canonicalizing because the "Norte" could be for emphasis ["Baja California Norte, Mexico"] = {alias_of = "Baja California, Mexico"}, ["Baja California Sur, Mexico"] = {}, ["Campeche, Mexico"] = {}, ["Chiapas, Mexico"] = {}, ["Chihuahua, Mexico"] = {wp = "%l (state)"}, ["Coahuila, Mexico"] = {}, ["Colima, Mexico"] = {}, ["Durango, Mexico"] = {}, ["Guanajuato, Mexico"] = {}, ["Guerrero, Mexico"] = {}, ["Hidalgo, Mexico"] = {wp = "%l (state)"}, ["Jalisco, Mexico"] = {}, ["State of Mexico, Mexico"] = {the = true}, ["Mexico, Mexico"] = {alias_of = "State of Mexico, Mexico"}, -- differs in "the" -- ["Mexico City, Mexico"] = {}, doesn't belong here because it's a city ["Michoacán, Mexico"] = {}, ["Michoacan, Mexico"] = {alias_of = "Michoacán, Mexico", display = true}, ["Morelos, Mexico"] = {}, ["Nayarit, Mexico"] = {}, ["Nuevo León, Mexico"] = {}, ["Nuevo Leon, Mexico"] = {alias_of = "Nuevo León, Mexico", display = true}, ["Oaxaca, Mexico"] = {}, ["Puebla, Mexico"] = {}, ["Querétaro, Mexico"] = {}, ["Queretaro, Mexico"] = {alias_of = "Querétaro, Mexico", display = true}, ["Quintana Roo, Mexico"] = {}, ["San Luis Potosí, Mexico"] = {}, ["San Luis Potosi, Mexico"] = {alias_of = "San Luis Potosí, Mexico", display = true}, ["Sinaloa, Mexico"] = {}, ["Sonora, Mexico"] = {}, ["Tabasco, Mexico"] = {}, ["Tamaulipas, Mexico"] = {}, ["Tlaxcala, Mexico"] = {}, ["Veracruz, Mexico"] = {}, ["Yucatán, Mexico"] = {}, ["Yucatan, Mexico"] = {alias_of = "Yucatán, Mexico", display = true}, ["Zacatecas, Mexico"] = {}, } -- Mexican states export.mexico_group = { default_container = "Mexico", default_placetype = "state", data = export.mexico_states, } export.moldova_districts_and_autonomous_territorial_units = { ["Anenii Noi District, Moldova"] = {}, -- capital [[Anenii Noi]] ["Basarabeasca District, Moldova"] = {}, -- capital [[Basarabeasca]] ["Briceni District, Moldova"] = {}, -- capital [[Briceni]] ["Cahul District, Moldova"] = {}, -- capital [[Cahul]] ["Cantemir District, Moldova"] = {}, -- capital [[Cantemir, Moldova|Cantemir]] ["Călărași District, Moldova"] = {}, -- capital [[Călărași, Moldova|Călărași]] ["Căușeni District, Moldova"] = {}, -- capital [[Căușeni]] ["Cimișlia District, Moldova"] = {}, -- capital [[Cimișlia]] ["Criuleni District, Moldova"] = {}, -- capital [[Criuleni]] ["Dondușeni District, Moldova"] = {}, -- capital [[Dondușeni]] ["Drochia District, Moldova"] = {}, -- capital [[Drochia]] ["Dubăsari District, Moldova"] = {}, -- capital [[Cocieri]] ["Edineț District, Moldova"] = {}, -- capital [[Edineț]] ["Fălești District, Moldova"] = {}, -- capital [[Fălești]] ["Florești District, Moldova"] = {}, -- capital [[Florești, Moldova|Florești]] ["Glodeni District, Moldova"] = {}, -- capital [[Glodeni]] ["Hîncești District, Moldova"] = {}, -- capital [[Hîncești]] ["Ialoveni District, Moldova"] = {}, -- capital [[Ialoveni]] ["Leova District, Moldova"] = {}, -- capital [[Leova]] ["Nisporeni District, Moldova"] = {}, -- capital [[Nisporeni]] ["Ocnița District, Moldova"] = {}, -- capital [[Ocnița]] ["Orhei District, Moldova"] = {}, -- capital [[Orhei]] ["Rezina District, Moldova"] = {}, -- capital [[Rezina]] ["Rîșcani District, Moldova"] = {}, -- capital [[Rîșcani]] ["Sîngerei District, Moldova"] = {}, -- capital [[Sîngerei]] ["Soroca District, Moldova"] = {}, -- capital [[Soroca]] ["Strășeni District, Moldova"] = {}, -- capital [[Strășeni]] ["Șoldănești District, Moldova"] = {}, -- capital [[Șoldănești]] ["Ștefan Vodă District, Moldova"] = {}, -- capital [[Ștefan Vodă]] ["Taraclia District, Moldova"] = {}, -- capital [[Taraclia]] ["Telenești District, Moldova"] = {}, -- capital [[Telenești]] ["Ungheni District, Moldova"] = {}, -- capital [[Ungheni]] ["Chișinău, Moldova"] = {placetype = "municipality"}, ["Bălți, Moldova"] = {placetype = "municipality"}, ["Gagauzia, Moldova"] = {placetype = {"autonomous territorial unit", "autonomous region", "region"}}, -- capital [[Comrat]] -- the remainder are under the de-facto control of the unrecognized state of Transnistria ["Bender, Moldova"] = {placetype = "municipality"}, ["Tighina, Moldova"] = {alias_of = "Bender, Moldova"}, ["Transnistria, Moldova"] = {placetype = {"autonomous territorial unit", "autonomous region", "region"}}, -- capital [[Tiraspol]] ["Left Bank of the Dniester, Moldova"] = {alias_of = "Transnistria, Moldova", the = true}, ["Administrative-Territorial Units of the Left Bank of the Dniester, Moldova"] = {alias_of = "Transnistria, Moldova", the = true}, } local function moldova_placename_to_key(placename) local elliptical_key = placename .. ", Moldova" if export.moldova_districts_and_autonomous_territorial_units[elliptical_key] then return elliptical_key end if placename:find(" District$") then return placename .. ", Moldova" end return placename .. " District, Moldova" end -- Moldovan districts (raions) and autonomous territorial units export.moldova_group = { key_to_placename = make_key_to_placename(", Moldova$", " District"), placename_to_key = moldova_placename_to_key, default_container = "Moldova", default_placetype = {"district", "raion"}, default_divs = "communes", data = export.moldova_districts_and_autonomous_territorial_units, } export.morocco_regions = { ["Tangier-Tetouan-Al Hoceima, Morocco"] = {}, ["Oriental, Morocco"] = {wp = "%l (%c)"}, ["L'Oriental, Morocco"] = {alias_of = "Oriental, Morocco", display = true}, ["Fez-Meknes, Morocco"] = {}, ["Rabat-Sale-Kenitra, Morocco"] = {wp = "Rabat-Salé-Kénitra"}, ["Rabat-Salé-Kénitra, Morocco"] = {alias_of = "Rabat-Sale-Kenitra, Morocco", display = true}, ["Beni Mellal-Khenifra, Morocco"] = {wp = "Béni Mellal-Khénifra"}, ["Béni Mellal-Khénifra, Morocco"] = {alias_of = "Beni Mellal-Khenifra, Morocco", display = true}, ["Casablanca-Settat, Morocco"] = {}, ["Marrakesh-Safi, Morocco"] = {wp = "Marrakesh–Safi"}, -- WP title has en-dash ["Marrakech-Safi, Morocco"] = {alias_of = "Marrakesh-Safi, Morocco", display = true}, ["Draa-Tafilalet, Morocco"] = {wp = "Drâa-Tafilalet"}, ["Drâa-Tafilalet, Morocco"] = {alias_of = "Draa-Tafilalet, Morocco", display = true}, ["Souss-Massa, Morocco"] = {}, ["Guelmim-Oued Noun, Morocco"] = { keydesc = "+++. '''NOTE:''' This region lies partly within the disputed territory of [[Western Sahara]]" }, ["Laayoune-Sakia El Hamra, Morocco"] = { wp = "Laâyoune-Sakia El Hamra", keydesc = "+++. '''NOTE:''' This region lies almost completely within the disputed territory of [[Western Sahara]]", }, ["Laâyoune-Sakia El Hamra, Morocco"] = {alias_of = "Laayoune-Sakia El Hamra, Morocco", display = true}, ["Dakhla-Oued Ed-Dahab, Morocco"] = { keydesc = "+++. '''NOTE:''' This region lies completely within the disputed territory of [[Western Sahara]]", }, } -- regions of Morocco export.morocco_group = { default_container = "Morocco", default_placetype = "region", data = export.morocco_regions, } export.egypt_governorates = { ["Cairo Governorate, Egypt"] = {}, ["Giza Governorate, Egypt"] = {}, ["Sharqia Governorate, Egypt"] = {}, ["Dakahlia Governorate, Egypt"] = {}, ["Beheira Governorate, Egypt"] = {}, ["Minya Governorate, Egypt"] = {}, ["Qalyubia Governorate, Egypt"] = {}, ["Sohag Governorate, Egypt"] = {}, ["Alexandria Governorate, Egypt"] = {}, ["Gharbia Governorate, Egypt"] = {}, ["Asyut Governorate, Egypt"] = {}, ["Monufia Governorate, Egypt"] = {}, ["Faiyum Governorate, Egypt"] = {}, ["Kafr El Sheikh Governorate, Egypt"] = {}, ["Qena Governorate, Egypt"] = {}, ["Beni Suef Governorate, Egypt"] = {}, ["Damietta Governorate, Egypt"] = {}, ["Aswan Governorate, Egypt"] = {}, ["Ismailia Governorate, Egypt"] = {}, ["Luxor Governorate, Egypt"] = {}, ["Suez Governorate, Egypt"] = {}, ["Port Said Governorate, Egypt"] = {}, ["Matrouh Governorate, Egypt"] = {}, ["North Sinai Governorate, Egypt"] = {}, ["Red Sea Governorate, Egypt"] = {}, ["New Valley Governorate, Egypt"] = {}, ["South Sinai Governorate, Egypt"] = {}, } -- governorates of Egypt export.egypt_group = { key_to_placename = make_key_to_placename(", Egypt$", " Governorate$"), placename_to_key = make_placename_to_key(", Egypt", " Governorate"), default_container = "Egypt", default_placetype = "governorate", data = export.egypt_governorates, } export.netherlands_provinces = { ["Drenthe, Netherlands"] = {}, ["Flevoland, Netherlands"] = {}, ["Friesland, Netherlands"] = {}, ["Gelderland, Netherlands"] = {}, ["Groningen, Netherlands"] = {wp = "%l (province)"}, ["Limburg, Netherlands"] = {wp = "%l (%c)"}, ["North Brabant, Netherlands"] = {}, -- Foreign forms get display-canonicalized. ["Noord-Brabant, Netherlands"] = {alias_of = "North Brabant, Netherlands", display = true}, ["North Holland, Netherlands"] = {}, ["Noord-Holland, Netherlands"] = {alias_of = "North Holland, Netherlands", display = true}, ["Overijssel, Netherlands"] = {}, ["South Holland, Netherlands"] = {}, ["Zuid-Holland, Netherlands"] = {alias_of = "South Holland, Netherlands", display = true}, ["Utrecht, Netherlands"] = {wp = "%l (province)"}, ["Zeeland, Netherlands"] = {}, } -- provinces of the Netherlands export.netherlands_group = { default_container = "Netherlands", default_placetype = "province", default_divs = "municipalities", data = export.netherlands_provinces, } export.new_zealand_regions = { -- North Island regions ["Northland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-NTL, number 1, capital [[Whangārei]] ["Auckland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-AUK, number 2, capital [[Auckland]] ["Waikato, New Zealand"] = {}, -- ISO 3166-2 code NZ-WKO, number 3, capital [[Hamilton, New Zealand|Hamilton]] ["Bay of Plenty, New Zealand"] = {the = true, wp = "%l Region"}, -- ISO 3166-2 code NZ-BOP, number 4, capital [[Whakatāne]] ["Gisborne, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-GIS, number 5, capital [[Gisborne, New Zealand|Gisborne]] ["Hawke's Bay, New Zealand"] = {}, -- ISO 3166-2 code NZ-HKB, number 6, capital [[Napier, New Zealand|Napier]] ["Taranaki, New Zealand"] = {}, -- ISO 3166-2 code NZ-TKI, number 7, capital [[Stratford, New Zealand|Stratford]] ["Manawatū-Whanganui, New Zealand"] = {}, -- ISO 3166-2 code NZ-MWT, number 8, capital [[Palmerston North]] ["Manawatu-Whanganui, New Zealand"] = {alias_of = "Manawatū-Whanganui, New Zealand", display = true}, ["Manawatu-Wanganui, New Zealand"] = {alias_of = "Manawatū-Whanganui, New Zealand", display = true}, ["Wellington, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-WGN, number 9, capital [[Wellington]] -- South Island regions ["Tasman, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-TAS, number 10, capital [[Richmond, New Zealand|Richmond]] ["Nelson, New Zealand"] = {placetype = {"region", "city"}, wp = "%l, %c", is_city = true}, -- ISO 3166-2 code NZ-NSN, number 11, capital [[Nelson, New Zealand|Nelson]] ["Marlborough, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-MBH, number 12, capital [[Blenheim, New Zealand|Blenheim]] ["West Coast, New Zealand"] = {the = true, wp = "%l Region"}, -- ISO 3166-2 code NZ-WTC, number 13, capital [[Greymouth]] ["Canterbury, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-CAN, number 14, capital [[Christchurch]] ["Otago, New Zealand"] = {}, -- ISO 3166-2 code NZ-OTA, number 15, capital [[Dunedin]] ["Southland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-STL, number 16, capital [[Invercargill]] } -- regions of New Zealand export.new_zealand_group = { default_container = "New Zealand", default_placetype = "region", data = export.new_zealand_regions, } export.nigeria_states = { ["Abia State, Nigeria"] = {}, ["Adamawa State, Nigeria"] = {}, ["Akwa Ibom State, Nigeria"] = {}, ["Anambra State, Nigeria"] = {}, ["Bauchi State, Nigeria"] = {}, ["Bayelsa State, Nigeria"] = {}, ["Benue State, Nigeria"] = {}, ["Borno State, Nigeria"] = {}, ["Cross River State, Nigeria"] = {}, ["Delta State, Nigeria"] = {}, ["Ebonyi State, Nigeria"] = {}, ["Edo State, Nigeria"] = {}, ["Ekiti State, Nigeria"] = {}, ["Enugu State, Nigeria"] = {}, ["Federal Capital Territory, Nigeria"] = { -- not a state but allow it to be referenced as one in holonyms placetype = {"federal territory", "territory", "state"}, the = true, wp = "%l (%c)", }, ["Gombe State, Nigeria"] = {}, ["Imo State, Nigeria"] = {}, ["Jigawa State, Nigeria"] = {}, ["Kaduna State, Nigeria"] = {}, ["Kano State, Nigeria"] = {}, ["Katsina State, Nigeria"] = {}, ["Kebbi State, Nigeria"] = {}, ["Kogi State, Nigeria"] = {}, ["Kwara State, Nigeria"] = {}, ["Lagos State, Nigeria"] = {}, ["Nasarawa State, Nigeria"] = {}, ["Niger State, Nigeria"] = {}, ["Ogun State, Nigeria"] = {}, ["Ondo State, Nigeria"] = {}, ["Osun State, Nigeria"] = {}, ["Oyo State, Nigeria"] = {}, ["Plateau State, Nigeria"] = {}, ["Rivers State, Nigeria"] = {}, ["Sokoto State, Nigeria"] = {}, ["Taraba State, Nigeria"] = {}, ["Yobe State, Nigeria"] = {}, ["Zamfara State, Nigeria"] = {}, } -- states of Nigeria export.nigeria_group = { key_to_placename = make_key_to_placename(", Nigeria$", " State$"), placename_to_key = make_placename_to_key(", Nigeria", " State"), default_container = "Nigeria", default_placetype = "state", data = export.nigeria_states, } export.north_korea_provinces = { ["Chagang Province, North Korea"] = {}, ["North Hamgyong Province, North Korea"] = {}, ["South Hamgyong Province, North Korea"] = {}, ["North Hwanghae Province, North Korea"] = {}, ["South Hwanghae Province, North Korea"] = {}, ["Kangwon Province, North Korea"] = {wp = "%l (%c)"}, ["North Pyongan Province, North Korea"] = {}, ["South Pyongan Province, North Korea"] = {}, ["Ryanggang Province, North Korea"] = {}, } -- provinces of North Korea export.north_korea_group = { key_to_placename = make_key_to_placename(", North Korea$", " Province$"), placename_to_key = make_placename_to_key(", North Korea", " Province"), default_container = "North Korea", default_placetype = "province", data = export.north_korea_provinces, } export.norwegian_counties = { ["Oslo, Norway"] = {}, ["Rogaland, Norway"] = {}, ["Møre og Romsdal, Norway"] = {}, ["Nordland, Norway"] = {}, ["Østfold, Norway"] = {}, ["Akershus, Norway"] = {}, ["Buskerud, Norway"] = {}, -- the following two were merged into Innlandet -- ["Hedmark, Norway"] = {}, -- ["Oppland, Norway"] = {}, ["Innlandet, Norway"] = {}, ["Vestfold, Norway"] = {}, ["Telemark, Norway"] = {}, -- the following two were merged into Agder -- ["Aust-Agder, Norway"] = {}, -- ["Vest-Agder, Norway"] = {}, ["Agder, Norway"] = {}, -- the following two were merged into Vestland -- ["Hordaland, Norway"] = {}, -- ["Sogn og Fjordane, Norway"] = {}, ["Vestland, Norway"] = {}, ["Trøndelag, Norway"] = {}, ["Troms, Norway"] = {}, ["Finnmark, Norway"] = {}, } -- counties of Norway export.norway_group = { default_container = "Norway", default_placetype = "county", data = export.norwegian_counties, } export.pakistan_provinces_and_territories = { ["Azad Kashmir, Pakistan"] = { placetype = {"administrative territory", "autonomous territory", "territory"}, }, ["Azad Jammu and Kashmir, Pakistan"] = {alias_of = "Azad Kashmir, Pakistan", display = true}, ["Balochistan, Pakistan"] = {wp = "%l, %c"}, ["Gilgit-Baltistan, Pakistan"] = { placetype = {"administrative territory", "territory"}, }, ["Islamabad Capital Territory, Pakistan"] = { the = true, divs = {}, -- no divisions placetype = {"federal territory", "administrative territory", "territory"}, }, -- Islamabad is an accepted alias for Islamabad Capital Territory given the above placetypes ["Islamabad, Pakistan"] = {alias_of = "Islamabad Capital Territory, Pakistan"}, ["Khyber Pakhtunkhwa, Pakistan"] = {}, ["Punjab, Pakistan"] = {wp = "%l, %c"}, ["Sindh, Pakistan"] = {}, } -- provinces and territories of Pakistan export.pakistan_group = { default_container = "Pakistan", default_placetype = "province", default_divs = "divisions", data = export.pakistan_provinces_and_territories, } export.philippines_provinces = { ["Abra, Philippines"] = {wp = "%l (province)"}, ["Agusan del Norte, Philippines"] = {}, ["Agusan del Sur, Philippines"] = {}, ["Aklan, Philippines"] = {}, ["Albay, Philippines"] = {}, ["Antique, Philippines"] = {wp = "%l (province)"}, ["Apayao, Philippines"] = {}, ["Aurora, Philippines"] = {wp = "%l (province)"}, ["Basilan, Philippines"] = {}, ["Bataan, Philippines"] = {}, ["Batanes, Philippines"] = {}, ["Batangas, Philippines"] = {}, ["Benguet, Philippines"] = {}, ["Biliran, Philippines"] = {}, ["Bohol, Philippines"] = {}, ["Bukidnon, Philippines"] = {}, ["Bulacan, Philippines"] = {}, ["Cagayan, Philippines"] = {}, ["Camarines Norte, Philippines"] = {}, ["Camarines Sur, Philippines"] = {}, ["Camiguin, Philippines"] = {}, ["Capiz, Philippines"] = {}, ["Catanduanes, Philippines"] = {}, ["Cavite, Philippines"] = {}, ["Cebu, Philippines"] = {}, ["Cotabato, Philippines"] = {}, ["Davao de Oro, Philippines"] = {}, ["Davao del Norte, Philippines"] = {}, ["Davao del Sur, Philippines"] = {}, ["Davao Occidental, Philippines"] = {}, ["Davao Oriental, Philippines"] = {}, ["Dinagat Islands, Philippines"] = {the = true}, ["Eastern Samar, Philippines"] = {}, ["Guimaras, Philippines"] = {}, ["Ifugao, Philippines"] = {}, ["Ilocos Norte, Philippines"] = {}, ["Ilocos Sur, Philippines"] = {}, ["Iloilo, Philippines"] = {}, ["Isabela, Philippines"] = {wp = "%l (province)"}, ["Kalinga, Philippines"] = {wp = "%l (province)"}, ["La Union, Philippines"] = {}, ["Laguna, Philippines"] = {wp = "%l (province)"}, ["Lanao del Norte, Philippines"] = {}, ["Lanao del Sur, Philippines"] = {}, ["Leyte, Philippines"] = {wp = "%l (province)"}, ["Maguindanao del Norte, Philippines"] = {}, ["Maguindanao del Sur, Philippines"] = {}, ["Marinduque, Philippines"] = {}, ["Masbate, Philippines"] = {}, ["Misamis Occidental, Philippines"] = {}, ["Misamis Oriental, Philippines"] = {}, ["Mountain Province, Philippines"] = {}, ["Negros Occidental, Philippines"] = {}, ["Negros Oriental, Philippines"] = {}, ["Northern Samar, Philippines"] = {}, ["Nueva Ecija, Philippines"] = {}, ["Nueva Vizcaya, Philippines"] = {}, ["Occidental Mindoro, Philippines"] = {}, ["Oriental Mindoro, Philippines"] = {}, ["Palawan, Philippines"] = {}, ["Pampanga, Philippines"] = {}, ["Pangasinan, Philippines"] = {}, ["Quezon, Philippines"] = {}, ["Quirino, Philippines"] = {}, ["Rizal, Philippines"] = {wp = "%l (province)"}, ["Romblon, Philippines"] = {}, ["Samar, Philippines"] = {wp = "%l (province)"}, ["Sarangani, Philippines"] = {}, ["Siquijor, Philippines"] = {}, ["Sorsogon, Philippines"] = {}, ["South Cotabato, Philippines"] = {}, ["Southern Leyte, Philippines"] = {}, ["Sultan Kudarat, Philippines"] = {}, ["Sulu, Philippines"] = {}, ["Surigao del Norte, Philippines"] = {}, ["Surigao del Sur, Philippines"] = {}, ["Tarlac, Philippines"] = {}, ["Tawi-Tawi, Philippines"] = {}, ["Zambales, Philippines"] = {}, ["Zamboanga del Norte, Philippines"] = {}, ["Zamboanga del Sur, Philippines"] = {}, ["Zamboanga Sibugay, Philippines"] = {}, -- not a province but treated as one; allow it to be referred to as a province in holonyms ["Metro Manila, Philippines"] = {placetype = {"region", "province"}}, } -- provinces of the Philippines export.philippines_group = { default_container = "Philippines", default_placetype = "province", default_divs = {"municipalities", "barangays"}, data = export.philippines_provinces, } export.poland_voivodeships = { ["Lower Silesian Voivodeship, Poland"] = {}, -- abbr DS, code 02, capital Wrocław ["Kuyavian-Pomeranian Voivodeship, Poland"] = {}, -- abbr KP, code 04, capital Bydgoszcz (seat of voivode), Toruń (seat of sejmik and marshal) ["Lublin Voivodeship, Poland"] = {}, -- abbr LU, code 06, capital Lublin ["Lubusz Voivodeship, Poland"] = {}, -- abbr LB, code 08, capital Gorzów Wielkopolski (seat of voivode), Zielona Góra (seat of sejmik and marshal) ["Lodz Voivodeship, Poland"] = {wp = "Łódź Voivodeship"}, -- abbr LD, code 10, capital Łódź ["Łódź Voivodeship, Poland"] = {alias_of = "Lodz Voivodeship, Poland", display = true, display_as_full = true}, ["Lesser Poland Voivodeship, Poland"] = {}, -- abbr MA, code 12, capital Kraków ["Masovian Voivodeship, Poland"] = {}, -- abbr MZ, code 14, capital Warsaw ["Opole Voivodeship, Poland"] = {}, -- abbr OP, code 16, capital Opole ["Subcarpathian Voivodeship, Poland"] = {}, -- abbr PK, code 18, capital Rzeszów ["Podlaskie Voivodeship, Poland"] = {}, -- abbr PD, code 20, capital Białystok ["Pomeranian Voivodeship, Poland"] = {}, -- abbr PM, code 22, capital Gdańsk ["Silesian Voivodeship, Poland"] = {}, -- abbr SL, code 24, capital Katowice ["Holy Cross Voivodeship, Poland"] = {wp = "Świętokrzyskie Voivodeship"}, -- abbr SK, code 26, capital Kielce ["Świętokrzyskie Voivodeship, Poland"] = {alias_of = "Holy Cross Voivodeship, Poland", display = true, display_as_full = true}, ["Warmian-Masurian Voivodeship, Poland"] = {}, -- abbr WN, code 28, capital Olsztyn ["Greater Poland Voivodeship, Poland"] = {}, -- abbr WP, code 30, capital Poznań ["West Pomeranian Voivodeship, Poland"] = {}, -- abbr ZP, code 32, capital Szczecin } -- voivodeships of Poland export.poland_group = { key_to_placename = make_key_to_placename(", Poland$", " Voivodeship$"), placename_to_key = make_placename_to_key(", Poland", " Voivodeship"), default_container = "Poland", default_placetype = "voivodeship", default_divs = { -- "counties", -- not enough of them currently {type = "Polish colonies", cat_as = {{type = "villages", prep = "in"}}}, }, data = export.poland_voivodeships, } export.portugal_districts_and_autonomous_regions = { ["Azores, Portugal"] = {the = true, placetype = {"autonomous region", "region"}}, ["Aveiro District, Portugal"] = {}, ["Beja District, Portugal"] = {}, ["Braga District, Portugal"] = {}, ["Bragança District, Portugal"] = {}, ["Castelo Branco District, Portugal"] = {}, ["Coimbra District, Portugal"] = {}, ["Évora District, Portugal"] = {}, ["Faro District, Portugal"] = {}, ["Guarda District, Portugal"] = {}, ["Leiria District, Portugal"] = {}, ["Lisbon District, Portugal"] = {}, ["Lisboa District, Portugal"] = {alias_of = "Lisbon District, Portugal", display = true}, ["Madeira, Portugal"] = {placetype = {"autonomous region", "region"}}, ["Portalegre District, Portugal"] = {}, ["Porto District, Portugal"] = {}, ["Santarém District, Portugal"] = {}, ["Setúbal District, Portugal"] = {}, ["Viana do Castelo District, Portugal"] = {}, ["Vila Real District, Portugal"] = {}, ["Viseu District, Portugal"] = {}, } local function portugal_placename_to_key(placename) if placename == "Azores" or placename == "Madeira" then return placename .. ", Portugal" end if placename:find(" District$") then return placename .. ", Portugal" end return placename .. " District, Portugal" end -- districts and autonomous regions of Portugal export.portugal_group = { key_to_placename = make_key_to_placename(", Portugal$", " District$"), placename_to_key = portugal_placename_to_key, default_container = "Portugal", default_placetype = "district", default_divs = "municipalities", data = export.portugal_districts_and_autonomous_regions, } export.romania_counties = { ["Alba County, Romania"] = {}, ["Arad County, Romania"] = {}, ["Argeș County, Romania"] = {}, ["Bacău County, Romania"] = {}, ["Bihor County, Romania"] = {}, ["Bistrița-Năsăud County, Romania"] = {}, ["Botoșani County, Romania"] = {}, ["Brașov County, Romania"] = {}, ["Brăila County, Romania"] = {}, -- Bucharest: not in a county ["Buzău County, Romania"] = {}, ["Caraș-Severin County, Romania"] = {}, ["Cluj County, Romania"] = {}, ["Constanța County, Romania"] = {}, ["Covasna County, Romania"] = {}, ["Călărași County, Romania"] = {}, ["Dolj County, Romania"] = {}, ["Dâmbovița County, Romania"] = {}, ["Galați County, Romania"] = {}, ["Giurgiu County, Romania"] = {}, ["Gorj County, Romania"] = {}, ["Harghita County, Romania"] = {}, ["Hunedoara County, Romania"] = {}, ["Ialomița County, Romania"] = {}, ["Iași County, Romania"] = {}, ["Ilfov County, Romania"] = {}, ["Maramureș County, Romania"] = {}, ["Mehedinți County, Romania"] = {}, ["Mureș County, Romania"] = {}, ["Neamț County, Romania"] = {}, ["Olt County, Romania"] = {}, ["Prahova County, Romania"] = {}, ["Satu Mare County, Romania"] = {}, ["Sibiu County, Romania"] = {}, ["Suceava County, Romania"] = {}, ["Sălaj County, Romania"] = {}, ["Teleorman County, Romania"] = {}, ["Timiș County, Romania"] = {}, ["Tulcea County, Romania"] = {}, ["Vaslui County, Romania"] = {}, ["Vrancea County, Romania"] = {}, ["Vâlcea County, Romania"] = {}, } -- counties of Romania export.romania_group = { key_to_placename = make_key_to_placename(", Romania$", " County$"), placename_to_key = make_placename_to_key(", Romania", " County"), default_container = "Romania", default_placetype = "county", default_divs = "communes", data = export.romania_counties, } local function make_russia_federal_subject_spec(spectype, use_the, wp) return { placetype = spectype, the = not not use_the, bare_category_parent_type = {"federal subjects", spectype .. "s"}, wp = wp, } end local russia_autonomous_okrug_no_the = {placetype = {"autonomous okrug", "okrug"}, bare_category_parent_type = {"federal subjects", "autonomous okrugs"}} local russia_autonomous_okrug_the = {placetype = {"autonomous okrug", "okrug"}, bare_category_parent_type = {"federal subjects", "autonomous okrugs"}, the = true} local russia_krai = make_russia_federal_subject_spec("krai") local russia_oblast = make_russia_federal_subject_spec("oblast") local russia_republic_the = make_russia_federal_subject_spec("republic", "use the") local russia_republic_no_the = make_russia_federal_subject_spec("republic") export.russia_federal_subjects = { -- autonomous oblasts ["Jewish Autonomous Oblast, Russia"] = {the = true, placetype = {"autonomous oblast", "oblast"}, bare_category_parent_type = {"federal subjects", "autonomous oblasts"}}, -- autonomous okrugs ["Chukotka Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Chukotka, Russia"] = {alias_of = "Chukotka Autonomous Okrug, Russia"}, ["Khanty-Mansi Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Khanty-Mansia, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Khantia-Mansia, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Yugra, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Nenets Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Nenetsia, Russia"] = {alias_of = "Nenets Autonomous Okrug, Russia"}, ["Yamalo-Nenets Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Yamalia, Russia"] = {alias_of = "Yamalo-Nenets Autonomous Okrug, Russia"}, -- krais ["Altai Krai, Russia"] = russia_krai, ["Kamchatka Krai, Russia"] = russia_krai, ["Khabarovsk Krai, Russia"] = russia_krai, ["Krasnodar Krai, Russia"] = russia_krai, ["Krasnoyarsk Krai, Russia"] = russia_krai, ["Perm Krai, Russia"] = russia_krai, ["Primorsky Krai, Russia"] = russia_krai, ["Stavropol Krai, Russia"] = russia_krai, ["Zabaykalsky Krai, Russia"] = russia_krai, -- oblasts ["Amur Oblast, Russia"] = russia_oblast, ["Arkhangelsk Oblast, Russia"] = russia_oblast, ["Astrakhan Oblast, Russia"] = russia_oblast, ["Belgorod Oblast, Russia"] = russia_oblast, ["Bryansk Oblast, Russia"] = russia_oblast, ["Chelyabinsk Oblast, Russia"] = russia_oblast, ["Irkutsk Oblast, Russia"] = russia_oblast, ["Ivanovo Oblast, Russia"] = russia_oblast, ["Kaliningrad Oblast, Russia"] = russia_oblast, ["Kaluga Oblast, Russia"] = russia_oblast, ["Kemerovo Oblast, Russia"] = russia_oblast, ["Kirov Oblast, Russia"] = russia_oblast, ["Kostroma Oblast, Russia"] = russia_oblast, ["Kurgan Oblast, Russia"] = russia_oblast, ["Kursk Oblast, Russia"] = russia_oblast, ["Leningrad Oblast, Russia"] = russia_oblast, ["Lipetsk Oblast, Russia"] = russia_oblast, ["Magadan Oblast, Russia"] = russia_oblast, ["Moscow Oblast, Russia"] = russia_oblast, ["Murmansk Oblast, Russia"] = russia_oblast, ["Nizhny Novgorod Oblast, Russia"] = russia_oblast, ["Novgorod Oblast, Russia"] = russia_oblast, ["Novosibirsk Oblast, Russia"] = russia_oblast, ["Omsk Oblast, Russia"] = russia_oblast, ["Orenburg Oblast, Russia"] = russia_oblast, ["Oryol Oblast, Russia"] = russia_oblast, ["Penza Oblast, Russia"] = russia_oblast, ["Pskov Oblast, Russia"] = russia_oblast, ["Rostov Oblast, Russia"] = russia_oblast, ["Ryazan Oblast, Russia"] = russia_oblast, ["Sakhalin Oblast, Russia"] = russia_oblast, ["Samara Oblast, Russia"] = russia_oblast, ["Saratov Oblast, Russia"] = russia_oblast, ["Smolensk Oblast, Russia"] = russia_oblast, ["Sverdlovsk Oblast, Russia"] = russia_oblast, ["Tambov Oblast, Russia"] = russia_oblast, ["Tomsk Oblast, Russia"] = russia_oblast, ["Tula Oblast, Russia"] = russia_oblast, ["Tver Oblast, Russia"] = russia_oblast, ["Tyumen Oblast, Russia"] = russia_oblast, ["Ulyanovsk Oblast, Russia"] = russia_oblast, ["Vladimir Oblast, Russia"] = russia_oblast, ["Volgograd Oblast, Russia"] = russia_oblast, ["Vologda Oblast, Russia"] = russia_oblast, ["Voronezh Oblast, Russia"] = russia_oblast, ["Yaroslavl Oblast, Russia"] = russia_oblast, -- republics -- -- We only need to include cases that aren't just shortened versions of the full federal subject name (i.e. where -- words like "Republic" and "Oblast" are omitted but the name is not otherwise modified; these are handled by -- key_to_placename). Non-display-canonicalizing aliases are generally due to differences in the presence or absence -- of "the". ["Adygea, Russia"] = russia_republic_no_the, ["Republic of Adygea, Russia"] = {alias_of = "Adygea, Russia", the = true}, ["Bashkortostan, Russia"] = russia_republic_no_the, ["Republic of Bashkortostan, Russia"] = {alias_of = "Bashkortostan, Russia", the = true}, ["Bashkiria, Russia"] = {alias_of = "Bashkortostan, Russia"}, ["Buryatia, Russia"] = russia_republic_no_the, ["Republic of Buryatia, Russia"] = {alias_of = "Buryatia, Russia", the = true}, ["Dagestan, Russia"] = russia_republic_no_the, ["Republic of Dagestan, Russia"] = {alias_of = "Dagestan, Russia", the = true}, ["Ingushetia, Russia"] = russia_republic_no_the, ["Republic of Ingushetia, Russia"] = {alias_of = "Ingushetia, Russia", the = true}, ["Kalmykia, Russia"] = russia_republic_no_the, ["Republic of Kalmykia, Russia"] = {alias_of = "Kalmykia, Russia", the = true}, ["Karelia, Russia"] = make_russia_federal_subject_spec("republic", nil, "Republic of Karelia"), ["Republic of Karelia, Russia"] = {alias_of = "Karelia, Russia", the = true}, ["Khakassia, Russia"] = russia_republic_no_the, ["Republic of Khakassia, Russia"] = {alias_of = "Khakassia, Russia", the = true}, ["Mordovia, Russia"] = russia_republic_no_the, ["Republic of Mordovia, Russia"] = {alias_of = "Mordovia, Russia", the = true}, ["North Ossetia-Alania, Russia"] = make_russia_federal_subject_spec("republic", nil, "North Ossetia–Alania"), -- with en-dash ["Republic of North Ossetia-Alania, Russia"] = {alias_of = "North Ossetia-Alania, Russia", the = true}, ["North Ossetia, Russia"] = {alias_of = "North Ossetia-Alania, Russia", display = true}, ["Alania, Russia"] = {alias_of = "North Ossetia-Alania, Russia", display = true}, ["Tatarstan, Russia"] = russia_republic_no_the, ["Republic of Tatarstan, Russia"] = {alias_of = "Tatarstan, Russia", the = true}, ["Altai Republic, Russia"] = russia_republic_the, ["Chechnya, Russia"] = russia_republic_no_the, ["Chechen Republic, Russia"] = {alias_of = "Chechnya, Russia", the = true}, ["Chuvashia, Russia"] = russia_republic_no_the, ["Chuvash Republic, Russia"] = {alias_of = "Chuvashia, Russia", the = true}, ["Kabardino-Balkaria, Russia"] = russia_republic_no_the, ["Kabardino-Balkariya, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", display = true}, ["Kabardino-Balkarian Republic, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", the = true}, ["Kabardino-Balkar Republic, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", display = "Kabardino-Balkarian Republic, Russia", the = true}, ["Karachay-Cherkessia, Russia"] = russia_republic_no_the, ["Karachay-Cherkess Republic, Russia"] = {alias_of = "Karachay-Cherkessia, Russia"}, ["Komi, Russia"] = make_russia_federal_subject_spec("republic", nil, "Komi Republic"), ["Komi Republic, Russia"] = {alias_of = "Komi, Russia", the = true}, ["Mari El, Russia"] = russia_republic_no_the, ["Mari El Republic, Russia"] = {alias_of = "Mari El, Russia", the = true}, ["Sakha, Russia"] = make_russia_federal_subject_spec("republic", nil, "Sakha Republic"), ["Sakha Republic, Russia"] = {alias_of = "Sakha, Russia", the = true}, ["Yakutia, Russia"] = {alias_of = "Sakha, Russia"}, ["Yakutiya, Russia"] = {alias_of = "Sakha, Russia", display = "Yakutia, Russia"}, ["Republic of Yakutia (Sakha), Russia"] = {alias_of = "Sakha, Russia", display = "Sakha Republic, Russia", the = true}, ["Tuva, Russia"] = russia_republic_no_the, ["Tyva, Russia"] = {alias_of = "Tuva, Russia", display = true}, ["Tuva Republic, Russia"] = {alias_of = "Tuva, Russia", the = true}, ["Tyva Republic, Russia"] = {alias_of = "Tuva, Russia", display= "Tuva Republic, Russia", the = true}, ["Udmurtia, Russia"] = russia_republic_no_the, ["Udmurt Republic, Russia"] = {alias_of = "Udmurtia, Russia", the = true}, -- Not included due to being unrecognized and only partly controlled: -- ["Crimea, Russia"] = make_russia_federal_subject_spec("republic", nil, "Republic of Crimea (Russia)") -- ["Donetsk People's Republic, Russia"] = russia_republic_the, -- ["Luhansk People's Republic, Russia"] = russia_republic_the, -- ["Zaporozhye Oblast, Russia"] = make_russia_federal_subject_spec("oblast", nil, "Russian occupation of Zaporizhzhia Oblast"), -- ["Kherson Oblast, Russia"] = make_russia_federal_subject_spec("oblast", nil, "Russian occupation of Kherson Oblast"), -- There are also federal cities (not included because they're cities): -- Moscow, Saint Petersburg; Sevastopol (unrecognized; same status as for "Crimea, Russia" above) } local function russia_key_to_placename(key) key = key:gsub(",.*", "") local full_placename = key if key == "Jewish Autonomous Oblast" then return full_placename, full_placename end local elliptical_placename for _, suffix in ipairs({"Krai", "Oblast"}) do elliptical_placename = key:match("^(.*) " .. suffix .. "$") if elliptical_placename then return full_placename, elliptical_placename end end return full_placename, full_placename end local function russia_placename_to_key(placename) local key = placename .. ", Russia" if export.russia_federal_subjects[key] then return key end -- We allow the user to say e.g. "obl/Samara" in place of "obl/Samara Oblast". for _, suffix in ipairs({"Krai", "Oblast"}) do local suffixed_key = placename .. " " .. suffix .. ", Russia" if export.russia_federal_subjects[suffixed_key] then return suffixed_key end end return placename .. ", Russia" end local function construct_russia_federal_subject_keydesc(group, key, spec) local placename = key:gsub(",.*", "") local linked_placename = export.construct_linked_placename(spec, placename) local placetype = spec.placetype if type(placetype) == "table" then placetype = placetype[1] end if placetype == "oblast" then -- Hack: Oblasts generally don't have entries under "Foo Oblast" -- but just under "Foo", so fix the linked key appropriately; -- doesn't apply to the Jewish Autonomous Oblast linked_placename = linked_placename:gsub(" Oblast%]%]", "%]%] Oblast") end return linked_placename .. ", a [[federal subject]] ([[" .. placetype .. "]]) of [[Russia]]" end -- federal subjects of Russia export.russia_group = { key_to_placename = russia_key_to_placename, placename_to_key = russia_placename_to_key, default_container = "Russia", default_keydesc = construct_russia_federal_subject_keydesc, default_overriding_bare_label_parents = {"federal subjects of Russia", "+++"}, data = export.russia_federal_subjects, } export.saudi_arabia_provinces = { ["Riyadh Province, Saudi Arabia"] = {}, ["Mecca Province, Saudi Arabia"] = {}, -- Name is too generic to assume it's in Saudi Arabia if not specified. ["Eastern Province, Saudi Arabia"] = {no_auto_augment_container = true, wp = "%l, %c"}, ["Medina Province, Saudi Arabia"] = {wp = "%l (%c)"}, ["Aseer Province, Saudi Arabia"] = {wp = "Asir"}, ["Asir Province, Saudi Arabia"] = {alias_of = "Aseer Province, Saudi Arabia", display = true}, ["Jazan Province, Saudi Arabia"] = {}, ["Qassim Province, Saudi Arabia"] = {wp = "Al-Qassim Province"}, ["Al-Qassim Province, Saudi Arabia"] = {alias_of = "Qassim Province, Saudi Arabia", display = true}, ["Tabuk Province, Saudi Arabia"] = {}, ["Hail Province, Saudi Arabia"] = {wp = "Ḥa'il Province"}, ["Ha'il Province, Saudi Arabia"] = {alias_of = "Hail Province, Saudi Arabia", display = true}, ["Ḥa'il Province, Saudi Arabia"] = {alias_of = "Hail Province, Saudi Arabia", display = true}, ["Al-Jouf Province, Saudi Arabia"] = {wp = "Al-Jawf Province"}, ["Al-Jawf Province, Saudi Arabia"] = {alias_of = "Al-Jouf Province, Saudi Arabia", display = true}, ["Najran Province, Saudi Arabia"] = {}, ["Northern Borders Province, Saudi Arabia"] = {}, ["Al-Bahah Province, Saudi Arabia"] = {}, } -- provinces of Saudi Arabia export.saudi_arabia_group = { key_to_placename = make_key_to_placename(", Saudi Arabia$", " Province$"), placename_to_key = make_placename_to_key(", Saudi Arabia", " Province"), default_container = "Saudi Arabia", default_placetype = "province", data = export.saudi_arabia_provinces, } export.south_africa_provinces = { ["Eastern Cape, South Africa"] = {the = true}, ["Free State, South Africa"] = {the = true, wp = "%l (province)"}, ["Gauteng, South Africa"] = {}, ["KwaZulu-Natal, South Africa"] = {}, ["Limpopo, South Africa"] = {}, ["Mpumalanga, South Africa"] = {}, -- per Wikipedia and other sources, `North West` doesn't normally have `the` before it ["North West, South Africa"] = {wp = "%l (South African province)"}, ["Northern Cape, South Africa"] = {the = true}, ["Western Cape, South Africa"] = {the = true}, } -- provinces of South Africa export.south_africa_group = { default_container = "South Africa", default_placetype = "province", default_divs = "municipalities", data = export.south_africa_provinces, } export.south_korea_provinces = { ["North Chungcheong Province, South Korea"] = {}, ["South Chungcheong Province, South Korea"] = {}, ["Gangwon Province, South Korea"] = {wp = "%l, %c"}, ["Gyeonggi Province, South Korea"] = {}, ["North Gyeongsang Province, South Korea"] = {}, ["South Gyeongsang Province, South Korea"] = {}, ["North Jeolla Province, South Korea"] = {}, ["South Jeolla Province, South Korea"] = {}, ["Jeju Province, South Korea"] = {}, } -- provinces of South Korea export.south_korea_group = { key_to_placename = make_key_to_placename(", South Korea$", " Province$"), placename_to_key = make_placename_to_key(", South Korea", " Province"), default_container = "South Korea", default_placetype = "province", data = export.south_korea_provinces, } export.spain_autonomous_communities = { ["Andalusia, Spain"] = {}, ["Aragon, Spain"] = {}, ["Asturias, Spain"] = {}, ["Balearic Islands, Spain"] = {the = true}, ["Basque Country, Spain"] = {the = true, wp = "%l (autonomous community)"}, ["Canary Islands, Spain"] = {the = true}, ["Cantabria, Spain"] = {}, ["Castile and León, Spain"] = {}, ["Castilla-La Mancha, Spain"] = {wp = "Castilla–La Mancha"}, -- with en-dash ["Catalonia, Spain"] = {}, ["Community of Madrid, Spain"] = {the = true}, ["Extremadura, Spain"] = {}, ["Galicia, Spain"] = {wp = "%l (Spain)"}, ["La Rioja, Spain"] = {}, ["Murcia, Spain"] = {wp = "Region of %l"}, ["Navarre, Spain"] = {}, ["Valencia, Spain"] = {wp = "Valencian Community"}, ["Valencian Community, Spain"] = {alias_of = "Valencia, Spain", the = true}, } -- autonomous communities of Spain export.spain_group = { default_container = "Spain", default_placetype = "autonomous community", default_divs = {"municipalities", "comarcas"}, data = export.spain_autonomous_communities, } export.taiwan_counties = { ["Changhua County, Taiwan"] = {}, ["Chiayi County, Taiwan"] = {}, ["Hsinchu County, Taiwan"] = {}, ["Hualien County, Taiwan"] = {}, ["Kinmen County, Taiwan"] = {wp = "Kinmen"}, ["Lienchiang County, Taiwan"] = {wp = "Matsu Islands"}, ["Miaoli County, Taiwan"] = {}, ["Nantou County, Taiwan"] = {}, ["Penghu County, Taiwan"] = {wp = "Penghu"}, ["Pingtung County, Taiwan"] = {}, ["Taitung County, Taiwan"] = {}, ["Yilan County, Taiwan"] = {wp = "%l, %c"}, ["Yunlin County, Taiwan"] = {}, } -- counties of Taiwan export.taiwan_group = { key_to_placename = make_key_to_placename(", Taiwan$", " County$"), placename_to_key = make_placename_to_key(", Taiwan", " County"), default_container = "Taiwan", default_placetype = "county", default_divs = {"districts", "townships"}, data = export.taiwan_counties, } export.thailand_provinces = { -- Bangkok (special administrative area) ["Amnat Charoen Province, Thailand"] = {}, ["Ang Thong Province, Thailand"] = {}, ["Bueng Kan Province, Thailand"] = {}, ["Buriram Province, Thailand"] = {}, ["Chachoengsao Province, Thailand"] = {}, ["Chai Nat Province, Thailand"] = {}, ["Chaiyaphum Province, Thailand"] = {}, ["Chanthaburi Province, Thailand"] = {}, ["Chiang Mai Province, Thailand"] = {}, ["Chiang Rai Province, Thailand"] = {}, ["Chonburi Province, Thailand"] = {}, ["Chumphon Province, Thailand"] = {}, ["Kalasin Province, Thailand"] = {}, ["Kamphaeng Phet Province, Thailand"] = {}, ["Kanchanaburi Province, Thailand"] = {}, ["Khon Kaen Province, Thailand"] = {}, ["Krabi Province, Thailand"] = {}, ["Lampang Province, Thailand"] = {}, ["Lamphun Province, Thailand"] = {}, ["Loei Province, Thailand"] = {}, ["Lopburi Province, Thailand"] = {}, ["Mae Hong Son Province, Thailand"] = {}, ["Maha Sarakham Province, Thailand"] = {}, ["Mukdahan Province, Thailand"] = {}, ["Nakhon Nayok Province, Thailand"] = {}, ["Nakhon Pathom Province, Thailand"] = {}, ["Nakhon Phanom Province, Thailand"] = {}, ["Nakhon Ratchasima Province, Thailand"] = {}, ["Nakhon Sawon Province, Thailand"] = {}, ["Nakhon Si Thammarat Province, Thailand"] = {}, ["Nan Province, Thailand"] = {}, ["Narathiwat Province, Thailand"] = {}, ["Nong Bua Lamphu Province, Thailand"] = {}, ["Nong Khai Province, Thailand"] = {}, ["Nonthaburi Province, Thailand"] = {}, ["Pathum Thani Province, Thailand"] = {}, ["Pattani Province, Thailand"] = {}, ["Phang Nga Province, Thailand"] = {}, ["Phatthalung Province, Thailand"] = {}, ["Phayao Province, Thailand"] = {}, ["Phetchabun Province, Thailand"] = {}, ["Phetchaburi Province, Thailand"] = {}, ["Phichit Province, Thailand"] = {}, ["Phitsanulok Province, Thailand"] = {}, ["Phra Nakhon Si Ayutthaya Province, Thailand"] = {}, ["Phrae Province, Thailand"] = {}, ["Phuket Province, Thailand"] = {}, ["Prachinburi Province, Thailand"] = {}, ["Prachuap Khiri Khan Province, Thailand"] = {}, ["Ranong Province, Thailand"] = {}, ["Ratchaburi Province, Thailand"] = {}, ["Rayong Province, Thailand"] = {}, ["Roi Et Province, Thailand"] = {}, ["Sa Kaeo Province, Thailand"] = {}, ["Sakon Nakhon Province, Thailand"] = {}, ["Samut Prakan Province, Thailand"] = {}, ["Samut Sakhon Province, Thailand"] = {}, ["Samut Songkhram Province, Thailand"] = {}, ["Saraburi Province, Thailand"] = {}, ["Satun Province, Thailand"] = {}, ["Sing Buri Province, Thailand"] = {}, ["Sisaket Province, Thailand"] = {}, ["Songkhla Province, Thailand"] = {}, ["Sukhothai Province, Thailand"] = {}, ["Suphan Buri Province, Thailand"] = {}, ["Surat Thani Province, Thailand"] = {}, ["Surin Province, Thailand"] = {}, ["Tak Province, Thailand"] = {}, ["Trang Province, Thailand"] = {}, ["Trat Province, Thailand"] = {}, ["Ubon Ratchathani Province, Thailand"] = {}, ["Udon Thani Province, Thailand"] = {}, ["Uthai Thani Province, Thailand"] = {}, ["Uttaradit Province, Thailand"] = {}, ["Yala Province, Thailand"] = {}, ["Yasothon Province, Thailand"] = {}, } -- provinces of Thailand export.thailand_group = { key_to_placename = make_key_to_placename(", Thailand$", " Province$"), placename_to_key = make_placename_to_key(", Thailand", " Province"), default_container = "Thailand", default_placetype = "province", default_divs = "districts", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.thailand_provinces, } export.turkey_provinces = { ["Adana Province, Turkey"] = {}, -- code 01 ["Adıyaman Province, Turkey"] = {}, -- code 02 ["Afyonkarahisar Province, Turkey"] = {}, -- code 03 ["Ağrı Province, Turkey"] = {}, -- code 04 ["Amasya Province, Turkey"] = {}, -- code 05 ["Ankara Province, Turkey"] = {}, -- code 06 ["Antalya Province, Turkey"] = {}, -- code 07 ["Artvin Province, Turkey"] = {}, -- code 08 ["Aydın Province, Turkey"] = {}, -- code 09 ["Balıkesir Province, Turkey"] = {}, -- code 10 ["Bilecik Province, Turkey"] = {}, -- code 11 ["Bingöl Province, Turkey"] = {}, -- code 12 ["Bitlis Province, Turkey"] = {}, -- code 13 ["Bolu Province, Turkey"] = {}, -- code 14 ["Burdur Province, Turkey"] = {}, -- code 15 ["Bursa Province, Turkey"] = {}, -- code 16 ["Çanakkale Province, Turkey"] = {}, -- code 17 ["Çankırı Province, Turkey"] = {}, -- code 18 ["Çorum Province, Turkey"] = {}, -- code 19 ["Denizli Province, Turkey"] = {}, -- code 20 ["Diyarbakır Province, Turkey"] = {}, -- code 21 ["Edirne Province, Turkey"] = {}, -- code 22 ["Elazığ Province, Turkey"] = {}, -- code 23 ["Elâzığ Province, Turkey"] = {alias_of = "Elazığ Province, Turkey", display = true}, ["Erzincan Province, Turkey"] = {}, -- code 24 ["Erzurum Province, Turkey"] = {}, -- code 25 ["Eskişehir Province, Turkey"] = {}, -- code 26 ["Gaziantep Province, Turkey"] = {}, -- code 27 ["Giresun Province, Turkey"] = {}, -- code 28 ["Gümüşhane Province, Turkey"] = {}, -- code 29 ["Hakkâri Province, Turkey"] = {}, -- code 30 ["Hakkari Province, Turkey"] = {alias_of = "Hakkâri Province, Turkey", display = true}, ["Hatay Province, Turkey"] = {}, -- code 31 ["Isparta Province, Turkey"] = {}, -- code 32 ["Mersin Province, Turkey"] = {}, -- code 33 -- ["Istanbul Province, Turkey"] = {}, -- code 34; this is coextensive with the city itself ["İzmir Province, Turkey"] = {}, -- code 35 ["Izmir Province, Turkey"] = {alias_of = "İzmir Province, Turkey", display = true}, ["Kars Province, Turkey"] = {}, -- code 36 ["Kastamonu Province, Turkey"] = {}, -- code 37 ["Kayseri Province, Turkey"] = {}, -- code 38 ["Kırklareli Province, Turkey"] = {}, -- code 39 ["Kırşehir Province, Turkey"] = {}, -- code 40 ["Kocaeli Province, Turkey"] = {}, -- code 41 ["Konya Province, Turkey"] = {}, -- code 42 ["Kütahya Province, Turkey"] = {}, -- code 43 ["Malatya Province, Turkey"] = {}, -- code 44 ["Manisa Province, Turkey"] = {}, -- code 45 ["Kahramanmaraş Province, Turkey"] = {}, -- code 46 ["Mardin Province, Turkey"] = {}, -- code 47 ["Muğla Province, Turkey"] = {}, -- code 48 ["Muş Province, Turkey"] = {}, -- code 49 ["Nevşehir Province, Turkey"] = {}, -- code 50 ["Niğde Province, Turkey"] = {}, -- code 51 ["Ordu Province, Turkey"] = {}, -- code 52 ["Rize Province, Turkey"] = {}, -- code 53 ["Sakarya Province, Turkey"] = {}, -- code 54 ["Samsun Province, Turkey"] = {}, -- code 55 ["Siirt Province, Turkey"] = {}, -- code 56 ["Sinop Province, Turkey"] = {}, -- code 57 ["Sivas Province, Turkey"] = {}, -- code 58 ["Tekirdağ Province, Turkey"] = {}, -- code 59 ["Tokat Province, Turkey"] = {}, -- code 60 ["Trabzon Province, Turkey"] = {}, -- code 61 ["Tunceli Province, Turkey"] = {}, -- code 62 ["Şanlıurfa Province, Turkey"] = {}, -- code 63 ["Uşak Province, Turkey"] = {}, -- code 64 ["Van Province, Turkey"] = {}, -- code 65 ["Yozgat Province, Turkey"] = {}, -- code 66 ["Zonguldak Province, Turkey"] = {}, -- code 67 ["Aksaray Province, Turkey"] = {}, -- code 68 ["Bayburt Province, Turkey"] = {}, -- code 69 ["Karaman Province, Turkey"] = {}, -- code 70 ["Kırıkkale Province, Turkey"] = {}, -- code 71 ["Batman Province, Turkey"] = {}, -- code 72 ["Şırnak Province, Turkey"] = {}, -- code 73 ["Bartın Province, Turkey"] = {}, -- code 74 ["Ardahan Province, Turkey"] = {}, -- code 75 ["Iğdır Province, Turkey"] = {}, -- code 76 ["Yalova Province, Turkey"] = {}, -- code 77 ["Karabük Province, Turkey"] = {}, -- code 78 ["Kilis Province, Turkey"] = {}, -- code 79 ["Osmaniye Province, Turkey"] = {}, -- code 80 ["Düzce Province, Turkey"] = {}, -- code 81 } -- provinces of Turkey export.turkey_group = { key_to_placename = make_key_to_placename(", Turkey$", " Province$"), placename_to_key = make_placename_to_key(", Turkey", " Province"), default_container = "Turkey", default_placetype = "province", default_divs = "districts", data = export.turkey_provinces, } export.ukraine_oblasts = { ["Cherkasy Oblast, Ukraine"] = {}, -- capital [[Cherkasy]], license plate prefix CA, IA ["Chernihiv Oblast, Ukraine"] = {}, -- capital [[Chernihiv]], license plate prefix CB, IB ["Chernivtsi Oblast, Ukraine"] = {}, -- capital [[Chernivtsi]], license plate prefix CE, IE -- apparently will be renamed to 'Dnipro Oblast' ["Dnipropetrovsk Oblast, Ukraine"] = {}, -- capital [[Dnipro]], license plate prefix AE, KE ["Donetsk Oblast, Ukraine"] = {}, -- capital ''[[Donetsk]] ([[Kramatorsk]])'', license plate prefix AH, KH ["Ivano-Frankivsk Oblast, Ukraine"] = {}, -- capital [[Ivano-Frankivsk]], license plate prefix AT, KT ["Kharkiv Oblast, Ukraine"] = {}, -- capital [[Kharkiv]], license plate prefix AX, KX ["Kherson Oblast, Ukraine"] = {}, -- capital ''[[Kherson]]'', license plate prefix ''BT, HT'' ["Khmelnytskyi Oblast, Ukraine"] = {}, -- capital [[Khmelnytskyi]], license plate prefix BX, HX -- apparently will be renamed to 'Kropyvnytskyi Oblast' ["Kirovohrad Oblast, Ukraine"] = {}, -- capital [[Kropyvnytskyi]], license plate prefix BA, HA ["Kyiv Oblast, Ukraine"] = {}, -- capital [[Kyiv]], license plate prefix AI, KI ["Kiev Oblast, Ukraine"] = {alias_of = "Kyiv Oblast, Ukraine", display = true}, ["Luhansk Oblast, Ukraine"] = {}, -- capital ''[[Luhansk]] ([[Sievierodonetsk]])'', license plate prefix BB, HB ["Lviv Oblast, Ukraine"] = {}, -- capital [[Lviv]], license plate prefix BC, HC ["Mykolaiv Oblast, Ukraine"] = {}, -- capital [[Mykolaiv]], license plate prefix BE, HE ["Odesa Oblast, Ukraine"] = {}, -- capital [[Odesa]], license plate prefix BH, HH ["Odessa Oblast, Ukraine"] = {alias_of = "Odesa Oblast, Ukraine", display = true}, ["Poltava Oblast, Ukraine"] = {}, -- capital [[Poltava]], license plate prefix BI, HI ["Rivne Oblast, Ukraine"] = {}, -- capital [[Rivne]], license plate prefix BK, HK ["Sumy Oblast, Ukraine"] = {}, -- capital [[Sumy]], license plate prefix BM, HM ["Ternopil Oblast, Ukraine"] = {}, -- capital [[Ternopil]], license plate prefix BO, HO ["Vinnytsia Oblast, Ukraine"] = {}, -- capital [[Vinnytsia]], license plate prefix AB, KB ["Volyn Oblast, Ukraine"] = {}, -- capital [[Lutsk]], license plate prefix AC, KC ["Zakarpattia Oblast, Ukraine"] = {}, -- capital [[Uzhhorod]], license plate prefix AO, KO ["Zaporizhzhia Oblast, Ukraine"] = {}, -- capital ''[[Zaporizhzhia]]'', license plate prefix AP, KP ["Zaporizhia Oblast, Ukraine"] = {alias_of = "Zaporizhzhia Oblast, Ukraine", display = true}, ["Zhytomyr Oblast, Ukraine"] = {}, -- capital [[Zhytomyr]], license plate prefix AM, KM } -- oblasts of Ukraine export.ukraine_group = { key_to_placename = make_key_to_placename(", Ukraine$", " Oblast$"), placename_to_key = make_placename_to_key(", Ukraine", " Oblast"), default_container = "Ukraine", default_placetype = "oblast", default_divs = {"raions", "hromadas"}, data = export.ukraine_oblasts, } export.united_kingdom_constituent_countries = { ["England"] = {divs = { "counties", "districts", {type = "local government districts", cat_as = "districts"}, { type = "local government districts with borough status", cat_as = {"districts", "boroughs"}, }, {type = "boroughs", cat_as = {"districts", "boroughs"}}, {type = "civil parishes", container_parent_type = false}, }}, ["Northern Ireland"] = { placetype = {"constituent country", "province", "country"}, divs = {"counties", "districts"}, }, ["Scotland"] = {divs = { {type = "council areas", container_parent_type = false}, "districts", }}, ["Wales"] = {divs = { "counties", {type = "county boroughs", container_parent_type = false}, {type = "communities", container_parent_type = false}, {type = "Welsh communities", cat_as = {{type = "communities", container_parent_type = false}}}, }}, } -- constituent countries and provinces of the United Kingdom export.united_kingdom_group = { placename_to_key = false, default_container = "United Kingdom", default_placetype = {"constituent country", "country"}, addl_divs = { "traditional counties", {type = "historical counties", cat_as = "traditional counties"}, }, -- Don't create categories like 'Category:en:Towns in the United Kingdom' -- or 'Category:en:Places in the United Kingdom'. default_no_container_cat = true, data = export.united_kingdom_constituent_countries, } export.england_counties = { -- NOTE: We used to have various other "no longer" counties commented out, which seems to refer to counties that -- existed officially at some point between 1889 and 1974, which I have removed. I have only kept the three -- ceremonial counties that existed from 1974 (when ceremonial counties were created) to 1996, as well as those -- still considered "historic counties" per [[w:Historic counties of England]]. -- ["Avon, England"] = {wp = "%l (county)"}, -- no longer (1974 to 1996) ["Bedfordshire, England"] = {}, ["Berkshire, England"] = {}, -- ["Brighton and Hove, England"] = {}, -- city -- ["Bristol, England"] = {}, -- city ["Buckinghamshire, England"] = {}, ["Cambridgeshire, England"] = {}, ["Cheshire, England"] = {}, -- ["Cleveland, England"] = {wp = "%l (county)"}, -- no longer (1974 to 1996) ["Cornwall, England"] = {}, -- ["Cumberland, England"] = {}, -- no longer (historic county) ["Cumbria, England"] = {}, ["Derbyshire, England"] = {}, ["Devon, England"] = {}, ["Dorset, England"] = {}, ["County Durham, England"] = {}, ["East Sussex, England"] = {}, ["Essex, England"] = {}, ["Gloucestershire, England"] = {}, ["Greater London, England"] = {}, ["Greater Manchester, England"] = {}, ["Hampshire, England"] = {}, ["Herefordshire, England"] = {}, ["Hertfordshire, England"] = {}, -- ["Humberside, England"] = {}, -- no longer (1974 to 1996) -- ["Huntingdonshire, England"] = {}, -- no longer (historic county) ["Isle of Wight, England"] = {the = true}, ["Kent, England"] = {}, ["Lancashire, England"] = {}, ["Leicestershire, England"] = {}, ["Lincolnshire, England"] = {}, ["Merseyside, England"] = {}, -- ["Middlesex, England"] = {}, -- no longer (historic county) ["Norfolk, England"] = {}, ["Northamptonshire, England"] = {}, ["Northumberland, England"] = {}, ["North Yorkshire, England"] = {}, ["Nottinghamshire, England"] = {}, ["Oxfordshire, England"] = {}, ["Rutland, England"] = {}, ["Shropshire, England"] = {}, ["Somerset, England"] = {}, ["South Humberside, England"] = {}, ["South Yorkshire, England"] = {}, ["Staffordshire, England"] = {}, ["Suffolk, England"] = {}, ["Surrey, England"] = {}, -- ["Sussex, England"] = {}, -- no longer (historic county) ["Tyne and Wear, England"] = {}, ["Warwickshire, England"] = {}, ["West Midlands, England"] = {the = true, wp = "%l (county)"}, -- ["Westmorland, England"] = {}, -- no longer (historic county) ["West Sussex, England"] = {}, ["West Yorkshire, England"] = {}, ["Wiltshire, England"] = {}, ["Worcestershire, England"] = {}, -- ["Yorkshire, England"] = {}, -- no longer (historic county) ["East Riding of Yorkshire, England"] = {the = true}, } -- counties of England export.england_group = { default_container = {key = "England", placetype = "constituent country"}, default_placetype = "county", default_divs = { "districts", {type = "local government districts", cat_as = "districts"}, { type = "local government districts with borough status", cat_as = {"districts", "boroughs"}, }, {type = "boroughs", cat_as = {"districts", "boroughs"}}, "civil parishes", }, data = export.england_counties, } export.northern_ireland_counties = { ["County Antrim, Northern Ireland"] = {}, ["County Armagh, Northern Ireland"] = {}, ["City of Belfast, Northern Ireland"] = {the = true, is_city = true, wp = "Belfast"}, ["County Down, Northern Ireland"] = {}, ["County Fermanagh, Northern Ireland"] = {}, ["County Londonderry, Northern Ireland"] = {}, ["City of Derry, Northern Ireland"] = {the = true, is_city = true, wp = "Derry"}, ["County Tyrone, Northern Ireland"] = {}, } -- counties of Northern Ireland export.northern_ireland_group = { key_to_placename = make_irish_type_key_to_placename(", Northern Ireland$"), placename_to_key = make_irish_type_placename_to_key(", Northern Ireland"), default_container = {key = "Northern Ireland", placetype = "constituent country"}, default_placetype = "county", data = export.northern_ireland_counties, } export.scotland_council_areas = { ["Aberdeenshire, Scotland"] = {}, ["Angus, Scotland"] = {wp = "%l, %c"}, ["Argyll and Bute, Scotland"] = {}, ["City of Aberdeen, Scotland"] = {the = true, wp = "Aberdeen"}, ["Aberdeen"] = {alias_of = "City of Aberdeen, Scotland"}, ["Aberdeen City"] = {alias_of = "City of Aberdeen, Scotland"}, ["City of Dundee, Scotland"] = {the = true, wp = "Dundee"}, ["Dundee"] = {alias_of = "City of Dundee, Scotland"}, ["Dundee City"] = {alias_of = "City of Dundee, Scotland"}, ["City of Edinburgh, Scotland"] = {the = true, wp = "%l council area"}, ["Edinburgh"] = {alias_of = "City of Edinburgh, Scotland"}, ["City of Glasgow, Scotland"] = {the = true, wp = "Glasgow"}, ["Glasgow"] = {alias_of = "City of Glasgow, Scotland"}, ["Clackmannanshire, Scotland"] = {}, ["Dumfries and Galloway, Scotland"] = {}, ["East Ayrshire, Scotland"] = {}, ["East Dunbartonshire, Scotland"] = {}, ["East Lothian, Scotland"] = {}, ["East Renfrewshire, Scotland"] = {}, ["Falkirk, Scotland"] = {wp = "%l council area"}, ["Fife, Scotland"] = {}, ["Highland, Scotland"] = {wp = "%l council area"}, ["Inverclyde, Scotland"] = {}, ["Midlothian, Scotland"] = {}, ["Moray, Scotland"] = {}, ["North Ayrshire, Scotland"] = {}, ["North Lanarkshire, Scotland"] = {}, ["Orkney Islands, Scotland"] = {the = true}, ["Perth and Kinross, Scotland"] = {}, ["Renfrewshire, Scotland"] = {}, ["Scottish Borders, Scotland"] = {the = true}, ["Shetland Islands, Scotland"] = {the = true}, ["South Ayrshire, Scotland"] = {}, ["South Lanarkshire, Scotland"] = {}, ["Stirling, Scotland"] = {wp = "%l council area"}, ["West Dunbartonshire, Scotland"] = {}, ["West Lothian, Scotland"] = {}, ["Western Isles, Scotland"] = {the = true, wp = "Outer Hebrides"}, ["Na h-Eileanan Siar, Scotland"] = {alias_of = "Western Isles, Scotland"}, } -- council areas of Scotland export.scotland_group = { default_container = {key = "Scotland", placetype = "constituent country"}, default_placetype = "council area", data = export.scotland_council_areas, } export.wales_principal_areas = { ["Blaenau Gwent, Wales"] = {}, ["Bridgend, Wales"] = {wp = "%l County Borough"}, ["Caerphilly, Wales"] = {wp = "%l County Borough"}, -- ["Cardiff, Wales"] = {placetype = "city"}, ["Carmarthenshire, Wales"] = {placetype = "county"}, ["Ceredigion, Wales"] = {placetype = "county"}, ["Conwy, Wales"] = {wp = "%l County Borough"}, ["Denbighshire, Wales"] = {placetype = "county"}, ["Flintshire, Wales"] = {placetype = "county"}, ["Gwynedd, Wales"] = {placetype = "county"}, ["Isle of Anglesey, Wales"] = {the = true, placetype = "county"}, ["Anglesey, Wales"] = {alias_of = "Isle of Anglesey, Wales"}, -- differs in "the" ["Merthyr Tydfil, Wales"] = {wp = "%l County Borough"}, ["Monmouthshire, Wales"] = {placetype = "county"}, ["Neath Port Talbot, Wales"] = {}, -- ["Newport, Wales"] = {placetype = "city", wp = "%l, %c"}, ["Pembrokeshire, Wales"] = {placetype = "county"}, ["Powys, Wales"] = {placetype = "county"}, ["Rhondda Cynon Taf, Wales"] = {}, -- ["Swansea, Wales"] = {placetype = "city"}, ["Torfaen, Wales"] = {}, ["Vale of Glamorgan, Wales"] = {the = true}, ["Wrexham, Wales"] = {wp = "%l County Borough"}, } -- principal areas (cities, counties and county boroughs) of Wales export.wales_group = { default_container = {key = "Wales", placetype = "constituent country"}, default_placetype = "county borough", data = export.wales_principal_areas, } export.united_states_states = { ["Alabama, USA"] = {}, ["Alaska, USA"] = {divs = { {type = "boroughs", container_parent_type = "counties"}, {type = "borough seats", container_parent_type = "county seats"}, }}, ["Arizona, USA"] = {}, ["Arkansas, USA"] = {}, ["California, USA"] = {}, ["Colorado, USA"] = {divs = {"counties", "county seats", "municipalities"}}, ["Connecticut, USA"] = {divs = {"counties", "county seats", "municipalities"}}, ["Delaware, USA"] = {}, ["Florida, USA"] = {}, ["Georgia, USA"] = {wp = "%l (U.S. state)"}, ["Hawaii, USA"] = {addl_parents = {"Polynesia"}}, ["Idaho, USA"] = {}, ["Illinois, USA"] = {}, ["Indiana, USA"] = {}, ["Iowa, USA"] = {}, ["Kansas, USA"] = {}, ["Kentucky, USA"] = {}, ["Louisiana, USA"] = {divs = { {type = "parishes", container_parent_type = "counties"}, {type = "parish seats", container_parent_type = "county seats"}, }}, ["Maine, USA"] = {}, ["Maryland, USA"] = {}, ["Massachusetts, USA"] = {}, ["Michigan, USA"] = {}, ["Minnesota, USA"] = {}, ["Mississippi, USA"] = {}, ["Missouri, USA"] = {}, ["Montana, USA"] = {}, ["Nebraska, USA"] = {}, ["Nevada, USA"] = {}, ["New Hampshire, USA"] = {}, ["New Jersey, USA"] = {divs = { "counties", "county seats", {type = "boroughs", prep = "in"}, }}, ["New Mexico, USA"] = {}, ["New York, USA"] = {wp = "%l (state)"}, ["North Carolina, USA"] = {}, ["North Dakota, USA"] = {}, ["Ohio, USA"] = {}, ["Oklahoma, USA"] = {}, ["Oregon, USA"] = {}, ["Pennsylvania, USA"] = {divs = { "counties", "county seats", {type = "boroughs", prep = "in"}, }}, ["Rhode Island, USA"] = {}, ["South Carolina, USA"] = {}, ["South Dakota, USA"] = {}, ["Tennessee, USA"] = {}, ["Texas, USA"] = {}, ["Utah, USA"] = {}, ["Vermont, USA"] = {}, ["Virginia, USA"] = {}, ["Washington, USA"] = {wp = "%l (state)"}, ["West Virginia, USA"] = {}, ["Wisconsin, USA"] = {}, ["Wyoming, USA"] = {}, } -- states of the United States export.united_states_group = { placename_to_key = make_placename_to_key(", USA"), default_container = "United States", default_placetype = "state", default_divs = {"counties", "county seats"}, addl_divs = { {type = "census-designated places", prep = "in"}, {type = "unincorporated communities", prep = "in"}, }, data = export.united_states_states, } export.vietnam_provinces = { -- [[Northeast (Vietnam)|Northeast]] region ["Bắc Giang Province, Vietnam"] = {}, -- capital [[Bắc Giang]] ["Bắc Kạn Province, Vietnam"] = {}, -- capital [[Bắc Kạn]] ["Cao Bằng Province, Vietnam"] = {}, -- capital [[Cao Bằng]] ["Hà Giang Province, Vietnam"] = {}, -- capital [[Hà Giang]] ["Lạng Sơn Province, Vietnam"] = {}, -- capital [[Lạng Sơn]] ["Phú Thọ Province, Vietnam"] = {}, -- capital [[Việt Trì]] ["Quảng Ninh Province, Vietnam"] = {}, -- capital [[Hạ Long]] ["Thái Nguyên Province, Vietnam"] = {}, -- capital [[Thái Nguyên]] ["Tuyên Quang Province, Vietnam"] = {}, -- capital [[Tuyên Quang]] -- [[Northwest (Vietnam)|Northwest]] region ["Lào Cai Province, Vietnam"] = {}, -- capital [[Lào Cai]] ["Yên Bái Province, Vietnam"] = {}, -- capital [[Yên Bái]] ["Điện Biên Province, Vietnam"] = {}, -- capital [[Điện Biên Phủ]] ["Hoà Bình Province, Vietnam"] = {}, -- capital [[Hoà Bình City|Hoà Bình]] ["Hòa Bình Province, Vietnam"] = {alias_of = "Hoà Bình Province, Vietnam", display = true}, ["Lai Châu Province, Vietnam"] = {}, -- capital [[Lai Châu]] ["Sơn La Province, Vietnam"] = {}, -- capital [[Sơn La]] -- [[Red River Delta]] region ["Bắc Ninh Province, Vietnam"] = {}, -- capital [[Bắc Ninh]] ["Hà Nam Province, Vietnam"] = {}, -- capital [[Phủ Lý]] ["Hải Dương Province, Vietnam"] = {}, -- capital [[Hải Dương]] ["Hưng Yên Province, Vietnam"] = {}, -- capital [[Hưng Yên]] ["Nam Định Province, Vietnam"] = {}, -- capital [[Nam Định]] ["Ninh Bình Province, Vietnam"] = {}, -- capital [[Ninh Bình|Hoa Lư]] ["Thái Bình Province, Vietnam"] = {}, -- capital [[Thái Bình]] ["Vĩnh Phúc Province, Vietnam"] = {}, -- capital [[Vĩnh Yên]] -- ["Hanoi"] = {placetype = {"municipality", "city"}}, -- capital [[Hoàn Kiếm district]] -- ["Haiphong"] = {placetype = {"municipality", "city"}}, -- capital [[Hồng Bàng district]] -- [[North Central Coast]] region ["Hà Tĩnh Province, Vietnam"] = {}, -- capital [[Hà Tĩnh]] ["Nghệ An Province, Vietnam"] = {}, -- capital [[Vinh]] ["Quảng Bình Province, Vietnam"] = {}, -- capital [[Đồng Hới]] ["Quảng Trị Province, Vietnam"] = {}, -- capital [[Đông Hà]] ["Thanh Hoá Province, Vietnam"] = {}, -- capital [[Thanh Hoá]] ["Thanh Hóa Province, Vietnam"] = {alias_of = "Thanh Hoá Province, Vietnam", display = true}, -- ["Hue"] = {placetype = {"municipality", "city"}, wp = "Huế"}, -- capital [[Thuận Hoá district]] -- [[Central Highlands (Vietnam)|Central Highlands]] region ["Đắk Lắk Province, Vietnam"] = {}, -- capital [[Buôn Ma Thuột]] ["Đăk Nông Province, Vietnam"] = {}, -- capital [[Gia Nghĩa]] ["Gia Lai Province, Vietnam"] = {}, -- capital [[Pleiku]] ["Kon Tum Province, Vietnam"] = {}, -- capital [[Kon Tum]] ["Lâm Đồng Province, Vietnam"] = {}, -- capital [[Đà Lạt]] -- [[South Central Coast]] region ["Bình Định Province, Vietnam"] = {}, -- capital [[Quy Nhon]] ["Bình Thuận Province, Vietnam"] = {}, -- capital [[Phan Thiết]] ["Khánh Hoà Province, Vietnam"] = {}, -- capital [[Nha Trang]] ["Khánh Hòa Province, Vietnam"] = {alias_of = "Khánh Hoà Province, Vietnam", display = true}, ["Ninh Thuận Province, Vietnam"] = {}, -- capital [[Phan Rang–Tháp Chàm]] ["Phú Yên Province, Vietnam"] = {}, -- capital [[Tuy Hoà]] ["Quảng Nam Province, Vietnam"] = {}, -- capital [[Tam Kỳ]] ["Quảng Ngãi Province, Vietnam"] = {}, -- capital [[Quảng Ngãi]] -- ["Da Nang"] = {placetype = {"municipality", "city"}}, -- capital [[Hải Châu district]] -- [[Southeast (Vietnam)|Southeast]] region ["Bà Rịa–Vũng Tàu Province, Vietnam"] = {}, -- capital [[Bà Rịa]] ["Bình Dương Province, Vietnam"] = {}, -- capital [[Thủ Dầu Một]] ["Bình Phước Province, Vietnam"] = {}, -- capital [[Đồng Xoài]] ["Đồng Nai Province, Vietnam"] = {}, -- capital [[Biên Hoà]] ["Tây Ninh Province, Vietnam"] = {}, -- capital [[Tây Ninh]] -- ["Ho Chi Minh City"] = {placetype = {"municipality", "city"}}, -- capital [[District 1, Ho Chi Minh City|'''District 1''']] -- [[Mekong Delta]] region ["An Giang Province, Vietnam"] = {}, -- capital [[Long Xuyên]] ["Bạc Liêu Province, Vietnam"] = {}, -- capital [[Bạc Liêu]] ["Bến Tre Province, Vietnam"] = {}, -- capital [[Bến Tre]] ["Cà Mau Province, Vietnam"] = {}, -- capital [[Cà Mau]] ["Đồng Tháp Province, Vietnam"] = {}, -- capital [[Cao Lãnh City|Cao Lãnh]] ["Hậu Giang Province, Vietnam"] = {}, -- capital [[Vị Thanh]] ["Kiên Giang Province, Vietnam"] = {}, -- capital [[Rạch Giá]] ["Long An Province, Vietnam"] = {}, -- capital [[Tân An]] ["Sóc Trăng Province, Vietnam"] = {}, -- capital [[Sóc Trăng]] ["Tiền Giang Province, Vietnam"] = {}, -- capital [[Mỹ Tho]] ["Trà Vinh Province, Vietnam"] = {}, -- capital [[Trà Vinh]] ["Vĩnh Long Province, Vietnam"] = {}, -- capital [[Vĩnh Long]] -- ["Can Tho"] = {placetype = {"municipality", "city"}, wp = "Cần Thơ"}, -- capital [[Ninh Kiều district]] } -- provinces of Vietnam export.vietnam_group = { key_to_placename = make_key_to_placename(", Vietnam$", " Province$"), placename_to_key = make_placename_to_key(", Vietnam", " Province"), default_container = "Vietnam", default_placetype = "province", -- There may not be enough districts to subcategorize like this. -- default_divs = "districts", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.vietnam_provinces, } ----------------------------------------------------------------------------------- -- City data -- ----------------------------------------------------------------------------------- export.australia_cities = { ["Adelaide"] = {container = "South Australia"}, -- 1,450,000 (Agglomeration) ["Brisbane"] = {container = "Queensland"}, -- 3,450,000 (Conglomeration; including the Gold Coast [750,997 2024 estiamte]) ["Canberra"] = {container = {key = "Australian Capital Territory, Australia", placetype = "territory"}}, -- 510,641 (2024 estimate) ["Melbourne"] = {container = "Victoria"}, -- 5,200,000 (Agglomeration) ["Newcastle, New South Wales"] = {container = "New South Wales", wp = "%l, %c"}, -- 534,033 (2024 estimate) ["Newcastle"] = {alias_of = "Newcastle, New South Wales"}, ["Perth"] = {container = "Western Australia"}, -- 2,350,000 (Agglomeration) ["Sydney"] = {container = "New South Wales"}, -- 5,100,000 (Agglomeration) } export.australia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Australia", "state"), default_placetype = "city", data = export.australia_cities, } export.brazil_cities = { -- Figures from citypopulation.de; retrieved 2025-04-27; reference date 2025-01-01. ["São Paulo"] = {container = "São Paulo"}, -- 22,600,000 (Consolidated Urban Area; including Guarulhos) ["Sao Paulo"] = {alias_of = "São Paulo", display = true}, ["Rio de Janeiro"] = {container = "Rio de Janeiro"}, -- 13,600,000 (Consolidated Urban Area) ["Belo Horizonte"] = {container = "Minas Gerais"}, -- 5,300,000 ["Recife"] = {container = "Pernambuco"}, -- 4,100,000 ["Porto Alegre"] = {container = "Rio Grande do Sul"}, -- 3,950,000 (Consolidated Urban Area) ["Brasília"] = {container = "Distrito Federal"}, -- 3,850,000 ["Brasilia"] = {alias_of = "Brasília", display = true}, ["Fortaleza"] = {container = "Ceará"}, -- 3,825,000 ["Salvador"] = {container = "Bahia", wp = "%l, %c", commonscat = "%l (%c)"}, -- 3,400,000 ["Curitiba"] = {container = "Paraná"}, -- 3,375,000 ["Campinas"] = {container = "São Paulo"}, -- 3,250,000 ["Goiânia"] = {container = "Goiás"}, -- 2,525,000 ["Goiania"] = {alias_of = "Goiânia", display = true}, ["Manaus"] = {container = "Amazonas"}, -- 2,275,000 ["Belém"] = {container = "Pará"}, -- 2,200,000 ["Belem"] = {alias_of = "Belém", display = true}, ["Vitória"] = {container = "Espírito Santo", wp = "%l, %c"}, -- 1,870,000 ["Vitoria"] = {alias_of = "Vitória", display = true}, ["Santos"] = {container = "São Paulo", wp = "%l, %c"}, -- 1,760,000 ["São Luís"] = {container = "Maranhão", wp = "%l, %c"}, -- 1,530,000 ["Sao Luis"] = {alias_of = "São Luís", display = true}, ["Natal"] = {container = "Rio Grande do Norte", wp = "%l, %c"}, -- 1,360,000 ["Florianópolis"] = {container = "Santa Catarina"}, -- 1,260,000 ["Florianopolis"] = {alias_of = "Florianópolis", display = true}, ["Maceió"] = {container = "Alagoas"}, -- 1,220,000 ["Maceio"] = {alias_of = "Maceió", display = true}, ["João Pessoa"] = {container = "Paraíba", wp = "%l, %c"}, -- 1,210,000 ["Joao Pessoa"] = {alias_of = "João Pessoa", display = true}, ["São José dos Campos"] = {container = "São Paulo"}, -- 1,090,000 ["Sao Jose dos Campos"] = {alias_of = "São José dos Campos", display = true}, ["Londrina"] = {container = "Paraná"}, -- 1,050,000 ["Teresina"] = {container = "Piauí"}, -- 1,040,000 } export.brazil_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Brazil", "state"), default_placetype = "city", data = export.brazil_cities, } export.canada_cities = { -- Figures from citypopulation.de; retrieved 2025-04-27; reference date 2025-01-01. ["Toronto"] = {container = "Ontario"}, -- 7,850,000 (Consolidated Urban Area; including Hamilton) ["Montreal"] = {container = "Quebec"}, -- 4,500,000 (Consolidated Urban Area) ["Vancouver"] = {container = "British Columbia"}, -- 3,175,000 (Consolidated Urban Area) ["Calgary"] = {container = "Alberta"}, -- 1,510,000 (Consolidated Urban Area) ["Edmonton"] = {container = "Alberta"}, -- 1,460,000 (Consolidated Urban Area) ["Ottawa"] = {container = "Ontario"}, -- 1,390,000 (Consolidated Urban Area) ["Quebec City"] = {container = "Quebec"}, -- 839,311 metro per Wikipedia (2021 census) ["Winnipeg"] = {container = "Manitoba"}, -- 834,678 metro per Wikipedia (2021 census) ["Hamilton"] = {container = "Ontario", wp = "%l, %c"}, -- 785,184 metro per Wikipedia (2021 census) ["Kitchener"] = {container = "Ontario", wp = "%l, %c"}, -- 575,847 metro per Wikipedia (2021 census) } export.canada_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Canada", "province"), default_placetype = "city", data = export.canada_cities, } export.france_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. ["Paris"] = {container = "Île-de-France"}, -- 11,500,000 (Conglomeration) ["Lyon"] = {container = "Auvergne-Rhône-Alpes"}, -- 2,050,000 (Conglomeration) ["Lyons"] = {alias_of = "Lyon", display = true}, ["Marseille"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 1,710,000 (Conglomeration) ["Marseilles"] = {alias_of = "Marseille", display = true}, ["Lille"] = {container = "Hauts-de-France"}, -- 1,320,000 (Conglomeration) ["Bordeaux"] = {container = "Nouvelle-Aquitaine"}, -- 1,160,000 (Conglomeration) ["Toulouse"] = {container = "Occitania"}, -- 1,150,000 (Conglomeration) ["Nice"] = {container = "Provence-Alpes-Côte d'Azur"}, ["Nantes"] = {container = "Pays de la Loire"}, ["Strasbourg"] = {container = "Grand Est"}, ["Rennes"] = {container = "Brittany"}, } export.france_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", France", "region"), default_placetype = "city", data = export.france_cities, } export.germany_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. -- listed under Rhein-Ruhr Area, total population 10,900,000 (Consolidated Urban Area) ["Cologne"] = {container = "North Rhine-Westphalia"}, ["Köln"] = {alias_of = "Cologne", display = true}, ["Düsseldorf"] = {container = "North Rhine-Westphalia"}, ["Dusseldorf"] = {alias_of = "Düsseldorf", display = true}, ["Dortmund"] = {container = "North Rhine-Westphalia"}, ["Essen"] = {container = "North Rhine-Westphalia"}, ["Duisberg"] = {container = "North Rhine-Westphalia"}, ["Berlin"] = {}, -- 4,700,000 ["Frankfurt"] = {container = "Hesse"}, -- 3,225,000 ["Frankfurt am Main"] = {alias_of = "Frankfurt"}, -- not a display alias as it's longer ["Hamburg"] = {}, -- 2,900,000 ["Munich"] = {container = "Bavaria"}, -- 2,300,000 ["Stuttgart"] = {container = "Baden-Württemberg"}, -- 2,300,000 ["Mannheim"] = {container = "Baden-Württemberg"}, -- 1,550,000 ["Nuremberg"] = {container = "Bavaria"}, -- 1,120,000 ["Hanover"] = {"Lower Saxony"}, -- 1,090,000 ["Bielefeld"] = {container = "North Rhine-Westphalia"}, -- 1,080,000 ["Leipzig"] = {container = "Saxony"}, -- 1,080,000 ["Aachen"] = {container = "North Rhine-Westphalia"}, -- 1,000,000 ["Aix-la-Chapelle"] = {alias_of = "Aachen"}, -- historical; not a display alias ["Bremen"] = {}, } export.germany_cities_group = { default_container = "Germany", canonicalize_key_container = make_canonicalize_key_container(", Germany", "state"), default_placetype = "city", data = export.germany_cities, } export.india_cities = { -- This lists the 65 metro areas per Demographia's 2023 estimates, as found in -- [[w:List_of_million-plus_urban_agglomerations_in_India]]. The last census in India (as of April 2025) was -- conducted in 2011, and the results are not accurate any more. ["Delhi"] = {container = {key = "Delhi, India", placetype = "union territory"}}, -- 31,190,000 ["Mumbai"] = {container = "Maharashtra"}, -- 25,189,000 ["Kolkata"] = {container = "West Bengal"}, -- 21,747,000 ["Bangalore"] = {container = "Karnataka", wp = "Bengaluru"}, -- 15,257,000 ["Bengaluru"] = {alias_of = "Bangalore"}, ["Chennai"] = {container = "Tamil Nadu"}, -- 11,570,000 ["Hyderabad"] = {container = "Telangana"}, -- 9,797,000 ["Ahmedabad"] = {container = "Gujarat"}, -- 8,006,000 ["Pune"] = {container = "Maharashtra"}, -- 6,819,000 ["Surat"] = {container = "Gujarat"}, -- 6,601,000 ["Lucknow"] = {container = "Uttar Pradesh"}, -- 4,661,000 ["Jaipur"] = {container = "Rajasthan"}, -- 4,360,000 ["Kanpur"] = {container = "Uttar Pradesh"}, -- 4,350,000 ["Indore"] = {container = "Madhya Pradesh"}, -- 3,765,000 ["Nagpur"] = {container = "Maharashtra"}, -- 3,493,000 ["Patna"] = {container = "Bihar"}, -- 3,331,000 ["Varanasi"] = {container = "Uttar Pradesh"}, -- 3,229,000 ["Kozhikode"] = {container = "Kerala"}, -- 3,049,000 ["Thiruvananthapuram"] = {container = "Kerala"}, -- 2,851,000 ["Agra"] = {container = "Uttar Pradesh"}, -- 2,737,000 ["Bhopal"] = {container = "Madhya Pradesh"}, -- 2,562,000 ["Coimbatore"] = {container = "Tamil Nadu"}, -- 2,551,000 ["Allahabad"] = {container = "Uttar Pradesh", wp = "Prayagraj"}, -- 2,438,000 ["Prayagraj"] = {alias_of = "Allahabad"}, ["Kochi"] = {container = "Kerala"}, -- 2,381,000 ["Ludhiana"] = {container = "Punjab"}, -- 2,205,000 ["Vadodara"] = {container = "Gujarat"}, -- 2,182,000 ["Chandigarh"] = {container = {key = "Chandigarh, India", placetype = "union territory"}}, -- 2,168,000 ["Madurai"] = {container = "Tamil Nadu"}, -- 2,048,000 ["Meerut"] = {container = "Uttar Pradesh"}, -- 2,011,000 ["Visakhapatnam"] = {container = "Andhra Pradesh"}, -- 2,005,000 ["Jamshedpur"] = {container = "Jharkhand"}, -- 1,925,000 ["Malappuram"] = {container = "Kerala"}, -- 1,868,000 ["Nashik"] = {container = "Maharashtra"}, -- 1,810,000 ["Asansol"] = {container = "West Bengal"}, -- 1,720,000 ["Aligarh"] = {container = "Uttar Pradesh"}, -- 1,660,000 ["Ranchi"] = {container = "Jharkhand"}, -- 1,638,000 ["Thrissur"] = {container = "Kerala"}, -- 1,578,000 ["Kollam"] = {container = "Kerala"}, -- 1,576,000 ["Jabalpur"] = {container = "Madhya Pradesh"}, -- 1,533,000 ["Dhanbad"] = {container = "Jharkhand"}, -- 1,503,000 ["Jodhpur"] = {container = "Rajasthan"}, -- 1,497,000 ["Aurangabad"] = {container = "Maharashtra"}, -- 1,490,000 ["Chhatrapati Sambhajinagar"] = {alias_of = "Aurangabad"}, ["Rajkot"] = {container = "Gujarat"}, -- 1,487,000 ["Gwalior"] = {container = "Madhya Pradesh"}, -- 1,477,000 ["Raipur"] = {container = "Chhattisgarh"}, -- 1,429,000 ["Gorakhpur"] = {container = "Uttar Pradesh"}, -- 1,410,000 ["Kannur"] = {container = "Kerala"}, -- 1,360,000 ["Bareilly"] = {container = "Uttar Pradesh"}, -- 1,355,000 ["Guwahati"] = {container = "Assam"}, -- 1,355,000 ["Moradabad"] = {container = "Uttar Pradesh"}, -- 1,345,000 ["Amritsar"] = {container = "Punjab"}, -- 1,313,000 ["Mysore"] = {container = "Karnataka"}, -- 1,296,000 ["Bhilai"] = {container = "Chhattisgarh"}, -- 1,293,000 ["Durg-Bhilainagar"] = {alias_of = "Bhilai"}, ["Durg-Bhilai"] = {alias_of = "Bhilai"}, ["Durg"] = {alias_of = "Bhilai"}, ["Bhilainagar"] = {alias_of = "Bhilai"}, ["Vijayawada"] = {container = "Andhra Pradesh"}, -- 1,232,000 ["Srinagar"] = {container = {key = "Jammu and Kashmir, India", placetype = "union territory"}}, -- 1,212,000 ["Salem"] = {container = "Tamil Nadu", wp = "%l, %c"}, -- 1,189,000 ["Kota"] = {container = "Rajasthan"}, -- 1,172,000 ["Jalandhar"] = {container = "Punjab"}, -- 1,165,000 ["Saharanpur"] = {container = "Uttar Pradesh"}, -- 1,152,000 ["Dehradun"] = {container = "Uttarakhand"}, -- 1,136,000 ["Tiruchirappalli"] = {container = "Tamil Nadu"}, -- 1,131,000 ["Bhubaneswar"] = {container = "Odisha"}, -- 1,112,000 ["Jammu"] = {container = {key = "Jammu and Kashmir, India", placetype = "union territory"}}, -- 1,103,000 ["Solapur"] = {container = "Maharashtra"}, -- 1,082,000 ["Hubli-Dharwad"] = {container = "Karnataka", wp = "Hubli–Dharwad"}, -- 1,062,000; wp with en dash ["Hubli"] = {alias_of = "Hubli-Dharwad"}, ["Dharwad"] = {alias_of = "Hubli-Dharwad"}, ["Puducherry"] = {container = {key = "Puducherry, India", placetype = "union territory"}}, -- 1,024,000 ["Pondicherry"] = {alias_of = "Puducherry", display = true}, -- satellite/secondary cities of metro area (none in citypopulation.de) ["Ghaziabad"] = {container = "Uttar Pradesh"}, -- 1,729,000 city, 2,358,525 urban agglomeration per 2011 census; 3,406,061 2025 estimate from official website; part of Delhi metro area ["Faridabad"] = {container = "Haryana"}, -- 1,414,050 city per 2011 census; part of Delhi metro area ["Thane"] = {container = "Maharashtra"}, -- 1,841,488 city per 2011 census; part of Mumbai metro area ["Kalyan-Dombivli"] = {container = "Maharashtra"}, -- 1,246,381 city per 2011 census; part of Mumbai metro area ["Kalyan-Dombivali"] = {alias_of = "Kalyan-Dombivli", display = true}, ["Kalyan"] = {alias_of = "Kalyan-Dombivli"}, ["Dombivli"] = {alias_of = "Kalyan-Dombivli"}, ["Dombivali"] = {alias_of = "Kalyan-Dombivli"}, ["Vasai-Virar"] = {container = "Maharashtra"}, -- 1,221,233 city per 2011 census; part of Mumbai metro area ["Vasai"] = {alias_of = "Vasai-Virar"}, ["Virar"] = {alias_of = "Vasai-Virar"}, ["Navi Mumbai"] = {container = "Maharashtra"}, -- 1,120,547 city per 2011 census; part of Mumbai metro area ["Howrah"] = {container = "West Bengal"}, -- 1,077,075 city ("metropolis"), 2,811,344 "metro" per 2011 census; part of Kolkata metro area ["Pimpri-Chinchwad"] = {container = "Maharashtra"}, -- 1,727,692 per 2011 census; part of Pune metro area ["Pimpri Chinchwad"] = {alias_of = "Pimpri-Chinchwad", display = true}, } export.india_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", India", "state"), default_placetype = "city", data = export.india_cities, } export.indonesia_cities = { -- cities where the city proper has more than 1,000,000 people as of mid-2023 estimate ["Jakarta"] = {container = "Special Capital Region of Jakarta", divs = { {type = "subdistricts", container_parent_type = false}, }}, ["Surabaya"] = {container = "East Java"}, ["Bekasi"] = {container = "West Java"}, -- part of Jakarta metro area ["Bandung"] = {container = "West Java"}, ["Medan"] = {container = "North Sumatra"}, ["Depok"] = {container = "West Java"}, -- part of Jakarta metro area ["Tangerang"] = {container = "Banten"}, -- part of Jakarta metro area ["Palembang"] = {container = "South Sumatra"}, ["Semarang"] = {container = "Central Java"}, ["Makassar"] = {container = "South Sulawesi"}, ["South Tangerang"] = {container = "Banten"}, -- part of Jakarta metro area ["Batam"] = {container = "Riau Islands"}, ["Bogor"] = {container = "West Java"}, -- part of Jakarta metro area ["Pekanbaru"] = {container = "Riau"}, ["Bandar Lampung"] = {container = "Lampung"}, -- other metro areas over 1,000,000 people ["Padang"] = {container = "West Sumatra"}, ["Samarinda"] = {container = "East Kalimantan"}, ["Malang"] = {container = "East Java"}, ["Yogyakarta"] = {container = "Special Region of Yogyakarta"}, ["Denpasar"] = {container = "Bali"}, ["Cirebon"] = {container = "West Java"}, ["Surakarta"] = {container = "Central Java"}, ["Banjarmasin"] = {container = "South Kalimantan"}, ["Tasikmalaya"] = {container = "West Java"}, } export.indonesia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Indonesia", "province"), default_placetype = "city", data = export.indonesia_cities, } export.italy_cities = { -- Data per [[w:List_of_metropolitan_areas_of_Italy]]. There are several lists given; the most recent one, used -- here, only gives estimates as of Jan 1, 2014. ["Milan"] = {container = "Lombardy"}, -- 6,623,798 ["Naples"] = {container = "Campania"}, -- 5,294,546 ["Rome"] = {container = "Lazio"}, -- 4,447,881 ["Turin"] = {container = "Piedmont"}, -- 1,865,284 ["Venice"] = {container = "Veneto"}, -- 1,645,900 ["Florence"] = {container = "Tuscany"}, -- 1,485,030 ["Bari"] = {container = "Apulia"}, -- 1,257,459 ["Palermo"] = {container = "Sicily"}, -- 1,183,084 -- include a few just below 1,000,000 metro area that may be above it by now (depending on the definition). ["Catania"] = {container = "Sicily"}, -- 988,240 ["Brescia"] = {container = "Lombardy"}, -- 924,090 ["Genoa"] = {container = "Liguria"}, -- 861,318 } export.italy_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Italy", "region"), default_placetype = "city", data = export.italy_cities, } export.japan_cities = { -- Population figures from [[w:List of cities in Japan]]. Metro areas from -- [[w:List of metropolitan areas in Japan]]. ["Tokyo"] = {keydesc = "[[Tokyo]] Metropolis, the [[capital city]] and a [[prefecture]] of [[Japan]] (which is a country in [[Asia]])", placetype = {"city", "prefecture"}, divs = { {type = "special wards", container_parent_type = false}, {type = "cities", prep = "in"}, }, }, ["Yokohama"] = {container = "Kanagawa"}, -- 3,697,894 ["Osaka"] = {container = "Osaka"}, -- 2,668,586 ["Nagoya"] = {container = "Aichi"}, -- 2,283,289 -- FIXME, Hokkaido is handled specially. ["Sapporo"] = {container = "Hokkaido"}, -- 1,918,096 ["Fukuoka"] = {container = "Fukuoka"}, -- 1,581,527 ["Kobe"] = {container = "Hyōgo"}, -- 1,530,847 ["Kyoto"] = {container = "Kyoto"}, -- 1,474,570 ["Kawasaki"] = {container = "Kanagawa", wp = "%l, Kanagawa"}, -- 1,373,630 ["Saitama"] = {container = "Saitama", wp = "%l (city)", commonscat = "%l, %c"}, -- 1,192,418 ["Hiroshima"] = {container = "Hiroshima"}, -- 1,163,806 ["Sendai"] = {container = "Miyagi"}, -- 1,029,552 -- the remaining cities are considered "central cities" in a 1,000,000+ metro area -- (sometimes there is more than one central city in the area). ["Kitakyushu"] = {container = "Fukuoka"}, -- 986,998 ["Chiba"] = {container = "Chiba", wp = "%l (city)", commonscat = "%l, %c"}, -- 938,695 ["Sakai"] = {container = "Osaka"}, -- 835,333 ["Niigata"] = {container = "Niigata", wp = "%l (city)", commonscat = "%l, %c"}, -- 813,053 ["Hamamatsu"] = {container = "Shizuoka"}, -- 811,431 ["Shizuoka"] = {container = "Shizuoka", wp = "%l (city)", commonscat = "%l, %c"}, -- 710,944 ["Sagamihara"] = {container = "Kanagawa"}, -- 706,342 ["Okayama"] = {container = "Okayama"}, -- 701,293 ["Kumamoto"] = {container = "Kumamoto"}, -- 670,348 ["Kagoshima"] = {container = "Kagoshima"}, -- 605,196 -- skipped 6 cities (Funabashi, Hachiōji, Kawaguchi, Himeji, Matsuyama, Higashiōsaka) -- with population in the range 509k - 587k because not central cities in any -- 1,000,000+ metro area. ["Utsunomiya"] = {container = "Tochigi"}, -- 507,833 } export.japan_cities_group = { default_container = "Japan", canonicalize_key_container = make_canonicalize_key_container(" Prefecture, Japan", "prefecture"), default_placetype = "city", data = export.japan_cities, } export.mexico_cities = { ["Mexico City"] = {}, -- its own state ["Monterrey"] = {container = "Nuevo León"}, ["Guadalajara"] = {container = "Jalisco"}, ["Puebla"] = {container = "Puebla", wp = "%l (city)"}, ["Toluca"] = {container = "State of Mexico"}, ["Tijuana"] = {container = "Baja California"}, -- Include the state in the category for León due to possible confusion with León, Spain. ["León, Guanajuato"] = {container = "Guanajuato", wp = "%l, %c"}, ["León"] = {alias_of = "León, Guanajuato"}, ["Leon"] = {alias_of = "León, Guanajuato", display = true}, ["Querétaro"] = {container = "Querétaro", wp = "%l (city)"}, ["Queretaro"] = {alias_of = "Querétaro", display = true}, ["Ciudad Juárez"] = {container = "Chihuahua"}, ["Juárez"] = {alias_of = "Ciudad Juárez"}, ["Juarez"] = {alias_of = "Ciudad Juárez", display = "Juárez"}, ["Torreón"] = {container = "Coahuila"}, ["Torreon"] = {alias_of = "Torreón", display = true}, -- Include the state in the category for Mérida due to possible confusion with Mérida, Spain or -- Mérida, Venezuela. ["Mérida, Yucatán"] = {container = "Yucatán", wp = "%l, %c"}, ["Mérida"] = {alias_of = "Mérida, Yucatán"}, ["Merida"] = {alias_of = "Mérida, Yucatán", display = true}, ["San Luis Potosí"] = {container = "San Luis Potosí", wp = "%l (city)"}, ["San Luis Potosi"] = {alias_of = "San Luis Potosí", display = true}, ["Aguascalientes"] = {container = "Aguascalientes", wp = "%l (city)"}, ["Mexicali"] = {container = "Baja California"}, } export.mexico_cities_group = { default_container = "Mexico", canonicalize_key_container = make_canonicalize_key_container(", Mexico", "state"), default_placetype = "city", data = export.mexico_cities, } export.nigeria_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. ["Lagos"] = {container = "Lagos"}, -- 21,300,000 (unindicated; population of low reliability) ["Kano"] = {container = "Kano", wp = "%l (city)"}, -- 5,350,000 (unindicated; population of low reliability) ["Ibadan"] = {container = "Oyo"}, -- 3,400,000 (unindicated; population of low reliability) ["Abuja"] = {container = {key = "Federal Capital Territory, Nigeria", placetype = "federal territory"}}, -- 3,050,000 (unindicated; population of low reliability) ["Port Harcourt"] = {container = "Rivers"}, -- 2,250,000 (unindicated; population of low reliability) ["Kaduna"] = {container = "Kaduna"}, -- 1,980,000 (unindicated; population of low reliability) ["Benin City"] = {container = "Edo"}, -- 1,790,000 (unindicated; population of low reliability) ["Aba"] = {container = "Abia", wp = "%l, Nigeria"}, -- 1,280,000 (unindicated; population of low reliability) ["Onitsha"] = {container = "Anambra"}, -- 1,230,000 (unindicated; population of low reliability) ["Maiduguri"] = {container = "Borno"}, -- 1,190,000 (unindicated; population of low reliability) ["Ilorin"] = {container = "Kwara"}, -- 1,160,000 (unindicated; population of low reliability) ["Sokoto"] = {container = "Sokoto", wp = "%l (city)"}, -- 1,140,000 (unindicated; population of low reliability) ["Jos"] = {container = "Plateau"}, -- 1,110,000 (unindicated; population of low reliability) ["Zaria"] = {container = "Kaduna"}, -- 1,050,000 (unindicated; population of low reliability) ["Enugu"] = {container = "Enugu", wp = "%l (city)"}, -- 1,010,000 (unindicated; population of low reliability) } export.nigeria_cities_group = { default_container = "Nigeria", canonicalize_key_container = make_canonicalize_key_container(" State, Nigeria", "state"), default_placetype = "city", data = export.nigeria_cities, } export.pakistan_cities = { -- Figures from citypopulation.de; retrieved 2025-04-26; reference date 2025-01-01. ["Karachi"] = {container = "Sindh"}, -- 21,000,000 (Consolidated Urban Area) ["Lahore"] = {container = "Punjab"}, -- 14,600,000 (Consolidated Urban Area) ["Rawalpindi"] = {container = "Punjab"}, -- 5,600,000 (Consolidated Urban Area; including Islamabad) ["Islamabad"] = {container = {key = "Islamabad Capital Territory, Pakistan", placetype = "federal territory"}}, -- 5,600,000 (Consolidated Urban Area; including Rawalpindi) ["Faisalabad"] = {container = "Punjab"}, -- 4,125,000 (Consolidated Urban Area) ["Gujranwala"] = {container = "Punjab"}, -- 3,450,000 (Consolidated Urban Area) -- there is also Hyderabad in India (very confusing) ["Hyderabad, Pakistan"] = {container = "Sindh", wp = "%l, %c"}, -- 2,475,000 (Consolidated Urban Area) ["Hyderabad"] = {alias_of = "Hyderabad, Pakistan"}, ["Multan"] = {container = "Punjab"}, -- 2,425,000 (Consolidated Urban Area) ["Peshawar"] = {container = "Khyber Pakhtunkhwa"}, -- 2,150,000 (Consolidated Urban Area) ["Quetta"] = {container = "Balochistan"}, -- 1,720,000 (Urban Area) ["Sargodha"] = {container = "Punjab"}, -- 1,080,000 (Urban Area) ["Sialkot"] = {container = "Punjab"}, -- 1,050,000 (Consolidated Urban Area) } export.pakistan_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Pakistan", "province"), default_placetype = "city", data = export.pakistan_cities, } export.philippines_cities = { -- Skipped some cities in Metro Manila (Taguig, Pasig) which don't have districts. -- Other cities outside Metro Manila skipped as not central city in their urban area. ["Quezon City"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, -- Don't display-canonicalize Foo to Foo City as it may make the display weird. ["Quezon"] = {alias_of = "Quezon City"}, ["Manila"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, ["Davao City"] = {container = "Davao del Sur"}, ["Davao"] = {alias_of = "Davao City"}, ["Caloocan"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, ["Zamboanga City"] = {container = "Zamboanga del Sur"}, ["Zamboanga"] = {alias_of = "Zamboanga City"}, ["Cebu City"] = {container = "Cebu"}, ["Cebu"] = {alias_of = "Cebu City"}, ["Antipolo"] = {container = "Rizal"}, ["Cagayan de Oro"] = {container = "Misamis Oriental"}, ["Dasmariñas"] = {container = "Cavite"}, ["Dasmarinas"] = {alias_of = "Dasmariñas", display = true}, ["General Santos"] = {container = "South Cotabato"}, ["San Jose del Monte"] = {container = "Bulacan"}, ["Bacolod"] = {container = "Negros Occidental"}, ["Calamba"] = {container = "Laguna", wp = "%l, %c"}, ["Angeles"] = {container = "Pampanga", wp = "Angeles City"}, ["Angeles City"] = {alias_of = "Angeles"}, ["Iloilo City"] = {container = "Iloilo"}, ["Iloilo"] = {alias_of = "Iloilo City"}, } export.philippines_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Philippines", "province"), default_placetype = "city", data = export.philippines_cities, } export.russia_cities = { -- Figures from citypopulation.de; retrieved 2025-04-26; reference date 2025-01-01. ["Moscow"] = {}, -- 18,800,000 (Agglomeration) ["Saint Petersburg"] = {}, -- 6,350,000 (Agglomeration) ["Novosibirsk"] = {container = "Novosibirsk Oblast"}, -- 1,820,000 (Agglomeration) ["Yekaterinburg"] = {container = "Sverdlovsk Oblast"}, -- 1,810,000 (Agglomeration) ["Nizhny Novgorod"] = {container = "Nizhny Novgorod Oblast"}, -- 1,620,000 (Agglomeration) ["Kazan"] = {container = {key = "Tatarstan, Russia", placetype = "republic"}}, -- 1,560,000 (Agglomeration) ["Chelyabinsk"] = {container = "Chelyabinsk Oblast"}, -- 1,430,000 (Agglomeration) ["Rostov-on-Don"] = {container = "Rostov Oblast"}, -- 1,390,000 (Agglomeration) ["Rostov-na-Donu"] = {alias_of = "Rostov-on-Don", display = true}, ["Krasnodar"] = {container = {key = "Krasnodar Krai, Russia", placetype = "krai"}}, -- 1,370,000 (Agglomeration) ["Samara"] = {container = "Samara Oblast"}, -- 1,350,000 (Agglomeration) ["Krasnoyarsk"] = {container = {key = "Krasnoyarsk Krai, Russia", placetype = "krai"}}, -- 1,270,000 (Agglomeration) ["Ufa"] = {container = {key = "Bashkortostan, Russia", placetype = "republic"}}, -- 1,230,000 (Agglomeration) ["Saratov"] = {container = "Saratov Oblast"}, -- 1,170,000 (Agglomeration) ["Omsk"] = {container = "Omsk Oblast"}, -- 1,140,000 (Agglomeration) ["Voronezh"] = {container = "Voronezh Oblast"}, -- 1,130,000 (Agglomeration) ["Volgograd"] = {container = "Volgograd Oblast"}, -- 1,080,000 (Agglomeration) ["Perm"] = {container = {key = "Perm Krai, Russia", placetype = "krai"}, wp = "%l, Russia"}, -- 1,070,000 (Agglomeration) } export.russia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Russia", "oblast"), default_container = "Russia", default_placetype = "city", data = export.russia_cities, } export.saudi_arabia_cities = { -- Figures for the first five from [[w:List of cities and towns in Saudi Arabia]] as of 2022. Unclear if these are -- metro, urban or city proper figures. ["Riyadh"] = {container = "Riyadh"}, -- 7,000,100; 7,700,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Jeddah"] = {container = "Mecca"}, -- 3,751,917; 3,950,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Jedda"] = {alias_of = "Jeddah", display = true}, ["Jiddah"] = {alias_of = "Jeddah", display = true}, ["Jidda"] = {alias_of = "Jeddah", display = true}, ["Dammam"] = {container = "Eastern"}, -- 2,638,166; 2,925,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Mecca"] = {container = "Mecca"}, -- 2,385,509; 2,675,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Makkah"] = {alias_of = "Mecca", display = true}, ["Medina"] = {container = "Medina"}, -- 1,477,023; 1,530,000 per citypopulation.de 2025-01-01 (City) ["Hofuf"] = {container = "Eastern"}, -- 1,060,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Khamis Mushait"] = {container = "Aseer"}, -- 1,030,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Khamis Mushayt"] = {alias_of = "Khamis Mushait", display = true}, } export.saudi_arabia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(" Province, Saudi Arabia", "province"), default_placetype = "city", data = export.saudi_arabia_cities, } export.south_korea_cities = { -- All cities listed are not associated with any county. ["Seoul"] = {}, ["Busan"] = {}, ["Incheon"] = {}, ["Daegu"] = {}, ["Daejeon"] = {}, ["Gwangju"] = {}, ["Ulsan"] = {}, } export.south_korea_cities_group = { default_container = "South Korea", canonicalize_key_container = make_canonicalize_key_container(" County, South Korea", "province"), default_placetype = "city", data = export.south_korea_cities, } export.spain_cities = { ["Madrid"] = {container = "Community of Madrid"}, ["Barcelona"] = {container = "Catalonia"}, ["Valencia"] = {container = "Valencia"}, ["Seville"] = {container = "Andalusia"}, ["Bilbao"] = {container = "Basque Country"}, } export.spain_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Spain", "autonomous community"), default_placetype = "city", data = export.spain_cities, } export.taiwan_cities = { ["New Taipei City"] = {}, ["New Taipei"] = {alias_of = "New Taipei City", display = true}, ["Taichung"] = {}, ["Kaohsiung"] = {wp = "%l, Taiwan"}, ["Taipei"] = {}, ["Taoyuan"] = {}, ["Tainan"] = {}, -- these last three are not special municipalities ["Chiayi"] = {placetype = "city"}, ["Hsinchu"] = {placetype = "city"}, ["Keelung"] = {placetype = "city"}, } export.taiwan_cities_group = { placename_to_key = false, -- don't add ", Taiwan" to make the key canonicalize_key_container = make_canonicalize_key_container(", Taiwan", "county"), default_container = "Taiwan", default_placetype = {"special municipality", "municipality", "city"}, default_is_city = true, default_divs = {"districts"}, data = export.taiwan_cities, } -- NOTE: It's OK to mix cities from different constituent countries; as long as the immediate container is correct, -- everything else will be figured out. export.united_kingdom_cities = { ["London"] = {container = "Greater London"}, ["Manchester"] = {container = "Greater Manchester"}, ["Birmingham"] = {container = "West Midlands"}, ["Liverpool"] = {container = "Merseyside"}, ["Glasgow"] = {container = {key = "City of Glasgow, Scotland", placetype = "council area"}}, ["Leeds"] = {container = "West Yorkshire"}, ["Newcastle upon Tyne"] = {container = "Tyne and Wear"}, ["Newcastle"] = {alias_of = "Newcastle upon Tyne"}, ["Bristol"] = {container = {key = "England", placetype = "constituent country"}}, ["Cardiff"] = {container = {key = "Wales", placetype = "constituent country"}}, ["Portsmouth"] = {container = "Hampshire"}, ["Edinburgh"] = {container = {key = "City of Edinburgh, Scotland", placetype = "council area"}}, -- under 1,000,000 people but principal areas of Wales; requested by [[User:Donnanz]] ["Swansea"] = {container = {key = "Wales", placetype = "constituent country"}}, ["Newport"] = {container = {key = "Wales", placetype = "constituent country"}, wp = "Newport, Wales"}, } export.united_kingdom_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", England", "county"), default_placetype = "city", data = export.united_kingdom_cities, } export.united_states_cities = { -- top 50 CSA's by population, with the top and sometimes 2nd or 3rd city listed ["New York City"] = {container = "New York", wp = "%l", divs = { {type = "boroughs", container_parent_type = false}, }}, -- Don't display-canonicalize as it may make the display weird (e.g. in the context New York, New York). ["New York"] = {alias_of = "New York City"}, ["Newark"] = {container = "New Jersey"}, ["Los Angeles"] = {container = "California", wp = "%l"}, ["Long Beach"] = {container = "California"}, ["Riverside"] = {container = "California"}, ["Chicago"] = {container = "Illinois", wp = "%l"}, ["Washington, D.C."] = {wp = "%l"}, ["Washington, DC"] = {alias_of = "Washington, D.C.", display = true}, ["Washington D.C."] = {alias_of = "Washington, D.C.", display = true}, ["Washington DC"] = {alias_of = "Washington, D.C.", display = true}, -- Don't display-canonicalize as it may make the display weird (e.g. if the holonym is followed by a District of -- Columbia holonym). ["Washington"] = {alias_of = "Washington, D.C."}, ["Baltimore"] = {container = "Maryland", wp = "%l"}, -- to avoid conflict with San Jose in Costa Rica ["San Jose, California"] = {container = "California"}, ["San Jose"] = {alias_of = "San Jose, California"}, ["San Francisco"] = {container = "California", wp = "%l"}, ["Oakland"] = {container = "California"}, ["Boston"] = {container = "Massachusetts", wp = "%l"}, ["Providence"] = {container = "Rhode Island"}, ["Dallas"] = {container = "Texas", wp = "%l", commonscat = "%l, %c"}, ["Fort Worth"] = {container = "Texas"}, ["Philadelphia"] = {container = "Pennsylvania", wp = "%l"}, ["Houston"] = {container = "Texas", wp = "%l"}, ["Miami"] = {container = "Florida", wp = "%l", commonscat = "%l, %c"}, ["Atlanta"] = {container = "Georgia", wp = "%l"}, ["Detroit"] = {container = "Michigan", wp = "%l"}, ["Phoenix"] = {container = "Arizona", wp = "%l", commonscat = "%l, %c"}, ["Mesa"] = {container = "Arizona"}, ["Seattle"] = {container = "Washington", wp = "%l"}, ["Orlando"] = {container = "Florida"}, ["Minneapolis"] = {container = "Minnesota", wp = "%l"}, ["Cleveland"] = {container = "Ohio", wp = "%l", commonscat = "%l, %c"}, ["Denver"] = {container = "Colorado", wp = "%l", commonscat = "%l, %c"}, ["San Diego"] = {container = "California", wp = "%l", commonscat = "%l, %c"}, ["Portland"] = {container = "Oregon"}, ["Tampa"] = {container = "Florida"}, ["St. Louis"] = {container = "Missouri", wp = "%l", commonscat = "%l, %c"}, ["Saint Louis"] = {alias_of = "St. Louis", display = true}, ["Charlotte"] = {container = "North Carolina"}, ["Sacramento"] = {container = "California"}, ["Pittsburgh"] = {container = "Pennsylvania", wp = "%l"}, ["Salt Lake City"] = {container = "Utah", wp = "%l"}, ["San Antonio"] = {container = "Texas", wp = "%l", commonscat = "%l, %c"}, ["Columbus"] = {container = "Ohio"}, ["Kansas City"] = {container = "Missouri", wp = "%l metropolitan area", commonscat = "%l, %c"}, ["Indianapolis"] = {container = "Indiana", wp = "%l"}, ["Las Vegas"] = {container = "Nevada", wp = "%l"}, ["Cincinnati"] = {container = "Ohio", wp = "%l", commonscat = "%l, %c"}, ["Austin"] = {container = "Texas"}, ["Milwaukee"] = {container = "Wisconsin", wp = "%l", commonscat = "%l, %c"}, ["Raleigh"] = {container = "North Carolina"}, ["Nashville"] = {container = "Tennessee"}, ["Virginia Beach"] = {container = "Virginia"}, ["Norfolk"] = {container = "Virginia"}, ["Greensboro"] = {container = "North Carolina"}, ["Winston-Salem"] = {container = "North Carolina"}, ["Jacksonville"] = {container = "Florida"}, ["New Orleans"] = {container = "Louisiana", wp = "%l"}, ["Louisville"] = {container = "Kentucky"}, ["Greenville"] = {container = "South Carolina"}, ["Hartford"] = {container = "Connecticut"}, ["Oklahoma City"] = {container = "Oklahoma", wp = "%l"}, ["Grand Rapids"] = {container = "Michigan"}, ["Memphis"] = {container = "Tennessee"}, ["Birmingham, Alabama"] = {container = "Alabama"}, ["Birmingham"] = {alias_of = "Birmingham, Alabama"}, ["Fresno"] = {container = "California"}, ["Richmond"] = {container = "Virginia"}, ["Harrisburg"] = {container = "Pennsylvania"}, -- any major city of top 50 MSA's that's missed by previous ["Buffalo"] = {container = "New York"}, -- any of the top 50 city by city population that's missed by previous ["El Paso"] = {container = "Texas"}, ["Albuquerque"] = {container = "New Mexico"}, ["Tucson"] = {container = "Arizona"}, ["Colorado Springs"] = {container = "Colorado"}, ["Omaha"] = {container = "Nebraska"}, ["Tulsa"] = {container = "Oklahoma"}, -- skip Arlington, Texas; too obscure and likely to be interpreted as Arlington, Virginia } export.united_states_cities_group = { default_container = "United States", canonicalize_key_container = make_canonicalize_key_container(", USA", "state"), default_placetype = "city", default_wp = "%l, %c", data = export.united_states_cities, } export.new_york_boroughs = { ["Bronx"] = {the = true, wp = "The Bronx"}, ["Brooklyn"] = {}, ["Manhattan"] = {}, ["Queens"] = {}, ["Staten Island"] = {}, } export.new_york_boroughs_group = { default_container = {key = "New York City", placetype = "city"}, default_placetype = "borough", default_is_city = true, data = export.new_york_boroughs, } export.vietnam_cities = { -- Figures from citypopulation.de (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated. ["Ho Chi Minh City"] = {}, -- 14,300,000 (Agglomeration; inclunding Bien Hoa) ["Saigon"] = {alias_of = "Ho Chi Minh City"}, ["Hanoi"] = {}, -- 7,350,000 (Agglomeration) ["Da Nang"] = {}, -- 1,500,000 (Agglomeration) ["Danang"] = {alias_of = "Da Nang", display = true}, ["Haiphong"] = {}, -- 1,450,000 (Agglomeration) ["Hai Phong"] = {alias_of = "Haiphong", display = true}, -- This is the one entry in this list that is not a province-level municipality; instead it's a "provincial city" -- meaning it is directly under its province as opposed to being contained in a district. ["Bien Hoa"] = {placetype = "city", container = "Đồng Nai", wp = "Biên Hòa"}, -- 1,272,235 (2022 city population per Wikipedia) ["Biên Hòa"] = {alias_of = "Bien Hoa", display = true}, ["Biên Hoà"] = {alias_of = "Bien Hoa", display = true}, -- These two not in citypopulation.de because the urban population may be slightly under 1,000,000, but they are -- both province-level municipalities and close to the 1,000,000 mark. ["Can Tho"] = {wp = "Cần Thơ"}, -- 1,456,000 municipality (2019 census), 994,704 urban (2022 General Statistics Office of Vietnam estimate); capital [[Ninh Kiều district]] ["Cần Thơ"] = {alias_of = "Can Tho", display = true}, ["Hue"] = {wp = "Huế"}, -- 1,257,000 municipality (2019 census), 840,000 urban (2022 General Statistics Office of Vietnam estimate); -- capital [[Thuận Hóa district]] ["Huế"] = {alias_of = "Hue", display = true}, } export.vietnam_cities_group = { placename_to_key = false, -- don't add ", Vietnam" to make the key default_container = "Vietnam", canonicalize_key_container = make_canonicalize_key_container(" Province, Vietnam", "province"), -- Most of the cities listed are province-level municipalities in addition, which contain a certain amount of -- rural territory surrounding the city, but not enough to separate the municipality from the city as distinct -- known locations. default_placetype = {"municipality", "city"}, default_is_city = true, -- There may not be enough districts to subcategorize like this. -- default_divs = "districts", data = export.vietnam_cities, } export.misc_cities = { ------------------ Africa ------------------- -- Sorted by country and then within the country, by decreasing population; figures from citypopulation.de -- (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated; combined with data from -- [[w:List of urban areas in Africa by population]]. ["Algiers"] = {container = "Algeria"}, -- 4,325,000 (Consolidated Urban Area) ["Oran"] = {container = "Algeria"}, -- 1,640,000 (Consolidated Urban Area) ["Luanda"] = {container = "Angola"}, -- 9,650,000 (Urban Area) ["Benguela"] = {container = "Angola"}, -- 1,420,000 (Urban Area) ["Cotonou"] = {container = "Benin"}, -- 2,150,000 (Agglomeration) ["Ouagadougou"] = {container = "Burkina Faso"}, -- 3,425,000 (Agglomeration) ["Bobo-Dioulasso"] = {container = "Burkina Faso"}, -- 1,100,000 (Agglomeration) ["Bujumbura"] = {container = "Burundi"}, -- 1,143,202 (Urban Area 2023 per PopulationStat, cited in Wikipedia) ["Yaoundé"] = {container = "Cameroon"}, -- 3,975,000 (City) ["Yaounde"] = {alias_of = "Yaoundé", display = true}, ["Douala"] = {container = "Cameroon"}, -- 3,900,000 (City) ["Bangui"] = {container = "Central African Republic"}, -- 1,680,000 (Agglomeration) ["N'Djamena"] = {container = "Chad"}, -- 1,950,000 (City) ["Ndjamena"] = {alias_of = "N'Djamena", display = true}, ["Kinshasa"] = {container = "Democratic Republic of the Congo"}, -- 16,300,000 (City; population of low reliability) ["Lubumbashi"] = {container = "Democratic Republic of the Congo"}, -- 2,875,000 (City; population of low reliability) ["Mbuji-Mayi"] = {container = "Democratic Republic of the Congo"}, -- 2,500,000 (City; population of low reliability) ["Kananga"] = {container = "Democratic Republic of the Congo"}, -- 1,370,000 (City; population of low reliability) ["Kisangani"] = {container = "Democratic Republic of the Congo"}, -- 1,300,000 (City; population of low reliability) ["Bukavu"] = {container = "Democratic Republic of the Congo"}, -- 1,100,000 (City; population of low reliability) ["Goma"] = {container = "Democratic Republic of the Congo"}, -- 1,010,000 (City; population of low reliability) ["Tshikapa"] = {container = "Democratic Republic of the Congo"}, -- 1,020,468 (2023 Wikipedia [[w:List of cities with over one million inhabitants]] from populationstat.com; not in citypopulation.de) ["Cairo"] = {container = "Egypt"}, -- 22,800,000 (Agglomeration, including Giza and Subhra El Kheima) ["Alexandria"] = {container = "Egypt"}, -- 6,250,000 (Agglomeration) ["Giza"] = {container = "Egypt"}, -- 4,458,135 (2023 from citypopulation.de) ["Shubra El Kheima"] = {container = "Egypt"}, -- 1,240,239 (2021 from citypopulation.de) ["Asmara"] = {container = "Eritrea"}, -- 1,090,000 (City; population of low reliability) ["Asmera"] = {alias_of = "Asmara", display = true}, ["Addis Ababa"] = {container = "Ethiopia"}, -- 4,825,000 (Agglomeration) ["Banjul"] = {container = "Gambia"}, -- 1,170,000 (Agglomeration) ["Accra"] = {container = "Ghana"}, -- 6,800,000 (Agglomeration) ["Kumasi"] = {container = "Ghana"}, -- 2,900,000 (Agglomeration) ["Conakry"] = {container = "Guinea"}, -- 2,975,000 (Consolidated Urban Area) ["Abidjan"] = {container = "Ivory Coast"}, -- 7,050,000 (Agglomeration) ["Nairobi"] = {container = "Kenya"}, -- 6,900,000 (unindicated) ["Mombasa"] = {container = "Kenya"}, -- 1,370,000 (City) ["Monrovia"] = {container = "Liberia"}, -- 1,940,000 (Urban Area) ["Tripoli"] = {container = "Libya", wp = "%l, %c"}, -- 1,870,000 (unindicated) ["Antananarivo"] = {container = "Madagascar"}, -- 3,150,000 (Agglomeration) ["Lilongwe"] = {container = "Malawi"}, -- 1,210,000 (City) ["Bamako"] = {container = "Mali"}, -- 5,700,000 (Agglomeration) ["Nouakchott"] = {container = "Mauritania"}, -- 1,500,000 (City) ["Casablanca"] = {container = {key = "Casablanca-Settat, Morocco", placetype = "region"}}, -- 4,450,000 (Municipality (urban population)) ["Rabat"] = {container = {key = "Rabat-Sale-Kenitra, Morocco", placetype = "region"}}, -- 2,125,000 (Municipality (urban population)) ["Tangier"] = {container = {key = "Tangier-Tetouan-Al Hoceima, Morocco", placetype = "region"}}, -- 1,410,000 (Municipality (urban population)) ["Tanger"] = {alias_of = "Tangier", display = true}, ["Tangiers"] = {alias_of = "Tangier", display = true}, ["Fez"] = {container = {key = "Fez-Meknes, Morocco", placetype = "region"}, wp = "%l, Morocco"}, -- 1,310,000 (Municipality (urban population)) ["Fes"] = {alias_of = "Fez", display = true}, ["Fès"] = {alias_of = "Fez", display = true}, ["Agadir"] = {container = {key = "Souss-Massa, Morocco", placetype = "region"}}, -- 1,270,000 (Municipality (urban population)) ["Marrakesh"] = {container = {key = "Marrakesh-Safi, Morocco", placetype = "region"}}, -- 1,140,000 (Municipality (urban population)) ["Marrakech"] = {alias_of = "Marrakesh", display = true}, ["Maputo"] = {container = "Mozambique"}, -- 2,575,000 (Agglomeration) ["Niamey"] = {container = "Niger"}, -- 1,530,000 (City) ["Brazzaville"] = {container = "Republic of the Congo"}, -- 2,475,000 (Agglomeration) ["Pointe-Noire"] = {container = "Republic of the Congo"}, -- 1,480,000 (City) ["Kigali"] = {container = "Rwanda"}, -- 1,960,000 (Municipality (urban population)) ["Dakar"] = {container = "Senegal"}, -- 4,225,000 (Agglomeration) ["Touba"] = {container = "Senegal"}, -- 1,320,000 (Agglomeration) ["Freetown"] = {container = "Sierra Leone"}, -- 1,420,000 (Agglomeration) ["Mogadishu"] = {container = "Somalia"}, -- 2,250,000 (unindicated; population of low reliability) ["Johannesburg"] = {container = {key = "Gauteng, South Africa", placetype = "province"}}, -- 14,800,000 (Consolidated Urban Area; including Pretoria, Soweto, etc.) ["Cape Town"] = {container = {key = "Western Cape, South Africa", placetype = "province"}}, -- 5,100,000 (Consolidated Urban Area) ["Durban"] = {container = {key = "KwaZulu-Natal, South Africa", placetype = "province"}}, -- 3,900,000 (Consolidated Urban Area) ["Pretoria"] = {container = {key = "Gauteng, South Africa", placetype = "province"}}, -- 2,921,488 (2011 census) ["Port Elizabeth"] = {container = {key = "Eastern Cape, South Africa", placetype = "province"}, wp = "Gqeberha"}, -- 1,200,000 (Consolidated Urban Area) ["Gqeberha"] = {alias_of = "Port Elizabeth"}, -- official name; not a display alias ["Khartoum"] = {container = "Sudan"}, -- 7,200,000 (unindicated; population of low reliability) ["Dar es Salaam"] = {container = "Tanzania"}, -- 6,650,000 (Agglomeration) ["Mwanza"] = {container = "Tanzania"}, -- 1,340,000 (Agglomeration) ["Mwanza City"] = {alias_of = "Mwanza", display = true}, ["Arusha"] = {container = "Tanzania"}, -- 1,190,000 (Agglomeration) ["Zanzibar"] = {container = "Tanzania"}, -- 1,030,000 (Agglomeration) ["Lomé"] = {container = "Togo"}, -- 2,625,000 (unindicated) ["Lome"] = {alias_of = "Lomé", display = true}, ["Tunis"] = {container = "Tunisia"}, -- 2,725,000 (Municipality (urban population)) ["Sousse"] = {container = "Tunisia"}, -- 1,180,000 (Municipality (urban population)) ["Soussa"] = {alias_of = "Sousse", display = true}, ["Kampala"] = {container = "Uganda"}, -- 4,300,000 (unindicated) ["Lusaka"] = {container = "Zambia"}, -- 3,000,000 (Consolidated Urban Area) ["Harare"] = {container = "Zimbabwe"}, -- 2,675,000 (Agglomeration) ------------------ Asia ------------------- -- sorted by country and then within the country, by decreasing population; figures from citypopulation.de -- (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated. ["Kabul"] = {container = "Afghanistan"}, -- 5,250,000 (Agglomeration) ["Baku"] = {container = "Azerbaijan"}, -- 3,725,000 (Administrative Area (urban population)) ["Manama"] = {container = "Bahrain"}, -- 1,560,000 (unindicated) ["Dhaka"] = {container = {key = "Dhaka Division, Bangladesh", placetype = "division"}}, -- 23,100,000 (Agglomeration) ["Dacca"] = {alias_of = "Dhaka", display = true}, ["Chittagong"] = {container = {key = "Chittagong Division, Bangladesh", placetype = "division"}}, -- 5,050,000 (Agglomeration) ["Gazipur"] = {container = {key = "Dhaka Division, Bangladesh", placetype = "division"}}, -- 2,674,697 (City per 2022; countied in citypopulation.de as part of Dhaka metro area) ["Khulna"] = {container = {key = "Khulna Division, Bangladesh", placetype = "division"}}, -- 1,210,000 (Agglomeration) ["Phnom Penh"] = {container = "Cambodia"}, -- 2,925,000 (Agglomeration) ["Tehran"] = {container = {key = "Tehran Province, Iran", placetype = "province"}}, -- 16,800,000 (Agglomeration) ["Teheran"] = {alias_of = "Tehran", display = true}, ["Mashhad"] = {container = {key = "Razavi Khorasan Province, Iran", placetype = "province"}}, -- 3,475,000 (Agglomeration) ["Mashad"] = {alias_of = "Mashhad", display = true}, ["Meshhed"] = {alias_of = "Mashhad", display = true}, ["Meshed"] = {alias_of = "Mashhad", display = true}, ["Isfahan"] = {container = {key = "Isfahan Province, Iran", placetype = "province"}}, -- 3,425,000 (Agglomeration) ["Esfahan"] = {alias_of = "Isfahan", display = true}, ["Tabriz"] = {container = {key = "East Azerbaijan Province, Iran", placetype = "province"}}, -- 1,970,000 (Agglomeration) ["Shiraz"] = {container = {key = "Fars Province, Iran", placetype = "province"}}, -- 1,950,000 (Agglomeration) ["Ahvaz"] = {container = {key = "Khuzestan Province, Iran", placetype = "province"}}, -- 1,550,000 (Agglomeration) ["Qom"] = {container = {key = "Qom Province, Iran", placetype = "province"}}, -- 1,450,000 (City) ["Kermanshah"] = {container = {key = "Kermanshah Province, Iran", placetype = "province"}}, -- 1,130,000 (City) ["Baghdad"] = {container = "Iraq"}, -- 7,800,000 (Administrative Area (urban population)) ["Basra"] = {container = "Iraq"}, -- 1,710,000 (Administrative Area (urban population)) ["Mosul"] = {container = "Iraq"}, -- 1,550,000 (Administrative Area (urban population)) ["Erbil"] = {container = "Iraq"}, -- 1,220,000 (Administrative Area (urban population)) ["Kirkuk"] = {container = "Iraq"}, -- 1,160,000 (Administrative Area (urban population)) ["Najaf"] = {container = "Iraq"}, -- 1,050,000 (Administrative Area (urban population)) ["Tel Aviv"] = {container = "Israel"}, -- 3,000,000 (Agglomeration) -- Jerusalem is not recognized internationally as part of either Israel or Palestine, but as a -- [[w:corpus separatum]], so put the container as "Asia" and list Israel and Palestine as additional parents for -- categorization purposes. ["Jerusalem"] = {container = {key = "Asia", placetype = "continent"}, addl_parents = {"Israel", "Palestine"}}, -- 1,080,000 (Agglomeration) ["Amman"] = {container = "Jordan"}, -- 6,150,000 (unindicated) ["Irbid"] = {container = "Jordan"}, -- 1,070,000 (unindicated) ["Almaty"] = {container = "Kazakhstan"}, -- 2,700,000 (Agglomeration) ["Alma-Ata"] = {alias_of = "Almaty"}, -- former name, sometimes still used; don't display-canonicalize ["Astana"] = {container = "Kazakhstan"}, -- 1,600,000 (Agglomeration) ["Shymkent"] = {container = "Kazakhstan"}, -- 1,370,000 (Agglomeration) ["Kuwait City"] = {container = "Kuwait"}, -- 5,050,000 (Agglomeration) ["Bishkek"] = {container = "Kyrgyzstan"}, -- 1,540,000 (Agglomeration) ["Beirut"] = {container = "Lebanon"}, -- 1,930,000 (unindicated; population of low reliability) -- Kuala Lumpur is a federal capital city, not in any state ["Kuala Lumpur"] = {container = "Malaysia"}, -- 9,550,000 (Agglomeration) -- there are various George Towns and Georgetowns ["George Town, Malaysia"] = {container = {key = "Penang, Malaysia", placetype = "state"}, wp = "%l, %c"}, -- 2,075,000 (Agglomeration) ["George Town"] = {alias_of = "George Town, Malaysia"}, ["Ulaanbaatar"] = {container = "Mongolia"}, -- 1,610,000 (City) ["Ulan Bator"] = {alias_of = "Ulaanbaatar", display = true}, ["Yangon"] = {container = "Myanmar"}, -- 5,650,000 (Municipality (urban population)) ["Rangoon"] = {alias_of = "Yangon", display = true}, ["Mandalay"] = {container = "Myanmar"}, -- 1,600,000 (Municipality (urban population)) ["Kathmandu"] = {container = "Nepal"}, -- 3,175,000 (Agglomeration) -- Pyongyang is a directly governed city, not in any province ["Pyongyang"] = {container = "North Korea"}, -- 3,025,000 (Administrative Area (urban population)) ["Muscat"] = {container = "Oman"}, -- 1,620,000 (Agglomeration) ["Gaza"] = {container = "Palestine", wp = "Gaza City"}, -- 2,275,000 (unindicated) ["Gaza City"] = {alias_of = "Gaza"}, ["Doha"] = {container = "Qatar"}, -- 2,650,000 (Agglomeration) ["Colombo"] = {container = "Sri Lanka"}, -- 4,975,000 (unindicated) ["Damascus"] = {container = "Syria"}, -- 3,975,000 (unindicated; population of low reliability) ["Aleppo"] = {container = "Syria"}, -- 1,980,000 (unindicated; population of low reliability) ["Dushanbe"] = {container = "Tajikistan"}, -- 1,270,000 (City) ["Bangkok"] = {container = "Thailand"}, -- 21,800,000 (Agglomeration) -- Chiang Mai not in citypopulation.de, but 1,198,000 urban population in 2021 per Wikipedia -- [[w:List_of_municipalities_in_Thailand#Largest_cities_by_urban_population]] ["Chiang Mai"] = {container = {key = "Chiang Mai Province, Thailand", placetype = "province"}}, ["Chonburi"] = {container = {key = "Chonburi Province, Thailand", placetype = "province"}}, -- 1,570,000 (Agglomeration; including Pattaya) -- metro area population stats from https://www.statista.com/statistics/255483/biggest-cities-in-turkey/ as of 2021; -- second source is citypopulation.de reference date 2025-01-01. ["Istanbul"] = {placetype = {"city", "province"}, divs = {"districts"}, container = "Turkey"}, -- 15.2 million; 16,000,000 (Agglomeration) ["İstanbul"] = {alias_of = "Istanbul", display = true}, ["Ankara"] = {container = {key = "Ankara Province, Turkey", placetype = "province"}}, -- 5.15 million; 5,200,000 (Agglomeration) ["Izmir"] = {container = {key = "İzmir Province, Turkey", placetype = "province"}, wp = "İzmir"}, -- 2.95 million; 3,025,000 (Agglomeration) ["İzmir"] = {alias_of = "Izmir", display = true}, ["Bursa"] = {container = {key = "Bursa Province, Turkey", placetype = "province"}}, -- 2.02 million; 2,200,000 (Agglomeration) ["Adana"] = {container = {key = "Adana Province, Turkey", placetype = "province"}}, -- 1.77 million; 1,780,000 (Agglomeration) ["Gaziantep"] = {container = {key = "Gaziantep Province, Turkey", placetype = "province"}}, -- 1.71 million; 1,750,000 (Agglomeration) ["Antalya"] = {container = {key = "Antalya Province, Turkey", placetype = "province"}}, -- 1.3 million; 1,400,000 (Agglomeration) ["Konya"] = {container = {key = "Konya Province, Turkey", placetype = "province"}}, -- 1.35 million; 1,390,000 (Agglomeration) ["Diyarbakır"] = {container = {key = "Diyarbakır Province, Turkey", placetype = "province"}}, -- 1.07 million; 1,100,000 (Agglomeration) -- Diyarbakır is more common per Ngrams and Google Scholar, but Diyarbakir is the Kurdish form, so we should not -- display-canonicalize to the Turkish form Diyarbakır. ["Diyarbakir"] = {alias_of = "Diyarbakır"}, ["Mersin"] = {container = {key = "Mersin Province, Turkey", placetype = "province"}}, -- 1.03 million; 1,060,000 (Agglomeration) ["Ashgabat"] = {container = "Turkmenistan"}, -- 1,150,000 (Agglomeration) ["Dubai"] = {container = "United Arab Emirates"}, -- 6,050,000 (Agglomeration; including Sharjah) ["Abu Dhabi"] = {container = "United Arab Emirates"}, -- 1,850,000 (City) ["Sharjah"] = {container = "United Arab Emirates"}, -- 1,800,000 (Metro area 2022-2023 per Wikipedia; separate from Dubai) ["Tashkent"] = {container = "Uzbekistan"}, -- 3,850,000 (unindicated) ["Sanaa"] = {container = "Yemen"}, -- 3,275,000 (City; population of low reliability) ["Sana'a"] = {alias_of = "Sanaa", display = true}, ["Aden"] = {container = "Yemen"}, -- 1,079,060 (?; 2023 estimate from World Population Review per Wikipedia) ------------------ Europe or Europe-like (Caucasus etc.) --------------------- ["Yerevan"] = {container = "Armenia"}, -- 1,520,000 (Agglomeration) ["Vienna"] = {container = "Austria"}, -- 2,375,000 (Agglomeration) ["Minsk"] = {container = "Belarus"}, -- 2,100,000 (unindicated) ["Brussels"] = {container = "Belgium"}, -- 2,800,000 (Consolidated Urban Area) ["Antwerp"] = {container = "Belgium"}, -- 1,270,000 (Consolidated Urban Area) ["Sofia"] = {container = "Bulgaria"}, -- 1,260,000 (Agglomeration) ["Zagreb"] = {container = "Croatia"}, ["Prague"] = {container = "Czech Republic"}, -- 1,470,000 (Agglomeration) ["Brno"] = {container = "Czech Republic"}, -- 729,405 (metro area per Wikipedia as of 2024-01-01 Czech Statistical Office) ["Olomouc"] = {container = "Czech Republic"}, -- 102,293 (city; included only because someone went crazy creating Olomouc-related terms) ["Copenhagen"] = {container = "Denmark"}, -- 1,800,000 (Consolidated Urban Area) ["Helsinki"] = {container = {key = "Uusimaa, Finland", placetype = "region"}}, -- 1,560,000 (Consolidated Urban Area) ["Tbilisi"] = {container = "Georgia"}, -- 1,430,000 (Agglomeration) ["Athens"] = {container = "Greece"}, ["Thessaloniki"] = {container = "Greece"}, ["Budapest"] = {container = "Hungary"}, -- FIXME, per Wikipedia "County Dublin" is now the "Dublin Region" ["Dublin"] = {container = {key = "County Dublin, Ireland", placetype = "county"}}, ["Riga"] = {container = "Latvia"}, ["Amsterdam"] = {container = {key = "North Holland, Netherlands", placetype = "province"}}, ["Rotterdam"] = {container = {key = "South Holland, Netherlands", placetype = "province"}}, ["The Hague"] = {container = {key = "South Holland, Netherlands", placetype = "province"}}, -- Christchurch (metro 546,600) and Wellington (metro 439,800) are too small to make it. ["Auckland"] = {container = {key = "Auckland, New Zealand", placetype = "region"}}, ["Oslo"] = {container = {key = "Oslo, Norway", placetype = "county"}}, ["Warsaw"] = {container = {key = "Masovian Voivodeship, Poland", placetype = "voivodeship"}}, ["Katowice"] = {container = {key = "Silesian Voivodeship, Poland", placetype = "voivodeship"}}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Krakow" without accent. ["Krakow"] = {container = {key = "Lesser Poland Voivodeship, Poland", placetype = "voivodeship"}, wp = "Kraków"}, ["Kraków"] = {alias_of = "Krakow", display = true}, ["Cracow"] = {alias_of = "Krakow", display = true}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirm "Gdańsk" and "Poznań" with accent. ["Gdańsk"] = {container = {key = "Pomeranian Voivodeship, Poland", placetype = "voivodeship"}}, ["Gdansk"] = {alias_of = "Gdańsk", display = true}, ["Poznań"] = {container = {key = "Greater Poland Voivodeship, Poland", placetype = "voivodeship"}}, ["Poznan"] = {alias_of = "Poznań", display = true}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Lodz" without accents. ["Lodz"] = {container = {key = "Lodz Voivodeship, Poland", placetype = "voivodeship"}, wp = "Łódź"}, ["Łódź"] = {alias_of = "Lodz", display = true}, ["Lisbon"] = {container = {key = "Lisbon District, Portugal", placetype = "district"}}, ["Porto"] = {container = {key = "Porto District, Portugal", placetype = "district"}}, ["Oporto"] = {alias_of = "Porto", display = true}, ["Bucharest"] = {container = "Romania"}, ["Belgrade"] = {container = "Serbia"}, ["Stockholm"] = {container = "Sweden"}, ["Zurich"] = {container = "Switzerland"}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Zurich" without umlaut. --- Even Wikipedia uses the form without umlaut. ["Zürich"] = {alias_of = "Zurich", display = true}, ["Kyiv"] = {container = "Ukraine"}, -- not in Kyiv Oblast -- Don't display-canonicalize Kiev -> Kyiv because in ancient contexts, Kiev is still more common. ["Kiev"] = {alias_of = "Kyiv"}, ["Kharkiv"] = {container = {key = "Kharkiv Oblast, Ukraine", placetype = "oblast"}}, ["Odessa"] = {container = {key = "Odesa Oblast, Ukraine", placetype = "oblast"}, wp = "Odesa"}, -- Don't display-canonicalize Odesa -> Odessa because it may be interpreted as a political statement. ["Odesa"] = {alias_of = "Odessa"}, ------------------ North America, South America --------------------- -- Primary figures from citypopulation.de retrieved on 2025-04-26 (reference date 2025-01-01); -- Wikipedia metropolitan figures from [[w:List of metropolitan areas in the Americas]] based on per-country data; -- Wikipedia city limits figures from [[w:List of largest cities in the Americas]]. ["Buenos Aires"] = {container = "Argentina"}, -- 16,800,000 (Consolidated Urban Area; 13,985,794 metropolitan area per Wikipedia) ["Córdoba, Argentina"] = {container = "Argentina", wp = "%l, %c"}, -- 1,810,000 (Consolidated Urban Area; 1,505,25 city limits per Wikipedia) -- to avoid confusion with Córdoba in Spain ["Córdoba"] = {alias_of = "Córdoba, Argentina"}, ["Cordoba"] = {alias_of = "Córdoba, Argentina", display = "Córdoba"}, ["Rosario"] = {container = "Argentina", wp = "%l, Santa Fe"}, -- 1,510,000 (Consolidated Urban Area; 1,348,725 metropolitan area per Wikipedia) ["Mendoza"] = {container = "Argentina", wp = "%l, %c"}, -- 1,180,000 (Consolidated Urban Area) ["San Miguel de Tucumán"] = {container = "Argentina"}, -- 1,110,000 (Consolidated Urban Area) ["Tucumán"] = {alias_of = "San Miguel de Tucumán"}, ["Tucuman"] = {alias_of = "San Miguel de Tucumán", display = "Tucumán"}, ["Santa Cruz de la Sierra"] = {container = "Bolivia"}, -- 1,960,000 (Consolidated Urban Area); 1,606,671 (city limits per Wikipedia) ["Santa Cruz"] = {alias_of = "Santa Cruz de la Sierra"}, ["La Paz"] = {container = "Bolivia"}, -- 1,870,000 (Consolidated Urban Area; composed of El Alto, now slightly larger, and La Paz) ["El Alto"] = {container = "Bolivia"}, ["Cochabamba"] = {container = "Bolivia"}, -- 1,280,000 (Consolidated Urban Area) ["Santiago"] = {container = "Chile"}, -- 8,400,000 (Consolidated Urban Area; 6,903,479 city limits? per Wikipedia) ["Valparaíso"] = {container = "Chile"}, -- 1,060,000 (Consolidated Urban Area) ["Valparaiso"] = {alias_of = "Valparaíso"}, -- 1,060,000 (Consolidated Urban Area) ["Bogotá"] = {container = "Colombia"}, -- 10,600,000 (Agglomeration; 12,772,828 metropolitan area per Wikipedia) ["Bogota"] = {alias_of = "Bogotá", display = true}, ["Medellín"] = {container = "Colombia"}, -- 4,350,000 (Agglomeration; 4,068,000 metropolitan area per Wikipedia) ["Medellin"] = {alias_of = "Medellín", display = true}, ["Cali"] = {container = "Colombia"}, -- 2,975,000 (Agglomeration; 2,837,000 metropolitan area per Wikipedia) ["Barranquilla"] = {container = "Colombia"}, -- 2,375,000 (Agglomeration; 1,341,160 city limits per Wikipedia) ["Bucaramanga"] = {container = "Colombia"}, -- 1,380,000 (Agglomeration) ["Cartagena, Colombia"] = {container = "Colombia", wp = "%l, %c"}, -- 1,250,000 (Agglomeration) -- to avoid confusion with Cartagena, Spain ["Cartagena"] = {alias_of = "Cartagena, Colombia"}, ["Cúcuta"] = {container = "Colombia"}, -- 1,130,000 (Agglomeration) ["Cucuta"] = {alias_of = "Cúcuta", display = true}, -- to avoid conflict with San Jose, California ["San José, Costa Rica"] = {container = "Costa Rica", wp = "%l, %c"}, -- 2,450,000 (Municipality (urban population); 3,160,000 metropolitan area per Wikipedia) ["San José"] = {alias_of = "San José, Costa Rica"}, ["San Jose"] = {alias_of = "San José, Costa Rica"}, -- display = "San José"; causes error due to San Jose alias for California city; FIXME ["Havana"] = {container = "Cuba"}, -- 2,150,000 (City; 2,137,847 city limits? per Wikipedia) ["Santo Domingo"] = {container = "Dominican Republic"}, -- 3,900,000 (Municipality (urban population); 4,274,651 ??? per Wikipedia) ["Guayaquil"] = {container = "Ecuador"}, -- 3,350,000 (Agglomeration; 3,092,000 metro area? per Wikipedia) ["Quito"] = {container = "Ecuador"}, -- 2,875,000 (Agglomeration; 2,889,703 metro area? per Wikipedia) ["San Salvador"] = {container = "El Salvador"}, -- 1,580,000 (Municipality (urban population)) ["Guatemala City"] = {container = "Guatemala"}, -- 3,375,000 (Municipality (urban population); 3,160,000 metro area? per Wikipedia) ["Port-au-Prince"] = {container = "Haiti"}, -- 3,050,000 (Agglomeration; population of low reliability; 2,915,000 metro area? per Wikipedia) ["San Pedro Sula"] = {container = "Honduras"}, -- 1,330,000 (Consolidated Urban Area) ["Tegucigalpa"] = {container = "Honduras"}, -- 1,220,000 (Urban Area) ["Managua"] = {container = "Nicaragua"}, -- 1,400,000 (Consolidated Urban Area) ["Panama City"] = {container = "Panama"}, -- 1,430,000 (Urban Area) ["Asunción"] = {container = "Paraguay"}, -- 2,350,000 (Municipality (urban population)) ["Lima"] = {container = "Peru"}, -- 12,000,000 (Agglomeration; 11,283,787 ??? per Wikipedia) ["Arequipa"] = {container = "Peru"}, -- 1,210,000 (Agglomeration) ["San Juan"] = {container = {key = "Puerto Rico", placetype = "commonwealth"}, wp = "%l, %c"}, -- 1,910,000 (Consolidated Urban Area) ["Montevideo"] = {container = "Uruguay"}, -- 1,810,000 (Agglomeration; 1,302,954 ??? per Wikipedia) ["Caracas"] = {container = "Venezuela"}, -- 3,850,000 (Consolidated Urban Area; 5,243,301 ??? per Wikipedia) ["Maracaibo"] = {container = "Venezuela"}, -- 2,825,000 (Consolidated Urban Area; 5,278,448 ??? per Wikipedia) -- to avoid confusion with Valencia (city and autonomous community of Spain) ["Valencia, Venezuela"] = {container = "Venezuela", wp = "%l, %c"}, -- 2,100,000 (Consolidated Urban Area) ["Valencia"] = {alias_of = "Valencia, Venezuela"}, ["Maracay"] = {container = "Venezuela"}, -- 1,480,000 (Consolidated Urban Area) ["Barquisimeto"] = {container = "Venezuela"}, -- 1,360,000 (Consolidated Urban Area) } export.misc_cities_group = { canonicalize_key_container = make_canonicalize_key_container(nil, "country"), default_placetype = "city", data = export.misc_cities, } --[==[ var: List of all known locations, in groups. The first group lists continents and continental regions, followed by three groups listing top-level locations: countries, "country-like entities" (de-facto/unrecognized/etc. countries and dependent territories) and former polities (countries, empires, etc.). After that come first-level subpolities (administrative divisions) of several, mostly large, countries, followed by groups of cities. China and the United Kingdom include second-level subpolities (in the case of China, only the largest ones as the full list runs in the hundreds). ]==] export.locations = { export.continents_group, export.countries_group, export.country_like_entities_group, export.former_countries_group, export.australia_group, export.austria_group, export.bangladesh_group, export.brazil_group, export.bulgaria_group, export.canada_group, export.china_group, export.china_prefecture_level_cities_group, export.china_prefecture_level_cities_group_2, export.egypt_group, export.finland_group, export.france_group, export.france_departments_group, export.germany_group, export.greece_group, export.india_group, export.indonesia_group, export.iran_group, export.ireland_group, export.italy_group, export.japan_group, export.laos_group, export.lebanon_group, export.malaysia_group, export.malta_group, export.mexico_group, export.moldova_group, export.morocco_group, export.netherlands_group, export.new_zealand_group, export.nigeria_group, export.north_korea_group, export.norway_group, export.pakistan_group, export.philippines_group, export.poland_group, export.portugal_group, export.romania_group, export.russia_group, export.saudi_arabia_group, export.south_africa_group, export.south_korea_group, export.spain_group, export.taiwan_group, export.thailand_group, export.turkey_group, export.ukraine_group, export.united_kingdom_group, export.united_states_group, export.england_group, export.northern_ireland_group, export.scotland_group, export.wales_group, export.vietnam_group, export.australia_cities_group, export.brazil_cities_group, export.canada_cities_group, export.france_cities_group, export.germany_cities_group, export.india_cities_group, export.indonesia_cities_group, export.italy_cities_group, export.japan_cities_group, export.mexico_cities_group, export.nigeria_cities_group, export.pakistan_cities_group, export.philippines_cities_group, export.russia_cities_group, export.saudi_arabia_cities_group, export.south_korea_cities_group, export.spain_cities_group, export.taiwan_cities_group, export.united_kingdom_cities_group, export.united_states_cities_group, export.new_york_boroughs_group, export.vietnam_cities_group, export.misc_cities_group, } return export dws9ii25xu6ehccq914gw62b8c7d56n 88791 88790 2026-08-06T18:24:42Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:place/locations]] 88790 Scribunto text/plain local export = {} export.force_cat = false -- set to true to force category generation even on non-mainspace pages local m_table = require("Module:table") local string_utilities_module = "Module:string utilities" local en_utilities_module = "Module:en-utilities" local insert = table.insert local concat = table.concat local dump = mw.dumpObject local unpack = unpack or table.unpack -- Lua 5.2 compatibility --[==[ intro: This module contains data on all known locations, along with some lower-level code to process them (higher-level known-location code is in [[Module:place/placetypes]]). You must load this module using require(), not using mw.loadData(). ===Location data=== '''NOTE: In order to understand the following better, first read the introductory documentation in [[Module:place]], especially the section `More about known locations`.''' The bulk of the code in this module (after some helper functions and placetype tables) describes the known locations and their relationships. Locations are grouped into ''location groups'' that share some common properties (examples are states of the United States and cities in Brazil). Each location group is associated with two tables, a ''data table'' that lists the locations and their individual properties, and a ''metadata table'' that lists group-level properties and defaults for the location properties. Each metadata table points to the associated data table (i.e. contains the data table as its `data` field), and the global `locations` variable holds a list of all group metadata tables. A given location is generally described by three values: (a) the group metadata table for the group the location is part of; (b) the location's canonical ''key'', which is the actual key in the group's data table and is globally unique across all locations; and (c) the location's ''spec'', which is the initialized object describing the properties of the location and comes from the value in the data table corresponding to the canonical key, transformed by the `initialize_spec()` function. These are typically named `group`, `key` and `spec`, respectively and in that order, and are found in the arguments to many functions. In a per-group data table, the keys are either ''canonical keys'' describing locations (which, as mentioned above, must be globally unique) or ''alias keys'' specifying an allowed alias for a given location. There may be multiple aliases for a given location and the alias keys only need to be unique within a particular group data table, not across all groups. It is also possible for the same string to serve as an alias key in one group and a canonical key in another group. (For example, `Newcastle` appears as an alias key in two different groups, referring to two different locations, canonically known as `Newcastle upon Tyne`, for the city in England, and `Newcastle, New South Wales`, for the city in New South Wales, Australia; and `Birmingham` appears both as a canonical key in the group of English cities and an alias key for canonical `Birmingham, Alabama` in the group of US cities.) The corresponding value objects are different for canonical and alias keys. Corresponding to canonical keys are ''location specs'', describing the properies of the location that cannot be derived from default properties of the group or global defaults. Corresponding to alias keys are ''alias specs'', which are highly restricted in the properties they can contain, and whose properties do not have per-group defaults, but only global defaults. The canonical key is always the same as the bare category corresponding to the location, which is one of the reasons it must be globally unique. For example, the country of Georgia uses the canonical key `Georgia` and corresponding bare category [[:Category:Georgia]], while the US state of Georgia uses the canonical key `Georgia, USA` and corresponding bare category [[:Category:Georgia, USA]]. The following conventions are followed in naming keys: * Countries, ''country-like entities'' (which are a mixture of unrecognized de-facto states and dependent territories) and ''former countries'' (which also includes other types of polities, such as the Roman Empire) use their unqualified placename as the canonical key. (See the documentation for [[Module:place]] for the distinction between keys and placenames, which is critical to understand when working with location data.) This also applies to constituent countries (such as England, Aruba and the Faroe Islands) and constituent parts of grouped dependent territories (such as the island of Saint Helena, which is administratively part of the British overseas territory of Saint Helena, Ascension and Tristan da Cunha). * Cities (including prefecture-level cities in China, which behave in most respects more like non-city administrative divisions) also normally use their unqualified placename as the canonical key, but if this causes name conflicts or ambiguities, they use a ''qualified key'' containing either the country name or immediate containing division (if different) following a comma, such as the case of `Newcastle, New South Wales` and `Birmingham, Alabama` above. Examples of name conflicts are the two cities just given; examples of ambiguities are the major cities of León and Mérida in Mexico and city of Cartagena, Colombia, which are given the respective canonical keys of `León, Guanajuato`, `Mérida, Yucatán` and `Cartagena, Colombia` to avoid ambiguity with the well-known respective cities of the same name in Spain, even though none of those cities are large enough to be included as known locations in this module. (The cutoff is generally having a metro area of at least 1,000,000 inhabitants, although there are exceptions.) * Administrative divisions of countries, other than the exceptions noted above for constituent countries and dependent territories, use a qualified key that contains the name of the country or constituent country in it, e.g. `Normandy, France` (a region), `Calvados, France` (a department in the region of Normandy), `Herefordshire, England` (a ceremonial county), `Northwest Territories, Canada` (a territory), `Central Finland, Finland` (a region), `Antalya Province, Turkey` (a province), `Cluj County, Romania` (a county), `County Cork, Ireland` (a county) and `New York, USA` (a state). As shown in these various examples, (a) first and second-level divisions are sometimes both included (as in France, the United Kingdom and China); (b) the qualifier after the comma is sometimes a constituent country (England) instead of a country (United Kingdom), and is sometimes abbreviated (USA rather than United States or Unites States of America); (c) the word `the` is not normally included in the key even if the location is normally preceded by `the` when following a preposition (there is a property in the location and alias specs to indicate this), except in a very few cases (most notably `The Hague`); (d) the country is included as a qualifier even if it creates an apparent redundancy, as with `Central Finland, Finland`; and (e) sometimes the placetype is included in the key, as with provinces in Turkey and several other countries; states in Nigeria; and counties in Ireland, Romania and several other countries. Whether the placetype is included, and whether it follows or precedes the placename, depends on per-country conventions. For example, provinces in Turkey, Iran and several other countries (likewise for states in Nigeria, oblasts in Russia, etc.) conventionally include the word "Province", "State", "Oblast" etc. in their name because they are normally named after the largest city in the division, which would otherwise lead to ambiguity; and counties in Ireland and Northern Ireland (and likewise County Durham, England) normally have the word "County" preceding rather than following them in their conventional name, so we follow this practice. The Wikipedia article naming scheme for a given administrative division is a strong clue as to how the division is normally referred to, and we usually follow this practice. (A minor exception is that the Wikipedia articles for provinces in Iran, Laos and Thailand include the word `province` with an initial lowercase letter while provinces elsewhere, e.g. North and South Korea, Saudi Arabia and Turkey, use uppercase `Province`; we normalize to uppercase `Province` in all cases.) As mentioned above, associated with canonical keys in the group data table are location specs, which are objects containing properties. It is important here to distinguish ''initialized specs'' from ''uninitialized specs''. Unininitialized specs are as directly specified in [[Module:place/locations]], containing only those properties that differ from the per-group or global defaults. Initialized specs result from calling `initialize_spec()` on an uninitialized spec (it is idempotent in that it will do nothing if encountering an already-initialized spec). This copies all group-level defaults that are not overridden in the location spec itself from the group-level metadata table into the location spec, so that in general, no more reference need be made to the group to fetch the correct value of a given location property. (The initialization process also does more transformations in a few cases, noted below.) Note that the default value of a given property is stored under a key in the group metadata table that is preceded by the string `default_`; for example, the default value corresponding to the `placetype` property of a given location is specified in the `default_placetype` key in the group metadata table. The following are the properties of the location spec. * `placetype`: String specifying the placetype of the location (e.g. "country", "state", province"). This can also be a table of such types; in this case, the first listed type is the canonical type that will be used in descriptions, but the location will be recognized (e.g. in a holonym, or for categorizing into the bare category) when tagged with any of the specified types. The placetype '''must''' be either specified on an individual location or defaulted at the group level, or an error occurs. * `container`: Either a string, a ''canonicalized container'' structure or a list of either type, specifying the immediate ''container'' (or containers) of the given location. A container is another location which this location is considered to be directly part of, either politically or (above the country level) geographically. Some locations belong to multiple immediate containers; this applies especially to transcontinental countries such as Russia and Turkey. Containers can themselves have containers, forming a tree (or more correctly, a [[w:directed acyclic graph]]) of locations. The list of immediate container(s), followed by the container(s) of the container(s), etc., is termed the ''container trail'', and some functions compute and return this trail as part of their operation. When a location spec is initialized, the given container spec is canonicalized into ''canonical container form'', which consists of a list of canonicalized container structures, each of which is of the form `{key = "``container_key``", placetype = "``container_placetype``"}`, where ``container_key`` is a canonical location key and ``container_placetype`` should be the listed placetype for the location, or the first listed placetype if there are multiple. (FIXME: Since the key uniquely identifies the container location, we should eliminate the placetype from the container structure.) The list of canonicalized container structures is stored into the `.containers` field of the location spec (this happens even if the container value is unset in its uninitialized spec form, causing it to default to the corresponding group-level value), and the `.container` field is set to {nil}. The canonicalization process is described in more detail below under [[#Container spec canonicalization]]. * `divs`: List of recognized political divisions; e.g. for the Netherlands, a specification of the form `divs = {"provinces", "municipalities"}` will allow categories such as [[:Category:de:Provinces of the Netherlands]] and [[:Category:pt:Municipalities of the Netherlands]] to be created. Any division that appears here must also be found in `placetype_data`, or an error occurs. The entities appearing in the `divs` list can be structures as well as just strings; this is explained more below under [[#Location divisions]]. Additional political divisions that apply to all locations in a group can be specified at the group level using the group-only property `addl_divs`, which has the same format as `divs`. This is intended to be used in the situation where some division types are shared among all locations in the group and others differ from location to location. An example where this is used is the United States, where `census-designated places` is specified in the group-level `addl_divs` so that all 50 states have census-designated places categorized as e.g. [[:Category:Census-designated places in Arizona, USA]], but `counties` and `county seats` are specified in the group-level `default_divs` because not all states have counties and county seats (Alaska has boroughs and borough seats and Louisiana has parishes and parish seats), and some states have additional divisions (New Jersey and Pennsylvania also have boroughs, while Colorado and Connecticut have municipalities). Note that under most circumstances (particularly, if `container_parent_type` is not set as a property associated with the division type), any division type specified on a sub-country-level location must also be specified on all containers up through the country. For example, since French departments specify `communes` and `municipalities` in `default_divs`, the same division types must be (and are) specified on French regions and for France itself. * `keydesc`: String directly specifying a description of the location, for use in generating the contents of category pages related to the location. In place of a string, a function of three arguments (`group`, `key`, `spec`, as is normal for locations) that computes the location description can also be given. This is used, for example, for Russian federal subjects; see `construct_russia_federal_subject_keydesc`. The special string `+++` contained in the keydesc is replaced with the default value of the location description, which specifies the location's placename, placetype, and the corresponding values for each container in the container trail, generally up through (but not beyond) the country level; see `no_include_container_in_desc` below. The location description is used to construct the full description of various categories, such as bare location categories, whose description generally reads `"{{(((}}langname}}} terms related to the people, culture, or territory of ``keydesc``."` where ``keydesc`` is the specified or auto-constructed location description. * `fulldesc`: String overriding the full description for the bare location category (but not for any other category). This is currently used only for the location `Earth`, at the very top of the tree (because the standard `people, culture or territory of ...` text doesn't make sense here), and for `Antarctica` (because it has no permanent inhabitants). FIXME: This should be renamed `bare_category_fulldesc`. * `addl_parents`: Specify additional parents for the bare location category, in addition to the category or categories generated based on the immediate container(s). For example, `Hawaii, USA` specifies `Polynesia` as an additional parent category; both `North Korea` and `South Korea` specify `Korea` (which is a specially handled location category) as an additional parent; and `Earth` specifies `nature` (not a location category, but still a topic category) as an additional parent (which in this case becomes the first parent, as `Earth` has no container). The only restriction on the categories in `addl_parents` is that they must be topic categories, because each language-specific version of the bare location category gets the corresponding language-specific versions of the categories in `addl_parents`. FIXME: This shoudl be renamed `bare_category_addl_parents`. * `wp`: Spec describing how to construct the Wikipedia article for the location. Each spec is either `true` (equivalent to `"%l"`, i.e. use the full location placename directly) or a string containing formatting directives, indicating how to construct the article name. The allowed formatting directives are `%l` (the full location placename), `%e` (the elliptical location placename) and `%c` (the full placename of the first immediate container). For example, the default value of `wp` for the group of United States cities is `"%l, %c"` since the city articles tend to be named e.g. `Austin, Texas` (but with many exceptions, specified using `wp` fields at the city level). Another example is Thai provinces, which specify a group-level default of `"%e province"` as the Wikipedia articles have lowercase `province` in their name but the Thai province keys specified in this module have uppercase `Province`. Here we have to use `%e` to get the placename without the word `Province` in it. The default is `true`, which simply uses the full location placename as the article name. Note that the Wikipedia article, along with the Wikipedia and Commons category pages, are shown in the upper right of bare category pages. * `wpcat`: Spec describing how to construct the Wikipedia category page for the location (i.e. the page listing articles and categories relevant to the location). The format is the same as with `wp`, and it defaults to the value of `wp`. It rarely needs to be specified because the category page and the article page almost always follow the same format. * `commonscat`: Spec describing how to construct the Commons category page for the location (i.e. the page on the MediaWiki Commons site listing articles and categories relevant to the location). It has the same format as `wp` and `wpcat` and defaults to `wpcat`, which is usually (but not always) correct. * `the`: Boolean specifying whether a location should be preceded by `the` when following a preposition, e.g. in category names such as [[:Category:Cities in the Northern Territory, Australia]] and in old-style place descriptions when the location occurs as the first holonym, such as the city [[Darwin]] described using {{tl|place|city|terr/Northern Territory|c/Australia}}. Note that the global default for this and all Boolean properties is {nil}, which amounts to the same as {false}. * `british_spelling`: Boolean indicating whether the location in question uses British spelling. Currently this only affects whether the spelling `neighborhoods` or `neighbourhoods` is used in categories such as [[:Category:Neighborhoods of New York City]] and [[:Category:Neighbourhoods of Sydney]]. This usually needs to be set only at the top level (i.e. country or country-like entity), because lower-level entities look up the container trail for any container that has `british_spelling = true` set, and if found, assume that British spelling applies. The general principle used in setting this is that all countries in Europe, all dependent territories of any such country, all former British colonies, and any dependent territories of these former colonies, are assumed to use British spelling, while all other countries and associated dependent territories are assumed to use American spelling. This can potentially be modified on a case-by-case basis. * `is_city`: Boolean indicating whether the location in question is a city. This is explicitly set to `true` for city-states (e.g. Monaco and Vatican City), dependent territories that are cities (e.g. Hong Kong, Macau, Bonaire, Gibraltar, etc.), certain city-level administrative divisions (such as `City of Belfast, Northern Ireland`) and (through a group-levell setting) New York boroughs. In addition, it is set to `true` in initialize_spec() whenever the group-level `default_placetype == "city"`, so that all cities get it set without explicitly needing to add a group-level setting for this. Note that the condition `default_placetype == "city"` intentionally excludes Chinese prefecture-level cities, which aren't really cities in that (for example) they don't directly contain neighborhoods, but do contain cities within them. This setting is used in various places: (a) to add cities, rivers, etc. to categories like [[:Category:Rivers in Osaka Prefecture, Japan]] and [[:Category:Cities in Wuhan]] for holonyms that are ''not'' cities; (b) to add districts, neighborhoods, and the like to categories like [[:Category:Neighborhoods of Brooklyn]] and [[:Category:Neighborhoods of Monaco]] for holoynms that ''are'' cities; (c) generally, to determine which "generic" placetypes (cities, rivers, neighborhoods, etc.) apply to the location. (Those that can occur with cities have a `generic_before_cities` setting in [[Module:place/placetypes]], and those that can occur with non-cities have a `generic_before_non_cities` setting.) * `is_former_place`: Boolean that should be set on former places such as the Soviet Union and the Roman Empire. For such places, categories such as [[:Category:fr:Rivers in the Soviet Union]] are neither generated nor recognized (more generally, no "generic" placetypes apply except for `places`), and category descriptions include the word `former`. * `overriding_bare_label_parents`: Document me! * `bare_category_parent_type`: Document me! * `no_container_cat`: Document me! * `no_container_parent`: Document me! * `no_generic_place_cat`: Document me! * `no_check_holonym_mismatch`: Document me! * `no_auto_augment_container`: Document me! * `no_include_container_in_desc`: Document me! ====Location divisions==== The `divs` field of a location describes the recognized political division types of that location. Specifying a given division type will cause places defined as being of the specified division type and with the location as a holonym will cause the place to be categorized as ` ``placetypes`` in/of ``location`` `; for example, specifying that the United States has `"states"` as a division will cause anything defined as {{tl|place|fr|state|c/US}} to be categorized under [[:Category:fr:States of the United States]]. Note that you do not have to explicitly specify division types for "generic" placetypes (those that have a `generic_before_non_cities` field if the location is not a city, or that have a `generic_before_cities` field if the location is a city); this includes things like cities, towns, villages, neighbo(u)rhoods and rivers. A given element in the `divs` list is usually a string naming a plural placetype; the placetype is automatically converted to the singular for recognizing the placetype in a {{tl|place}} spec, and irregular plurals such as `kibbutzim` are handled correctly as long as the placetype specifies an appropriate `plural` field (if the `plural` isn't explicitly given, the default singularization algorithm in [[Module:en-utilities]] is run, which gets most things correctly but has problems with `passes` and `fortresses`, which are singularized to `passe` and `fortresse`; for this reason, an explicit plural entry is added to terms in ''-ss''). In place of a string, an object can be given with the plural placetype in the `type` field; this allows additional properties to be specified along with the placetype. An example of this is the `divs` list for Canada: { ["Canada"] = {divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, "counties", "districts", "municipalities", "regional municipalities", "rural municipalities", "parishes", "Indian reserves", "census divisions", {type = "townships", prep = "in"}, }, ...}, } Here, both provinces and territories are set to categorize as `provinces and territories`, meaning that there is a single category [[:Category:Provinces and territories of Canada]] rather than separate categories for provinces and territories. Similar things are done for other countries that have more than one type of first-level administrative division (e.g. Australia, China, India and Pakistan). Note that any placetype listed under `cat_as` must exist in the table of placetypes in [[Module:place/placetypes]], and in fact there is a category-only entry there for `provinces and territories!` (the use of exclamation point following a plural placetype means that the placetype is present only for use in categories and won't be recognized as the placetype field in a {{tl|place}} description). In addition, townships are declared to use `in` rather than `of` as the preposition in the category; hence the category name will be [[:Category:Townships in Canada]] rather than [[:Category:Townships of Canada]]. (The use of `in` vs. `of` is somewhat related to whether a given placetype is an official administrative or statistical division of the location in question and comes in a defined list, in which case `of` should be used, or is more ill-defined, in which case `in` should be used; the default is `of`, and the use of `in` with `townships` is probably by analogy with the use of `in` with cities and towns.) Another more complex example is the divisions given for Quebec: { ["Quebec, Canada"] = {divs = { "counties", {type = "regional county municipalities", container_parent_type = "regional municipalities"}, {type = "regions", container_parent_type = false}, {type = "townships", prep = "in"}, {type = "parish municipalities", cat_as = {{type = "parishes", container_parent_type = "counties"}, "municipalities"}}, {type = "township municipalities", cat_as = {{type = "townships", prep = "in"}, "municipalities"}}, {type = "village municipalities", cat_as = {{type = "villages", prep = "in"}, "municipalities"}}, }, ...}, } Here, `container_parent_type` controls the second parent category of the placetype/location category associated with the entry. In this case, for example, [[:Category:Counties of Quebec, Canada]] will have [[:Category:Counties of Canada]] as its second or ''container-level'' parent. However, this doesn't make sense for `regional county municipalities`, which exist only in Quebec (so the parent category [[:Category:Regional county municipalities of Canada]] would have only one subcategory); but they are similar to regional municipalities in British Columbia, Nova Scotia and Ontario, so the `container_parent_type = "regional municipalities"` spec causes the container-level parent of this category to be [[:Category:Regional municipalities of Canada]]. Likewise, `regions` as administrative divisions (as opposed to mere geographic regions) exist only in Quebec; they have no equivalent elsewhere, so we disable the container-level parent using `container_parent_type = false`. The specs for `parish municipalities`, `township municipalities` and `village municipalities` show both that multiple types can be specified under `cat_as` (here, for example, we categorize `parish municipalities` as both `parishes` and `municipalities`) and that these types can themselves have properties, just as for entries directly under `divs`. Specifically, `{type = "parishes", container_parent_type = "counties"}` means that any place defined as a parish municipality in Quebec will be categorized under both [[:Category:Parishes of Quebec, Canada]] and [[:Category:Municipalities of Quebec, Canada]], and that the former will have a container-level parent of [[:Category:Counties of Canada]] (rather than the default of [[:Category:Parishes of Canada]]). Similarly, `township municipalities` will be categorized under both [[:Category:Townships in Quebec, Canada]] (''not'' [[:Category:Townships of Quebec, Canada]]) and [[:Category:Municipalities of Quebec, Canada]]. ====Container spec canonicalization==== A fully canonicalized container spec for a given location consists of a list of ''canonicalized container objects'', each with a `key` and `placetype` field. The `key` field should name the canonical key of some other location at a higher level (e.g. French cities are contained in French departments, which are contained in French regions, which are contained in France, which is contained in Europe, which is contained in Eurasia, which is contained in the Earth). The `placetype` field should correspond to the first (canonical) placetype listed for the key in question. The process of initializing a locaion spec converts the container spec in `.container` into a canonicalized spec in `.containers` and removes the spec from `.container`. It works as follows: # If the `container` field is missing, and there is a group-level `default_container` field, it is used in its place. For example, none of the Brazilian states listed in `brazil_states` specifies a container, but the group specifies `default_container = "Brazil"`. # A single string or canonicalized container object is allowed and made into a one-element list. # If a list element is a string that did ''not'' come from `default_container`, and there is a group-level `canonicalize_key_container` field, it is assumed to be a one-argument function and is called on the string to get a canonicalized container object. # Any remaining strings are assumed to be countries and are used directly as the `key`, with `placetype` set to `"country"`. ====Alias keys==== Aliases can be provided for canonical keys using ''alias keys''. Alias keys have a very different location spec structure from canonical keys. This structure does not, in general, have defaults at the group level and is not initialized using `initialize_spec()`, but is used as-is. The following properties are recognized in an alias location spec: * `alias_of`: The canonical key of which this key is an alias. Required. * `the`: If true, this alias key is preceded by `the` following a preposition. Defaults to the group-level `default_the` but does not pay attention to the value of `the` for the corresponding canonical key. * `display`: This is a display alias, meaning that holonyms using the placename corresponding to this alias will be converted to the placename corresponding to the canonical key when formatting the holonym for display. (Otherwise, the aliasing applies only to categorization.) If the value is true, the display canonicalization is to the placename of the canonical key; otherwise, the value should be a key whose corresponding placename is used when display canonicalizing. * `placetype`: The placetype of the alias. Rarely needs to be specified as it defaults to the canonical key's placetype, and if that is unspecified, to the group-level default placetype. ====Location group metadata tables==== As mentioned above, associated with each location group is a ''metadata table'' listing group-level properties. The metadata table contains two types of keys: group-level defaults (named like the corresponding location-level keys but preceded by `default_`, e.g. `default_placetype` corresponding to the location-level `placetype` key) and group-only keys, which are mostly functions. The following are the possible group-only keys: * `data`: This points to the group data table for the group, as described above. * `key_to_placename`: This is a function of one argument to transform the location's key (whether canonical or alias) into the full and elliptical placenames. The difference between full and elliptical placenames is described in the documentation for [[Module:place]], but in essence, it applies for keys that include the placetype in them (e.g. `Phuket Province, Thailand` or `County Mayo, Ireland`), in which case the full placename includes the placetype and the elliptical placename does not. For keys that do not include the placetype in them (e.g. `Arizona, USA` or `Gloucestershire, England`), the full and elliptical placenames are identical. Note that neither the full nor the elliptical placename includes the container in it; hence, for `Phuket Province, Thailand`, the full placename is `Phuket Province` and the elliptical placename is just `Phuket`. (Note that the full vs. elliptical placename distinction is intended only for handling cases where the placetype follows or precedes the raw placename and there is no difference between the two in whether they are normally preceded by `the`. More complex situations, such as `State of Mexico` (which normally takes `the`) vs. just `Mexico` (which doesn't), or `Islamabad Capital Territory` vs. just `Islamabad`, should be handled instead by aliases.) The `key_to_placename` function takes one argument, the key, and returns two arguments, the full and elliptical placenames, respectively. If left undefined, the default is to chop off anything starting with a comma and return the result as both full and elliptical placename, and if specifically set to `false`, the key is used directly as both full and elliptical placename. If it needs to be defined, it is best to use the helper function `make_key_to_placename`, if possible (or `make_irish_type_key_to_placename` in the case of Ireland and Northern Ireland, where `County` precedes), rather than rolling your own. In addition, you should use the global `key_to_placename` function (which takes care of the default implementation and such) rather than directly calling the function in the `key_to_placename` field. * `placename_to_key`: This is approximately the inverse of `key_to_placename`, transforming a placename (which can be either in full or elliptical form) into the corresponding key. As with `key_to_placename`, if you need to define this (generally, when the full and elliptical placenames are different), prefer using `make_placename_to_key` (or `make_irish_type_placename_to_key` for Ireland and Northern Ireland) to rolling your own. In addition, similarly to `key_to_placename`, use the global `placename_to_key` function to convert placenames to keys rather than directly invoking the function in the `placename_to_key` field. If the field is set to `false`, the placename is used unchanged as the key. Otherwise, the default algorithm works as follows: *# If the group-level `default_placetype == "city"`, use the placename unchanged as the key. *# Otherwise, if the group-level `default_container` exists and is a string, append it to the placename after a comma + space and use the result as the key. *# Otherwise, if the group-level `default_container` is a canonical container object (an object with `key` and `placetype` fields), and the `placetype` field is either `country` or `constituent country`, append the `key` field to the placename after a comma + space and use the result as the key. *# Otherwise, use the placename unchanged as the key. * `canonicalize_key_container`: A function of one argument to convert the specified `container` field, when a string, to canonical form. Described in more detail above under [[#Container spec canonicalization]]. It is preferable to construct the function using `make_canonicalize_key_container`, if possible, rather than rolling your own. * `addl_divs`: Additional political divisions appended, for all locations in the group, to the list of divisions derived from the location-level `divs` or group-level `default_divs` fields to get the final list of divisions for the location. See [[#Location divisions]] for more details. ]==] ----------------------------------------------------------------------------------- -- Helper functions -- ----------------------------------------------------------------------------------- --[==[ Throw an error. `fmt` is a format string and the remaining arguments are passed through `mw.dumpObject` and then used to format the format string as if `fmt:format(...)` were called. In general, callers should use `internal_error` unless the error was due to bad user input rather than a logic error (which usually isn't the case in deep back-end code like this). ]==] function export.process_error(fmt, ...) local args = {...} for i = 1, select("#", ...) do args[i] = dump(args[i]) end return error(string.format(fmt, unpack(args))) end --[==[ Throw an internal error (a logic error that should never happen unless there is a bug in the code, as opposed to a user error triggered by bad input or a system error due to something like running out of memory or hitting a time limit). `fmt` is a format string and the remaining arguments are passed through `mw.dumpObject` and then used to format the format string as if `fmt:format(...)` were called. ]==] function export.internal_error(fmt, ...) export.process_error("Internal error: " .. fmt, ...) end local internal_error = export.internal_error -- Return whether `list_or_element` (a list of strings, or a single string) "contains" `item` (a string). If -- `list_or_element` is a list, this returns true if `item` is in the list; otherwise it returns true if `item` -- equals `list_or_element`. local function list_or_element_contains(list_or_element, item) if type(list_or_element) == "table" then return m_table.contains(list_or_element, item) and true or false end return list_or_element == item end --[==[ Call the location group's `key_to_placename` function if it exists (see the comment at the top of [[Module:place]] for the distinction between keys and placenames). Two values are returned, the full and elliptical placenames (e.g. full `"County Durham"` vs. elliptical `"Durham"`). If the group does not define `key_to_placename`, both full and elliptical placenames are computed by chopping off anything starting with a comma. ]==] function export.key_to_placename(group, key) if group.key_to_placename == false then return key, key end if group.key_to_placename then local full_placename, elliptical_placename = group.key_to_placename(key) if type(full_placename) ~= "string" then internal_error("Key %s returned a non-string full placename: %s", key, full_placename) end if type(elliptical_placename) ~= "string" then internal_error("Key %s returned a non-string elliptical placename: %s", key, elliptical_placename) end return full_placename, elliptical_placename end key = key:gsub(",.*", "") return key, key end --[==[ Call the location group's `placename_to_key` function if it exists (see the comment at the top of [[Module:place]] for the distinction between keys and placenames) and return the result. If `placename_to_key` exists with the value `false`, return the placename unchanged. If the group does not define `placename_to_key`, and it defines a `default_container` whose placetype is either `country` or `constituent country`, the container name is appended to the placename after a comma and a space. Otherwise the placename is returned unchanged. ]==] function export.placename_to_key(group, placename) if group.placename_to_key == false then return placename elseif group.placename_to_key then local key = group.placename_to_key(placename) if type(key) ~= "string" then internal_error("Placename %s returned a non-string key: %s", placename, key) end return key elseif group.default_placetype == "city" then return placename else local defcon = group.default_container if not defcon then return placename elseif type(defcon) == "string" then return placename .. ", " .. defcon elseif type(defcon) == "table" and (defcon.placetype == "country" or defcon.placetype == "constituent country") then return placename .. ", " .. defcon.key else return placename end end end --[==[ Initialize the location spec `spec`, augmenting it with default values taken from `group` if the spec itself doesn't specify values for the properties. This sets `containers` to a canonicalized list of objects, each with `key` and `placetype` keys, describing the immediate containers of the location, and erases (sets to nil) the original non-canonicalized `container` field. (Most locations have only one immediate container but some, e.g. Russia, have more than one. Containers should be carefully distinguished from category parents. Generally the container is the first category parent, or the first ``n`` parents if there are ``n`` containers, but there may be additional category parents, which indicate some sort of relation between the category parent and the location but not necessarily one of containment.) This function is idempotent in that nothing happens if called more than once on the same spec. FIXME: Consider reimplementing this in a more standardly object-oriented way using metatables. ]==] function export.initialize_spec(group, key, spec) if spec.initialized then return end local container = spec.container local containers local container_from_default if not container then container = group.default_container container_from_default = true end if container then if type(container) == "string" or container.key then container = {container} end containers = {} for _, cont in ipairs(container) do if type(cont) == "string" then if group.canonicalize_key_container and not container_from_default then cont = group.canonicalize_key_container(cont) else cont = {key = cont, placetype = "country"} end end insert(containers, cont) end end spec.containers = containers spec.container = nil local function value_with_default(val, default_val) if val == nil then return default_val else return val end end local function set_or_default(prop) spec[prop] = value_with_default(spec[prop], group["default_" .. prop]) end set_or_default("placetype") if not spec.placetype then internal_error("No placetype found in key %s for spec %s or in group `default_placetype`", key, spec) end set_or_default("divs") spec.addl_divs = group.addl_divs for _, prop in ipairs { "keydesc", "fulldesc", "addl_parents", "overriding_bare_label_parents", "bare_category_parent_type", "wp", "wpcat", "commonscat", "british_spelling", "the", "no_container_cat", "no_container_parent", "no_generic_place_cat", "no_check_holonym_mismatch", "no_auto_augment_container", "no_include_container_in_desc", "is_city", "is_former_place", } do set_or_default(prop) end -- `default_placetype == "city"` is correct; if `default_placetype` has something else like `prefecture-level city` -- as the canonical placetype but also lists `city` (as Chinese prefecture-level cities do), don't mark as -- is_city. spec.is_city = value_with_default(spec.is_city, group.default_placetype == "city") spec.initialized = true end --[=[ Given a location group, key and possible placetypes that the placename must match, check if the key exists in the group with at least one of the group's key's placetypes matching one of the passed-in placetypes. If so, return two values: the group key (which potentially could differ from the passed-in key due to aliases) and the corresponding spec object, which (as with all functions that return spec objects) has been initialized using `initialize_spec()` (i.e. default property values have been copied from the group into the spec, if the spec doesn't itself specify a value for the property in question). `alias_resolution` controls how aliases are resolved. Normally, both display and category aliases are followed, and the returned key will reflect the canonical location key. However, if `alias_resolution` is {"none"}, no alias following happens. In that case, if the key specifies an alias, the spec for the alias rather than the spec for the canonical location is returned, and importantly, it is returned uninitialized, meaning that properties from the group are not copied into the spec. (If the key specifies a canonical location, its spec is returned initialized, as in the normal case where `alias_resolution` is unspecified.) The caller needs to check whether the returned spec is an alias by looking for an `alias_of` property. If `alias_resolution` is {"display"}, the behavior is the same as for {"none"} except that if the alias contains a setting `display = true`, the returned key will reflect the canonical location key, and if the alias contains a setting `display = ``string`` `, the returned key will reflect that string. This is a low-level function meant for internal use; external callers should generally use `get_matching_location` (for internally-derived locations), `find_matching_holonym_location` (for externally-derived locations) or `find_canonical_key` (for known-canonical locations where the placetype isn't known). ]=] local function find_matching_key_in_group(group, placetypes, key, alias_resolution) if alias_resolution ~= nil and alias_resolution ~= "none" and alias_resolution ~= "display" and alias_resolution ~= "all" then internal_error("Bad value for 'alias_resolution': %s", alias_resolution) end local spec = group.data[key] if not spec then return nil end local function check_correct_placetype(placetype) if type(placetype) == "table" then for _, pt in ipairs(placetype) do if list_or_element_contains(placetypes, pt) then return true end end return false else return list_or_element_contains(placetypes, placetype) end end if spec.alias_of then local resolved_key = spec.alias_of local resolved_spec = group.data[resolved_key] if not resolved_spec then internal_error("Key %s is an alias of %s, which doesn't exist", key, resolved_key) elseif resolved_spec.alias_of then internal_error("Key %s is an alias of %s, which is itself an alias; indirect aliasing not allowed", key, resolved_key) end if alias_resolution == "none" or alias_resolution == "display" then -- We could be working with non-initialized/defaulted spec, since we're pulling it directly from the group. local placetype = spec.placetype or resolved_spec.placetype or group.default_placetype if not placetype then internal_error("No placetype found for key %s in any of spec %s, alias-resolved spec %s or in group " .. "`default_placetype`", key, spec, resolved_spec) end if not check_correct_placetype(placetype) then return nil end if alias_resolution == "display" then if spec.display == true then key = resolved_key elseif spec.display then key = spec.display end end return key, spec end key = resolved_key spec = resolved_spec end -- We could be working with non-initialized/defaulted spec, since we're pulling it directly from the group. local placetype = spec.placetype or group.default_placetype if not placetype then internal_error("No placetype found for key %s in spec %s or group `default_placetype`", key, spec) end if not check_correct_placetype(placetype) then return nil end export.initialize_spec(group, key, spec) return key, spec end --[=[ Given a location group, placename and possible placetypes that the placename must match, check if the placename exists in the group with at least one of the placetypes of the key in the group that corresponds to the placename matching one of the passed-in placetypes. If so, return two values: the key corrsponding to the passed-in placename and the corresponding spec object. This is similar to `find_matching_key_in_group()` but works with placenames rather than keys. `alias_resolution` is as in `find_matching_key_in_group()`. This is a low-level function meant for internal use; external callers should generally use `get_matching_location` (for internally-derived locations), `find_matching_holonym_location` (for externally-derived locations) or `find_canonical_key` (for known-canonical locations where the placetype isn't known). ]=] local function find_matching_placename_in_group(group, placetypes, placename, alias_resolution) local key = export.placename_to_key(group, placename) return find_matching_key_in_group(group, placetypes, key, alias_resolution) end --[==[ If `key` is a canonical known location key (i.e. not an alias), return the corresponding group and initialized spec. If no such key exists, return {nil}. This throws an internal error if two locations with the same key are found. ]==] function export.find_canonical_key(key) local found_locations = {} for _, group in ipairs(export.locations) do local spec = group.data[key] if not spec then -- do nothing elseif spec.alias_of then mw.log(("Skipping alias '%s' of canonical '%s'"):format(key, spec.alias_of)) else insert(found_locations, {group, spec}) end end if not found_locations[1] then return nil elseif found_locations[2] then internal_error("Found multiple matching locations for canonical key %s: %s", key, found_locations) else local group, spec = unpack(found_locations[1]) export.initialize_spec(group, key, spec) return group, spec end end --[==[ Iterator that returns all locations matching a given description, where the description consists of either a placename or a key along with a list of possible placetypes. Usually there will be at most one such location. The iterator returns three values at each iteration: the location group, canonical key by which the location is known and the spec object describing the location. `data` contains the following possible fields: * `placetypes`: A list of possible placetypes, one of which must match one of the location's placetypes; or a string specifying a placetype, which must match one of the location's placetypes. This must be specified. * `placename`: The placename of the location. Either this or `key` must be specified. * `key`: The key of the location. Either this or `placename` must be specified. * `alias_resolution`: If specified, it behaves the same as for `find_matching_key_in_group`. The spec is normally initialized using `initialize_spec()` prior to it being returned (but may not be if `alias_resolution` is given and the specified key or placename is an alias; see the documentation for `find_matching_key_in_group`). ]==] function export.iterate_matching_location(data) local i = 0 local n = #export.locations return function() while true do i = i + 1 if i > n then break end local group = export.locations[i] local key, spec if data.placename then key, spec = find_matching_placename_in_group(group, data.placetypes, data.placename, data.alias_resolution) else if not data.key then internal_error("'.placename' or '.key' must be defined: %s", data) end key, spec = find_matching_key_in_group(group, data.placetypes, data.key, data.alias_resolution) end if key then return group, key, spec end end end end --[==[ Return the location matching a given description, where the description consists of either a placename or a key along with a list of possible placetypes. This is similar to `iterate_matching_location()` but throws an internal error if there is not exactly one location found; as such, it is for use with internally specified locations (such as the containers of known locations) rather than externally specified locations, which may not match a known location and in some cases may match multiple known locations. For finding an externally specified location, consider using `find_matching_holonym_location`, which returns {nil} rather than throwing an error if the location isn't found, but also (more importantly) checks to make sure there are no conflicting holonyms among the user-specified holonyms (e.g. {{tl|place|city|s/Delaware|c/USA|t=Newark}} will not match the known location `Newark` (in New Jersey, not Delaware). ]==] function export.get_matching_location(data) local all_found = {} for group, key, spec in export.iterate_matching_location(data) do insert(all_found, {group, key, spec}) end if not all_found[1] then internal_error("Couldn't find matching location for data %s", data) elseif all_found[2] then internal_error("Found multiple matching locations for data %s: %s", data, all_found) else return unpack(all_found[1]) end end --[==[ Successively iterate over a location's containers, and then the containers of those containers, etc. Keep in mind that locations may have multiple containers (e.g. Russia has both Europe and Asia as containers, and both Europe and Asia have Eurasia as their container). A given container will never be returned twice (e.g. in the case where a specific location A has locations B and C as containers, and B has C as its container, C will not be returned twice). An internal error happens if a container loop is detected. The return value is a list of location objects, each of which contains `group`, `key` and `spec` fields. ]==] function export.iterate_containers(group, key, spec) local keys_seen = {} keys_seen[key] = true local iterations = 0 local last_iteration_containers = {{group = group, key = key, spec = spec}} return function() iterations = iterations + 1 if iterations > 10 then internal_error("Probable loop in containers when processing key %s", key) end local next_iteration_containers = {} for _, location in ipairs(last_iteration_containers) do local containers = location.spec.containers if containers then for _, container in ipairs(containers) do local container_group, container_key, container_spec = export.get_matching_location { placetypes = container.placetype, key = container.key, } if not keys_seen[container_key] then insert(next_iteration_containers, { group = container_group, key = container_key, spec = container_spec }) keys_seen[container_key] = true end end end end if not next_iteration_containers[1] then return nil end last_iteration_containers = next_iteration_containers return next_iteration_containers end end --[==[ Given a placename, convert it into a link (two-part if `display_form` is given and differs from `placename`) and add `"the "` to the beginning if called for in `spec`. ]==] function export.construct_linked_placename(spec, placename, display_form) local linked_placename = display_form and placename ~= display_form and ("[[%s|%s]]"):format(placename, display_form) or ("[[%s]]"):format(placename) if spec.the then linked_placename = "the " .. linked_placename end return linked_placename end --[=[ This is typically used to define `key_to_placename`. It generates a function that chops off parts of a string (a location key), typically at the end, in order to get the full and elliptical versions of a placename. (See the documentation above for `key_to_placename` under "Location group tables" for the difference between full and elliptical placenames.) `container_patterns` is a Lua pattern or a list of possible patterns matching the container at the end of the key, which will be used to remove that container. If multiple patterns are specified, each one is tried until one matches. If `container_patterns` is omitted, this part of the process is skipped. The reulting string becomes the full placename. If `divtype_patterns` is specified, it is likewise either a Lua pattern or list of possible patterns to match and remove the political division affixed onto the end (or possibly the beginning) of the key in the keys of certain countries (such as South Korean and North Korean counties, which include the word "County" in the key). The resulting chopped string becomes the elliptical placename. If `divtype_patterns` is omitted, this part of the process is skipped and the full and elliptical placenames are the same. Typical usage is as follows: ``` key_to_placename = make_key_to_placename(", England$"), ``` or (when the political division is part of the key) ``` key_to_placename = make_key_to_placename(", South Korea$", " County$") ``` ]=] local function make_key_to_placename(container_patterns, divtype_patterns) if type(container_patterns) == "string" then container_patterns = {container_patterns} end if type(divtype_patterns) == "string" then divtype_patterns = {divtype_patterns} end return function(key) local full_placename = key if container_patterns then for _, container_pattern in ipairs(container_patterns) do local nsubs full_placename, nsubs = full_placename:gsub(container_pattern, "") if nsubs > 0 then break end end end local elliptical_placename = full_placename if divtype_patterns then for _, divtype_pattern in ipairs(divtype_patterns) do local nsubs elliptical_placename, nsubs = elliptical_placename:gsub(divtype_pattern, "") if nsubs > 0 then break end end end return full_placename, elliptical_placename end end --[=[ This is typically used to define `placename_to_key`. It generates a function that appends a string to the end of a given placename to get the key (see the definition of `placename_to_key` above in the documentation under "Location group tables"). Optional `divtype_suffix` is a raw string (which should not contain hyphens or other characters that have special meaning in Lua patterns) to be appended first to the placename; if already present at the end, it is not appended. `container_suffix` is then added in the same fashion if given. Typical usage is like this: ``` placename_to_key = make_placename_to_key(", England") ``` (which will convert e.g. `"Hampshire"` into `"Hampshire, England"`) or ``` placename_to_key = make_placename_to_key(", South Korea", " County") ``` (which will convert e.g. `"Gangwon"` or `"Gangwon County"` into `"Gangwon County, South Korea"`). ]=] local function make_placename_to_key(container_suffix, divtype_suffix) return function(placename) local key = placename if divtype_suffix then if not key:find(divtype_suffix .. "$") then key = key .. divtype_suffix end end if container_suffix then key = key .. container_suffix end return key end end --[=[ This is typically used to define `canonicalize_key_container`, which converts a container as specified in the location data into the canonical form containing both the full container key and its placetype. It generates a function to do the canonicalization of a given container. If the container is a string, `suffix` is appended onto the string (use {nil} or {""} if there is no suffix to append), and the placetype is set to `placetype`. Otherwise the container is left as-is. Typical usage is like this: ``` canonicalize_key_container = make_canonicalize_key_container(", Canada", "province") ``` which will convert e.g. `"Ontario"` into `{key = "Ontario, Canada", placetype = "province"}`. ]=] local function make_canonicalize_key_container(suffix, placetype) return function(container) if type(container) == "string" then return {key = container .. (suffix or ""), placetype = placetype} else return container end end end ----------------------------------------------------------------------------------- -- Top-level tables -- ----------------------------------------------------------------------------------- export.continents = { ["Earth"] = {the = true, placetype = "planet", addl_parents = {"nature"}, fulldesc = "=the planet [[Earth]] and the features found on it"}, ["Africa"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}}, ["America"] = {placetype = {"supercontinent", "continent"}, container = {key = "Earth", placetype = "planet"}, keydesc = "[[America]], in the sense of [[North America]] and [[South America]] combined", wp = "Americas"}, ["Americas"] = {alias_of = "America", the = true}, ["North America"] = {placetype = "continent", container = {key = "America", placetype = "supercontinent"}}, ["Caribbean"] = {the = true, placetype = {"continental region", "region"}, container = {key = "North America", placetype = "continent"}}, ["Central America"] = {placetype = {"continental region", "region"}, container = {key = "North America", placetype = "continent"}}, ["South America"] = {placetype = "continent", container = {key = "America", placetype = "supercontinent"}}, ["Antarctica"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}, fulldesc = "=the territory of [[Antarctica]]"}, ["Eurasia"] = {placetype = {"supercontinent", "continent"}, container = {key = "Earth", placetype = "planet"}, keydesc = "[[Eurasia]], i.e. [[Europe]] and [[Asia]] together"}, ["Asia"] = {placetype = "continent", container = {key = "Eurasia", placetype = "supercontinent"}}, ["Europe"] = {placetype = "continent", container = {key = "Eurasia", placetype = "supercontinent"}}, ["Oceania"] = {placetype = "continent", container = {key = "Earth", placetype = "planet"}}, ["Melanesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, ["Micronesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, ["Polynesia"] = {placetype = {"continental region", "region"}, container = {key = "Oceania", placetype = "continent"}}, } export.continents_group = { default_overriding_bare_label_parents = {}, -- container parents should be used default_divs = {{type = "countries", prep = "in"}}, -- It's enough to mention the first-level continent or continent group. It seems excessive to write e.g. -- "El Salvador, a country in Central America, a continental region in North America, a continent in America, ...". default_no_include_container_in_desc = true, default_no_container_cat = true, default_no_container_parent = true, default_no_auto_augment_container = true, default_no_generic_place_cat = true, -- French Guyana is in France but not in Europe, which should not be an issue, so don't check holonym mismatches at -- this level. We also run into problems with supercontinents, which have "continent" as the fallback and cause -- mismatches. default_no_check_holonym_mismatch = true, data = export.continents, } -- Countries: including those with partial recognition that are normally considered countries (e.g. Kosovo, Taiwan). export.countries = { ["Afghanistan"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Albania"] = {container = "Europe", divs = {"counties", "municipalities", "communes", {type = "administrative units", cat_as = "communes"}, }, british_spelling = true}, ["Algeria"] = {container = "Africa", divs = {"provinces", "communes", "districts", "municipalities"}}, ["Andorra"] = {container = "Europe", divs = {"parishes"}, british_spelling = true}, ["Angola"] = {container = "Africa", divs = {"provinces", "municipalities"}}, ["Antigua and Barbuda"] = {container = "Caribbean", divs = {"provinces"}, british_spelling = true}, ["Argentina"] = {container = "South America", divs = {"provinces", "departments", "municipalities"}}, ["Armenia"] = {container = {"Europe", "Asia"}, divs = {"provinces", "districts", "municipalities"}, british_spelling = true}, ["Republic of Armenia"] = {alias_of = "Armenia", the = true}, -- differs in "the" -- Both a country and continent ["Australia"] = {container = "Oceania", divs = { {type = "states", cat_as = "states and territories"}, {type = "territories", cat_as = "states and territories"}, {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states and territories"}, {type = "ABBREVIATION_OF territories", cat_as = "abbreviations of states and territories"}, "local government areas", "dependent territories", }, british_spelling = true}, ["Austria"] = {container = "Europe", divs = {"states", "districts", "municipalities"}, british_spelling = true}, ["Azerbaijan"] = {container = {"Europe", "Asia"}, divs = {"districts", "municipalities"}, british_spelling = true}, ["Bahamas"] = {the = true, container = "Caribbean", divs = {"districts"}, british_spelling = true, wp = "The %l"}, ["Bahrain"] = {container = "Asia", divs = {"governorates"}}, ["Bangladesh"] = {container = "Asia", divs = {"divisions", "districts", "municipalities"}, british_spelling = true}, ["Barbados"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Belarus"] = {container = "Europe", divs = {"regions", "districts"}, british_spelling = true}, ["Belgium"] = {container = "Europe", divs = {"regions", "provinces", "municipalities"}, british_spelling = true}, ["Belize"] = {container = "Central America", divs = {"districts"}, british_spelling = true}, ["Benin"] = {container = "Africa", divs = {"departments", "communes"}}, ["Bhutan"] = {container = "Asia", divs = {"districts", "gewogs", "chiwogs"}}, ["Bolivia"] = {container = "South America", divs = {"provinces", "departments", "municipalities"}}, ["Bosnia and Herzegovina"] = {container = "Europe", divs = {"entities", "cantons", "municipalities"}, british_spelling = true}, ["Bosnia and Hercegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia-Herzegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia-Hercegovina"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Bosnia"] = {alias_of = "Bosnia and Herzegovina", display = true}, ["Botswana"] = {container = "Africa", divs = {"districts", "subdistricts"}, british_spelling = true}, ["Brazil"] = {container = "South America", divs = { "states", "municipalities", "macroregions", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, }}, ["Brunei"] = {container = "Asia", divs = {"districts", "mukims"}, british_spelling = true}, ["Bulgaria"] = {container = "Europe", divs = {"provinces", "municipalities"}, british_spelling = true}, ["Burkina Faso"] = {container = "Africa", divs = {"regions", "departments", "provinces"}}, ["Burundi"] = {container = "Africa", divs = {"provinces", "communes"}}, ["Cambodia"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Cameroon"] = {container = "Africa", divs = {"regions", "departments"}}, ["Canada"] = {container = "North America", divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, {type = "ABBREVIATION_OF provinces", cat_as = "abbreviations of provinces and territories"}, {type = "ABBREVIATION_OF territories", cat_as = "abbreviations of provinces and territories"}, "counties", "districts", "municipalities", "regional municipalities", "rural municipalities", "parishes", -- Don't change the following to something more politically correct (e.g. "First Nations reserves") until/unless -- the Canadian government makes a similar switch (and note that as of Apr 18 2025, the Wikipedia article is -- still at [[w:Indian reserves]]). "Indian reserves", "census divisions", {type = "townships", prep = "in"}, }, british_spelling = true}, ["Cape Verde"] = {container = "Africa", divs = {"municipalities", "parishes"}}, ["Cabo Verde"] = {alias_of = "Cape Verde", display = true}, ["Central African Republic"] = {the = true, container = "Africa", divs = {"prefectures", "subprefectures"}}, ["CAR"] = {alias_of = "Central African Republic", display = true, the = true}, ["C.A.R"] = {alias_of = "Central African Republic", display = true, the = true}, ["Chad"] = {container = "Africa", divs = {"regions", "departments"}}, ["Chile"] = {container = "South America", divs = {"regions", "provinces", "communes"}}, ["China"] = {container = "Asia", divs = { {type = "provinces", cat_as = "provinces and autonomous regions"}, {type = "autonomous regions", cat_as = "provinces and autonomous regions"}, {type = "FORMER provinces", cat_as = "former provinces"}, "special administrative regions", "prefectures", {type = "FORMER prefectures", cat_as = "former prefectures"}, "prefecture-level cities", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, {type = "FORMER counties", cat_as = "former counties and county-level cities"}, {type = "FORMER county-level cities", cat_as = "former counties and county-level cities"}, -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities. "districts", {type = "FORMER districts", cat_as = "former districts"}, "subdistricts", "townships", "municipalities", {type = "direct-administered municipalities", cat_as = "municipalities"}, }}, ["People's Republic of China"] = {alias_of = "China", the = true}, -- differs in "the" ["Colombia"] = {container = "South America", divs = {"departments", "municipalities"}}, ["Comoros"] = {the = true, container = "Africa", divs = {"autonomous islands"}}, ["Costa Rica"] = {container = "Central America", divs = {"provinces", "cantons"}}, ["Croatia"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Cuba"] = {container = "Caribbean", divs = {"provinces", "municipalities"}}, ["Cyprus"] = {container = {"Europe", "Asia"}, divs = {"districts"}, british_spelling = true}, ["Czech Republic"] = {the = true, container = "Europe", divs = {"regions", "districts", "municipalities"}, british_spelling = true}, ["Czechia"] = {alias_of = "Czech Republic"}, -- differs in "the" ["Democratic Republic of the Congo"] = {the = true, container = "Africa", divs = {"provinces", "territories"}}, ["Congo"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["DRC"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["D.R.C"] = {alias_of = "Democratic Republic of the Congo", display = true, the = true}, ["Denmark"] = {container = "Europe", divs = {"regions", "municipalities", "dependent territories"}, british_spelling = true, -- Wikipedia separates [[w:Denmark]] (constituent country) from [[w:Danish Realm]] (country) }, ["Djibouti"] = {container = "Africa", divs = {"regions", "districts"}}, ["Dominica"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Dominican Republic"] = {the = true, container = "Caribbean", divs = {"provinces", "municipalities"}, keydesc = "the [[Dominican Republic]], the country that shares the [[Caribbean]] island of [[Hispaniola]] with [[Haiti]]"}, ["East Timor"] = {container = "Asia", divs = {"municipalities"}, wp = "Timor-Leste"}, ["Timor-Leste"] = {alias_of = "East Timor", display = true}, ["Ecuador"] = {container = "South America", divs = {"provinces", "cantons"}}, ["Egypt"] = {container = "Africa", divs = {"governorates", "regions"}, british_spelling = true}, ["El Salvador"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Equatorial Guinea"] = {container = "Africa", divs = {"provinces"}}, ["Eritrea"] = {container = "Africa", divs = {"regions", "subregions"}}, ["Estonia"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Eswatini"] = {container = "Africa", british_spelling = true}, ["Swaziland"] = {alias_of = "Eswatini", display = true}, ["Ethiopia"] = {container = "Africa", divs = {"regions", "zones"}}, ["Federated States of Micronesia"] = {the = true, container = "Micronesia", divs = {"states"}}, ["Micronesia"] = {alias_of = "Federated States of Micronesia"}, ["Fiji"] = {container = "Melanesia", divs = {"divisions", "provinces"}, british_spelling = true}, ["Finland"] = {container = "Europe", divs = {"regions", "municipalities"}, british_spelling = true}, ["France"] = {container = "Europe", divs = {"regions", "cantons", "collectivities", "communes", {type = "municipalities", cat_as = "communes"}, "departments", {type = "prefectures", cat_as = {"prefectures", "departmental capitals"}}, {type = "French prefectures", cat_as = {"prefectures", "departmental capitals"}}, "dependent territories", "territories", "provinces", }, british_spelling = true}, ["Gabon"] = {container = "Africa", divs = {"provinces", "departments"}}, ["Gambia"] = {the = true, container = "Africa", divs = {"divisions", "districts"}, british_spelling = true, wp = "The %l"}, ["Georgia"] = {container = {"Europe", "Asia"}, divs = {"regions", "districts"}, keydesc = "the country of [[Georgia]], in [[Eurasia]]", british_spelling = true, wp = "%l (country)"}, ["Germany"] = {container = "Europe", divs = { "states", -- Bavaria, Baden-Württemberg, Hesse and North Rhine-Westphalia have administrative regions as divisions, but -- there aren't really enough of them to categorize per state. "regions", "municipalities", "districts"}, british_spelling = true}, ["Ghana"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Greece"] = {container = "Europe", divs = {"regions", "regional units", "municipalities", {type = "peripheries", cat_as = {"regions"}}, }, british_spelling = true}, ["Grenada"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Guatemala"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Guinea"] = {container = "Africa", divs = {"regions", "prefectures"}}, ["Guinea-Bissau"] = {container = "Africa", divs = {"regions"}}, ["Guyana"] = {container = "South America", divs = {"regions"}, british_spelling = true}, ["Haiti"] = {container = "Caribbean", divs = {"departments", "arrondissements"}}, ["Honduras"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Hungary"] = {container = "Europe", divs = {"counties", "districts"}, british_spelling = true}, ["Iceland"] = {container = "Europe", divs = {"regions", "municipalities", "counties"}, british_spelling = true}, ["India"] = {container = "Asia", divs = { {type = "states", cat_as = "states and union territories"}, {type = "union territories", cat_as = "states and union territories"}, {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states and union territories"}, {type = "ABBREVIATION_OF union territories", cat_as = "abbreviations of states and union territories"}, "divisions", "districts", "municipalities", }, british_spelling = true}, ["Indonesia"] = {container = "Asia", divs = {"regencies", "provinces", {type = "ABBREVIATION_OF provinces", cat_as = "abbreviations of provinces"}, }}, ["Iran"] = {container = "Asia", divs = {"provinces", "counties"}}, ["Iraq"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Ireland"] = {container = "Europe", addl_parents = {"British Isles"}, divs = {"counties", "districts", "provinces"}, british_spelling = true, wp = "Republic of %l"}, ["Republic of Ireland"] = {alias_of = "Ireland", the = true}, -- differs in "the" ["Israel"] = {container = "Asia", divs = {"districts"}}, ["Italy"] = {container = "Europe", divs = { "regions", "provinces", "metropolitan cities", "municipalities", {type = "autonomous regions", cat_as = "regions"}, }, british_spelling = true}, ["Ivory Coast"] = {container = "Africa", divs = {"districts", "regions"}}, -- We should really be using Ivory Coast (common name) but there are political ramifications to the use of -- Côte d'Ivoire so don't make it a display alias. ["Côte d'Ivoire"] = {alias_of = "Ivory Coast"}, ["Jamaica"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Japan"] = {container = "Asia", divs = {"prefectures", "subprefectures", "municipalities"}}, ["Jordan"] = {container = "Asia", divs = {"governorates"}}, ["Kazakhstan"] = {container = {"Asia", "Europe"}, divs = {"regions", "districts"}}, ["Kenya"] = {container = "Africa", divs = {"counties"}, british_spelling = true}, ["Kiribati"] = {container = "Micronesia", british_spelling = true}, ["Kosovo"] = {container = "Europe", divs = {"districts", "municipalities"}, british_spelling = true}, ["Kuwait"] = {container = "Asia", divs = {"governorates", "areas"}}, ["Kyrgyzstan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Laos"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Latvia"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["Lebanon"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Lesotho"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Liberia"] = {container = "Africa", divs = {"counties", "districts"}}, ["Libya"] = {container = "Africa", divs = {"districts", "municipalities"}}, ["Liechtenstein"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["Lithuania"] = {container = "Europe", divs = {"counties", "municipalities"}, british_spelling = true}, ["Luxembourg"] = {container = "Europe", divs = {"cantons", "districts"}, british_spelling = true}, ["Madagascar"] = {container = "Africa", divs = {"regions", "districts"}}, ["Malawi"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Malaysia"] = {container = "Asia", divs = {"states", "federal territories", "districts"}, british_spelling = true}, ["Maldives"] = {the = true, container = "Asia", divs = {"provinces", "administrative atolls"}, british_spelling = true}, ["Mali"] = {container = "Africa", divs = {"regions", "cercles"}}, ["Malta"] = {container = "Europe", divs = {"regions", "local councils"}, british_spelling = true}, ["Marshall Islands"] = {the = true, container = "Micronesia", divs = {"municipalities"}}, ["Mauritania"] = {container = "Africa", divs = {"regions", "departments"}}, ["Mauritius"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Mexico"] = {container = "North America", addl_parents = {"Central America"}, divs = { "states", "municipalities", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, }}, ["Moldova"] = {container = "Europe", divs = { {type = "districts", cat_as = "districts and autonomous territorial units"}, {type = "autonomous territorial units", cat_as = "districts and autonomous territorial units"}, "communes", "municipalities", }, british_spelling = true}, ["Monaco"] = {placetype = {"city-state", "country"}, container = "Europe", -- We want the first placetype to be 'city-state' so the description of Monaco says it's a city-state, but we -- want its parent to be "countries in Europe". bare_category_parent_type = {type = "countries", prep = "in"}, is_city = true, british_spelling = true}, ["Mongolia"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Montenegro"] = {container = "Europe", divs = {"municipalities"}}, ["Morocco"] = {container = "Africa", divs = {"regions", "prefectures", "provinces"}}, ["Mozambique"] = {container = "Africa", divs = {"provinces", "districts"}}, ["Myanmar"] = {container = "Asia", divs = {"regions", "states", "union territories", {type = "self-administered zones", cat_as = "self-administered areas"}, {type = "self-administered divisions", cat_as = "self-administered areas"}, "districts"}}, ["Burma"] = {alias_of = "Myanmar"}, -- not display-canonicalizing; has political connotations ["Namibia"] = {container = "Africa", divs = {"regions", "constituencies"}, british_spelling = true}, ["Nauru"] = {container = "Micronesia", divs = {"districts"}, british_spelling = true}, ["Nepal"] = {container = "Asia", divs = {"provinces", "districts"}}, ["Netherlands"] = {the = true, placetype = {"country", "constituent country"}, container = "Europe", divs = {"provinces", "municipalities", {type = "FORMER municipalities", cat_as = "former municipalities"}, "dependent territories", "constituent countries"}, british_spelling = true, -- Wikipedia separates [[w:Netherlands]] (constituent country) from [[w:Kingdom of the Netherlands]] -- (country) }, ["New Zealand"] = {container = "Polynesia", divs = { "regions", "dependent territories", "territorial authorities", {type = "districts", cat_as = "territorial authorities"}, }, british_spelling = true}, ["Nicaragua"] = {container = "Central America", divs = {"departments", "municipalities"}}, ["Niger"] = {container = "Africa", divs = {"regions", "departments"}}, ["Nigeria"] = {container = "Africa", divs = { "states", -- Categorize the Federal Capital Territory as a state because there's only one of it; we could categorize -- everything under 'states and territories' but that seems a bit pointless. {type = "federal territories", cat_as = "states"}, "local government areas", }, british_spelling = true}, ["North Korea"] = {container = "Asia", addl_parents = {"Korea"}, divs = {"provinces", "counties"}}, ["North Macedonia"] = {container = "Europe", divs = {"regions", "municipalities"}, british_spelling = true}, ["Macedonia"] = {alias_of = "North Macedonia", display = true}, ["Republic of North Macedonia"] = {alias_of = "North Macedonia", the = true}, -- differs in "the" ["Republic of Macedonia"] = {alias_of = "North Macedonia", the = true}, -- differs in "the" ["Norway"] = {container = "Europe", divs = {"counties", "municipalities", "dependent territories", "districts", "unincorporated areas"}, british_spelling = true}, ["Oman"] = {container = "Asia", divs = {"governorates", "provinces"}}, ["Pakistan"] = {container = "Asia", divs = { {type = "provinces", cat_as = "provinces and territories"}, {type = "administrative territories", cat_as = "provinces and territories"}, {type = "federal territories", cat_as = "provinces and territories"}, {type = "territories", cat_as = "provinces and territories"}, "divisions", "districts", }, british_spelling = true}, ["Palau"] = {container = "Micronesia", divs = {"states"}}, ["Palestine"] = {container = "Asia", divs = {"governorates"}}, ["State of Palestine"] = {alias_of = "Palestine", the = true}, -- differs in "the" ["Panama"] = {container = "Central America", divs = {"provinces", "districts"}}, ["Papua New Guinea"] = {container = "Melanesia", divs = {"provinces", "districts"}, british_spelling = true}, ["Paraguay"] = {container = "South America", divs = {"departments", "districts"}}, ["Peru"] = {container = "South America", divs = {"regions", "provinces", "districts"}}, ["Philippines"] = {the = true, container = "Asia", divs = {"regions", "provinces", "districts", "municipalities", "barangays"}}, ["Poland"] = {divs = {"voivodeships", "counties", {type = "Polish colonies", cat_as = {{type = "villages", prep = "in"}}}, }, container = "Europe", british_spelling = true}, ["Portugal"] = {container = "Europe", divs = { {type = "autonomous regions", cat_as = "districts and autonomous regions"}, {type = "districts", cat_as = "districts and autonomous regions"}, "provinces", "municipalities"}, british_spelling = true}, ["Qatar"] = {container = "Asia", divs = {"municipalities", "zones"}}, ["Republic of the Congo"] = {the = true, container = "Africa", divs = {"departments", "districts"}}, ["Congo Republic"] = {alias_of = "Republic of the Congo", display = true, the = true}, ["Romania"] = {container = "Europe", divs = { "regions", "counties", "communes", {type = "ABBREVIATION_OF counties", cat_as = "abbreviations of counties"}, }, british_spelling = true}, ["Russia"] = {container = {"Europe", "Asia"}, divs = { "federal subjects", "republics", "autonomous oblasts", "autonomous okrugs", "oblasts", "krais", "federal cities", "districts", "federal districts"}, british_spelling = true}, ["Rwanda"] = {container = "Africa", divs = {"provinces", "districts"}}, ["Saint Kitts and Nevis"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Saint Kitts"] = {alias_of = "Saint Kitts and Nevis", display = true}, ["Saint Lucia"] = {container = "Caribbean", divs = {"districts"}, british_spelling = true}, ["Saint Vincent and the Grenadines"] = {container = "Caribbean", divs = {"parishes"}, british_spelling = true}, ["Saint Vincent"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["SVG"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["S.V.G"] = {alias_of = "Saint Vincent and the Grenadines", display = true}, ["Samoa"] = {container = "Polynesia", divs = {"districts"}, british_spelling = true}, ["San Marino"] = {container = "Europe", divs = {"municipalities"}, british_spelling = true}, ["São Tomé and Príncipe"] = {container = "Africa", divs = {"districts"}}, ["São Tome and Principe"] = {alias_of = "São Tomé and Príncipe", display = true}, ["São Tomé"] = {alias_of = "São Tomé and Príncipe", display = true}, ["São Tome"] = {alias_of = "São Tomé and Príncipe", display = true}, ["Saudi Arabia"] = {container = "Asia", divs = {"provinces", "governorates"}}, ["Senegal"] = {container = "Africa", divs = {"regions", "departments"}}, ["Serbia"] = {container = "Europe", divs = {"districts", "municipalities", "autonomous provinces"}}, ["Seychelles"] = {container = "Africa", divs = {"districts"}, british_spelling = true}, ["Sierra Leone"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, ["Singapore"] = {container = "Asia", divs = {"districts", "regions"}, british_spelling = true}, ["Slovakia"] = {container = "Europe", divs = {"regions", "districts"}, british_spelling = true}, ["Slovenia"] = {container = "Europe", divs = {"statistical regions", "municipalities"}, british_spelling = true}, -- Note: While the official name does not include "the" at the beginning, -- it sounds strange in English to leave it out and it's commonly included. ["Solomon Islands"] = {the = true, container = "Melanesia", divs = {"provinces"}, british_spelling = true}, ["Somalia"] = {container = "Africa", divs = {"regions", "districts"}}, ["South Africa"] = {container = "Africa", divs = { "provinces", "districts", {type = "district municipalities", cat_as = "districts"}, {type = "metropolitan municipalities", cat_as = "districts"}, "municipalities", }, british_spelling = true}, ["South Korea"] = {container = "Asia", addl_parents = {"Korea"}, divs = {"provinces", "counties", "districts"}}, ["South Sudan"] = {container = "Africa", divs = {"regions", "states", "counties"}, british_spelling = true}, ["Spain"] = {container = "Europe", divs = {"autonomous communities", "provinces", "municipalities", "comarcas", "autonomous cities"}, british_spelling = true}, ["Sri Lanka"] = {container = "Asia", divs = {"provinces", "districts"}, british_spelling = true}, ["Sudan"] = {container = "Africa", divs = {"states", "districts"}, british_spelling = true}, ["Suriname"] = {container = "South America", divs = {"districts"}}, ["Sweden"] = {container = "Europe", divs = {"provinces", "counties", "municipalities"}, british_spelling = true}, ["Switzerland"] = {container = "Europe", divs = {"cantons", "municipalities", "districts"}, british_spelling = true}, ["Syria"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Taiwan"] = {container = "Asia", divs = {"counties", "districts", "townships", "special municipalities"}}, ["Republic of China"] = {alias_of = "Taiwan", the = true}, -- differs in "the", different political connotations ["Tajikistan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Tanzania"] = {container = "Africa", divs = {"regions", "districts"}, british_spelling = true}, ["Thailand"] = {container = "Asia", divs = {"provinces", "districts", "subdistricts"}}, ["Togo"] = {container = "Africa", divs = {"provinces", "prefectures"}}, ["Tonga"] = {container = "Polynesia", divs = {"divisions"}, british_spelling = true}, ["Trinidad and Tobago"] = {container = "Caribbean", divs = {"regions", "municipalities"}, british_spelling = true}, ["Tunisia"] = {container = "Africa", divs = {"governorates", "delegations"}}, ["Turkey"] = {container = {"Europe", "Asia"}, divs = {"provinces", "districts"}}, -- Foreign names generally get display-canonicalized. ["Türkiye"] = {alias_of = "Turkey", display = true}, ["Turkmenistan"] = {container = "Asia", divs = { -- The 5 regions are often also called provinces "regions", {type = "provinces", cat_as = "regions"}, "districts"}, }, ["Tuvalu"] = {container = "Polynesia", divs = {"atolls"}, british_spelling = true}, ["Uganda"] = {container = "Africa", divs = {"districts", "counties"}, british_spelling = true}, ["Ukraine"] = {container = "Europe", divs = { {type = "oblasts", cat_as = "oblasts and autonomous republics"}, {type = "autonomous republics", cat_as = "oblasts and autonomous republics"}, "raions", "hromadas", }, british_spelling = true}, ["United Arab Emirates"] = {the = true, container = "Asia", divs = {"emirates"}}, -- Abbreviations get display-canonicalized. ["UAE"] = {alias_of = "United Arab Emirates", display = true, the = true}, ["U.A.E."] = {alias_of = "United Arab Emirates", display = true, the = true}, ["United Kingdom"] = {the = true, container = "Europe", addl_parents = {"British Isles"}, divs = {"constituent countries", "counties", "districts", "boroughs", "territories", "dependent territories", "traditional counties"}, keydesc = "the [[United Kingdom]] of Great Britain and Northern Ireland", british_spelling = true}, -- Abbreviations get display-canonicalized. ["UK"] = {alias_of = "United Kingdom", display = true, the = true}, ["U.K."] = {alias_of = "United Kingdom", display = true, the = true}, ["United States"] = {the = true, container = "North America", divs = {"counties", "county seats", "states", "territories", "dependent territories", {type = "ABBREVIATION_OF states", cat_as = "abbreviations of states"}, {type = "DEROGATORY_NAME_FOR states", cat_as = "derogatory names for states"}, {type = "NICKNAME_FOR states", cat_as = "nicknames for states"}, {type = "OFFICIAL_NICKNAME_FOR states", cat_as = "official nicknames for states"}, {type = "boroughs", prep = "in"}, -- exist in Pennsylvania and New Jersey "municipalities", -- these exist politically at least in Colorado and Connecticut {type = "census-designated places", prep = "in"}, {type = "unincorporated communities", prep = "in"}, -- Don't change the following to something more politically correct until/unless the US government makes a -- similar switch (and note that as of Apr 18 2025, the Wikipedia article is still at -- [[w:Indian reservations]]). "Indian reservations", }}, -- Abbreviations and long forms (when possible) get display-canonicalized. ["US"] = {alias_of = "United States", display = true, the = true}, ["U.S."] = {alias_of = "United States", display = true, the = true}, ["USA"] = {alias_of = "United States", display = true, the = true}, ["U.S.A."] = {alias_of = "United States", display = true, the = true}, ["United States of America"] = {alias_of = "United States", display = true, the = true}, ["Uruguay"] = {container = "South America", divs = {"departments", "municipalities"}}, ["Uzbekistan"] = {container = "Asia", divs = {"regions", "districts"}}, ["Vanuatu"] = {container = "Melanesia", divs = {"provinces"}, british_spelling = true}, ["Vatican City"] = {placetype = {"city-state", "country"}, container = "Europe", -- First placetype should be 'city-state' for to shown up in its description, -- Its parent should still be "countries in Europe". bare_category_parent_type = {type = "countries", prep = "in"}, addl_parents = {"Rome"}, is_city = true, british_spelling = true}, ["Vatican"] = {alias_of = "Vatican City", the = true}, -- differs in "the" ["Venezuela"] = {container = "South America", divs = {"states", "municipalities"}}, ["Vietnam"] = {container = "Asia", divs = {"provinces", "districts", "municipalities"}}, ["Western Sahara"] = {placetype = {"territory", "country"}, container = "Africa", bare_category_parent_type = {type = "countries", prep = "in"}, }, -- Not display-canonicalizable both due to differences in 'the' and the sovereignty dispute over Western Sahara ["Sahrawi Arab Democratic Republic"] = {alias_of = "Western Sahara", the = true}, ["SADR"] = {alias_of = "Sahrawi Arab Democratic Republic", display = true, the = true}, ["Yemen"] = {container = "Asia", divs = {"governorates", "districts"}}, ["Zambia"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, ["Zimbabwe"] = {container = "Africa", divs = {"provinces", "districts"}, british_spelling = true}, } local function canonicalize_continent_container(key) if type(key) ~= "string" then return key end if export.continents[key] then return {key = key, placetype = export.continents[key].placetype} end internal_error("Unrecognized key %s in `canonicalize_continent_like`", key) end export.countries_group = { canonicalize_key_container = canonicalize_continent_container, default_overriding_bare_label_parents = {"+++", "countries"}, default_placetype = "country", default_no_container_cat = true, default_no_container_parent = true, -- No need to augment country holonyms with continents; not needed for disambiguation. default_no_auto_augment_container = true, data = export.countries, } -- Country-like entities: typically overseas territories or de-facto independent countries, which in both cases -- are not internationally recognized as sovereign nations but which we treat similarly to countries. export.country_like_entities = { -- British Overseas Territory ["Akrotiri and Dhekelia"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Cyprus", "Europe", "Asia"}, british_spelling = true, }, -- Åland: Listed as a region of Finland. Wikipedia lists this under "dependent territories" in -- [[w:List of sovereign states and dependent territories by continent]]. -- unincorporated territory of the United States ["American Samoa"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Polynesia"}, }, -- British Overseas Territory ["Anguilla"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Georgia ["Abkhazia"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Georgia", "Europe", "Asia"}, divs = {"districts"}, keydesc = "the de-facto independent state of [[Abkhazia]], internationally recognized as part of the country of [[Georgia]]", british_spelling = true, }, -- Australian external territory ["Ashmore and Cartier Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, }, -- constituent country of the Netherlands ["Aruba"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- British Overseas Territory ["Bermuda"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"North America"}, british_spelling = true, }, -- special municipality of the Netherlands ["Bonaire"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- British Overseas Territory ["British Indian Ocean Territory"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Asia"}, british_spelling = true, }, -- British Overseas Territory ["British Virgin Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- Norwegian dependent territory ["Bouvet Island"] = { placetype = {"dependent territory", "territory"}, container = "Norway", addl_parents = {"Africa"}, british_spelling = true, }, -- British Overseas Territory ["Cayman Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- Australian external territory ["Christmas Island"] = { placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, british_spelling = true, }, -- Sui generis French "state private property" per Wikipedia; classify as overseas territory like the -- French Southern and Antarctic Lands. ["Clipperton Island"] = { placetype = {"overseas territory", "territory"}, container = "France", addl_parents = {"North America"}, }, -- Australian external territory; also called the Keeling Islands or (officially) the Cocos (Keeling) Islands ["Cocos Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Asia"}, wp = "Cocos (Keeling) Islands", british_spelling = true, }, ["Cocos (Keeling) Islands"] = {alias_of = "Cocos Islands", display = true, the = true}, ["Keeling Islands"] = {alias_of = "Cocos Islands", display = true, the = true}, -- self-governing but in free association with New Zealand ["Cook Islands"] = { the = true, placetype = {"country"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- constituent country of the Netherlands ["Curaçao"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- special territory of Chile ["Easter Island"] = { placetype = {"special territory", "territory"}, container = "Chile", addl_parents = {"Polynesia"}, }, -- British Overseas Territory ["Falkland Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"South America"}, british_spelling = true, }, -- autonomous territory of Denmark ["Faroe Islands"] = { the = true, placetype = {"autonomous territory", "territory"}, container = "Denmark", addl_parents = {"Europe"}, british_spelling = true, }, -- overseas department and region of France ["French Guiana"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"South America"}, british_spelling = true, }, -- overseas collectivity of France ["French Polynesia"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Polynesia"}, british_spelling = true, }, -- French overseas territory ["French Southern and Antarctic Lands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "France", addl_parents = {"Africa"}, }, -- British Overseas Territory ["Gibraltar"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Europe"}, is_city = true, british_spelling = true, }, -- autonomous territory of Denmark ["Greenland"] = { placetype = {"autonomous territory", "territory"}, container = "Denmark", addl_parents = {"North America"}, divs = {"municipalities"}, british_spelling = true, }, -- overseas department and region of France ["Guadeloupe"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", addl_parents = {"Caribbean"}, divs = {"communes"}, british_spelling = true, }, -- unincorporated territory of the United States ["Guam"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- self-governing British Crown dependency; technically called the Bailiwick of Guernsey ["Guernsey"] = { placetype = {"crown dependency", "dependency", "dependent territory", "bailiwick", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, wp = "Bailiwick of %l", }, ["Bailiwick of Guernsey"] = {alias_of = "Guernsey", the = true}, -- Australian external territory ["Heard Island and McDonald Islands"] = { the = true, placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Africa"}, }, -- special administrative region of China ["Hong Kong"] = { placetype = {"special administrative region", "city"}, container = "China", is_city = true, british_spelling = true, }, -- self-governing British Crown dependency ["Isle of Man"] = { the = true, placetype = {"crown dependency", "dependency", "dependent territory", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, }, -- Norwegian unincorporated area ["Jan Mayen"] = { placetype = {"unincorporated area", "dependent territory", "territory", "island"}, container = "Norway", addl_parents = {"Europe"}, british_spelling = true, }, -- self-governing British Crown dependency; technically called the Bailiwick of Jersey ["Jersey"] = { placetype = {"crown dependency", "dependency", "dependent territory", "bailiwick", "territory"}, container = "United Kingdom", addl_parents = {"British Isles", "Europe"}, british_spelling = true, }, ["Bailiwick of Jersey"] = {alias_of = "Jersey", the = true}, -- special administrative region of China ["Macau"] = { placetype = {"special administrative region", "city"}, container = "China", is_city = true, british_spelling = true, }, -- overseas department and region of France ["Martinique"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Caribbean"}, british_spelling = true, }, -- overseas department and region of France ["Mayotte"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Africa"}, british_spelling = true, }, -- British Overseas Territory ["Montserrat"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- special collectivity of France ["New Caledonia"] = { placetype = {"special collectivity", "collectivity"}, container = "France", addl_parents = {"Melanesia"}, british_spelling = true, }, -- dependent territory of New Zealand ["New Zealand Subantarctic Islands"] = { the = true, placetype = {"dependent territory", "territory"}, container = "New Zealand", addl_parents = {"Antarctica"}, british_spelling = true, }, -- self-governing but in free association with New Zealand ["Niue"] = { placetype = {"country"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- Australian external territory ["Norfolk Island"] = { placetype = {"external territory", "territory"}, container = "Australia", addl_parents = {"Polynesia"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Cyprus ["Northern Cyprus"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Cyprus", "Turkey", "Europe", "Asia"}, divs = {"districts"}, keydesc = "the de-facto independent state of [[Northern Cyprus]], internationally recognized as part of the country of [[Cyprus]]", british_spelling = true, }, -- commonwealth, unincorporated territory of the United States ["Northern Mariana Islands"] = { the = true, placetype = {"commonwealth", "unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- British Overseas Territory ["Pitcairn Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Polynesia"}, british_spelling = true, }, -- commonwealth of the United States ["Puerto Rico"] = { placetype = {"commonwealth", "overseas territory", "territory"}, container = "United States", addl_parents = {"Caribbean"}, divs = {"municipalities"}, }, -- overseas department and region of France ["Réunion"] = { placetype = {"overseas department", "department", "administrative region", "region"}, container = "France", divs = {"communes"}, addl_parents = {"Africa"}, british_spelling = true, }, -- special municipality of the Netherlands ["Saba"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- overseas collectivity of France ["Saint Barthélemy"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Caribbean"}, british_spelling = true, }, -- British Overseas Territory ["Saint Helena, Ascension and Tristan da Cunha"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", divs = {{type = "constituent parts", container_parent_type = false}}, addl_parents = {"Atlantic Ocean", "Africa"}, british_spelling = true, }, -- constituent parts of the combined oveseas territory ["Ascension Island"] = { placetype = {"constituent part", "territory", "island"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, ["Saint Helena"] = { placetype = {"constituent part", "territory", "island"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, ["Tristan da Cunha"] = { placetype = {"constituent part", "territory", "archipelago"}, container = {key = "Saint Helena, Ascension and Tristan da Cunha", placetype = "overseas territory"}, addl_parents = {"Atlantic Ocean"}, overriding_bare_label_parents = {}, no_container_cat = false, no_container_parent = false, no_auto_augment_container = false, }, -- overseas collectivity of France ["Saint Martin"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Caribbean"}, british_spelling = true, }, -- overseas collectivity of France ["Saint Pierre and Miquelon"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", divs = {"communes"}, addl_parents = {"North America"}, british_spelling = true, }, -- special municipality of the Netherlands ["Sint Eustatius"] = { placetype = {"special municipality", "municipality", "overseas territory", "territory"}, container = "Netherlands", addl_parents = {"Caribbean"}, is_city = true, british_spelling = true, }, -- constituent country of the Netherlands ["Sint Maarten"] = { placetype = {"constituent country", "country"}, container = "Netherlands", addl_parents = {"Caribbean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Somalia ["Somaliland"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Somalia", "Africa"}, keydesc = "the de-facto independent state of [[Somaliland]], internationally recognized as part of the country of [[Somalia]]", british_spelling = true, }, -- British Overseas Territory -- FIXME: We should form the group "South Georgia and the South Sandwich Islands" like we did for -- "Saint Helena, Ascension and Tristan da Cunha". ["South Georgia"] = { placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Atlantic Ocean"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Georgia ["South Ossetia"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Georgia", "Europe", "Asia"}, keydesc = "the de-facto independent state of [[South Ossetia]], internationally recognized as part of the country of [[Georgia]]", british_spelling = true, }, -- British Overseas Territory ["South Sandwich Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Atlantic Ocean"}, wp = true, wpcat = "South Georgia and the South Sandwich Islands", british_spelling = true, }, -- Norwegian unincorporated area ["Svalbard"] = { placetype = {"unincorporated area", "dependent territory", "territory", "archipelago"}, container = "Norway", addl_parents = {"Europe"}, british_spelling = true, }, -- dependent territory of New Zealand ["Tokelau"] = { placetype = {"dependent territory", "territory"}, container = "New Zealand", addl_parents = {"Polynesia"}, british_spelling = true, }, -- de-facto independent state, internationally recognized as part of Moldova ["Transnistria"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Moldova", "Europe"}, keydesc = "the de-facto independent state of [[Transnistria]], internationally recognized as part of [[Moldova]]", british_spelling = true, }, -- British Overseas Territory ["Turks and Caicos Islands"] = { the = true, placetype = {"overseas territory", "territory"}, container = "United Kingdom", addl_parents = {"Caribbean"}, british_spelling = true, }, -- unincorporated territory of the United States ["United States Minor Outlying Islands"] = { the = true, placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Islands", "Micronesia", "Polynesia", "Caribbean"}, }, -- FIXME: We should add entries for the other minor outlying islands. -- Baker Island (Oceania) -- Howland Island (Oceania) -- Jarvis Island (Oceania) -- Johnston Atoll (Oceania) -- Kingman Reef (Oceania) -- Midway Atoll (Oceania) -- Navassa Island (Caribbean) -- Palmyra Atoll (Oceania) -- Wake Island (Oceania) ["Wake Island"] = { placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Micronesia"}, }, -- unincorporated territory of the United States ["United States Virgin Islands"] = { the = true, placetype = {"unincorporated territory", "overseas territory", "territory"}, container = "United States", addl_parents = {"Caribbean"}, }, ["U.S. Virgin Islands"] = {alias_of = "United States Virgin Islands", display = true, the = true}, ["US Virgin Islands"] = {alias_of = "United States Virgin Islands", display = true, the = true}, -- overseas collectivity of France ["Wallis and Futuna"] = { placetype = {"overseas collectivity", "collectivity"}, container = "France", addl_parents = {"Polynesia"}, british_spelling = true, }, } export.country_like_entities_group = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Saint Helena, Ascension and Tristan da Cunha". key_to_placename = false, placename_to_key = false, canonicalize_key_container = make_canonicalize_key_container(nil, "country"), default_overriding_bare_label_parents = {"country-like entities"}, default_no_container_cat = true, default_no_container_parent = true, -- These entities often aren't really part of their container; a village in Wallis and Futuna (an overseas -- collectivity of France in Polynesia), for example, shouldn't be treated as a village in France, nor as a village -- in Europe. default_no_auto_augment_container = true, data = export.country_like_entities, } -- Former countries and such; we don't create "Cities in ..." categories because they don't exist anymore export.former_countries = { -- de-facto independent state of Armenian ethnicity, internationally recognized as part of Azerbaijan -- (also known as Nagorno-Karabakh) -- NOTE: Formerly listed Armenia as a parent; this seems politically non-neutral so I've taken it out. ["Artsakh"] = { placetype = {"unrecognized country", "country"}, addl_parents = {"Azerbaijan", "Europe", "Asia"}, keydesc = "the former de-facto independent state of [[Artsakh]], internationally recognized as part of [[Azerbaijan]]", british_spelling = true, }, ["Nagorno-Karabakh"] = {alias_of = "Artsakh"}, ["Czechoslovakia"] = {container = "Europe", british_spelling = true}, ["East Germany"] = {container = "Europe", addl_parents = {"Germany"}, british_spelling = true}, ["North Vietnam"] = {container = "Asia", addl_parents = {"Vietnam"}}, ["Persia"] = {placetype = {"empire", "country"}, container = "Asia", divs = {"provinces"}}, ["Byzantine Empire"] = { the = true, placetype = {"empire", "country"}, container = {"Europe", "Africa", "Asia"}, addl_parents = {"Ancient Europe", "Ancient Near East"}, divs = { "provinces", "themes", }}, ["Roman Empire"] = { the = true, placetype = {"empire", "country"}, container = {"Europe", "Africa", "Asia"}, addl_parents = {"Rome"}, divs = { "provinces", {type = "FORMER provinces", cat_as = "provinces"}, }}, ["South Vietnam"] = {container = "Asia", addl_parents = {"Vietnam"}}, ["Soviet Union"] = { the = true, container = {"Europe", "Asia"}, divs = {"republics", "autonomous republics"}, british_spelling = true}, ["West Germany"] = {container = "Europe", addl_parents = {"Germany"}, british_spelling = true}, ["Yugoslavia"] = {container = "Europe", divs = {"districts"}, keydesc = "the former [[Kingdom of Yugoslavia]] (1918–1943) or the former [[Socialist Federal Republic of Yugoslavia]] (1943–1992)", british_spelling = true}, } export.former_countries_group = { canonicalize_key_container = canonicalize_continent_container, default_overriding_bare_label_parents = {"former countries and country-like entities"}, default_is_former_place = true, default_placetype = "country", default_no_container_cat = true, default_no_container_parent = true, -- No need to augment country holonyms with continents; not needed for disambiguation. default_no_auto_augment_container = true, data = export.former_countries, } ----------------------------------------------------------------------------------- -- Subpolity tables -- ----------------------------------------------------------------------------------- export.australia_states_and_territories = { ["Australian Capital Territory, Australia"] = {the = true, placetype = "territory"}, ["Jervis Bay Territory, Australia"] = {the = true, placetype = "territory"}, ["New South Wales, Australia"] = {}, ["Northern Territory, Australia"] = {the = true, placetype = "territory"}, ["Queensland, Australia"] = {}, ["South Australia, Australia"] = {}, ["Tasmania, Australia"] = {}, ["Victoria, Australia"] = {}, ["Western Australia, Australia"] = {}, } -- states and territories of Australia export.australia_group = { default_container = "Australia", default_placetype = "state", default_divs = "local government areas", data = export.australia_states_and_territories, } export.austria_states = { ["Vienna, Austria"] = {}, ["Lower Austria, Austria"] = {}, ["Upper Austria, Austria"] = {}, ["Styria, Austria"] = {}, ["Tyrol, Austria"] = {wp = "Tyrol (state)"}, ["Carinthia, Austria"] = {}, ["Salzburg, Austria"] = {wp = "Salzburg (state)"}, ["Vorarlberg, Austria"] = {}, ["Burgenland, Austria"] = {}, } -- states of Austria export.austria_group = { default_container = "Austria", default_placetype = "state", default_divs = "municipalities", data = export.austria_states, } export.bangladesh_divisions = { ["Barisal Division, Bangladesh"] = {}, ["Chittagong Division, Bangladesh"] = {}, ["Dhaka Division, Bangladesh"] = {}, ["Khulna Division, Bangladesh"] = {}, ["Mymensingh Division, Bangladesh"] = {}, ["Rajshahi Division, Bangladesh"] = {}, ["Rangpur Division, Bangladesh"] = {}, ["Sylhet Division, Bangladesh"] = {}, } -- divisions of Bangladesh export.bangladesh_group = { key_to_placename = make_key_to_placename(", Bangladesh$", " Division$"), placename_to_key = make_placename_to_key(", Bangladesh", " Division"), default_container = "Bangladesh", default_placetype = "division", default_divs = "districts", data = export.bangladesh_divisions, } export.brazil_states = { ["Acre, Brazil"] = {wp = "%l (state)"}, ["Alagoas, Brazil"] = {}, ["Amapá, Brazil"] = {}, ["Amazonas, Brazil"] = {wp = "%l (Brazilian state)"}, ["Bahia, Brazil"] = {}, ["Ceará, Brazil"] = {}, ["Distrito Federal, Brazil"] = {wp = "Federal District (Brazil)"}, ["Espírito Santo, Brazil"] = {}, ["Goiás, Brazil"] = {}, ["Maranhão, Brazil"] = {}, ["Mato Grosso, Brazil"] = {}, ["Mato Grosso do Sul, Brazil"] = {}, ["Minas Gerais, Brazil"] = {}, ["Pará, Brazil"] = {}, ["Paraíba, Brazil"] = {}, ["Paraná, Brazil"] = {wp = "%l (state)"}, ["Pernambuco, Brazil"] = {}, ["Piauí, Brazil"] = {}, ["Rio de Janeiro, Brazil"] = {wp = "%l (state)"}, ["Rio Grande do Norte, Brazil"] = {}, ["Rio Grande do Sul, Brazil"] = {}, ["Rondônia, Brazil"] = {}, ["Roraima, Brazil"] = {}, ["Santa Catarina, Brazil"] = {wp = "%l (state)"}, ["São Paulo, Brazil"] = {wp = "%l (state)"}, ["Sergipe, Brazil"] = {}, ["Tocantins, Brazil"] = {}, } -- states of Brazil export.brazil_group = { default_container = "Brazil", default_placetype = "state", default_divs = "municipalities", data = export.brazil_states, } -- provinces (a.k.a. oblasts) of Bulgaria export.bulgaria_provinces = { ["Blagoevgrad Province, Bulgaria"] = {}, ["Burgas Province, Bulgaria"] = {}, ["Dobrich Province, Bulgaria"] = {}, ["Gabrovo Province, Bulgaria"] = {}, ["Haskovo Province, Bulgaria"] = {}, ["Kardzhali Province, Bulgaria"] = {}, ["Kyustendil Province, Bulgaria"] = {}, ["Lovech Province, Bulgaria"] = {}, ["Montana Province, Bulgaria"] = {}, ["Pazardzhik Province, Bulgaria"] = {}, ["Pernik Province, Bulgaria"] = {}, ["Pleven Province, Bulgaria"] = {}, ["Plovdiv Province, Bulgaria"] = {}, ["Razgrad Province, Bulgaria"] = {}, ["Ruse Province, Bulgaria"] = {}, ["Shumen Province, Bulgaria"] = {}, ["Silistra Province, Bulgaria"] = {}, ["Sliven Province, Bulgaria"] = {}, ["Smolyan Province, Bulgaria"] = {}, ["Sofia City Province, Bulgaria"] = {}, ["Sofia Province, Bulgaria"] = {}, ["Stara Zagora Province, Bulgaria"] = {}, ["Targovishte Province, Bulgaria"] = {}, ["Varna Province, Bulgaria"] = {}, ["Veliko Tarnovo Province, Bulgaria"] = {}, ["Vidin Province, Bulgaria"] = {}, ["Vratsa Province, Bulgaria"] = {}, ["Yambol Province, Bulgaria"] = {}, } export.bulgaria_group = { key_to_placename = make_key_to_placename(", Bulgaria$", " Province$"), placename_to_key = make_placename_to_key(", Bulgaria", " Province"), default_container = "Bulgaria", --== source: https://en.wikipedia.org/wiki/NUTS_statistical_regions_of_Bulgaria == divs = {"regions", "planning regions", "provinces", "municipalities", "settlements"}, default_placetype = "province", data = export.bulgaria_provinces, } export.canada_provinces_and_territories = { ["Alberta, Canada"] = {divs = { {type = "municipal districts", container_parent_type = "rural municipalities"}, }}, ["British Columbia, Canada"] = {divs = {type = "regional districts", container_parent_type = false}, "regional municipalities", }, ["Manitoba, Canada"] = {divs = {"rural municipalities"}}, ["New Brunswick, Canada"] = {divs = {"counties", "parishes", {type = "civil parishes", cat_as = "parishes"}}}, ["Newfoundland and Labrador, Canada"] = {}, ["Northwest Territories, Canada"] = {the = true, placetype = "territory"}, ["Nova Scotia, Canada"] = {divs = {"counties", "regional municipalities"}}, ["Nunavut, Canada"] = {placetype = "territory"}, ["Ontario, Canada"] = {divs = {"counties", "regional municipalities", {type = "townships", prep = "in"}}}, ["Prince Edward Island, Canada"] = {divs = {"counties", "parishes", "rural municipalities"}}, ["Saskatchewan, Canada"] = {divs = {"rural municipalities"}}, ["Quebec, Canada"] = {divs = { "counties", {type = "regional county municipalities", container_parent_type = "regional municipalities"}, -- administrative regions have an official (but non-governmental) function but there don't appear to be any -- equivalent regions elsewhere in Canada, so disable the [[Category:Regions of Canada]] grouping {type = "regions", container_parent_type = false}, {type = "townships", prep = "in"}, {type = "parish municipalities", cat_as = {{type = "parishes", container_parent_type = "counties"}, "municipalities"}}, {type = "township municipalities", cat_as = {{type = "townships", prep = "in"}, "municipalities"}}, {type = "village municipalities", cat_as = {{type = "villages", prep = "in"}, "municipalities"}}, }}, ["Yukon, Canada"] = {placetype = "territory"}, ["Yukon Territory, Canada"] = {alias_of = "Yukon, Canada", the = true}, } -- provinces and territories of Canada export.canada_group = { default_container = "Canada", default_placetype = "province", data = export.canada_provinces_and_territories, } export.china_provinces_and_autonomous_regions = { -- direct-administered municipalities are not here but below under prefecture-level cities ["Anhui, China"] = {}, ["Fujian, China"] = {}, ["Fuchien, China"] = {alias_of = "Fujian, China", display = true}, ["Gansu, China"] = {}, ["Guangdong, China"] = {}, ["Guangxi, China"] = {placetype = "autonomous region"}, ["Guizhou, China"] = {}, ["Hainan, China"] = {}, ["Hebei, China"] = {}, ["Heilongjiang, China"] = {}, ["Henan, China"] = {}, ["Hubei, China"] = {}, ["Hunan, China"] = {}, ["Inner Mongolia, China"] = {placetype = "autonomous region"}, ["Jiangsu, China"] = {}, ["Jiangxi, China"] = {}, ["Jilin, China"] = {}, ["Liaoning, China"] = {}, ["Ningxia, China"] = {placetype = "autonomous region"}, ["Qinghai, China"] = {}, ["Shaanxi, China"] = {}, ["Shandong, China"] = {}, ["Shanxi, China"] = {}, ["Sichuan, China"] = {}, ["Tibet, China"] = {placetype = "autonomous region", wp = "Tibet Autonomous Region"}, ["Xinjiang, China"] = {placetype = "autonomous region"}, ["Yunnan, China"] = {}, ["Zhejiang, China"] = {}, } -- provinces and autonomous regions of China export.china_group = { default_container = "China", default_placetype = "province", default_divs = { "prefectures", "prefecture-level cities", "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_provinces_and_autonomous_regions, } export.china_prefecture_level_cities = { -- In China, a "prefecture-level city" is not a city in any real sense. It is rather a prefecture, which is an -- administrative unit smaller than a province but bigger than a county, which is administratively controlled by -- the chief city of the prefecture (which bears the same name as the prefecture), in a unified government. Prior -- to the mid-1980's, in fact, prefecture-level cities *were* prefectures, and a few of them (especially in the -- western portion of China) have not yet been converted. Generally a given province is entirely tiled by -- prefecture-level cities, another indication that they should be treated as prefectures and not cities per se. -- Yet another indication is that prefecture-level cities can contain counties and county-level cities (which, much -- like prefecture-level cities, are effectively counties surrounding a chief city of the county, again which bears -- the same name as the county-level city). -- -- For this reason, we treat prefecture-level cities as non-city political divisions, and separately enumerate the -- most populous so we can separately categorize districts and counties under them instead of lumping them at the -- province level. -- -- Note also that China separately distinguishes "urban area" from "metro area". Sometimes the two figures are -- identical but sometimes the metro area is larger (and very occasionally smaller, which I assume is an error). I'm -- guessing that the "urban area" is the contiguous urban area over a certain density while the metro area includes -- all urban areas above a certain density; when the latter is greater, it's because of satellite cities in the -- metro area separated by suburban/exurban or rural land. -- At first I chose all prefecture/province-level cities with a total prefecture/province-level population of at -- least 6,000,000 per the 2020 census with data taken from https://www.citypopulation.de/en/china/admin/ (a total -- of 67, including the four direct-administered municipalities), and also chose all prefecture/province-level -- cities whose "urban population" was at least 2,000,000 per the 2020 census with data taken from Wikipedia -- [[w:List of cities in China by population#Cities and towns by population]] (a total of 61 cities; if we cut off -- at 1.5 million we'd have 84 cities, and if we cut off at 1 million we'd have 105 cities). Merging them produces -- 87 cities. Note that this leaves off a few well-known cities (Guilin, Qiqihar, Kashgar, Lhasa, ...) but includes -- a lot of obscure cities. -- -- At a later date I added all cities from citypopulation.de whose "urban" population per the 2020 China census was -- >= 1 million, and then finally added all urban agglomerations from citypopulation.de whose 2025-01-01 estimate -- was >= 1 million. These are sorted below by the urban agglomeration value (which is generally of the "adm-urb" = -- "administrative area (urban population)" type) and sometimes groups nearby cities into a single agglomeration -- (most notably in the case of the Pearl River Delta, grouped under Guangzhou with an agglomeration population of -- 72,700,000 but including a large number of nearby large cities in the agglomeration (although for some reason not -- Hong Kong, maybe due to the administrative issues involved). In addition, citypopulation.de includes divisions -- under a prefecture-level city if they are city-like and have an agglomeration population of at least 1 million; -- this includes several county-level cities, one county and one district (Wanzhou, a "district" of Chongqing -- despite being 142 miles away). None of the county-level cities or counties have districts under them, only -- subdistricts, towns and townships. ["Guangzhou"] = {container = "Guangdong"}, -- 18.7 prefectural, 18.8 urban; sub-provincial city; 16.097 urban (72.700 adm-urb including Dongguan, Foshan, Huizhou, Jiangmen, Shenzhen, Zhongshan) per citypopulation.de ["Dongguan"] = {container = "Guangdong"}, -- 10.5 prefectural, 10.5 urban; 9.645 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Foshan"] = {container = "Guangdong"}, -- 9.5 prefectural, 9.5 urban; 9.043 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Huizhou"] = {container = "Guangdong"}, -- 6.0 prefectural, 2.5 urban; 2.900 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Jiangmen"] = {container = "Guangdong"}, -- 4.798 prefectural, 2.7 urban; 1.795 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Shenzhen"] = {container = "Guangdong"}, -- 17.5 prefectural, 14.7 urban; sub-provincial city; 17.445 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Zhongshan"] = {container = "Guangdong"}, -- 4.418 prefectural, 4.4 urban; 3.842 per citypopulation.de; included by citypopulation.de in Guangzhou agglomeration ["Shanghai"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 24.9 prefectural, 29.9 urban; 21.910 urban (41.600 adm-urb including Changshu, Changzhou, Suzhou, Wuxi) per citypopulation.de ["Changshu"] = {container = "Jiangsu"}, -- 1.231 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration -- NOTE: Not to be confused with Cangzhou in Hebei ["Changzhou"] = {container = "Jiangsu"}, -- 5.278 prefectural, 3.6 urban; 3.187 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration -- NOTE: There is also a prefecture-level city Suzhou in Anhui with 5.3 million prefectural inhabitants ["Suzhou"] = {container = "Jiangsu"}, -- 12.8 prefectural, 4.3 urban; 5.893 urban per citypopulation.de; included by citypopulation.de in Shanghai agglomeration ["Wuxi"] = {container = "Jiangsu"}, -- 7.5 prefectural, 3.3 urban; 3.957 per citypopulation.de; included by citypopulation.de in Shanghai agglomeration ["Beijing"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 21.9 prefectural, 21.9 urban; 18.961 urban (21.500 adm-urb) per citypopulation.de ["Chengdu"] = {container = "Sichuan"}, -- 20.9 prefectural, 16.9 urban; sub-provincial city; 13.568 urban (18.100 adm-urb) per citypopulation.de ["Xiamen"] = {container = "Fujian"}, -- 5.163 prefectural, 5.2 urban; sub-provincial city; 4.617 urban (15.400 adm-urb including Jinjiang, Quanzhou, Putian) per citypopulation.de ["Jinjiang"] = {container = "Fujian"}, -- 1.416 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Quanzhou"] = {container = "Fujian"}, -- 8.8 prefectural, 1.7 urban (6.7 metro); 1.469 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Putian"] = {container = "Fujian"}, -- 3.210 prefectural, 2.0 urban; 1.539 urban per citypopulation.de; included by citypopulation.de in Xiamen agglomeration ["Hangzhou"] = {container = "Zhejiang"}, -- 11.9 prefectural, 10.7 urban; sub-provincial city; 9.236 urban (14.600 adm-urb including Shaoxing) per citypopulation.de ["Shaoxing"] = {container = "Zhejiang"}, -- 5.270 prefectural, 2.5 urban; 2.333 urban per citypopulation.de; included by citypopulation.de in Hangzhou agglomeration ["Xi'an"] = {container = "Shaanxi"}, -- 12.1 prefectural, 11.9 urban; sub-provincial city; 9.393 urban (13.400 adm-urb including Xianyang) per citypopulation.de ["Xianyang"] = {container = "Shaanxi"}, -- 1.193 urban per citypopulation.de; included by citypopulation.de in Xi'an agglomeration ["Chongqing"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 32.1 prefectural, 16.9 urban; 9.581 urban (12.900 adm-urb) per citypopulation.de ["Wuhan"] = {container = "Hubei"}, -- 12.4 prefectural, 12.3 urban; sub-provincial city; 10.495 urban (12.600 adm-urb) per citypopulation.de ["Tianjin"] = {placetype = {"direct-administered municipality", "municipality", "city"}}, -- 13.9 prefectural, 13.9 urban; 11.052 urban (11.700 adm-urb) per citypopulation.de ["Changsha"] = {container = "Hunan"}, -- 10.0 prefectural, 6.0 urban; 5.630 urban (11.500 adm-urb including Xiangtan, Zhuzhou) per citypopulation.de -- Changsha County -- 1.024 urban per citypopulation.de ["Zhuzhou"] = {container = "Hunan"}, -- 1.510 urban per citypopulation.de; included by citypopulation.de in Changsha agglomeration ["Zhengzhou"] = {container = "Henan"}, -- 12.6 prefectural, 6.7 urban; 6.461 urban (10.300 adm-urb) per citypopulation.de ["Nanjing"] = {container = "Jiangsu"}, -- 9.3 prefectural, 9.3 urban; sub-provincial city; 7.520 urban (9.500 adm-urb including Ma'anshan) per citypopulation.de ["Shenyang"] = {container = "Liaoning"}, -- 9.1 prefectural, 7.9 urban; sub-provincial city; 7.026 urban (8.800 adm-urb including Fushun) per citypopulation.de ["Fushun"] = {container = "Liaoning"}, -- 1.229 urban per citypopulation.de; included by citypopulation.de in Shenyang agglomeration ["Hefei"] = {container = "Anhui"}, -- 9.4 prefectural, 4.2 urban; 5.056 urban (8.200 adm-urb) per citypopulation.de ["Shantou"] = {container = "Guangdong"}, -- 5.502 prefectural, 4.3 urban; 3.839 urban (8.050 adm-urb including Chaozhou, Jieyang, Puning) per citypopulation.de ["Chaozhou"] = {container = "Guangdong"}, -- 1.254 urban per citypopulation.de; included by citypopulation.de in Shantou agglomeration ["Jieyang"] = {container = "Guangdong"}, -- 1.243 urban per citypopulation.de; included by citypopulation.de in Shantou agglomeration ["Qingdao"] = {container = "Shandong"}, -- 10.1 prefectural, 7.1 urban; sub-provincial city; 6.165 urban (7.700 adm-urb) per citypopulation.de ["Ningbo"] = {container = "Zhejiang"}, -- 9.4 prefectural, 5.1 urban; sub-provincial city; 3.731 urban (7.600 adm-urb including Cixi, Yuyao) per citypopulation.de ["Cixi"] = {container = "Zhejiang"}, -- 1.458 urban per citypopulation.de; included by citypopulation.de in Ningbo agglomeration ["Yuyao"] = {container = "Zhejiang"}, -- 1.014 urban per citypopulation.de; included by citypopulation.de in Ningbo agglomeration -- Hong Kong 7.500 agglomeration per citypopulation.de 2025-01-01 estimate including Kowloon, Victoria ["Wenzhou"] = {container = "Zhejiang"}, -- 9.6 prefectural, 3.6 urban; 2.582 urban (7.000 adm-urb including Rui'an, Cangnan, Pingyang) per citypopulation.de -- Rui'an is a "county-level city" of the "prefecture-level city" of Wenzhou but in fact is 19 miles away from Wenzhou city proper (urban core to urban core). ["Rui'an"] = {placetype = "county-level city", container = {key = "Wenzhou", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 1.013 urban per citypopulation.de; included by citypopulation.de in Wenzhou agglomeration ["Kunming"] = {container = "Yunnan"}, -- 8.5 prefectural, 6.0 urban; 5.273 urban (6.800 adm-urb) per citypopulation.de -- includes Láiwú city ["Jinan"] = {container = "Shandong", wp = "%l, %c"}, -- 9.2 prefectural, 8.4 urban; sub-provincial city; 5.648 urban (6.750 adm-urb) per citypopulation.de -- includes Xīnjí city ["Shijiazhuang"] = {container = "Hebei"}, -- 11.2 prefectural, 4.1 urban; 5.090 urban (6.450 adm-urb) per citypopulation.de ["Taiyuan"] = {container = "Shanxi"}, -- 5.304 prefectural, 4.5 urban; 4.304 urban (6.150 adm-urb) per citypopulation.de ["Harbin"] = {container = "Heilongjiang"}, -- 10.0 prefectural, 7.0 urban; sub-provincial city; 5.243 urban (5.550 adm-urb) per citypopulation.de ["Nanning"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 8.7 prefectural, 3.8 urban; 4.583 urban (5.550 adm-urb) per citypopulation.de ["Dalian"] = {container = "Liaoning"}, -- 7.5 prefectural, 5.7 urban; sub-provincial city; 4.914 urban (5.400 adm-urb) per citypopulation.de ["Guiyang"] = {container = "Guizhou"}, -- 5.987 prefectural, 3.5 urban; 4.021 urban (5.300 adm-urb) per citypopulation.de ["Changchun"] = {container = "Jilin"}, -- 9.1 prefectural, 5.7 urban; sub-provincial city; 4.557 urban (5.200 adm-urb) per citypopulation.de ["Nanchang"] = {container = "Jiangxi"}, -- 6.3 prefectural, 3.6 (3.9?) urban, 5.3 metro; 3.519 urban (5.150 adm-urb) per citypopulation.de ["Ürümqi"] = {container = {key = "Xinjiang, China", placetype = "autonomous region"}}, -- 4.054 prefectural, 4.3 urban; 3.843 urban (5.000 adm-urb) per citypopulation.de ["Urumqi"] = {alias_of = "Ürümqi", display = true}, ["Fuzhou"] = {container = "Fujian"}, -- 8.3 prefectural, 4.1 urban; 3.723 urban (4.775 adm-urb) per citypopulation.de ["Linyi"] = {container = "Shandong"}, -- 11.0 prefectural, 2.3 urban; 2.744 urban (4.650 adm-urb) per citypopulation.de ["Zibo"] = {container = "Shandong"}, -- 4.704 prefectural, 2.6 urban; 2.750 urban (3.975 adm-urb) per citypopulation.de ["Luoyang"] = {container = "Henan"}, -- 7.1 prefectural, 2.4 urban; 2.231 urban (3.750 adm-urb) per citypopulation.de ["Lanzhou"] = {container = "Gansu"}, -- 4.359 prefectural, 3.1 urban; 3.013 urban (3.575 adm-urb) per citypopulation.de ["Nantong"] = {container = "Jiangsu"}, -- 7.7 prefectural, 2.3 urban; 2.988 urban (3.475 adm-urb) citypopulation.de ["Weifang"] = {container = "Shandong"}, -- 9.4 prefectural, 2.7 urban; 1.998 urban (3.325 adm-urb) per citypopulation.de ["Jiangyin"] = {container = "Jiangsu"}, -- 1.331 urban (3.200 adm-urb including Zhangjiagang) per citypopulation.de ["Zhangjiagang"] = {container = "Jiangsu"}, -- 1.056 urban per citypopulation.de; included in Jiangyin figures ["Xuzhou"] = {container = "Jiangsu"}, -- 9.1 prefectural, 2.6 urban; 2.846 urban (3.150 adm-urb) per citypopulation.de ["Handan"] = {container = "Hebei"}, -- 9.4 prefectural, 2.8 urban; 2.095 urban (2.925 adm-urb) per citypopulation.de ["Hohhot"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 3.446 prefectural, 2.7 urban; 2.373 urban (2.850 adm-urb) per citypopulation.de ["Haikou"] = {container = "Hainan"}, -- 2.873 prefectural, 2.3 urban; 2.349 urban (2.800 adm-urb) per citypopulation.de ["Tangshan"] = {container = "Hebei"}, -- 7.7 prefectural, 3.4 urban; 2.550 urban (2.750 adm-urb) per citypopulation.de ["Xinxiang"] = {container = "Henan"}, -- 6.3 prefectural, 1.2 urban, 2.7 metro; 1.271 urban (2.700 adm-urb) per citypopulation.de ["Yiwu"] = {container = "Zhejiang"}, -- 1.481 urban (2.700 adm-urb) per citypopulation.de ["Zhuhai"] = {container = "Guangdong"}, -- 2.439 prefectural, 2.4 urban; 2.207 urban (2.675 adm-urb) per citypopulation.de ["Taizhou, Zhejiang"] = {container = "Zhejiang"}, -- 6.6 prefectural, 1.6 urban; 1.486 urban (2.625 adm-urb) per citypopulation.de ["Taizhou"] = {alias_of = "Taizhou, Zhejiang"}, ["Yantai"] = {container = "Shandong"}, -- 7.1 prefectural, 2.5 urban; 2.312 urban (2.550 adm-urb) per citypopulation.de ["Yinchuan"] = {container = {key = "Ningxia, China", placetype = "autonomous region"}}, -- 1.663 urban (2.525 adm-urb) per citypopulation.de ["Liuzhou"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 4.157 prefectural, 2.2 urban; 2.205 urban (2.500 adm-urb) per citypopulation.de ["Anshan"] = {container = "Liaoning"}, -- 1.480 urban (2.350 adm-urb including Liáoyáng) per citypopulation.de ["Yangzhou"] = {container = "Jiangsu"}, -- 2.067 urban (2.300 adm-urb) per citypopulation.de ["Jiaxing"] = {container = "Zhejiang"}, -- 1.188 urban (2.275 adm-urb) per citypopulation.de ["Xining"] = {container = "Qinghai"}, -- 1.677 urban (2.250 adm-urb) per citypopulation.de -- includes Dìngzhōu city and Xióngān Xīnqū ["Baoding"] = {container = "Hebei"}, -- 11.5 prefectural, 2.0 urban; 1.940 urban (2.225 adm-urb) per citypopulation.de ["Baotou"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 2.709 prefectural, 2.2 urban; 2.104 urban (2.200 adm-urb) per citypopulation.de ["Ganzhou"] = {container = "Jiangxi"}, -- 9.0 prefectural, 1.6 urban; 1.778 urban (2.150 adm-urb) per citypopulation.de ["Pingdingshan"] = {container = "Henan"}, -- 1.046 urban (2.100 adm-urb) per citypopulation.de ["Zunyi"] = {container = "Guizhou"}, -- 6.6 prefectural, 2.4 urban/metro; 1.675 urban (2.025 adm-urb) per citypopulation.de ["Bengbu"] = {container = "Anhui"}, -- 1.078 urban (2.000 adm-urb) per citypopulation.de ["Datong"] = {container = "Shanxi"}, -- 3.105 prefectural, 2.0 urban; 1.810 urban (2.000 adm-urb) per citypopulation.de ["Anyang"] = {container = "Henan"}, -- 1.188 urban (1.960 adm-urb) per citypopulation.de ["Huai'an"] = {container = "Jiangsu"}, -- 4.556 prefectural, 2.6 urban; 1.805 urban (1.940 adm-urb) per citypopulation.de ["Zaozhuang"] = {container = "Shandong"}, -- 1.350 urban (1.900 adm-urb) per citypopulation.de ["Zhanjiang"] = {container = "Guangdong"}, -- 7.0 prefectural, 1.9 urban; 1.401 urban (1.890 adm-urb) per citypopulation.de ["Huainan"] = {container = "Anhui"}, -- 1.256 urban (1.880 adm-urb) per citypopulation.de ["Jining"] = {container = "Shandong"}, -- 8.4 prefectural, 1.5 urban; 1.700 urban (1.880 adm-urb) per citypopulation.de ["Daqing"] = {container = "Heilongjiang"}, -- 1.604 urban (1.860 adm-urb) per citypopulation.de ["Wuhu"] = {container = "Anhui"}, -- 1.598 urban (1.850 adm-urb) per citypopulation.de ["Guilin"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 1.361 urban (1.830 adm-urb) per citypopulation.de ["Mianyang"] = {container = "Sichuan"}, -- 1.549 urban (1.800 adm-urb) per citypopulation.de ["Xiangyang"] = {container = "Hubei"}, -- 1.686 urban (1.800 adm-urb) per citypopulation.de ["Huzhou"] = {container = "Zhejiang"}, -- 1.084 urban (1.750 adm-urb) per citypopulation.de ["Puyang"] = {container = "Henan"}, -- 0.824 urban (1.750 adm-urb) per citypopulation.de ["Shangqiu"] = {container = "Henan"}, -- 7.8 prefectural, 1.9 urban (2.8 metro); 1.031 urban (1.750 adm-urb) per citypopulation.de ["Qinhuangdao"] = {container = "Hebei"}, -- 1.520 urban (1.740 adm-urb) per citypopulation.de ["Xingtai"] = {container = "Hebei"}, -- 7.1 prefectural, 971,000 urban; 1.5 urban (1.700 adm-urb) per citypopulation.de ["Nanyang"] = {container = "Henan", wp = "%l, %c"}, -- 9.7 prefectural, 2.1 urban/metro; 1.481 urban (1.680 adm-urb) per citypopulation.de ["Jiaozuo"] = {container = "Henan"}, -- 0.875 urban (1.640 adm-urb) per citypopulation.de ["Jilin City"] = {container = "Jilin"}, -- 1.509 urban (1.610 adm-urb) per citypopulation.de ["Jilin"] = {alias_of = "Jilin City"}, ["Jinhua"] = {container = "Zhejiang"}, -- 7.1 prefectural, 1.5 urban; 1.041 urban (1.590 adm-urb) per citypopulation.de ["Shangrao"] = {container = "Jiangxi"}, -- 6.5 prefectural, 2.1 urban, 1.3 metro [sic]; 1.342 urban (1.580 adm-urb) per citypopulation.de ["Heze"] = {container = "Shandong"}, -- 8.8 prefectural, 1.3 urban; 1.294 urban (1.570 adm-urb) per citypopulation.de ["Yulin"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}, wp = "%l, %c"}, -- 0.878 urban (1.570 adm-urb) per citypopulation.de ["Tai'an"] = {container = "Shandong"}, -- 1.417 urban (1.560 adm-urb) per citypopulation.de ["Weihai"] = {container = "Shandong"}, -- 1.340 urban (1.510 adm-urb) per citypopulation.de -- Taizhou, Jiangsu would be here (1.490 adm-urb) but moved to china_prefecture_level_cities_2 to avoid clash ["Yancheng"] = {container = "Jiangsu"}, -- 6.7 prefectural, 1.6 urban; 1.353 urban (1.460 adm-urb) per citypopulation.de ["Zhangjiakou"] = {container = "Hebei"}, -- 1.339 urban (1.450 adm-urb) per citypopulation.de ["Maoming"] = {container = "Guangdong"}, -- 6.2 prefectural, 2.5 urban; 1.308 urban (1.440 adm-urb) per citypopulation.de ["Nanchong"] = {container = "Sichuan"}, -- 1.254 urban (1.440 adm-urb) per citypopulation.de ["Fuyang"] = {container = "Anhui", wp = "%l, %c"}, -- 8.2 prefectural, 2.1 urban; 1.191 urban (1.410 adm-urb) per citypopulation.de ["Xuchang"] = {container = "Henan"}, -- 0.850 urban (1.390 adm-urb) per citypopulation.de ["Yichang"] = {container = "Hubei"}, -- 1.284 urban (1.390 adm-urb) per citypopulation.de ["Dazhou"] = {container = "Sichuan"}, -- 1.136 urban (1.380 adm-urb) per citypopulation.de ["Kaifeng"] = {container = "Henan"}, -- 1.194 urban (1.340 adm-urb) per citypopulation.de ["Luzhou"] = {container = "Sichuan"}, -- 1.128 urban (1.340 adm-urb) per citypopulation.de ["Qingyuan"] = {container = "Guangdong"}, -- 1.198 urban (1.340 adm-urb) per citypopulation.de ["Huaibei"] = {container = "Anhui"}, -- 0.831 urban (1.330 adm-urb) per citypopulation.de ["Yibin"] = {container = "Sichuan"}, -- 1.101 urban (1.310 adm-urb) per citypopulation.de ["Lu'an"] = {container = "Anhui"}, -- 1.070 urban (1.300 adm-urb) per citypopulation.de ["Dezhou"] = {container = "Shandong"}, -- 0.843 urban (1.290 adm-urb) per citypopulation.de ["Rizhao"] = {container = "Shandong"}, -- 1.147 urban (1.270 adm-urb) per citypopulation.de ["Changzhi"] = {container = "Shanxi"}, -- 1.047 urban (1.250 adm-urb) per citypopulation.de ["Hengyang"] = {container = "Hunan"}, -- 6.6 prefectural, 1.5 urban; 1.185 urban (1.250 adm-urb) per citypopulation.de ["Jinzhou"] = {container = "Liaoning"}, -- 1.021 urban (1.240 adm-urb) per citypopulation.de ["Liaocheng"] = {container = "Shandong"}, -- 1.020 urban (1.240 adm-urb) per citypopulation.de ["Changde"] = {container = "Hunan"}, -- 1.101 urban (1.230 adm-urb) per citypopulation.de ["Suqian"] = {container = "Jiangsu"}, -- 1.082 urban (1.230 adm-urb) per citypopulation.de ["Xinyang"] = {container = "Henan"}, -- 6.2 prefectural, 1.4 urban/metro; 1.015 urban (1.230 adm-urb) per citypopulation.de ["Baoji"] = {container = "Shaanxi"}, -- 1.108 urban (1.220 adm-urb) per citypopulation.de ["Yueyang"] = {container = "Hunan"}, -- 1.125 urban (1.220 adm-urb) per citypopulation.de ["Zhenjiang"] = {container = "Jiangsu"}, -- 1.124 urban (1.210 adm-urb) per citypopulation.de -- Wanzhou is a "district" of the "direct-administered municipality" of Chongqing but in fact is 142 miles away from Chongqing city proper. ["Wanzhou"] = {placetype = "district", container = {key = "Chongqing", placetype = "direct-administered municipality"}, divs = {"subdistricts", "townships"}, wp = "%l, %c"}, -- 1.078 urban (1.190 adm-urb) per citypopulation.de ["Ulanhad"] = {container = {key = "Inner Mongolia, China", placetype = "autonomous region"}}, -- 1.093 urban (1.180 adm-urb) per citypopulation.de ["Chifeng"] = {alias_of = "Ulanhad"}, ["Ulankhad"] = {alias_of = "Ulanhad", display = true}, ["Ezhou"] = {container = "Hubei"}, -- < 0.750 urban (1.180 adm-urb) per citypopulation.de ["Zhaoqing"] = {container = "Guangdong"}, -- 1.036 urban (1.160 adm-urb) per citypopulation.de ["Lianyungang"] = {container = "Jiangsu"}, -- 4.599 prefectural, 2.0 urban; 1.071 urban (1.150 adm-urb) per citypopulation.de ["Qujing"] = {container = "Yunnan"}, -- 0.976 urban (1.150 adm-urb) per citypopulation.de -- Shuyang is a "county" of the "prefecture-level city" of Suqian but in fact is 38 miles away from Suqian city proper (urban core to urban core). -- The county itself is 37 miles by 34 miles. ["Shuyang"] = {placetype = "county", container = {key = "Suqian", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}, wp = "%l County"}, -- 0.986 urban (1.120 adm-urb) per citypopulation.de -- Yongkang is a "county-level city" of the "prefecture-level city" of Jinhua but in fact is 32 miles away from Jinhua city proper (urban core to urban core). ["Yongkang"] = {placetype = "county-level city", container = {key = "Jinhua", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}, wp = "%l, Zhejiang"}, -- < 0.750 urban (1.110 adm-urb) per citypopulation.de ["Zhoukou"] = {container = "Henan"}, -- 9.0 prefectural, 721,000 urban (1.6 metro); < 0.750 urban (1.100 adm-urb) per citypopulation.de ["Beihai"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- < 1 urban (1.090 adm-urb) per citypopulation.de ["Jiujiang"] = {container = "Jiangxi"}, -- < 0.750 urban (1.080 adm-urb) per citypopulation.de ["Shaoyang"] = {container = "Hunan"}, -- 6.6 prefectural, 802,000 urban, 1.4 metro; < 1 urban (1.080 adm-urb) per citypopulation.de ["Chuzhou"] = {container = "Anhui"}, -- < 0.750 urban (1.070 adm-urb) per citypopulation.de ["Hengshui"] = {container = "Hebei"}, -- 0.885 urban (1.070 adm-urb) per citypopulation.de ["Shiyan"] = {container = "Hubei"}, -- 0.955 urban (1.070 adm-urb) per citypopulation.de ["Huludao"] = {container = "Liaoning"}, -- 0.764 urban (1.060 adm-urb) per citypopulation.de ["Dongying"] = {container = "Shandong"}, -- 0.961 urban (1.050 adm-urb) per citypopulation.de ["Guigang"] = {container = {key = "Guangxi, China", placetype = "autonomous region"}}, -- 0.921 urban (1.050 adm-urb) per citypopulation.de -- Liuyang is a "county-level city" of the "prefecture-level city" of Changsha but in fact is 47 miles away from Changsha city proper (urban core to urban core). ["Liuyang"] = {placetype = "county-level city", container = {key = "Changsha", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 0.886 urban (1.040 adm-urb) per citypopulation.de -- NOTE: Not to be confused with Changzhou in Jiangsu ["Cangzhou"] = {container = "Hebei"}, -- 7.3 prefectural, 621,000 urban; 0.759 urban (1.030 adm-urb) per citypopulation.de ["Liupanshui"] = {container = "Guizhou"}, -- < 0.750 urban (1.030 adm-urb) per citypopulation.de ["Panjin"] = {container = "Liaoning"}, -- 0.980 urban (1.030 adm-urb) per citypopulation.de ["Qiqihar"] = {container = "Heilongjiang"}, -- 1.030 urban (1.030 adm-urb) per citypopulation.de ["Linfen"] = {container = "Shanxi"}, -- < 0.750 urban (1.010 adm-urb) per citypopulation.de -- Tengzhou is a "county-level city" of the "prefecture-level city" of Zaozhuang but in fact is 30 miles away from Zaozhuang city proper (urban core to urban core). ["Tengzhou"] = {placetype = "county-level city", container = {key = "Zaozhuang", placetype = "prefecture-level city"}, divs = {"subdistricts", "townships"}}, -- 0.937 urban (1.010 adm-urb) per citypopulation.de -- 3 extra that got added in earlier incarnations and aren't found in the "major agglomerations of the world" page https://citypopulation.de/en/world/agglomerations/ reference date 2025-01-01 ["Kunshan"] = {container = "Jiangsu"}, -- 1.652 urban (2020 China census) per citypopulation.de ["Zhumadian"] = {container = "Henan"}, -- 7.0 prefectural, 722,000 urban per Wikipedia; 0.754 urban per citypopulation.de ["Bijie"] = {container = "Guizhou"}, -- 6.9 prefectural, ? urban, ? metro (not listed in Wikipedia); < 0.750 urban per citypopulation.de } export.china_prefecture_level_cities_group = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Taizhou, Zhejiang" or "Suzhou, Anhui". key_to_placename = false, placename_to_key = false, -- don't add ", China" to make the key default_container = "China", canonicalize_key_container = make_canonicalize_key_container(", China", "province"), -- Prefecture-level cities aren't really cities but allow them to be identified that way, as many people -- don't understand how Chinese administrative divisions work. default_placetype = {"prefecture-level city", "city"}, default_divs = { -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities, -- and prefecture-level cities (as well as county-level cities) are considered non-cities. "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_prefecture_level_cities, } -- Needed to avoid problems with two cities called Taizhou and Suzhou. export.china_prefecture_level_cities_2 = { -- NOTE: There is also a larger and better-known prefecture-level city Taizhou in Zhejiang. ["Taizhou, Jiangsu"] = {container = "Jiangsu"}, -- 1.3 urban (1.490 adm-urb) per citypopulation.de 2020 census ["Taizhou"] = {alias_of = "Taizhou, Jiangsu"}, -- NOTE: There is also a larger and better-known prefecture-level city Suzhou in Jiangsu. ["Suzhou, Anhui"] = {container = "Anhui"}, -- 5.3 prefectural, 1.766 metro and "urban"; < 1 urban (1.010 adm-urb) per citypopulation.de 2020 census -- hopefully this will work because we also have Suzhou as a key by itself for the larger, more-well-known Suzhou in Jiangsu ["Suzhou"] = {alias_of = "Suzhou, Anhui"}, } export.china_prefecture_level_cities_group_2 = { -- don't do any transformations between key and placename; in particular, don't chop off anything from -- "Taizhou, Jiangsu". placename_to_key = false, -- don't add ", China" to make the key default_container = "China", canonicalize_key_container = make_canonicalize_key_container(", China", "province"), -- Prefecture-level cities aren't really cities but allow them to be identified that way, as many people -- don't understand how Chinese administrative divisions work. default_placetype = {"prefecture-level city", "city"}, default_divs = { -- "towns" (but not "townships") are automatically added as they are specified as generic_before_non_cities, -- and prefecture-level cities (as well as county-level cities) are considered non-cities. "districts", "subdistricts", "townships", {type = "counties", cat_as = "counties and county-level cities"}, {type = "county-level cities", cat_as = "counties and county-level cities"}, }, data = export.china_prefecture_level_cities_2, } export.finland_regions = { ["Lapland, Finland"] = {wp = "%l (%c)"}, ["North Ostrobothnia, Finland"] = {}, ["Northern Ostrobothnia, Finland"] = {alias_of = "North Ostrobothnia, Finland", display = true}, ["Kainuu, Finland"] = {}, ["North Karelia, Finland"] = {}, ["Northern Savonia, Finland"] = {}, ["North Savo, Finland"] = {alias_of = "Northern Savonia, Finland", display = true}, ["Southern Savonia, Finland"] = {}, ["South Savo, Finland"] = {alias_of = "Southern Savonia, Finland", display = true}, ["South Karelia, Finland"] = {}, ["Central Finland, Finland"] = {}, ["South Ostrobothnia, Finland"] = {}, ["Southern Ostrobothnia, Finland"] = {alias_of = "South Ostrobothnia, Finland", display = true}, ["Ostrobothnia, Finland"] = {wp = "%l (region)"}, ["Central Ostrobothnia, Finland"] = {}, ["Pirkanmaa, Finland"] = {}, ["Satakunta, Finland"] = {}, ["Päijänne Tavastia, Finland"] = {}, ["Päijät-Häme, Finland"] = {alias_of = "Päijänne Tavastia, Finland", display = true}, ["Tavastia Proper, Finland"] = {}, ["Kanta-Häme, Finland"] = {alias_of = "Tavastia Proper, Finland", display = true}, ["Kymenlaakso, Finland"] = {}, ["Uusimaa, Finland"] = {}, ["Southwest Finland, Finland"] = {}, ["Åland Islands, Finland"] = {the = true, wp = "Åland"}, ["Åland, Finland"] = {alias_of = "Åland Islands, Finland"}, -- differs in "the" } -- regions of Finland export.finland_group = { default_container = "Finland", default_placetype = "region", default_divs = "municipalities", data = export.finland_regions, } export.france_administrative_regions = { ["Auvergne-Rhône-Alpes, France"] = {}, ["Bourgogne-Franche-Comté, France"] = {}, ["Brittany, France"] = {wp = "%l (administrative region)"}, ["Centre-Val de Loire, France"] = {}, ["Corsica, France"] = {}, -- overseas departments are handled in `export.country_like_entities` -- ["French Guiana"] = {}, ["Grand Est, France"] = {}, -- ["Guadeloupe"] = {}, ["Hauts-de-France, France"] = {}, ["Île-de-France, France"] = {}, -- ["Martinique"] = {}, -- ["Mayotte"] = {}, ["Normandy, France"] = {wp = "%l (administrative region)"}, ["Nouvelle-Aquitaine, France"] = {}, ["Occitania, France"] = {wp = "%l (administrative region)"}, ["Occitanie, France"] = {alias_of = "Occitania, France", display = true}, ["Pays de la Loire, France"] = {}, ["Provence-Alpes-Côte d'Azur, France"] = {}, -- ["Réunion"] = {}, } -- administrative regions of France export.france_group = { default_container = "France", -- Canonically these are 'administrative regions' but also treat as 'region' ('administrative region' falls back -- to 'region'). default_placetype = "region", default_divs = { "communes", {type = "municipalities", cat_as = "communes"}, "departments", {type = "prefectures", cat_as = {"prefectures", "departmental capitals"}}, {type = "French prefectures", cat_as = {"prefectures", "departmental capitals"}}, }, data = export.france_administrative_regions, } export.france_departments = { ["Ain, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 01 ["Aisne, France"] = {container = "Hauts-de-France"}, -- 02 ["Allier, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 03 ["Alpes-de-Haute-Provence, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 04 ["Hautes-Alpes, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 05 ["Alpes-Maritimes, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 06 ["Ardèche, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 07 ["Ardennes, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 08 ["Ariège, France"] = {container = "Occitania", wp = "%l (department)"}, -- 09 ["Aube, France"] = {container = "Grand Est"}, -- 10 ["Aude, France"] = {container = "Occitania"}, -- 11 ["Aveyron, France"] = {container = "Occitania"}, -- 12 ["Bouches-du-Rhône, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 13 ["Calvados, France"] = {container = "Normandy", wp = "%l (department)"}, -- 14 ["Cantal, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 15 ["Charente, France"] = {container = "Nouvelle-Aquitaine"}, -- 16 ["Charente-Maritime, France"] = {container = "Nouvelle-Aquitaine"}, -- 17 ["Cher, France"] = {container = "Centre-Val de Loire", wp = "%l (department)"}, -- 18 ["Corrèze, France"] = {container = "Nouvelle-Aquitaine"}, -- 19 ["Corse-du-Sud, France"] = {container = "Corsica"}, -- 2A ["Haute-Corse, France"] = {container = "Corsica"}, -- 2B ["Côte-d'Or, France"] = {container = "Bourgogne-Franche-Comté"}, -- 21 ["Côte d'Or, France"] = {alias_of = "Côte-d'Or, France", display = true}, ["Côtes-d'Armor, France"] = {container = "Brittany"}, -- 22 ["Côtes d'Armor, France"] = {alias_of = "Côtes-d'Armor, France", display = true}, ["Creuse, France"] = {container = "Nouvelle-Aquitaine"}, -- 23 ["Dordogne, France"] = {container = "Nouvelle-Aquitaine"}, -- 24 ["Doubs, France"] = {container = "Bourgogne-Franche-Comté"}, -- 25 ["Drôme, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 26 ["Eure, France"] = {container = "Normandy"}, -- 27 ["Eure-et-Loir, France"] = {container = "Centre-Val de Loire"}, -- 28 ["Finistère, France"] = {container = "Brittany"}, -- 29 ["Gard, France"] = {container = "Occitania"}, -- 30 ["Haute-Garonne, France"] = {container = "Occitania"}, -- 31 ["Gers, France"] = {container = "Occitania"}, -- 32 ["Gironde, France"] = {container = "Nouvelle-Aquitaine"}, -- 33 ["Hérault, France"] = {container = "Occitania"}, -- 34 ["Ille-et-Vilaine, France"] = {container = "Brittany"}, -- 35 ["Indre, France"] = {container = "Centre-Val de Loire"}, -- 36 ["Indre-et-Loire, France"] = {container = "Centre-Val de Loire"}, -- 37 ["Isère, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 38 ["Jura, France"] = {container = "Bourgogne-Franche-Comté", wp = "%l (department)"}, -- 39 ["Landes, France"] = {container = "Nouvelle-Aquitaine", wp = "%l (department)"}, -- 40 ["Loir-et-Cher, France"] = {container = "Centre-Val de Loire"}, -- 41 ["Loire, France"] = {container = "Auvergne-Rhône-Alpes", wp = "%l (department)"}, -- 42 ["Haute-Loire, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 43 ["Loire-Atlantique, France"] = {container = "Pays de la Loire"}, -- 44 ["Loiret, France"] = {container = "Centre-Val de Loire"}, -- 45 ["Lot, France"] = {container = "Occitania", wp = "%l (department)"}, -- 46 ["Lot-et-Garonne, France"] = {container = "Nouvelle-Aquitaine"}, -- 47 ["Lozère, France"] = {container = "Occitania"}, -- 48 ["Maine-et-Loire, France"] = {container = "Pays de la Loire"}, -- 49 ["Manche, France"] = {container = "Normandy"}, -- 50 ["Marne, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 51 ["Haute-Marne, France"] = {container = "Grand Est"}, -- 52 ["Mayenne, France"] = {container = "Pays de la Loire"}, -- 53 ["Meurthe-et-Moselle, France"] = {container = "Grand Est"}, -- 54 ["Meuse, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 55 ["Morbihan, France"] = {container = "Brittany"}, -- 56 ["Moselle, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 57 ["Nièvre, France"] = {container = "Bourgogne-Franche-Comté"}, -- 58 ["Nord, France"] = {container = "Hauts-de-France", wp = "%l (French department)"}, -- 59 ["Oise, France"] = {container = "Hauts-de-France"}, -- 60 ["Orne, France"] = {container = "Normandy"}, -- 61 ["Pas-de-Calais, France"] = {container = "Hauts-de-France"}, -- 62 ["Puy-de-Dôme, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 63 ["Pyrénées-Atlantiques, France"] = {container = "Nouvelle-Aquitaine"}, -- 64 ["Hautes-Pyrénées, France"] = {container = "Occitania"}, -- 65 ["Pyrénées-Orientales, France"] = {container = "Occitania"}, -- 66 ["Bas-Rhin, France"] = {container = "Grand Est"}, -- 67 ["Haut-Rhin, France"] = {container = "Grand Est"}, -- 68 ["Rhône, France"] = {container = "Auvergne-Rhône-Alpes", wp = "%l (department)"}, -- 69D ["Metropolis of Lyon, France"] = {container = "Auvergne-Rhône-Alpes", the = true}, -- 69M ["Lyon Metropolis, France"] = {alias_of = "Metropolis of Lyon, France"}, ["Lyon, France"] = {alias_of = "Metropolis of Lyon, France"}, ["Haute-Saône, France"] = {container = "Bourgogne-Franche-Comté"}, -- 70 ["Saône-et-Loire, France"] = {container = "Bourgogne-Franche-Comté"}, -- 71 ["Sarthe, France"] = {container = "Pays de la Loire"}, -- 72 ["Savoie, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 73 ["Haute-Savoie, France"] = {container = "Auvergne-Rhône-Alpes"}, -- 74 ["Paris, France"] = {container = "Île-de-France"}, -- 75 ["Seine-Maritime, France"] = {container = "Normandy"}, -- 76 ["Seine-et-Marne, France"] = {container = "Île-de-France"}, -- 77 ["Yvelines, France"] = {container = "Île-de-France"}, -- 78 ["Deux-Sèvres, France"] = {container = "Nouvelle-Aquitaine"}, -- 79 ["Somme, France"] = {container = "Hauts-de-France", wp = "%l (department)"}, -- 80 ["Tarn, France"] = {container = "Occitania", wp = "%l (department)"}, -- 81 ["Tarn-et-Garonne, France"] = {container = "Occitania"}, -- 82 ["Var, France"] = {container = "Provence-Alpes-Côte d'Azur", wp = "%l (department)"}, -- 83 ["Vaucluse, France"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 84 ["Vendée, France"] = {container = "Pays de la Loire"}, -- 85 ["Vienne, France"] = {container = "Nouvelle-Aquitaine", wp = "%l (department)"}, -- 86 ["Haute-Vienne, France"] = {container = "Nouvelle-Aquitaine"}, -- 87 ["Vosges, France"] = {container = "Grand Est", wp = "%l (department)"}, -- 88 ["Yonne, France"] = {container = "Bourgogne-Franche-Comté"}, -- 89 ["Territoire de Belfort, France"] = {container = "Bourgogne-Franche-Comté"}, -- 90 ["Essonne, France"] = {container = "Île-de-France"}, -- 91 ["Hauts-de-Seine, France"] = {container = "Île-de-France"}, -- 92 ["Seine-Saint-Denis, France"] = {container = "Île-de-France"}, -- 93 ["Val-de-Marne, France"] = {container = "Île-de-France"}, -- 94 ["Val-d'Oise, France"] = {container = "Île-de-France"}, -- 95 --["Guadeloupe"] = {container = "Guadeloupe"}, -- 971 --["Martinique"] = {container = "Martinique"}, -- 972 --["Guyane"] = {container = "French Guiana", wp = "French Guiana"}, -- 973 --["La Réunion"] = {container = "Réunion", wp = "Réunion"}, -- 974 --["Mayotte"] = {container = "Mayotte"}, -- 976 } export.france_departments_group = { placename_to_key = make_placename_to_key(", France"), canonicalize_key_container = make_canonicalize_key_container(", France", "region"), default_placetype = "department", default_divs = { "communes", {type = "municipalities", cat_as = "communes"}, }, data = export.france_departments, } export.germany_states = { ["Baden-Württemberg, Germany"] = {}, ["Bavaria, Germany"] = {}, -- Berlin, Bremen and Hamburg are effectively city-states and don't have districts ([[Kreise]]), so override -- the default_divs setting. Better not to include them at all since they're included as cities down below. -- ["Berlin"] = {divs = {}}, ["Brandenburg, Germany"] = {}, -- ["Bremen"] = {divs = {}}, -- ["Hamburg"] = {divs = {}}, ["Hesse, Germany"] = {}, ["Lower Saxony, Germany"] = {}, ["Mecklenburg-Vorpommern, Germany"] = {}, ["Mecklenburg-Western Pomerania, Germany"] = {alias_of = "Mecklenburg-Vorpommern, Germany", display = true}, ["North Rhine-Westphalia, Germany"] = {}, ["Rhineland-Palatinate, Germany"] = {}, ["Saarland, Germany"] = {}, ["Saxony, Germany"] = {}, ["Saxony-Anhalt, Germany"] = {}, ["Schleswig-Holstein, Germany"] = {}, ["Thuringia, Germany"] = {}, } -- states of Germany export.germany_group = { default_container = "Germany", default_placetype = "state", default_divs = {"districts", "municipalities"}, data = export.germany_states, } export.greece_regions = { ["Attica, Greece"] = {wp = "%l (region)"}, ["Central Greece, Greece"] = {wp = "%l (administrative region)"}, ["Central Macedonia, Greece"] = {}, ["Crete, Greece"] = {}, ["Eastern Macedonia and Thrace, Greece"] = {}, ["Epirus, Greece"] = {wp = "%l (region)"}, ["Ionian Islands, Greece"] = {the = true, wp = "%l (region)"}, ["North Aegean, Greece"] = {the = true}, -- I would expect 'the Peloponnese' but Wikipedia mostly has categories like [[w:Category:Geography of Peloponnese (region)]] -- and [[w:Category:Buildings and structures in Peloponnese (region)]]; only [[w:Category:People from the Peloponnese (region)]] -- has "the" in it. ["Peloponnese, Greece"] = {wp = "%l (region)"}, ["South Aegean, Greece"] = {the = true}, ["Thessaly, Greece"] = {}, ["Western Greece, Greece"] = {}, ["Western Macedonia, Greece"] = {}, ["Mount Athos, Greece"] = {placetype = {"autonomous region", "region"}, wp = "Monastic community of Mount Athos"}, } -- regions of Greece export.greece_group = { default_container = "Greece", default_placetype = "region", data = export.greece_regions, } local india_polity_with_divisions = {"divisions", "districts"} local india_polity_without_divisions = {"districts"} -- States and union territories of India. Only some of them are divided into divisions. export.india_states_and_union_territories = { ["Andaman and Nicobar Islands, India"] = {the = true, placetype = "union territory", divs = india_polity_without_divisions}, ["Andhra Pradesh, India"] = {divs = india_polity_without_divisions}, ["Arunachal Pradesh, India"] = {divs = india_polity_with_divisions}, ["Assam, India"] = {divs = india_polity_with_divisions}, ["Bihar, India"] = {divs = india_polity_with_divisions}, ["Chandigarh, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Chhattisgarh, India"] = {divs = india_polity_with_divisions}, ["Dadra and Nagar Haveli and Daman and Diu, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Delhi, India"] = {placetype = "union territory", divs = india_polity_with_divisions}, ["Goa, India"] = {divs = india_polity_without_divisions}, ["Gujarat, India"] = {divs = india_polity_without_divisions}, ["Haryana, India"] = {divs = india_polity_with_divisions}, ["Himachal Pradesh, India"] = {divs = india_polity_with_divisions}, ["Jammu and Kashmir, India"] = {placetype = "union territory", divs = india_polity_with_divisions, wp = "%l (union territory)"}, ["Jharkhand, India"] = {divs = india_polity_with_divisions}, ["Karnataka, India"] = {divs = india_polity_with_divisions}, ["Kerala, India"] = {divs = india_polity_without_divisions}, ["Ladakh, India"] = {placetype = "union territory", divs = india_polity_with_divisions}, ["Lakshadweep, India"] = {placetype = "union territory", divs = india_polity_without_divisions}, ["Madhya Pradesh, India"] = {divs = india_polity_with_divisions}, ["Maharashtra, India"] = {divs = india_polity_with_divisions}, ["Manipur, India"] = {divs = india_polity_without_divisions}, ["Meghalaya, India"] = {divs = india_polity_with_divisions}, ["Mizoram, India"] = {divs = india_polity_without_divisions}, ["Nagaland, India"] = {divs = india_polity_with_divisions}, ["Odisha, India"] = {divs = india_polity_with_divisions}, ["Puducherry, India"] = {placetype = "union territory", divs = india_polity_without_divisions, wp = "%l (union territory)"}, ["Pondicherry, India"] = {alias_of = "Puducherry, India", display = true}, ["Punjab, India"] = {divs = india_polity_with_divisions, wp = "%l, %c"}, ["Rajasthan, India"] = {divs = india_polity_with_divisions}, ["Sikkim, India"] = {divs = india_polity_without_divisions}, ["Tamil Nadu, India"] = {divs = india_polity_without_divisions}, ["Telangana, India"] = {divs = india_polity_without_divisions}, ["Tripura, India"] = {divs = india_polity_without_divisions}, ["Uttar Pradesh, India"] = {divs = india_polity_with_divisions}, ["Uttarakhand, India"] = {divs = india_polity_with_divisions}, ["West Bengal, India"] = {divs = india_polity_with_divisions}, } -- states and union territories of India export.india_group = { default_container = "India", default_placetype = "state", data = export.india_states_and_union_territories, } export.indonesia_provinces = { ["Aceh, Indonesia"] = {}, ["Bali, Indonesia"] = {}, ["Bangka Belitung Islands, Indonesia"] = {the = true}, ["Banten, Indonesia"] = {}, ["Bengkulu, Indonesia"] = {}, ["Central Java, Indonesia"] = {}, ["Central Kalimantan, Indonesia"] = {}, ["Central Papua, Indonesia"] = {}, ["Central Sulawesi, Indonesia"] = {}, ["East Java, Indonesia"] = {}, ["East Kalimantan, Indonesia"] = {}, ["East Nusa Tenggara, Indonesia"] = {}, ["Gorontalo, Indonesia"] = {}, ["Highland Papua, Indonesia"] = {wp = "%l"}, ["Special Capital Region of Jakarta, Indonesia"] = {the = true, wp = "Jakarta"}, ["Jakarta, Indonesia"] = {alias_of = "Special Capital Region of Jakarta, Indonesia"}, ["Jambi, Indonesia"] = {}, ["Lampung, Indonesia"] = {}, ["Maluku, Indonesia"] = {}, ["North Kalimantan, Indonesia"] = {}, ["North Maluku, Indonesia"] = {}, ["North Sulawesi, Indonesia"] = {}, ["North Papua, Indonesia"] = {}, ["North Sumatra, Indonesia"] = {}, ["Papua, Indonesia"] = {wp = "%l (province)"}, ["Riau, Indonesia"] = {}, ["Riau Islands, Indonesia"] = {the = true}, ["Southeast Sulawesi, Indonesia"] = {}, ["South Kalimantan, Indonesia"] = {}, ["South Papua, Indonesia"] = {}, ["South Sulawesi, Indonesia"] = {}, ["South Sumatra, Indonesia"] = {}, ["Southwest Papua, Indonesia"] = {}, ["West Java, Indonesia"] = {}, ["West Kalimantan, Indonesia"] = {}, ["West Nusa Tenggara, Indonesia"] = {}, ["West Papua, Indonesia"] = {wp = "%l (province)"}, ["West Sulawesi, Indonesia"] = {}, ["West Sumatra, Indonesia"] = {}, ["Special Region of Yogyakarta, Indonesia"] = {the = true}, ["Yogyakarta, Indonesia"] = {alias_of = "Special Region of Yogyakarta, Indonesia"}, } -- provinces of Indonesia export.indonesia_group = { default_container = "Indonesia", default_placetype = "province", -- per https://www.quora.com/Does-Indonesia-use-British-or-American-English, Indonesia tends to use American -- spellings. data = export.indonesia_provinces, } export.iran_provinces = { ["Alborz Province, Iran"] = {}, -- abbreviation AL, capital [[w:Karaj]] ["Ardabil Province, Iran"] = {}, -- abbreviation AR, capital [[w:Ardabil]] ["Bushehr Province, Iran"] = {}, -- abbreviation BU, capital [[w:Bushehr]] ["Chaharmahal and Bakhtiari Province, Iran"] = {}, -- abbreviation CB, capital [[w:Shahr-e Kord]] ["East Azerbaijan Province, Iran"] = {}, -- abbreviation EA, capital [[w:Tabriz]] ["Fars Province, Iran"] = {}, -- abbreviation FA, capital [[w:Shiraz]] ["Pars Province, Iran"] = {alias_of = "Fars Province, Iran", display = true}, ["Gilan Province, Iran"] = {}, -- abbreviation GN, capital [[w:Rasht]] ["Golestan Province, Iran"] = {}, -- abbreviation GO, capital [[w:Gorgan]] ["Hamadan Province, Iran"] = {}, -- abbreviation HA, capital [[w:Hamadan]] ["Hormozgan Province, Iran"] = {}, -- abbreviation HO, capital [[w:Bandar Abbas]] ["Ilam Province, Iran"] = {}, -- abbreviation IL, capital [[w:Ilam, Iran|Ilam]] ["Isfahan Province, Iran"] = {}, -- abbreviation IS, capital [[w:Isfahan]] ["Kerman Province, Iran"] = {}, -- abbreviation KN, capital [[w:Kerman]] ["Kermanshah Province, Iran"] = {}, -- abbreviation KE, capital [[w:Kermanshah]] ["Khuzestan Province, Iran"] = {}, -- abbreviation KH, capital [[w:Ahvaz]] ["Kohgiluyeh and Boyer-Ahmad Province, Iran"] = {}, -- abbreviation KB, capital [[w:Yasuj]] ["Kurdistan Province, Iran"] = {}, -- abbreviation KU, capital [[w:Sanandaj]] ["Lorestan Province, Iran"] = {}, -- abbreviation LO, capital [[w:Khorramabad]] ["Markazi Province, Iran"] = {}, -- abbreviation MA, capital [[w:Arak, Iran|Arak]] ["Mazandaran Province, Iran"] = {}, -- abbreviation MN, capital [[w:Sari, Iran|Sari]] ["North Khorasan Province, Iran"] = {}, -- abbreviation NK, capital [[w:Bojnord]] ["Qazvin Province, Iran"] = {}, -- abbreviation QA, capital [[w:Qazvin]] ["Qom Province, Iran"] = {}, -- abbreviation QM, capital [[w:Qom]] ["Razavi Khorasan Province, Iran"] = {}, -- abbreviation RK, capital [[w:Mashhad]] ["Semnan Province, Iran"] = {}, -- abbreviation SE, capital [[w:Semnan, Iran|Semnan]] ["Sistan and Baluchestan Province, Iran"] = {}, -- abbreviation SB, capital [[w:Zahedan]] ["South Khorasan Province, Iran"] = {}, -- abbreviation SK, capital [[w:Birjand]] ["Tehran Province, Iran"] = {}, -- abbreviation TE, capital [[w:Tehran]] ["West Azerbaijan Province, Iran"] = {}, -- abbreviation WA, capital [[w:Urmia]] ["Yazd Province, Iran"] = {}, -- abbreviation YA, capital [[w:Yazd]] ["Zanjan Province, Iran"] = {}, -- abbreviation ZA, capital [[w:Zanjan, Iran|Zanjan]] } -- provinces of Iran export.iran_group = { key_to_placename = make_key_to_placename(", Iran", " Province$"), placename_to_key = make_placename_to_key(", Iran", " Province"), default_container = "Iran", default_placetype = "province", -- There aren't nearly enough counties of Iran currently entered in any language to allow for categorizing them -- per-province. (As of 2025-05-09, there are only 6 counties in each of [[Category:en:Counties of Iran]], -- [[Category:fa:Counties of Iran]] and [[Category:ar:Counties of Iran]].) -- default_divs = "counties", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.iran_provinces, } export.ireland_counties = { ["County Carlow, Ireland"] = {}, ["County Cavan, Ireland"] = {}, ["County Clare, Ireland"] = {}, ["County Cork, Ireland"] = {}, ["County Donegal, Ireland"] = {}, ["County Dublin, Ireland"] = {}, ["County Galway, Ireland"] = {}, ["County Kerry, Ireland"] = {}, ["County Kildare, Ireland"] = {}, ["County Kilkenny, Ireland"] = {}, ["County Laois, Ireland"] = {}, ["County Leitrim, Ireland"] = {}, ["County Limerick, Ireland"] = {}, ["County Longford, Ireland"] = {}, ["County Louth, Ireland"] = {}, ["County Mayo, Ireland"] = {}, ["County Meath, Ireland"] = {}, ["County Monaghan, Ireland"] = {}, ["County Offaly, Ireland"] = {}, ["County Roscommon, Ireland"] = {}, ["County Sligo, Ireland"] = {}, ["County Tipperary, Ireland"] = {}, ["County Waterford, Ireland"] = {}, ["County Westmeath, Ireland"] = {}, ["County Wexford, Ireland"] = {}, ["County Wicklow, Ireland"] = {}, } local function make_irish_type_key_to_placename(container_pattern) return function(key) key = key:gsub(container_pattern, "") local elliptical_key = key:gsub("^County ", "") return key, elliptical_key end end local function make_irish_type_placename_to_key(container_suffix) return function(placename) if not placename:find("^County ") and not placename:find("^City ") then placename = "County " .. placename end return placename .. container_suffix end end -- counties of Ireland export.ireland_group = { key_to_placename = make_irish_type_key_to_placename(", Ireland$"), placename_to_key = make_irish_type_placename_to_key(", Ireland"), default_container = "Ireland", default_placetype = "county", data = export.ireland_counties, } export.italy_administrative_regions = { ["Abruzzo, Italy"] = {}, ["Aosta Valley, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Apulia, Italy"] = {}, ["Basilicata, Italy"] = {}, ["Calabria, Italy"] = {}, ["Campania, Italy"] = {}, ["Emilia-Romagna, Italy"] = {}, ["Friuli-Venezia Giulia, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Lazio, Italy"] = {}, ["Liguria, Italy"] = {}, ["Lombardy, Italy"] = {}, ["Marche, Italy"] = {}, ["Molise, Italy"] = {}, ["Piedmont, Italy"] = {}, ["Sardinia, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Sicily, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Trentino-Alto Adige, Italy"] = {placetype = {"autonomous region", "administrative region", "region"}}, ["Tuscany, Italy"] = {}, ["Umbria, Italy"] = {}, ["Veneto, Italy"] = {}, } -- administrative regions of Italy export.italy_group = { default_container = "Italy", default_placetype = "region", data = export.italy_administrative_regions, } -- table of Japanese prefectures; interpolated into the main 'places' table, but also needed separately export.japan_prefectures = { ["Aichi Prefecture, Japan"] = {}, ["Akita Prefecture, Japan"] = {}, ["Aomori Prefecture, Japan"] = {}, ["Chiba Prefecture, Japan"] = {}, ["Ehime Prefecture, Japan"] = {}, ["Fukui Prefecture, Japan"] = {}, ["Fukuoka Prefecture, Japan"] = {}, ["Fukushima Prefecture, Japan"] = {}, ["Gifu Prefecture, Japan"] = {}, ["Gunma Prefecture, Japan"] = {}, ["Hiroshima Prefecture, Japan"] = {}, ["Hokkaido Prefecture, Japan"] = {divs = "subprefectures", wp = "Hokkaido"}, ["Hyōgo Prefecture, Japan"] = {}, ["Hyogo Prefecture, Japan"] = {alias_of = "Hyōgo Prefecture, Japan", display = true}, ["Ibaraki Prefecture, Japan"] = {}, ["Ishikawa Prefecture, Japan"] = {}, ["Iwate Prefecture, Japan"] = {}, ["Kagawa Prefecture, Japan"] = {}, ["Kagoshima Prefecture, Japan"] = {}, ["Kanagawa Prefecture, Japan"] = {}, ["Kōchi Prefecture, Japan"] = {}, ["Kochi Prefecture, Japan"] = {alias_of = "Kōchi Prefecture, Japan", display = true}, ["Kumamoto Prefecture, Japan"] = {}, ["Kyoto Prefecture, Japan"] = {}, ["Mie Prefecture, Japan"] = {}, ["Miyagi Prefecture, Japan"] = {}, ["Miyazaki Prefecture, Japan"] = {}, ["Nagano Prefecture, Japan"] = {}, ["Nagasaki Prefecture, Japan"] = {}, ["Nara Prefecture, Japan"] = {}, ["Niigata Prefecture, Japan"] = {}, ["Ōita Prefecture, Japan"] = {}, ["Oita Prefecture, Japan"] = {alias_of = "Ōita Prefecture, Japan", display = true}, ["Okayama Prefecture, Japan"] = {}, ["Okinawa Prefecture, Japan"] = {}, ["Osaka Prefecture, Japan"] = {}, ["Saga Prefecture, Japan"] = {}, ["Saitama Prefecture, Japan"] = {}, ["Shiga Prefecture, Japan"] = {}, ["Shimane Prefecture, Japan"] = {}, ["Shizuoka Prefecture, Japan"] = {}, ["Tochigi Prefecture, Japan"] = {}, ["Tokushima Prefecture, Japan"] = {}, ["Tottori Prefecture, Japan"] = {}, ["Toyama Prefecture, Japan"] = {}, ["Wakayama Prefecture, Japan"] = {}, ["Yamagata Prefecture, Japan"] = {}, ["Yamaguchi Prefecture, Japan"] = {}, ["Yamanashi Prefecture, Japan"] = {}, } -- prefectures of Japan export.japan_group = { key_to_placename = make_key_to_placename(", Japan$", " Prefecture$"), placename_to_key = make_placename_to_key(", Japan", " Prefecture"), default_container = "Japan", default_placetype = "prefecture", data = export.japan_prefectures, } export.laos_provinces = { ["Attapeu Province, Laos"] = {}, ["Bokeo Province, Laos"] = {}, ["Bolikhamxai Province, Laos"] = {}, ["Champasak Province, Laos"] = {}, ["Houaphanh Province, Laos"] = {}, ["Khammouane Province, Laos"] = {}, ["Luang Namtha Province, Laos"] = {}, ["Luang Prabang Province, Laos"] = {}, ["Oudomxay Province, Laos"] = {}, ["Phongsaly Province, Laos"] = {}, ["Salavan Province, Laos"] = {}, ["Savannakhet Province, Laos"] = {}, ["Vientiane Province, Laos"] = {}, ["Vientiane Prefecture, Laos"] = {placetype = "prefecture", wp = "%l"}, ["Sainyabuli Province, Laos"] = {}, ["Sekong Province, Laos"] = {}, ["Xaisomboun Province, Laos"] = {}, ["Xiangkhouang Province, Laos"] = {}, } local function laos_placename_to_key(placename) if placename == "Vientiane Prefecture" then return placename .. ", Laos" end if placename:find(" Province$") then return placename .. ", Laos" end return placename .. " Province, Laos" end -- provinces of Laos export.laos_group = { key_to_placename = make_key_to_placename(", Laos$", {" Province$", " Prefecture$"}), placename_to_key = laos_placename_to_key, default_container = "Laos", default_placetype = "province", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.laos_provinces, } export.lebanon_governorates = { ["Akkar Governorate, Lebanon"] = {}, ["Baalbek-Hermel Governorate, Lebanon"] = {}, ["Beirut Governorate, Lebanon"] = {}, ["Beqaa Governorate, Lebanon"] = {}, ["Keserwan-Jbeil Governorate, Lebanon"] = {}, ["Mount Lebanon Governorate, Lebanon"] = {}, ["Nabatieh Governorate, Lebanon"] = {}, -- These two are generic enough that we don't want to automatically augment a use of `gov/North Governorate` or -- `gov/South Governorate` with `c/Lebanon`. ["North Governorate, Lebanon"] = {no_auto_augment_container = true}, ["South Governorate, Lebanon"] = {no_auto_augment_container = true}, } -- governorates of Lebanon export.lebanon_group = { key_to_placename = make_key_to_placename(", Lebanon$", " Governorate$"), placename_to_key = make_placename_to_key(", Lebanon", " Governorate"), default_container = "Lebanon", default_placetype = "governorate", data = export.lebanon_governorates, } export.malaysia_states = { ["Johor, Malaysia"] = {}, ["Kedah, Malaysia"] = {}, ["Kelantan, Malaysia"] = {}, ["Malacca, Malaysia"] = {}, ["Negeri Sembilan, Malaysia"] = {}, ["Pahang, Malaysia"] = {}, ["Penang, Malaysia"] = {}, ["Perak, Malaysia"] = {}, ["Perlis, Malaysia"] = {}, ["Sabah, Malaysia"] = {}, ["Sarawak, Malaysia"] = {}, ["Selangor, Malaysia"] = {}, ["Terengganu, Malaysia"] = {}, } -- states of Malaysia export.malaysia_group = { default_container = "Malaysia", default_placetype = "state", default_wp = "%l, %c", data = export.malaysia_states, } export.malta_regions = { -- Some of the regions are generic enough that we don't want to automatically augment a use of e.g. -- `r/Northern Region` with `c/Malta`. In particular; -- * "Eastern Region" also occurs at least in Ghana, Uganda, Iceland, Nigeria, Venezuela, North Macedonia and -- El Salvador; -- * "Northern Region" also occurs at least in Ghana, Uganda, Malawi, Nigeria, Canada and South Africa; -- * "Western Region" also occurs at least in Abu Dhabi, Bahrain, South Africa, Ghana, Iceland, Nepal, Nigeria, -- Serbia and Uganda; -- * "Southern Region" also occurs at least in Nigeria, Eritrea, Iceland, Ireland, Malawi and Serbia. ["Eastern Region, Malta"] = {no_auto_augment_container = true}, ["Gozo Region, Malta"] = {wp = "%l"}, ["Northern Region, Malta"] = {no_auto_augment_container = true}, ["Port Region, Malta"] = {}, ["Southern Region, Malta"] = {no_auto_augment_container = true}, ["Western Region, Malta"] = {no_auto_augment_container = true}, } -- regions of Malta export.malta_group = { key_to_placename = make_key_to_placename(", Malta$", " Region"), placename_to_key = make_placename_to_key(", Malta", " Region"), default_container = "Malta", default_placetype = "region", default_wp = "%l, %c", default_the = true, data = export.malta_regions, } export.mexico_states = { ["Aguascalientes, Mexico"] = {}, ["Baja California, Mexico"] = {}, -- not display-canonicalizing because the "Norte" could be for emphasis ["Baja California Norte, Mexico"] = {alias_of = "Baja California, Mexico"}, ["Baja California Sur, Mexico"] = {}, ["Campeche, Mexico"] = {}, ["Chiapas, Mexico"] = {}, ["Chihuahua, Mexico"] = {wp = "%l (state)"}, ["Coahuila, Mexico"] = {}, ["Colima, Mexico"] = {}, ["Durango, Mexico"] = {}, ["Guanajuato, Mexico"] = {}, ["Guerrero, Mexico"] = {}, ["Hidalgo, Mexico"] = {wp = "%l (state)"}, ["Jalisco, Mexico"] = {}, ["State of Mexico, Mexico"] = {the = true}, ["Mexico, Mexico"] = {alias_of = "State of Mexico, Mexico"}, -- differs in "the" -- ["Mexico City, Mexico"] = {}, doesn't belong here because it's a city ["Michoacán, Mexico"] = {}, ["Michoacan, Mexico"] = {alias_of = "Michoacán, Mexico", display = true}, ["Morelos, Mexico"] = {}, ["Nayarit, Mexico"] = {}, ["Nuevo León, Mexico"] = {}, ["Nuevo Leon, Mexico"] = {alias_of = "Nuevo León, Mexico", display = true}, ["Oaxaca, Mexico"] = {}, ["Puebla, Mexico"] = {}, ["Querétaro, Mexico"] = {}, ["Queretaro, Mexico"] = {alias_of = "Querétaro, Mexico", display = true}, ["Quintana Roo, Mexico"] = {}, ["San Luis Potosí, Mexico"] = {}, ["San Luis Potosi, Mexico"] = {alias_of = "San Luis Potosí, Mexico", display = true}, ["Sinaloa, Mexico"] = {}, ["Sonora, Mexico"] = {}, ["Tabasco, Mexico"] = {}, ["Tamaulipas, Mexico"] = {}, ["Tlaxcala, Mexico"] = {}, ["Veracruz, Mexico"] = {}, ["Yucatán, Mexico"] = {}, ["Yucatan, Mexico"] = {alias_of = "Yucatán, Mexico", display = true}, ["Zacatecas, Mexico"] = {}, } -- Mexican states export.mexico_group = { default_container = "Mexico", default_placetype = "state", data = export.mexico_states, } export.moldova_districts_and_autonomous_territorial_units = { ["Anenii Noi District, Moldova"] = {}, -- capital [[Anenii Noi]] ["Basarabeasca District, Moldova"] = {}, -- capital [[Basarabeasca]] ["Briceni District, Moldova"] = {}, -- capital [[Briceni]] ["Cahul District, Moldova"] = {}, -- capital [[Cahul]] ["Cantemir District, Moldova"] = {}, -- capital [[Cantemir, Moldova|Cantemir]] ["Călărași District, Moldova"] = {}, -- capital [[Călărași, Moldova|Călărași]] ["Căușeni District, Moldova"] = {}, -- capital [[Căușeni]] ["Cimișlia District, Moldova"] = {}, -- capital [[Cimișlia]] ["Criuleni District, Moldova"] = {}, -- capital [[Criuleni]] ["Dondușeni District, Moldova"] = {}, -- capital [[Dondușeni]] ["Drochia District, Moldova"] = {}, -- capital [[Drochia]] ["Dubăsari District, Moldova"] = {}, -- capital [[Cocieri]] ["Edineț District, Moldova"] = {}, -- capital [[Edineț]] ["Fălești District, Moldova"] = {}, -- capital [[Fălești]] ["Florești District, Moldova"] = {}, -- capital [[Florești, Moldova|Florești]] ["Glodeni District, Moldova"] = {}, -- capital [[Glodeni]] ["Hîncești District, Moldova"] = {}, -- capital [[Hîncești]] ["Ialoveni District, Moldova"] = {}, -- capital [[Ialoveni]] ["Leova District, Moldova"] = {}, -- capital [[Leova]] ["Nisporeni District, Moldova"] = {}, -- capital [[Nisporeni]] ["Ocnița District, Moldova"] = {}, -- capital [[Ocnița]] ["Orhei District, Moldova"] = {}, -- capital [[Orhei]] ["Rezina District, Moldova"] = {}, -- capital [[Rezina]] ["Rîșcani District, Moldova"] = {}, -- capital [[Rîșcani]] ["Sîngerei District, Moldova"] = {}, -- capital [[Sîngerei]] ["Soroca District, Moldova"] = {}, -- capital [[Soroca]] ["Strășeni District, Moldova"] = {}, -- capital [[Strășeni]] ["Șoldănești District, Moldova"] = {}, -- capital [[Șoldănești]] ["Ștefan Vodă District, Moldova"] = {}, -- capital [[Ștefan Vodă]] ["Taraclia District, Moldova"] = {}, -- capital [[Taraclia]] ["Telenești District, Moldova"] = {}, -- capital [[Telenești]] ["Ungheni District, Moldova"] = {}, -- capital [[Ungheni]] ["Chișinău, Moldova"] = {placetype = "municipality"}, ["Bălți, Moldova"] = {placetype = "municipality"}, ["Gagauzia, Moldova"] = {placetype = {"autonomous territorial unit", "autonomous region", "region"}}, -- capital [[Comrat]] -- the remainder are under the de-facto control of the unrecognized state of Transnistria ["Bender, Moldova"] = {placetype = "municipality"}, ["Tighina, Moldova"] = {alias_of = "Bender, Moldova"}, ["Transnistria, Moldova"] = {placetype = {"autonomous territorial unit", "autonomous region", "region"}}, -- capital [[Tiraspol]] ["Left Bank of the Dniester, Moldova"] = {alias_of = "Transnistria, Moldova", the = true}, ["Administrative-Territorial Units of the Left Bank of the Dniester, Moldova"] = {alias_of = "Transnistria, Moldova", the = true}, } local function moldova_placename_to_key(placename) local elliptical_key = placename .. ", Moldova" if export.moldova_districts_and_autonomous_territorial_units[elliptical_key] then return elliptical_key end if placename:find(" District$") then return placename .. ", Moldova" end return placename .. " District, Moldova" end -- Moldovan districts (raions) and autonomous territorial units export.moldova_group = { key_to_placename = make_key_to_placename(", Moldova$", " District"), placename_to_key = moldova_placename_to_key, default_container = "Moldova", default_placetype = {"district", "raion"}, default_divs = "communes", data = export.moldova_districts_and_autonomous_territorial_units, } export.morocco_regions = { ["Tangier-Tetouan-Al Hoceima, Morocco"] = {}, ["Oriental, Morocco"] = {wp = "%l (%c)"}, ["L'Oriental, Morocco"] = {alias_of = "Oriental, Morocco", display = true}, ["Fez-Meknes, Morocco"] = {}, ["Rabat-Sale-Kenitra, Morocco"] = {wp = "Rabat-Salé-Kénitra"}, ["Rabat-Salé-Kénitra, Morocco"] = {alias_of = "Rabat-Sale-Kenitra, Morocco", display = true}, ["Beni Mellal-Khenifra, Morocco"] = {wp = "Béni Mellal-Khénifra"}, ["Béni Mellal-Khénifra, Morocco"] = {alias_of = "Beni Mellal-Khenifra, Morocco", display = true}, ["Casablanca-Settat, Morocco"] = {}, ["Marrakesh-Safi, Morocco"] = {wp = "Marrakesh–Safi"}, -- WP title has en-dash ["Marrakech-Safi, Morocco"] = {alias_of = "Marrakesh-Safi, Morocco", display = true}, ["Draa-Tafilalet, Morocco"] = {wp = "Drâa-Tafilalet"}, ["Drâa-Tafilalet, Morocco"] = {alias_of = "Draa-Tafilalet, Morocco", display = true}, ["Souss-Massa, Morocco"] = {}, ["Guelmim-Oued Noun, Morocco"] = { keydesc = "+++. '''NOTE:''' This region lies partly within the disputed territory of [[Western Sahara]]" }, ["Laayoune-Sakia El Hamra, Morocco"] = { wp = "Laâyoune-Sakia El Hamra", keydesc = "+++. '''NOTE:''' This region lies almost completely within the disputed territory of [[Western Sahara]]", }, ["Laâyoune-Sakia El Hamra, Morocco"] = {alias_of = "Laayoune-Sakia El Hamra, Morocco", display = true}, ["Dakhla-Oued Ed-Dahab, Morocco"] = { keydesc = "+++. '''NOTE:''' This region lies completely within the disputed territory of [[Western Sahara]]", }, } -- regions of Morocco export.morocco_group = { default_container = "Morocco", default_placetype = "region", data = export.morocco_regions, } export.egypt_governorates = { ["Cairo Governorate, Egypt"] = {}, ["Giza Governorate, Egypt"] = {}, ["Sharqia Governorate, Egypt"] = {}, ["Dakahlia Governorate, Egypt"] = {}, ["Beheira Governorate, Egypt"] = {}, ["Minya Governorate, Egypt"] = {}, ["Qalyubia Governorate, Egypt"] = {}, ["Sohag Governorate, Egypt"] = {}, ["Alexandria Governorate, Egypt"] = {}, ["Gharbia Governorate, Egypt"] = {}, ["Asyut Governorate, Egypt"] = {}, ["Monufia Governorate, Egypt"] = {}, ["Faiyum Governorate, Egypt"] = {}, ["Kafr El Sheikh Governorate, Egypt"] = {}, ["Qena Governorate, Egypt"] = {}, ["Beni Suef Governorate, Egypt"] = {}, ["Damietta Governorate, Egypt"] = {}, ["Aswan Governorate, Egypt"] = {}, ["Ismailia Governorate, Egypt"] = {}, ["Luxor Governorate, Egypt"] = {}, ["Suez Governorate, Egypt"] = {}, ["Port Said Governorate, Egypt"] = {}, ["Matrouh Governorate, Egypt"] = {}, ["North Sinai Governorate, Egypt"] = {}, ["Red Sea Governorate, Egypt"] = {}, ["New Valley Governorate, Egypt"] = {}, ["South Sinai Governorate, Egypt"] = {}, } -- governorates of Egypt export.egypt_group = { key_to_placename = make_key_to_placename(", Egypt$", " Governorate$"), placename_to_key = make_placename_to_key(", Egypt", " Governorate"), default_container = "Egypt", default_placetype = "governorate", data = export.egypt_governorates, } export.netherlands_provinces = { ["Drenthe, Netherlands"] = {}, ["Flevoland, Netherlands"] = {}, ["Friesland, Netherlands"] = {}, ["Gelderland, Netherlands"] = {}, ["Groningen, Netherlands"] = {wp = "%l (province)"}, ["Limburg, Netherlands"] = {wp = "%l (%c)"}, ["North Brabant, Netherlands"] = {}, -- Foreign forms get display-canonicalized. ["Noord-Brabant, Netherlands"] = {alias_of = "North Brabant, Netherlands", display = true}, ["North Holland, Netherlands"] = {}, ["Noord-Holland, Netherlands"] = {alias_of = "North Holland, Netherlands", display = true}, ["Overijssel, Netherlands"] = {}, ["South Holland, Netherlands"] = {}, ["Zuid-Holland, Netherlands"] = {alias_of = "South Holland, Netherlands", display = true}, ["Utrecht, Netherlands"] = {wp = "%l (province)"}, ["Zeeland, Netherlands"] = {}, } -- provinces of the Netherlands export.netherlands_group = { default_container = "Netherlands", default_placetype = "province", default_divs = "municipalities", data = export.netherlands_provinces, } export.new_zealand_regions = { -- North Island regions ["Northland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-NTL, number 1, capital [[Whangārei]] ["Auckland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-AUK, number 2, capital [[Auckland]] ["Waikato, New Zealand"] = {}, -- ISO 3166-2 code NZ-WKO, number 3, capital [[Hamilton, New Zealand|Hamilton]] ["Bay of Plenty, New Zealand"] = {the = true, wp = "%l Region"}, -- ISO 3166-2 code NZ-BOP, number 4, capital [[Whakatāne]] ["Gisborne, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-GIS, number 5, capital [[Gisborne, New Zealand|Gisborne]] ["Hawke's Bay, New Zealand"] = {}, -- ISO 3166-2 code NZ-HKB, number 6, capital [[Napier, New Zealand|Napier]] ["Taranaki, New Zealand"] = {}, -- ISO 3166-2 code NZ-TKI, number 7, capital [[Stratford, New Zealand|Stratford]] ["Manawatū-Whanganui, New Zealand"] = {}, -- ISO 3166-2 code NZ-MWT, number 8, capital [[Palmerston North]] ["Manawatu-Whanganui, New Zealand"] = {alias_of = "Manawatū-Whanganui, New Zealand", display = true}, ["Manawatu-Wanganui, New Zealand"] = {alias_of = "Manawatū-Whanganui, New Zealand", display = true}, ["Wellington, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-WGN, number 9, capital [[Wellington]] -- South Island regions ["Tasman, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-TAS, number 10, capital [[Richmond, New Zealand|Richmond]] ["Nelson, New Zealand"] = {placetype = {"region", "city"}, wp = "%l, %c", is_city = true}, -- ISO 3166-2 code NZ-NSN, number 11, capital [[Nelson, New Zealand|Nelson]] ["Marlborough, New Zealand"] = {placetype = {"region", "district"}, wp = "%l District"}, -- ISO 3166-2 code NZ-MBH, number 12, capital [[Blenheim, New Zealand|Blenheim]] ["West Coast, New Zealand"] = {the = true, wp = "%l Region"}, -- ISO 3166-2 code NZ-WTC, number 13, capital [[Greymouth]] ["Canterbury, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-CAN, number 14, capital [[Christchurch]] ["Otago, New Zealand"] = {}, -- ISO 3166-2 code NZ-OTA, number 15, capital [[Dunedin]] ["Southland, New Zealand"] = {wp = "%l Region"}, -- ISO 3166-2 code NZ-STL, number 16, capital [[Invercargill]] } -- regions of New Zealand export.new_zealand_group = { default_container = "New Zealand", default_placetype = "region", data = export.new_zealand_regions, } export.nigeria_states = { ["Abia State, Nigeria"] = {}, ["Adamawa State, Nigeria"] = {}, ["Akwa Ibom State, Nigeria"] = {}, ["Anambra State, Nigeria"] = {}, ["Bauchi State, Nigeria"] = {}, ["Bayelsa State, Nigeria"] = {}, ["Benue State, Nigeria"] = {}, ["Borno State, Nigeria"] = {}, ["Cross River State, Nigeria"] = {}, ["Delta State, Nigeria"] = {}, ["Ebonyi State, Nigeria"] = {}, ["Edo State, Nigeria"] = {}, ["Ekiti State, Nigeria"] = {}, ["Enugu State, Nigeria"] = {}, ["Federal Capital Territory, Nigeria"] = { -- not a state but allow it to be referenced as one in holonyms placetype = {"federal territory", "territory", "state"}, the = true, wp = "%l (%c)", }, ["Gombe State, Nigeria"] = {}, ["Imo State, Nigeria"] = {}, ["Jigawa State, Nigeria"] = {}, ["Kaduna State, Nigeria"] = {}, ["Kano State, Nigeria"] = {}, ["Katsina State, Nigeria"] = {}, ["Kebbi State, Nigeria"] = {}, ["Kogi State, Nigeria"] = {}, ["Kwara State, Nigeria"] = {}, ["Lagos State, Nigeria"] = {}, ["Nasarawa State, Nigeria"] = {}, ["Niger State, Nigeria"] = {}, ["Ogun State, Nigeria"] = {}, ["Ondo State, Nigeria"] = {}, ["Osun State, Nigeria"] = {}, ["Oyo State, Nigeria"] = {}, ["Plateau State, Nigeria"] = {}, ["Rivers State, Nigeria"] = {}, ["Sokoto State, Nigeria"] = {}, ["Taraba State, Nigeria"] = {}, ["Yobe State, Nigeria"] = {}, ["Zamfara State, Nigeria"] = {}, } -- states of Nigeria export.nigeria_group = { key_to_placename = make_key_to_placename(", Nigeria$", " State$"), placename_to_key = make_placename_to_key(", Nigeria", " State"), default_container = "Nigeria", default_placetype = "state", data = export.nigeria_states, } export.north_korea_provinces = { ["Chagang Province, North Korea"] = {}, ["North Hamgyong Province, North Korea"] = {}, ["South Hamgyong Province, North Korea"] = {}, ["North Hwanghae Province, North Korea"] = {}, ["South Hwanghae Province, North Korea"] = {}, ["Kangwon Province, North Korea"] = {wp = "%l (%c)"}, ["North Pyongan Province, North Korea"] = {}, ["South Pyongan Province, North Korea"] = {}, ["Ryanggang Province, North Korea"] = {}, } -- provinces of North Korea export.north_korea_group = { key_to_placename = make_key_to_placename(", North Korea$", " Province$"), placename_to_key = make_placename_to_key(", North Korea", " Province"), default_container = "North Korea", default_placetype = "province", data = export.north_korea_provinces, } export.norwegian_counties = { ["Oslo, Norway"] = {}, ["Rogaland, Norway"] = {}, ["Møre og Romsdal, Norway"] = {}, ["Nordland, Norway"] = {}, ["Østfold, Norway"] = {}, ["Akershus, Norway"] = {}, ["Buskerud, Norway"] = {}, -- the following two were merged into Innlandet -- ["Hedmark, Norway"] = {}, -- ["Oppland, Norway"] = {}, ["Innlandet, Norway"] = {}, ["Vestfold, Norway"] = {}, ["Telemark, Norway"] = {}, -- the following two were merged into Agder -- ["Aust-Agder, Norway"] = {}, -- ["Vest-Agder, Norway"] = {}, ["Agder, Norway"] = {}, -- the following two were merged into Vestland -- ["Hordaland, Norway"] = {}, -- ["Sogn og Fjordane, Norway"] = {}, ["Vestland, Norway"] = {}, ["Trøndelag, Norway"] = {}, ["Troms, Norway"] = {}, ["Finnmark, Norway"] = {}, } -- counties of Norway export.norway_group = { default_container = "Norway", default_placetype = "county", data = export.norwegian_counties, } export.pakistan_provinces_and_territories = { ["Azad Kashmir, Pakistan"] = { placetype = {"administrative territory", "autonomous territory", "territory"}, }, ["Azad Jammu and Kashmir, Pakistan"] = {alias_of = "Azad Kashmir, Pakistan", display = true}, ["Balochistan, Pakistan"] = {wp = "%l, %c"}, ["Gilgit-Baltistan, Pakistan"] = { placetype = {"administrative territory", "territory"}, }, ["Islamabad Capital Territory, Pakistan"] = { the = true, divs = {}, -- no divisions placetype = {"federal territory", "administrative territory", "territory"}, }, -- Islamabad is an accepted alias for Islamabad Capital Territory given the above placetypes ["Islamabad, Pakistan"] = {alias_of = "Islamabad Capital Territory, Pakistan"}, ["Khyber Pakhtunkhwa, Pakistan"] = {}, ["Punjab, Pakistan"] = {wp = "%l, %c"}, ["Sindh, Pakistan"] = {}, } -- provinces and territories of Pakistan export.pakistan_group = { default_container = "Pakistan", default_placetype = "province", default_divs = "divisions", data = export.pakistan_provinces_and_territories, } export.philippines_provinces = { ["Abra, Philippines"] = {wp = "%l (province)"}, ["Agusan del Norte, Philippines"] = {}, ["Agusan del Sur, Philippines"] = {}, ["Aklan, Philippines"] = {}, ["Albay, Philippines"] = {}, ["Antique, Philippines"] = {wp = "%l (province)"}, ["Apayao, Philippines"] = {}, ["Aurora, Philippines"] = {wp = "%l (province)"}, ["Basilan, Philippines"] = {}, ["Bataan, Philippines"] = {}, ["Batanes, Philippines"] = {}, ["Batangas, Philippines"] = {}, ["Benguet, Philippines"] = {}, ["Biliran, Philippines"] = {}, ["Bohol, Philippines"] = {}, ["Bukidnon, Philippines"] = {}, ["Bulacan, Philippines"] = {}, ["Cagayan, Philippines"] = {}, ["Camarines Norte, Philippines"] = {}, ["Camarines Sur, Philippines"] = {}, ["Camiguin, Philippines"] = {}, ["Capiz, Philippines"] = {}, ["Catanduanes, Philippines"] = {}, ["Cavite, Philippines"] = {}, ["Cebu, Philippines"] = {}, ["Cotabato, Philippines"] = {}, ["Davao de Oro, Philippines"] = {}, ["Davao del Norte, Philippines"] = {}, ["Davao del Sur, Philippines"] = {}, ["Davao Occidental, Philippines"] = {}, ["Davao Oriental, Philippines"] = {}, ["Dinagat Islands, Philippines"] = {the = true}, ["Eastern Samar, Philippines"] = {}, ["Guimaras, Philippines"] = {}, ["Ifugao, Philippines"] = {}, ["Ilocos Norte, Philippines"] = {}, ["Ilocos Sur, Philippines"] = {}, ["Iloilo, Philippines"] = {}, ["Isabela, Philippines"] = {wp = "%l (province)"}, ["Kalinga, Philippines"] = {wp = "%l (province)"}, ["La Union, Philippines"] = {}, ["Laguna, Philippines"] = {wp = "%l (province)"}, ["Lanao del Norte, Philippines"] = {}, ["Lanao del Sur, Philippines"] = {}, ["Leyte, Philippines"] = {wp = "%l (province)"}, ["Maguindanao del Norte, Philippines"] = {}, ["Maguindanao del Sur, Philippines"] = {}, ["Marinduque, Philippines"] = {}, ["Masbate, Philippines"] = {}, ["Misamis Occidental, Philippines"] = {}, ["Misamis Oriental, Philippines"] = {}, ["Mountain Province, Philippines"] = {}, ["Negros Occidental, Philippines"] = {}, ["Negros Oriental, Philippines"] = {}, ["Northern Samar, Philippines"] = {}, ["Nueva Ecija, Philippines"] = {}, ["Nueva Vizcaya, Philippines"] = {}, ["Occidental Mindoro, Philippines"] = {}, ["Oriental Mindoro, Philippines"] = {}, ["Palawan, Philippines"] = {}, ["Pampanga, Philippines"] = {}, ["Pangasinan, Philippines"] = {}, ["Quezon, Philippines"] = {}, ["Quirino, Philippines"] = {}, ["Rizal, Philippines"] = {wp = "%l (province)"}, ["Romblon, Philippines"] = {}, ["Samar, Philippines"] = {wp = "%l (province)"}, ["Sarangani, Philippines"] = {}, ["Siquijor, Philippines"] = {}, ["Sorsogon, Philippines"] = {}, ["South Cotabato, Philippines"] = {}, ["Southern Leyte, Philippines"] = {}, ["Sultan Kudarat, Philippines"] = {}, ["Sulu, Philippines"] = {}, ["Surigao del Norte, Philippines"] = {}, ["Surigao del Sur, Philippines"] = {}, ["Tarlac, Philippines"] = {}, ["Tawi-Tawi, Philippines"] = {}, ["Zambales, Philippines"] = {}, ["Zamboanga del Norte, Philippines"] = {}, ["Zamboanga del Sur, Philippines"] = {}, ["Zamboanga Sibugay, Philippines"] = {}, -- not a province but treated as one; allow it to be referred to as a province in holonyms ["Metro Manila, Philippines"] = {placetype = {"region", "province"}}, } -- provinces of the Philippines export.philippines_group = { default_container = "Philippines", default_placetype = "province", default_divs = {"municipalities", "barangays"}, data = export.philippines_provinces, } export.poland_voivodeships = { ["Lower Silesian Voivodeship, Poland"] = {}, -- abbr DS, code 02, capital Wrocław ["Kuyavian-Pomeranian Voivodeship, Poland"] = {}, -- abbr KP, code 04, capital Bydgoszcz (seat of voivode), Toruń (seat of sejmik and marshal) ["Lublin Voivodeship, Poland"] = {}, -- abbr LU, code 06, capital Lublin ["Lubusz Voivodeship, Poland"] = {}, -- abbr LB, code 08, capital Gorzów Wielkopolski (seat of voivode), Zielona Góra (seat of sejmik and marshal) ["Lodz Voivodeship, Poland"] = {wp = "Łódź Voivodeship"}, -- abbr LD, code 10, capital Łódź ["Łódź Voivodeship, Poland"] = {alias_of = "Lodz Voivodeship, Poland", display = true, display_as_full = true}, ["Lesser Poland Voivodeship, Poland"] = {}, -- abbr MA, code 12, capital Kraków ["Masovian Voivodeship, Poland"] = {}, -- abbr MZ, code 14, capital Warsaw ["Opole Voivodeship, Poland"] = {}, -- abbr OP, code 16, capital Opole ["Subcarpathian Voivodeship, Poland"] = {}, -- abbr PK, code 18, capital Rzeszów ["Podlaskie Voivodeship, Poland"] = {}, -- abbr PD, code 20, capital Białystok ["Pomeranian Voivodeship, Poland"] = {}, -- abbr PM, code 22, capital Gdańsk ["Silesian Voivodeship, Poland"] = {}, -- abbr SL, code 24, capital Katowice ["Holy Cross Voivodeship, Poland"] = {wp = "Świętokrzyskie Voivodeship"}, -- abbr SK, code 26, capital Kielce ["Świętokrzyskie Voivodeship, Poland"] = {alias_of = "Holy Cross Voivodeship, Poland", display = true, display_as_full = true}, ["Warmian-Masurian Voivodeship, Poland"] = {}, -- abbr WN, code 28, capital Olsztyn ["Greater Poland Voivodeship, Poland"] = {}, -- abbr WP, code 30, capital Poznań ["West Pomeranian Voivodeship, Poland"] = {}, -- abbr ZP, code 32, capital Szczecin } -- voivodeships of Poland export.poland_group = { key_to_placename = make_key_to_placename(", Poland$", " Voivodeship$"), placename_to_key = make_placename_to_key(", Poland", " Voivodeship"), default_container = "Poland", default_placetype = "voivodeship", default_divs = { -- "counties", -- not enough of them currently {type = "Polish colonies", cat_as = {{type = "villages", prep = "in"}}}, }, data = export.poland_voivodeships, } export.portugal_districts_and_autonomous_regions = { ["Azores, Portugal"] = {the = true, placetype = {"autonomous region", "region"}}, ["Aveiro District, Portugal"] = {}, ["Beja District, Portugal"] = {}, ["Braga District, Portugal"] = {}, ["Bragança District, Portugal"] = {}, ["Castelo Branco District, Portugal"] = {}, ["Coimbra District, Portugal"] = {}, ["Évora District, Portugal"] = {}, ["Faro District, Portugal"] = {}, ["Guarda District, Portugal"] = {}, ["Leiria District, Portugal"] = {}, ["Lisbon District, Portugal"] = {}, ["Lisboa District, Portugal"] = {alias_of = "Lisbon District, Portugal", display = true}, ["Madeira, Portugal"] = {placetype = {"autonomous region", "region"}}, ["Portalegre District, Portugal"] = {}, ["Porto District, Portugal"] = {}, ["Santarém District, Portugal"] = {}, ["Setúbal District, Portugal"] = {}, ["Viana do Castelo District, Portugal"] = {}, ["Vila Real District, Portugal"] = {}, ["Viseu District, Portugal"] = {}, } local function portugal_placename_to_key(placename) if placename == "Azores" or placename == "Madeira" then return placename .. ", Portugal" end if placename:find(" District$") then return placename .. ", Portugal" end return placename .. " District, Portugal" end -- districts and autonomous regions of Portugal export.portugal_group = { key_to_placename = make_key_to_placename(", Portugal$", " District$"), placename_to_key = portugal_placename_to_key, default_container = "Portugal", default_placetype = "district", default_divs = "municipalities", data = export.portugal_districts_and_autonomous_regions, } export.romania_counties = { ["Alba County, Romania"] = {}, ["Arad County, Romania"] = {}, ["Argeș County, Romania"] = {}, ["Bacău County, Romania"] = {}, ["Bihor County, Romania"] = {}, ["Bistrița-Năsăud County, Romania"] = {}, ["Botoșani County, Romania"] = {}, ["Brașov County, Romania"] = {}, ["Brăila County, Romania"] = {}, -- Bucharest: not in a county ["Buzău County, Romania"] = {}, ["Caraș-Severin County, Romania"] = {}, ["Cluj County, Romania"] = {}, ["Constanța County, Romania"] = {}, ["Covasna County, Romania"] = {}, ["Călărași County, Romania"] = {}, ["Dolj County, Romania"] = {}, ["Dâmbovița County, Romania"] = {}, ["Galați County, Romania"] = {}, ["Giurgiu County, Romania"] = {}, ["Gorj County, Romania"] = {}, ["Harghita County, Romania"] = {}, ["Hunedoara County, Romania"] = {}, ["Ialomița County, Romania"] = {}, ["Iași County, Romania"] = {}, ["Ilfov County, Romania"] = {}, ["Maramureș County, Romania"] = {}, ["Mehedinți County, Romania"] = {}, ["Mureș County, Romania"] = {}, ["Neamț County, Romania"] = {}, ["Olt County, Romania"] = {}, ["Prahova County, Romania"] = {}, ["Satu Mare County, Romania"] = {}, ["Sibiu County, Romania"] = {}, ["Suceava County, Romania"] = {}, ["Sălaj County, Romania"] = {}, ["Teleorman County, Romania"] = {}, ["Timiș County, Romania"] = {}, ["Tulcea County, Romania"] = {}, ["Vaslui County, Romania"] = {}, ["Vrancea County, Romania"] = {}, ["Vâlcea County, Romania"] = {}, } -- counties of Romania export.romania_group = { key_to_placename = make_key_to_placename(", Romania$", " County$"), placename_to_key = make_placename_to_key(", Romania", " County"), default_container = "Romania", default_placetype = "county", default_divs = "communes", data = export.romania_counties, } local function make_russia_federal_subject_spec(spectype, use_the, wp) return { placetype = spectype, the = not not use_the, bare_category_parent_type = {"federal subjects", spectype .. "s"}, wp = wp, } end local russia_autonomous_okrug_no_the = {placetype = {"autonomous okrug", "okrug"}, bare_category_parent_type = {"federal subjects", "autonomous okrugs"}} local russia_autonomous_okrug_the = {placetype = {"autonomous okrug", "okrug"}, bare_category_parent_type = {"federal subjects", "autonomous okrugs"}, the = true} local russia_krai = make_russia_federal_subject_spec("krai") local russia_oblast = make_russia_federal_subject_spec("oblast") local russia_republic_the = make_russia_federal_subject_spec("republic", "use the") local russia_republic_no_the = make_russia_federal_subject_spec("republic") export.russia_federal_subjects = { -- autonomous oblasts ["Jewish Autonomous Oblast, Russia"] = {the = true, placetype = {"autonomous oblast", "oblast"}, bare_category_parent_type = {"federal subjects", "autonomous oblasts"}}, -- autonomous okrugs ["Chukotka Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Chukotka, Russia"] = {alias_of = "Chukotka Autonomous Okrug, Russia"}, ["Khanty-Mansi Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Khanty-Mansia, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Khantia-Mansia, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Yugra, Russia"] = {alias_of = "Khanty-Mansi Autonomous Okrug, Russia"}, ["Nenets Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Nenetsia, Russia"] = {alias_of = "Nenets Autonomous Okrug, Russia"}, ["Yamalo-Nenets Autonomous Okrug, Russia"] = russia_autonomous_okrug_the, ["Yamalia, Russia"] = {alias_of = "Yamalo-Nenets Autonomous Okrug, Russia"}, -- krais ["Altai Krai, Russia"] = russia_krai, ["Kamchatka Krai, Russia"] = russia_krai, ["Khabarovsk Krai, Russia"] = russia_krai, ["Krasnodar Krai, Russia"] = russia_krai, ["Krasnoyarsk Krai, Russia"] = russia_krai, ["Perm Krai, Russia"] = russia_krai, ["Primorsky Krai, Russia"] = russia_krai, ["Stavropol Krai, Russia"] = russia_krai, ["Zabaykalsky Krai, Russia"] = russia_krai, -- oblasts ["Amur Oblast, Russia"] = russia_oblast, ["Arkhangelsk Oblast, Russia"] = russia_oblast, ["Astrakhan Oblast, Russia"] = russia_oblast, ["Belgorod Oblast, Russia"] = russia_oblast, ["Bryansk Oblast, Russia"] = russia_oblast, ["Chelyabinsk Oblast, Russia"] = russia_oblast, ["Irkutsk Oblast, Russia"] = russia_oblast, ["Ivanovo Oblast, Russia"] = russia_oblast, ["Kaliningrad Oblast, Russia"] = russia_oblast, ["Kaluga Oblast, Russia"] = russia_oblast, ["Kemerovo Oblast, Russia"] = russia_oblast, ["Kirov Oblast, Russia"] = russia_oblast, ["Kostroma Oblast, Russia"] = russia_oblast, ["Kurgan Oblast, Russia"] = russia_oblast, ["Kursk Oblast, Russia"] = russia_oblast, ["Leningrad Oblast, Russia"] = russia_oblast, ["Lipetsk Oblast, Russia"] = russia_oblast, ["Magadan Oblast, Russia"] = russia_oblast, ["Moscow Oblast, Russia"] = russia_oblast, ["Murmansk Oblast, Russia"] = russia_oblast, ["Nizhny Novgorod Oblast, Russia"] = russia_oblast, ["Novgorod Oblast, Russia"] = russia_oblast, ["Novosibirsk Oblast, Russia"] = russia_oblast, ["Omsk Oblast, Russia"] = russia_oblast, ["Orenburg Oblast, Russia"] = russia_oblast, ["Oryol Oblast, Russia"] = russia_oblast, ["Penza Oblast, Russia"] = russia_oblast, ["Pskov Oblast, Russia"] = russia_oblast, ["Rostov Oblast, Russia"] = russia_oblast, ["Ryazan Oblast, Russia"] = russia_oblast, ["Sakhalin Oblast, Russia"] = russia_oblast, ["Samara Oblast, Russia"] = russia_oblast, ["Saratov Oblast, Russia"] = russia_oblast, ["Smolensk Oblast, Russia"] = russia_oblast, ["Sverdlovsk Oblast, Russia"] = russia_oblast, ["Tambov Oblast, Russia"] = russia_oblast, ["Tomsk Oblast, Russia"] = russia_oblast, ["Tula Oblast, Russia"] = russia_oblast, ["Tver Oblast, Russia"] = russia_oblast, ["Tyumen Oblast, Russia"] = russia_oblast, ["Ulyanovsk Oblast, Russia"] = russia_oblast, ["Vladimir Oblast, Russia"] = russia_oblast, ["Volgograd Oblast, Russia"] = russia_oblast, ["Vologda Oblast, Russia"] = russia_oblast, ["Voronezh Oblast, Russia"] = russia_oblast, ["Yaroslavl Oblast, Russia"] = russia_oblast, -- republics -- -- We only need to include cases that aren't just shortened versions of the full federal subject name (i.e. where -- words like "Republic" and "Oblast" are omitted but the name is not otherwise modified; these are handled by -- key_to_placename). Non-display-canonicalizing aliases are generally due to differences in the presence or absence -- of "the". ["Adygea, Russia"] = russia_republic_no_the, ["Republic of Adygea, Russia"] = {alias_of = "Adygea, Russia", the = true}, ["Bashkortostan, Russia"] = russia_republic_no_the, ["Republic of Bashkortostan, Russia"] = {alias_of = "Bashkortostan, Russia", the = true}, ["Bashkiria, Russia"] = {alias_of = "Bashkortostan, Russia"}, ["Buryatia, Russia"] = russia_republic_no_the, ["Republic of Buryatia, Russia"] = {alias_of = "Buryatia, Russia", the = true}, ["Dagestan, Russia"] = russia_republic_no_the, ["Republic of Dagestan, Russia"] = {alias_of = "Dagestan, Russia", the = true}, ["Ingushetia, Russia"] = russia_republic_no_the, ["Republic of Ingushetia, Russia"] = {alias_of = "Ingushetia, Russia", the = true}, ["Kalmykia, Russia"] = russia_republic_no_the, ["Republic of Kalmykia, Russia"] = {alias_of = "Kalmykia, Russia", the = true}, ["Karelia, Russia"] = make_russia_federal_subject_spec("republic", nil, "Republic of Karelia"), ["Republic of Karelia, Russia"] = {alias_of = "Karelia, Russia", the = true}, ["Khakassia, Russia"] = russia_republic_no_the, ["Republic of Khakassia, Russia"] = {alias_of = "Khakassia, Russia", the = true}, ["Mordovia, Russia"] = russia_republic_no_the, ["Republic of Mordovia, Russia"] = {alias_of = "Mordovia, Russia", the = true}, ["North Ossetia-Alania, Russia"] = make_russia_federal_subject_spec("republic", nil, "North Ossetia–Alania"), -- with en-dash ["Republic of North Ossetia-Alania, Russia"] = {alias_of = "North Ossetia-Alania, Russia", the = true}, ["North Ossetia, Russia"] = {alias_of = "North Ossetia-Alania, Russia", display = true}, ["Alania, Russia"] = {alias_of = "North Ossetia-Alania, Russia", display = true}, ["Tatarstan, Russia"] = russia_republic_no_the, ["Republic of Tatarstan, Russia"] = {alias_of = "Tatarstan, Russia", the = true}, ["Altai Republic, Russia"] = russia_republic_the, ["Chechnya, Russia"] = russia_republic_no_the, ["Chechen Republic, Russia"] = {alias_of = "Chechnya, Russia", the = true}, ["Chuvashia, Russia"] = russia_republic_no_the, ["Chuvash Republic, Russia"] = {alias_of = "Chuvashia, Russia", the = true}, ["Kabardino-Balkaria, Russia"] = russia_republic_no_the, ["Kabardino-Balkariya, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", display = true}, ["Kabardino-Balkarian Republic, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", the = true}, ["Kabardino-Balkar Republic, Russia"] = {alias_of = "Kabardino-Balkaria, Russia", display = "Kabardino-Balkarian Republic, Russia", the = true}, ["Karachay-Cherkessia, Russia"] = russia_republic_no_the, ["Karachay-Cherkess Republic, Russia"] = {alias_of = "Karachay-Cherkessia, Russia"}, ["Komi, Russia"] = make_russia_federal_subject_spec("republic", nil, "Komi Republic"), ["Komi Republic, Russia"] = {alias_of = "Komi, Russia", the = true}, ["Mari El, Russia"] = russia_republic_no_the, ["Mari El Republic, Russia"] = {alias_of = "Mari El, Russia", the = true}, ["Sakha, Russia"] = make_russia_federal_subject_spec("republic", nil, "Sakha Republic"), ["Sakha Republic, Russia"] = {alias_of = "Sakha, Russia", the = true}, ["Yakutia, Russia"] = {alias_of = "Sakha, Russia"}, ["Yakutiya, Russia"] = {alias_of = "Sakha, Russia", display = "Yakutia, Russia"}, ["Republic of Yakutia (Sakha), Russia"] = {alias_of = "Sakha, Russia", display = "Sakha Republic, Russia", the = true}, ["Tuva, Russia"] = russia_republic_no_the, ["Tyva, Russia"] = {alias_of = "Tuva, Russia", display = true}, ["Tuva Republic, Russia"] = {alias_of = "Tuva, Russia", the = true}, ["Tyva Republic, Russia"] = {alias_of = "Tuva, Russia", display= "Tuva Republic, Russia", the = true}, ["Udmurtia, Russia"] = russia_republic_no_the, ["Udmurt Republic, Russia"] = {alias_of = "Udmurtia, Russia", the = true}, -- Not included due to being unrecognized and only partly controlled: -- ["Crimea, Russia"] = make_russia_federal_subject_spec("republic", nil, "Republic of Crimea (Russia)") -- ["Donetsk People's Republic, Russia"] = russia_republic_the, -- ["Luhansk People's Republic, Russia"] = russia_republic_the, -- ["Zaporozhye Oblast, Russia"] = make_russia_federal_subject_spec("oblast", nil, "Russian occupation of Zaporizhzhia Oblast"), -- ["Kherson Oblast, Russia"] = make_russia_federal_subject_spec("oblast", nil, "Russian occupation of Kherson Oblast"), -- There are also federal cities (not included because they're cities): -- Moscow, Saint Petersburg; Sevastopol (unrecognized; same status as for "Crimea, Russia" above) } local function russia_key_to_placename(key) key = key:gsub(",.*", "") local full_placename = key if key == "Jewish Autonomous Oblast" then return full_placename, full_placename end local elliptical_placename for _, suffix in ipairs({"Krai", "Oblast"}) do elliptical_placename = key:match("^(.*) " .. suffix .. "$") if elliptical_placename then return full_placename, elliptical_placename end end return full_placename, full_placename end local function russia_placename_to_key(placename) local key = placename .. ", Russia" if export.russia_federal_subjects[key] then return key end -- We allow the user to say e.g. "obl/Samara" in place of "obl/Samara Oblast". for _, suffix in ipairs({"Krai", "Oblast"}) do local suffixed_key = placename .. " " .. suffix .. ", Russia" if export.russia_federal_subjects[suffixed_key] then return suffixed_key end end return placename .. ", Russia" end local function construct_russia_federal_subject_keydesc(group, key, spec) local placename = key:gsub(",.*", "") local linked_placename = export.construct_linked_placename(spec, placename) local placetype = spec.placetype if type(placetype) == "table" then placetype = placetype[1] end if placetype == "oblast" then -- Hack: Oblasts generally don't have entries under "Foo Oblast" -- but just under "Foo", so fix the linked key appropriately; -- doesn't apply to the Jewish Autonomous Oblast linked_placename = linked_placename:gsub(" Oblast%]%]", "%]%] Oblast") end return linked_placename .. ", a [[federal subject]] ([[" .. placetype .. "]]) of [[Russia]]" end -- federal subjects of Russia export.russia_group = { key_to_placename = russia_key_to_placename, placename_to_key = russia_placename_to_key, default_container = "Russia", default_keydesc = construct_russia_federal_subject_keydesc, default_overriding_bare_label_parents = {"federal subjects of Russia", "+++"}, data = export.russia_federal_subjects, } export.saudi_arabia_provinces = { ["Riyadh Province, Saudi Arabia"] = {}, ["Mecca Province, Saudi Arabia"] = {}, -- Name is too generic to assume it's in Saudi Arabia if not specified. ["Eastern Province, Saudi Arabia"] = {no_auto_augment_container = true, wp = "%l, %c"}, ["Medina Province, Saudi Arabia"] = {wp = "%l (%c)"}, ["Aseer Province, Saudi Arabia"] = {wp = "Asir"}, ["Asir Province, Saudi Arabia"] = {alias_of = "Aseer Province, Saudi Arabia", display = true}, ["Jazan Province, Saudi Arabia"] = {}, ["Qassim Province, Saudi Arabia"] = {wp = "Al-Qassim Province"}, ["Al-Qassim Province, Saudi Arabia"] = {alias_of = "Qassim Province, Saudi Arabia", display = true}, ["Tabuk Province, Saudi Arabia"] = {}, ["Hail Province, Saudi Arabia"] = {wp = "Ḥa'il Province"}, ["Ha'il Province, Saudi Arabia"] = {alias_of = "Hail Province, Saudi Arabia", display = true}, ["Ḥa'il Province, Saudi Arabia"] = {alias_of = "Hail Province, Saudi Arabia", display = true}, ["Al-Jouf Province, Saudi Arabia"] = {wp = "Al-Jawf Province"}, ["Al-Jawf Province, Saudi Arabia"] = {alias_of = "Al-Jouf Province, Saudi Arabia", display = true}, ["Najran Province, Saudi Arabia"] = {}, ["Northern Borders Province, Saudi Arabia"] = {}, ["Al-Bahah Province, Saudi Arabia"] = {}, } -- provinces of Saudi Arabia export.saudi_arabia_group = { key_to_placename = make_key_to_placename(", Saudi Arabia$", " Province$"), placename_to_key = make_placename_to_key(", Saudi Arabia", " Province"), default_container = "Saudi Arabia", default_placetype = "province", data = export.saudi_arabia_provinces, } export.south_africa_provinces = { ["Eastern Cape, South Africa"] = {the = true}, ["Free State, South Africa"] = {the = true, wp = "%l (province)"}, ["Gauteng, South Africa"] = {}, ["KwaZulu-Natal, South Africa"] = {}, ["Limpopo, South Africa"] = {}, ["Mpumalanga, South Africa"] = {}, -- per Wikipedia and other sources, `North West` doesn't normally have `the` before it ["North West, South Africa"] = {wp = "%l (South African province)"}, ["Northern Cape, South Africa"] = {the = true}, ["Western Cape, South Africa"] = {the = true}, } -- provinces of South Africa export.south_africa_group = { default_container = "South Africa", default_placetype = "province", default_divs = "municipalities", data = export.south_africa_provinces, } export.south_korea_provinces = { ["North Chungcheong Province, South Korea"] = {}, ["South Chungcheong Province, South Korea"] = {}, ["Gangwon Province, South Korea"] = {wp = "%l, %c"}, ["Gyeonggi Province, South Korea"] = {}, ["North Gyeongsang Province, South Korea"] = {}, ["South Gyeongsang Province, South Korea"] = {}, ["North Jeolla Province, South Korea"] = {}, ["South Jeolla Province, South Korea"] = {}, ["Jeju Province, South Korea"] = {}, } -- provinces of South Korea export.south_korea_group = { key_to_placename = make_key_to_placename(", South Korea$", " Province$"), placename_to_key = make_placename_to_key(", South Korea", " Province"), default_container = "South Korea", default_placetype = "province", data = export.south_korea_provinces, } export.spain_autonomous_communities = { ["Andalusia, Spain"] = {}, ["Aragon, Spain"] = {}, ["Asturias, Spain"] = {}, ["Balearic Islands, Spain"] = {the = true}, ["Basque Country, Spain"] = {the = true, wp = "%l (autonomous community)"}, ["Canary Islands, Spain"] = {the = true}, ["Cantabria, Spain"] = {}, ["Castile and León, Spain"] = {}, ["Castilla-La Mancha, Spain"] = {wp = "Castilla–La Mancha"}, -- with en-dash ["Catalonia, Spain"] = {}, ["Community of Madrid, Spain"] = {the = true}, ["Extremadura, Spain"] = {}, ["Galicia, Spain"] = {wp = "%l (Spain)"}, ["La Rioja, Spain"] = {}, ["Murcia, Spain"] = {wp = "Region of %l"}, ["Navarre, Spain"] = {}, ["Valencia, Spain"] = {wp = "Valencian Community"}, ["Valencian Community, Spain"] = {alias_of = "Valencia, Spain", the = true}, } -- autonomous communities of Spain export.spain_group = { default_container = "Spain", default_placetype = "autonomous community", default_divs = {"municipalities", "comarcas"}, data = export.spain_autonomous_communities, } export.taiwan_counties = { ["Changhua County, Taiwan"] = {}, ["Chiayi County, Taiwan"] = {}, ["Hsinchu County, Taiwan"] = {}, ["Hualien County, Taiwan"] = {}, ["Kinmen County, Taiwan"] = {wp = "Kinmen"}, ["Lienchiang County, Taiwan"] = {wp = "Matsu Islands"}, ["Miaoli County, Taiwan"] = {}, ["Nantou County, Taiwan"] = {}, ["Penghu County, Taiwan"] = {wp = "Penghu"}, ["Pingtung County, Taiwan"] = {}, ["Taitung County, Taiwan"] = {}, ["Yilan County, Taiwan"] = {wp = "%l, %c"}, ["Yunlin County, Taiwan"] = {}, } -- counties of Taiwan export.taiwan_group = { key_to_placename = make_key_to_placename(", Taiwan$", " County$"), placename_to_key = make_placename_to_key(", Taiwan", " County"), default_container = "Taiwan", default_placetype = "county", default_divs = {"districts", "townships"}, data = export.taiwan_counties, } export.thailand_provinces = { -- Bangkok (special administrative area) ["Amnat Charoen Province, Thailand"] = {}, ["Ang Thong Province, Thailand"] = {}, ["Bueng Kan Province, Thailand"] = {}, ["Buriram Province, Thailand"] = {}, ["Chachoengsao Province, Thailand"] = {}, ["Chai Nat Province, Thailand"] = {}, ["Chaiyaphum Province, Thailand"] = {}, ["Chanthaburi Province, Thailand"] = {}, ["Chiang Mai Province, Thailand"] = {}, ["Chiang Rai Province, Thailand"] = {}, ["Chonburi Province, Thailand"] = {}, ["Chumphon Province, Thailand"] = {}, ["Kalasin Province, Thailand"] = {}, ["Kamphaeng Phet Province, Thailand"] = {}, ["Kanchanaburi Province, Thailand"] = {}, ["Khon Kaen Province, Thailand"] = {}, ["Krabi Province, Thailand"] = {}, ["Lampang Province, Thailand"] = {}, ["Lamphun Province, Thailand"] = {}, ["Loei Province, Thailand"] = {}, ["Lopburi Province, Thailand"] = {}, ["Mae Hong Son Province, Thailand"] = {}, ["Maha Sarakham Province, Thailand"] = {}, ["Mukdahan Province, Thailand"] = {}, ["Nakhon Nayok Province, Thailand"] = {}, ["Nakhon Pathom Province, Thailand"] = {}, ["Nakhon Phanom Province, Thailand"] = {}, ["Nakhon Ratchasima Province, Thailand"] = {}, ["Nakhon Sawon Province, Thailand"] = {}, ["Nakhon Si Thammarat Province, Thailand"] = {}, ["Nan Province, Thailand"] = {}, ["Narathiwat Province, Thailand"] = {}, ["Nong Bua Lamphu Province, Thailand"] = {}, ["Nong Khai Province, Thailand"] = {}, ["Nonthaburi Province, Thailand"] = {}, ["Pathum Thani Province, Thailand"] = {}, ["Pattani Province, Thailand"] = {}, ["Phang Nga Province, Thailand"] = {}, ["Phatthalung Province, Thailand"] = {}, ["Phayao Province, Thailand"] = {}, ["Phetchabun Province, Thailand"] = {}, ["Phetchaburi Province, Thailand"] = {}, ["Phichit Province, Thailand"] = {}, ["Phitsanulok Province, Thailand"] = {}, ["Phra Nakhon Si Ayutthaya Province, Thailand"] = {}, ["Phrae Province, Thailand"] = {}, ["Phuket Province, Thailand"] = {}, ["Prachinburi Province, Thailand"] = {}, ["Prachuap Khiri Khan Province, Thailand"] = {}, ["Ranong Province, Thailand"] = {}, ["Ratchaburi Province, Thailand"] = {}, ["Rayong Province, Thailand"] = {}, ["Roi Et Province, Thailand"] = {}, ["Sa Kaeo Province, Thailand"] = {}, ["Sakon Nakhon Province, Thailand"] = {}, ["Samut Prakan Province, Thailand"] = {}, ["Samut Sakhon Province, Thailand"] = {}, ["Samut Songkhram Province, Thailand"] = {}, ["Saraburi Province, Thailand"] = {}, ["Satun Province, Thailand"] = {}, ["Sing Buri Province, Thailand"] = {}, ["Sisaket Province, Thailand"] = {}, ["Songkhla Province, Thailand"] = {}, ["Sukhothai Province, Thailand"] = {}, ["Suphan Buri Province, Thailand"] = {}, ["Surat Thani Province, Thailand"] = {}, ["Surin Province, Thailand"] = {}, ["Tak Province, Thailand"] = {}, ["Trang Province, Thailand"] = {}, ["Trat Province, Thailand"] = {}, ["Ubon Ratchathani Province, Thailand"] = {}, ["Udon Thani Province, Thailand"] = {}, ["Uthai Thani Province, Thailand"] = {}, ["Uttaradit Province, Thailand"] = {}, ["Yala Province, Thailand"] = {}, ["Yasothon Province, Thailand"] = {}, } -- provinces of Thailand export.thailand_group = { key_to_placename = make_key_to_placename(", Thailand$", " Province$"), placename_to_key = make_placename_to_key(", Thailand", " Province"), default_container = "Thailand", default_placetype = "province", default_divs = "districts", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.thailand_provinces, } export.turkey_provinces = { ["Adana Province, Turkey"] = {}, -- code 01 ["Adıyaman Province, Turkey"] = {}, -- code 02 ["Afyonkarahisar Province, Turkey"] = {}, -- code 03 ["Ağrı Province, Turkey"] = {}, -- code 04 ["Amasya Province, Turkey"] = {}, -- code 05 ["Ankara Province, Turkey"] = {}, -- code 06 ["Antalya Province, Turkey"] = {}, -- code 07 ["Artvin Province, Turkey"] = {}, -- code 08 ["Aydın Province, Turkey"] = {}, -- code 09 ["Balıkesir Province, Turkey"] = {}, -- code 10 ["Bilecik Province, Turkey"] = {}, -- code 11 ["Bingöl Province, Turkey"] = {}, -- code 12 ["Bitlis Province, Turkey"] = {}, -- code 13 ["Bolu Province, Turkey"] = {}, -- code 14 ["Burdur Province, Turkey"] = {}, -- code 15 ["Bursa Province, Turkey"] = {}, -- code 16 ["Çanakkale Province, Turkey"] = {}, -- code 17 ["Çankırı Province, Turkey"] = {}, -- code 18 ["Çorum Province, Turkey"] = {}, -- code 19 ["Denizli Province, Turkey"] = {}, -- code 20 ["Diyarbakır Province, Turkey"] = {}, -- code 21 ["Edirne Province, Turkey"] = {}, -- code 22 ["Elazığ Province, Turkey"] = {}, -- code 23 ["Elâzığ Province, Turkey"] = {alias_of = "Elazığ Province, Turkey", display = true}, ["Erzincan Province, Turkey"] = {}, -- code 24 ["Erzurum Province, Turkey"] = {}, -- code 25 ["Eskişehir Province, Turkey"] = {}, -- code 26 ["Gaziantep Province, Turkey"] = {}, -- code 27 ["Giresun Province, Turkey"] = {}, -- code 28 ["Gümüşhane Province, Turkey"] = {}, -- code 29 ["Hakkâri Province, Turkey"] = {}, -- code 30 ["Hakkari Province, Turkey"] = {alias_of = "Hakkâri Province, Turkey", display = true}, ["Hatay Province, Turkey"] = {}, -- code 31 ["Isparta Province, Turkey"] = {}, -- code 32 ["Mersin Province, Turkey"] = {}, -- code 33 -- ["Istanbul Province, Turkey"] = {}, -- code 34; this is coextensive with the city itself ["İzmir Province, Turkey"] = {}, -- code 35 ["Izmir Province, Turkey"] = {alias_of = "İzmir Province, Turkey", display = true}, ["Kars Province, Turkey"] = {}, -- code 36 ["Kastamonu Province, Turkey"] = {}, -- code 37 ["Kayseri Province, Turkey"] = {}, -- code 38 ["Kırklareli Province, Turkey"] = {}, -- code 39 ["Kırşehir Province, Turkey"] = {}, -- code 40 ["Kocaeli Province, Turkey"] = {}, -- code 41 ["Konya Province, Turkey"] = {}, -- code 42 ["Kütahya Province, Turkey"] = {}, -- code 43 ["Malatya Province, Turkey"] = {}, -- code 44 ["Manisa Province, Turkey"] = {}, -- code 45 ["Kahramanmaraş Province, Turkey"] = {}, -- code 46 ["Mardin Province, Turkey"] = {}, -- code 47 ["Muğla Province, Turkey"] = {}, -- code 48 ["Muş Province, Turkey"] = {}, -- code 49 ["Nevşehir Province, Turkey"] = {}, -- code 50 ["Niğde Province, Turkey"] = {}, -- code 51 ["Ordu Province, Turkey"] = {}, -- code 52 ["Rize Province, Turkey"] = {}, -- code 53 ["Sakarya Province, Turkey"] = {}, -- code 54 ["Samsun Province, Turkey"] = {}, -- code 55 ["Siirt Province, Turkey"] = {}, -- code 56 ["Sinop Province, Turkey"] = {}, -- code 57 ["Sivas Province, Turkey"] = {}, -- code 58 ["Tekirdağ Province, Turkey"] = {}, -- code 59 ["Tokat Province, Turkey"] = {}, -- code 60 ["Trabzon Province, Turkey"] = {}, -- code 61 ["Tunceli Province, Turkey"] = {}, -- code 62 ["Şanlıurfa Province, Turkey"] = {}, -- code 63 ["Uşak Province, Turkey"] = {}, -- code 64 ["Van Province, Turkey"] = {}, -- code 65 ["Yozgat Province, Turkey"] = {}, -- code 66 ["Zonguldak Province, Turkey"] = {}, -- code 67 ["Aksaray Province, Turkey"] = {}, -- code 68 ["Bayburt Province, Turkey"] = {}, -- code 69 ["Karaman Province, Turkey"] = {}, -- code 70 ["Kırıkkale Province, Turkey"] = {}, -- code 71 ["Batman Province, Turkey"] = {}, -- code 72 ["Şırnak Province, Turkey"] = {}, -- code 73 ["Bartın Province, Turkey"] = {}, -- code 74 ["Ardahan Province, Turkey"] = {}, -- code 75 ["Iğdır Province, Turkey"] = {}, -- code 76 ["Yalova Province, Turkey"] = {}, -- code 77 ["Karabük Province, Turkey"] = {}, -- code 78 ["Kilis Province, Turkey"] = {}, -- code 79 ["Osmaniye Province, Turkey"] = {}, -- code 80 ["Düzce Province, Turkey"] = {}, -- code 81 } -- provinces of Turkey export.turkey_group = { key_to_placename = make_key_to_placename(", Turkey$", " Province$"), placename_to_key = make_placename_to_key(", Turkey", " Province"), default_container = "Turkey", default_placetype = "province", default_divs = "districts", data = export.turkey_provinces, } export.ukraine_oblasts = { ["Cherkasy Oblast, Ukraine"] = {}, -- capital [[Cherkasy]], license plate prefix CA, IA ["Chernihiv Oblast, Ukraine"] = {}, -- capital [[Chernihiv]], license plate prefix CB, IB ["Chernivtsi Oblast, Ukraine"] = {}, -- capital [[Chernivtsi]], license plate prefix CE, IE -- apparently will be renamed to 'Dnipro Oblast' ["Dnipropetrovsk Oblast, Ukraine"] = {}, -- capital [[Dnipro]], license plate prefix AE, KE ["Donetsk Oblast, Ukraine"] = {}, -- capital ''[[Donetsk]] ([[Kramatorsk]])'', license plate prefix AH, KH ["Ivano-Frankivsk Oblast, Ukraine"] = {}, -- capital [[Ivano-Frankivsk]], license plate prefix AT, KT ["Kharkiv Oblast, Ukraine"] = {}, -- capital [[Kharkiv]], license plate prefix AX, KX ["Kherson Oblast, Ukraine"] = {}, -- capital ''[[Kherson]]'', license plate prefix ''BT, HT'' ["Khmelnytskyi Oblast, Ukraine"] = {}, -- capital [[Khmelnytskyi]], license plate prefix BX, HX -- apparently will be renamed to 'Kropyvnytskyi Oblast' ["Kirovohrad Oblast, Ukraine"] = {}, -- capital [[Kropyvnytskyi]], license plate prefix BA, HA ["Kyiv Oblast, Ukraine"] = {}, -- capital [[Kyiv]], license plate prefix AI, KI ["Kiev Oblast, Ukraine"] = {alias_of = "Kyiv Oblast, Ukraine", display = true}, ["Luhansk Oblast, Ukraine"] = {}, -- capital ''[[Luhansk]] ([[Sievierodonetsk]])'', license plate prefix BB, HB ["Lviv Oblast, Ukraine"] = {}, -- capital [[Lviv]], license plate prefix BC, HC ["Mykolaiv Oblast, Ukraine"] = {}, -- capital [[Mykolaiv]], license plate prefix BE, HE ["Odesa Oblast, Ukraine"] = {}, -- capital [[Odesa]], license plate prefix BH, HH ["Odessa Oblast, Ukraine"] = {alias_of = "Odesa Oblast, Ukraine", display = true}, ["Poltava Oblast, Ukraine"] = {}, -- capital [[Poltava]], license plate prefix BI, HI ["Rivne Oblast, Ukraine"] = {}, -- capital [[Rivne]], license plate prefix BK, HK ["Sumy Oblast, Ukraine"] = {}, -- capital [[Sumy]], license plate prefix BM, HM ["Ternopil Oblast, Ukraine"] = {}, -- capital [[Ternopil]], license plate prefix BO, HO ["Vinnytsia Oblast, Ukraine"] = {}, -- capital [[Vinnytsia]], license plate prefix AB, KB ["Volyn Oblast, Ukraine"] = {}, -- capital [[Lutsk]], license plate prefix AC, KC ["Zakarpattia Oblast, Ukraine"] = {}, -- capital [[Uzhhorod]], license plate prefix AO, KO ["Zaporizhzhia Oblast, Ukraine"] = {}, -- capital ''[[Zaporizhzhia]]'', license plate prefix AP, KP ["Zaporizhia Oblast, Ukraine"] = {alias_of = "Zaporizhzhia Oblast, Ukraine", display = true}, ["Zhytomyr Oblast, Ukraine"] = {}, -- capital [[Zhytomyr]], license plate prefix AM, KM } -- oblasts of Ukraine export.ukraine_group = { key_to_placename = make_key_to_placename(", Ukraine$", " Oblast$"), placename_to_key = make_placename_to_key(", Ukraine", " Oblast"), default_container = "Ukraine", default_placetype = "oblast", default_divs = {"raions", "hromadas"}, data = export.ukraine_oblasts, } export.united_kingdom_constituent_countries = { ["England"] = {divs = { "counties", "districts", {type = "local government districts", cat_as = "districts"}, { type = "local government districts with borough status", cat_as = {"districts", "boroughs"}, }, {type = "boroughs", cat_as = {"districts", "boroughs"}}, {type = "civil parishes", container_parent_type = false}, }}, ["Northern Ireland"] = { placetype = {"constituent country", "province", "country"}, divs = {"counties", "districts"}, }, ["Scotland"] = {divs = { {type = "council areas", container_parent_type = false}, "districts", }}, ["Wales"] = {divs = { "counties", {type = "county boroughs", container_parent_type = false}, {type = "communities", container_parent_type = false}, {type = "Welsh communities", cat_as = {{type = "communities", container_parent_type = false}}}, }}, } -- constituent countries and provinces of the United Kingdom export.united_kingdom_group = { placename_to_key = false, default_container = "United Kingdom", default_placetype = {"constituent country", "country"}, addl_divs = { "traditional counties", {type = "historical counties", cat_as = "traditional counties"}, }, -- Don't create categories like 'Category:en:Towns in the United Kingdom' -- or 'Category:en:Places in the United Kingdom'. default_no_container_cat = true, data = export.united_kingdom_constituent_countries, } export.england_counties = { -- NOTE: We used to have various other "no longer" counties commented out, which seems to refer to counties that -- existed officially at some point between 1889 and 1974, which I have removed. I have only kept the three -- ceremonial counties that existed from 1974 (when ceremonial counties were created) to 1996, as well as those -- still considered "historic counties" per [[w:Historic counties of England]]. -- ["Avon, England"] = {wp = "%l (county)"}, -- no longer (1974 to 1996) ["Bedfordshire, England"] = {}, ["Berkshire, England"] = {}, -- ["Brighton and Hove, England"] = {}, -- city -- ["Bristol, England"] = {}, -- city ["Buckinghamshire, England"] = {}, ["Cambridgeshire, England"] = {}, ["Cheshire, England"] = {}, -- ["Cleveland, England"] = {wp = "%l (county)"}, -- no longer (1974 to 1996) ["Cornwall, England"] = {}, -- ["Cumberland, England"] = {}, -- no longer (historic county) ["Cumbria, England"] = {}, ["Derbyshire, England"] = {}, ["Devon, England"] = {}, ["Dorset, England"] = {}, ["County Durham, England"] = {}, ["East Sussex, England"] = {}, ["Essex, England"] = {}, ["Gloucestershire, England"] = {}, ["Greater London, England"] = {}, ["Greater Manchester, England"] = {}, ["Hampshire, England"] = {}, ["Herefordshire, England"] = {}, ["Hertfordshire, England"] = {}, -- ["Humberside, England"] = {}, -- no longer (1974 to 1996) -- ["Huntingdonshire, England"] = {}, -- no longer (historic county) ["Isle of Wight, England"] = {the = true}, ["Kent, England"] = {}, ["Lancashire, England"] = {}, ["Leicestershire, England"] = {}, ["Lincolnshire, England"] = {}, ["Merseyside, England"] = {}, -- ["Middlesex, England"] = {}, -- no longer (historic county) ["Norfolk, England"] = {}, ["Northamptonshire, England"] = {}, ["Northumberland, England"] = {}, ["North Yorkshire, England"] = {}, ["Nottinghamshire, England"] = {}, ["Oxfordshire, England"] = {}, ["Rutland, England"] = {}, ["Shropshire, England"] = {}, ["Somerset, England"] = {}, ["South Humberside, England"] = {}, ["South Yorkshire, England"] = {}, ["Staffordshire, England"] = {}, ["Suffolk, England"] = {}, ["Surrey, England"] = {}, -- ["Sussex, England"] = {}, -- no longer (historic county) ["Tyne and Wear, England"] = {}, ["Warwickshire, England"] = {}, ["West Midlands, England"] = {the = true, wp = "%l (county)"}, -- ["Westmorland, England"] = {}, -- no longer (historic county) ["West Sussex, England"] = {}, ["West Yorkshire, England"] = {}, ["Wiltshire, England"] = {}, ["Worcestershire, England"] = {}, -- ["Yorkshire, England"] = {}, -- no longer (historic county) ["East Riding of Yorkshire, England"] = {the = true}, } -- counties of England export.england_group = { default_container = {key = "England", placetype = "constituent country"}, default_placetype = "county", default_divs = { "districts", {type = "local government districts", cat_as = "districts"}, { type = "local government districts with borough status", cat_as = {"districts", "boroughs"}, }, {type = "boroughs", cat_as = {"districts", "boroughs"}}, "civil parishes", }, data = export.england_counties, } export.northern_ireland_counties = { ["County Antrim, Northern Ireland"] = {}, ["County Armagh, Northern Ireland"] = {}, ["City of Belfast, Northern Ireland"] = {the = true, is_city = true, wp = "Belfast"}, ["County Down, Northern Ireland"] = {}, ["County Fermanagh, Northern Ireland"] = {}, ["County Londonderry, Northern Ireland"] = {}, ["City of Derry, Northern Ireland"] = {the = true, is_city = true, wp = "Derry"}, ["County Tyrone, Northern Ireland"] = {}, } -- counties of Northern Ireland export.northern_ireland_group = { key_to_placename = make_irish_type_key_to_placename(", Northern Ireland$"), placename_to_key = make_irish_type_placename_to_key(", Northern Ireland"), default_container = {key = "Northern Ireland", placetype = "constituent country"}, default_placetype = "county", data = export.northern_ireland_counties, } export.scotland_council_areas = { ["Aberdeenshire, Scotland"] = {}, ["Angus, Scotland"] = {wp = "%l, %c"}, ["Argyll and Bute, Scotland"] = {}, ["City of Aberdeen, Scotland"] = {the = true, wp = "Aberdeen"}, ["Aberdeen"] = {alias_of = "City of Aberdeen, Scotland"}, ["Aberdeen City"] = {alias_of = "City of Aberdeen, Scotland"}, ["City of Dundee, Scotland"] = {the = true, wp = "Dundee"}, ["Dundee"] = {alias_of = "City of Dundee, Scotland"}, ["Dundee City"] = {alias_of = "City of Dundee, Scotland"}, ["City of Edinburgh, Scotland"] = {the = true, wp = "%l council area"}, ["Edinburgh"] = {alias_of = "City of Edinburgh, Scotland"}, ["City of Glasgow, Scotland"] = {the = true, wp = "Glasgow"}, ["Glasgow"] = {alias_of = "City of Glasgow, Scotland"}, ["Clackmannanshire, Scotland"] = {}, ["Dumfries and Galloway, Scotland"] = {}, ["East Ayrshire, Scotland"] = {}, ["East Dunbartonshire, Scotland"] = {}, ["East Lothian, Scotland"] = {}, ["East Renfrewshire, Scotland"] = {}, ["Falkirk, Scotland"] = {wp = "%l council area"}, ["Fife, Scotland"] = {}, ["Highland, Scotland"] = {wp = "%l council area"}, ["Inverclyde, Scotland"] = {}, ["Midlothian, Scotland"] = {}, ["Moray, Scotland"] = {}, ["North Ayrshire, Scotland"] = {}, ["North Lanarkshire, Scotland"] = {}, ["Orkney Islands, Scotland"] = {the = true}, ["Perth and Kinross, Scotland"] = {}, ["Renfrewshire, Scotland"] = {}, ["Scottish Borders, Scotland"] = {the = true}, ["Shetland Islands, Scotland"] = {the = true}, ["South Ayrshire, Scotland"] = {}, ["South Lanarkshire, Scotland"] = {}, ["Stirling, Scotland"] = {wp = "%l council area"}, ["West Dunbartonshire, Scotland"] = {}, ["West Lothian, Scotland"] = {}, ["Western Isles, Scotland"] = {the = true, wp = "Outer Hebrides"}, ["Na h-Eileanan Siar, Scotland"] = {alias_of = "Western Isles, Scotland"}, } -- council areas of Scotland export.scotland_group = { default_container = {key = "Scotland", placetype = "constituent country"}, default_placetype = "council area", data = export.scotland_council_areas, } export.wales_principal_areas = { ["Blaenau Gwent, Wales"] = {}, ["Bridgend, Wales"] = {wp = "%l County Borough"}, ["Caerphilly, Wales"] = {wp = "%l County Borough"}, -- ["Cardiff, Wales"] = {placetype = "city"}, ["Carmarthenshire, Wales"] = {placetype = "county"}, ["Ceredigion, Wales"] = {placetype = "county"}, ["Conwy, Wales"] = {wp = "%l County Borough"}, ["Denbighshire, Wales"] = {placetype = "county"}, ["Flintshire, Wales"] = {placetype = "county"}, ["Gwynedd, Wales"] = {placetype = "county"}, ["Isle of Anglesey, Wales"] = {the = true, placetype = "county"}, ["Anglesey, Wales"] = {alias_of = "Isle of Anglesey, Wales"}, -- differs in "the" ["Merthyr Tydfil, Wales"] = {wp = "%l County Borough"}, ["Monmouthshire, Wales"] = {placetype = "county"}, ["Neath Port Talbot, Wales"] = {}, -- ["Newport, Wales"] = {placetype = "city", wp = "%l, %c"}, ["Pembrokeshire, Wales"] = {placetype = "county"}, ["Powys, Wales"] = {placetype = "county"}, ["Rhondda Cynon Taf, Wales"] = {}, -- ["Swansea, Wales"] = {placetype = "city"}, ["Torfaen, Wales"] = {}, ["Vale of Glamorgan, Wales"] = {the = true}, ["Wrexham, Wales"] = {wp = "%l County Borough"}, } -- principal areas (cities, counties and county boroughs) of Wales export.wales_group = { default_container = {key = "Wales", placetype = "constituent country"}, default_placetype = "county borough", data = export.wales_principal_areas, } export.united_states_states = { ["Alabama, USA"] = {}, ["Alaska, USA"] = {divs = { {type = "boroughs", container_parent_type = "counties"}, {type = "borough seats", container_parent_type = "county seats"}, }}, ["Arizona, USA"] = {}, ["Arkansas, USA"] = {}, ["California, USA"] = {}, ["Colorado, USA"] = {divs = {"counties", "county seats", "municipalities"}}, ["Connecticut, USA"] = {divs = {"counties", "county seats", "municipalities"}}, ["Delaware, USA"] = {}, ["Florida, USA"] = {}, ["Georgia, USA"] = {wp = "%l (U.S. state)"}, ["Hawaii, USA"] = {addl_parents = {"Polynesia"}}, ["Idaho, USA"] = {}, ["Illinois, USA"] = {}, ["Indiana, USA"] = {}, ["Iowa, USA"] = {}, ["Kansas, USA"] = {}, ["Kentucky, USA"] = {}, ["Louisiana, USA"] = {divs = { {type = "parishes", container_parent_type = "counties"}, {type = "parish seats", container_parent_type = "county seats"}, }}, ["Maine, USA"] = {}, ["Maryland, USA"] = {}, ["Massachusetts, USA"] = {}, ["Michigan, USA"] = {}, ["Minnesota, USA"] = {}, ["Mississippi, USA"] = {}, ["Missouri, USA"] = {}, ["Montana, USA"] = {}, ["Nebraska, USA"] = {}, ["Nevada, USA"] = {}, ["New Hampshire, USA"] = {}, ["New Jersey, USA"] = {divs = { "counties", "county seats", {type = "boroughs", prep = "in"}, }}, ["New Mexico, USA"] = {}, ["New York, USA"] = {wp = "%l (state)"}, ["North Carolina, USA"] = {}, ["North Dakota, USA"] = {}, ["Ohio, USA"] = {}, ["Oklahoma, USA"] = {}, ["Oregon, USA"] = {}, ["Pennsylvania, USA"] = {divs = { "counties", "county seats", {type = "boroughs", prep = "in"}, }}, ["Rhode Island, USA"] = {}, ["South Carolina, USA"] = {}, ["South Dakota, USA"] = {}, ["Tennessee, USA"] = {}, ["Texas, USA"] = {}, ["Utah, USA"] = {}, ["Vermont, USA"] = {}, ["Virginia, USA"] = {}, ["Washington, USA"] = {wp = "%l (state)"}, ["West Virginia, USA"] = {}, ["Wisconsin, USA"] = {}, ["Wyoming, USA"] = {}, } -- states of the United States export.united_states_group = { placename_to_key = make_placename_to_key(", USA"), default_container = "United States", default_placetype = "state", default_divs = {"counties", "county seats"}, addl_divs = { {type = "census-designated places", prep = "in"}, {type = "unincorporated communities", prep = "in"}, }, data = export.united_states_states, } export.vietnam_provinces = { -- [[Northeast (Vietnam)|Northeast]] region ["Bắc Giang Province, Vietnam"] = {}, -- capital [[Bắc Giang]] ["Bắc Kạn Province, Vietnam"] = {}, -- capital [[Bắc Kạn]] ["Cao Bằng Province, Vietnam"] = {}, -- capital [[Cao Bằng]] ["Hà Giang Province, Vietnam"] = {}, -- capital [[Hà Giang]] ["Lạng Sơn Province, Vietnam"] = {}, -- capital [[Lạng Sơn]] ["Phú Thọ Province, Vietnam"] = {}, -- capital [[Việt Trì]] ["Quảng Ninh Province, Vietnam"] = {}, -- capital [[Hạ Long]] ["Thái Nguyên Province, Vietnam"] = {}, -- capital [[Thái Nguyên]] ["Tuyên Quang Province, Vietnam"] = {}, -- capital [[Tuyên Quang]] -- [[Northwest (Vietnam)|Northwest]] region ["Lào Cai Province, Vietnam"] = {}, -- capital [[Lào Cai]] ["Yên Bái Province, Vietnam"] = {}, -- capital [[Yên Bái]] ["Điện Biên Province, Vietnam"] = {}, -- capital [[Điện Biên Phủ]] ["Hoà Bình Province, Vietnam"] = {}, -- capital [[Hoà Bình City|Hoà Bình]] ["Hòa Bình Province, Vietnam"] = {alias_of = "Hoà Bình Province, Vietnam", display = true}, ["Lai Châu Province, Vietnam"] = {}, -- capital [[Lai Châu]] ["Sơn La Province, Vietnam"] = {}, -- capital [[Sơn La]] -- [[Red River Delta]] region ["Bắc Ninh Province, Vietnam"] = {}, -- capital [[Bắc Ninh]] ["Hà Nam Province, Vietnam"] = {}, -- capital [[Phủ Lý]] ["Hải Dương Province, Vietnam"] = {}, -- capital [[Hải Dương]] ["Hưng Yên Province, Vietnam"] = {}, -- capital [[Hưng Yên]] ["Nam Định Province, Vietnam"] = {}, -- capital [[Nam Định]] ["Ninh Bình Province, Vietnam"] = {}, -- capital [[Ninh Bình|Hoa Lư]] ["Thái Bình Province, Vietnam"] = {}, -- capital [[Thái Bình]] ["Vĩnh Phúc Province, Vietnam"] = {}, -- capital [[Vĩnh Yên]] -- ["Hanoi"] = {placetype = {"municipality", "city"}}, -- capital [[Hoàn Kiếm district]] -- ["Haiphong"] = {placetype = {"municipality", "city"}}, -- capital [[Hồng Bàng district]] -- [[North Central Coast]] region ["Hà Tĩnh Province, Vietnam"] = {}, -- capital [[Hà Tĩnh]] ["Nghệ An Province, Vietnam"] = {}, -- capital [[Vinh]] ["Quảng Bình Province, Vietnam"] = {}, -- capital [[Đồng Hới]] ["Quảng Trị Province, Vietnam"] = {}, -- capital [[Đông Hà]] ["Thanh Hoá Province, Vietnam"] = {}, -- capital [[Thanh Hoá]] ["Thanh Hóa Province, Vietnam"] = {alias_of = "Thanh Hoá Province, Vietnam", display = true}, -- ["Hue"] = {placetype = {"municipality", "city"}, wp = "Huế"}, -- capital [[Thuận Hoá district]] -- [[Central Highlands (Vietnam)|Central Highlands]] region ["Đắk Lắk Province, Vietnam"] = {}, -- capital [[Buôn Ma Thuột]] ["Đăk Nông Province, Vietnam"] = {}, -- capital [[Gia Nghĩa]] ["Gia Lai Province, Vietnam"] = {}, -- capital [[Pleiku]] ["Kon Tum Province, Vietnam"] = {}, -- capital [[Kon Tum]] ["Lâm Đồng Province, Vietnam"] = {}, -- capital [[Đà Lạt]] -- [[South Central Coast]] region ["Bình Định Province, Vietnam"] = {}, -- capital [[Quy Nhon]] ["Bình Thuận Province, Vietnam"] = {}, -- capital [[Phan Thiết]] ["Khánh Hoà Province, Vietnam"] = {}, -- capital [[Nha Trang]] ["Khánh Hòa Province, Vietnam"] = {alias_of = "Khánh Hoà Province, Vietnam", display = true}, ["Ninh Thuận Province, Vietnam"] = {}, -- capital [[Phan Rang–Tháp Chàm]] ["Phú Yên Province, Vietnam"] = {}, -- capital [[Tuy Hoà]] ["Quảng Nam Province, Vietnam"] = {}, -- capital [[Tam Kỳ]] ["Quảng Ngãi Province, Vietnam"] = {}, -- capital [[Quảng Ngãi]] -- ["Da Nang"] = {placetype = {"municipality", "city"}}, -- capital [[Hải Châu district]] -- [[Southeast (Vietnam)|Southeast]] region ["Bà Rịa–Vũng Tàu Province, Vietnam"] = {}, -- capital [[Bà Rịa]] ["Bình Dương Province, Vietnam"] = {}, -- capital [[Thủ Dầu Một]] ["Bình Phước Province, Vietnam"] = {}, -- capital [[Đồng Xoài]] ["Đồng Nai Province, Vietnam"] = {}, -- capital [[Biên Hoà]] ["Tây Ninh Province, Vietnam"] = {}, -- capital [[Tây Ninh]] -- ["Ho Chi Minh City"] = {placetype = {"municipality", "city"}}, -- capital [[District 1, Ho Chi Minh City|'''District 1''']] -- [[Mekong Delta]] region ["An Giang Province, Vietnam"] = {}, -- capital [[Long Xuyên]] ["Bạc Liêu Province, Vietnam"] = {}, -- capital [[Bạc Liêu]] ["Bến Tre Province, Vietnam"] = {}, -- capital [[Bến Tre]] ["Cà Mau Province, Vietnam"] = {}, -- capital [[Cà Mau]] ["Đồng Tháp Province, Vietnam"] = {}, -- capital [[Cao Lãnh City|Cao Lãnh]] ["Hậu Giang Province, Vietnam"] = {}, -- capital [[Vị Thanh]] ["Kiên Giang Province, Vietnam"] = {}, -- capital [[Rạch Giá]] ["Long An Province, Vietnam"] = {}, -- capital [[Tân An]] ["Sóc Trăng Province, Vietnam"] = {}, -- capital [[Sóc Trăng]] ["Tiền Giang Province, Vietnam"] = {}, -- capital [[Mỹ Tho]] ["Trà Vinh Province, Vietnam"] = {}, -- capital [[Trà Vinh]] ["Vĩnh Long Province, Vietnam"] = {}, -- capital [[Vĩnh Long]] -- ["Can Tho"] = {placetype = {"municipality", "city"}, wp = "Cần Thơ"}, -- capital [[Ninh Kiều district]] } -- provinces of Vietnam export.vietnam_group = { key_to_placename = make_key_to_placename(", Vietnam$", " Province$"), placename_to_key = make_placename_to_key(", Vietnam", " Province"), default_container = "Vietnam", default_placetype = "province", -- There may not be enough districts to subcategorize like this. -- default_divs = "districts", -- For obscure reasons, provinces of Iran, Laos, Thailand and Vietnam use lowercase 'province' default_wp = "%e province", data = export.vietnam_provinces, } ----------------------------------------------------------------------------------- -- City data -- ----------------------------------------------------------------------------------- export.australia_cities = { ["Adelaide"] = {container = "South Australia"}, -- 1,450,000 (Agglomeration) ["Brisbane"] = {container = "Queensland"}, -- 3,450,000 (Conglomeration; including the Gold Coast [750,997 2024 estiamte]) ["Canberra"] = {container = {key = "Australian Capital Territory, Australia", placetype = "territory"}}, -- 510,641 (2024 estimate) ["Melbourne"] = {container = "Victoria"}, -- 5,200,000 (Agglomeration) ["Newcastle, New South Wales"] = {container = "New South Wales", wp = "%l, %c"}, -- 534,033 (2024 estimate) ["Newcastle"] = {alias_of = "Newcastle, New South Wales"}, ["Perth"] = {container = "Western Australia"}, -- 2,350,000 (Agglomeration) ["Sydney"] = {container = "New South Wales"}, -- 5,100,000 (Agglomeration) } export.australia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Australia", "state"), default_placetype = "city", data = export.australia_cities, } export.brazil_cities = { -- Figures from citypopulation.de; retrieved 2025-04-27; reference date 2025-01-01. ["São Paulo"] = {container = "São Paulo"}, -- 22,600,000 (Consolidated Urban Area; including Guarulhos) ["Sao Paulo"] = {alias_of = "São Paulo", display = true}, ["Rio de Janeiro"] = {container = "Rio de Janeiro"}, -- 13,600,000 (Consolidated Urban Area) ["Belo Horizonte"] = {container = "Minas Gerais"}, -- 5,300,000 ["Recife"] = {container = "Pernambuco"}, -- 4,100,000 ["Porto Alegre"] = {container = "Rio Grande do Sul"}, -- 3,950,000 (Consolidated Urban Area) ["Brasília"] = {container = "Distrito Federal"}, -- 3,850,000 ["Brasilia"] = {alias_of = "Brasília", display = true}, ["Fortaleza"] = {container = "Ceará"}, -- 3,825,000 ["Salvador"] = {container = "Bahia", wp = "%l, %c", commonscat = "%l (%c)"}, -- 3,400,000 ["Curitiba"] = {container = "Paraná"}, -- 3,375,000 ["Campinas"] = {container = "São Paulo"}, -- 3,250,000 ["Goiânia"] = {container = "Goiás"}, -- 2,525,000 ["Goiania"] = {alias_of = "Goiânia", display = true}, ["Manaus"] = {container = "Amazonas"}, -- 2,275,000 ["Belém"] = {container = "Pará"}, -- 2,200,000 ["Belem"] = {alias_of = "Belém", display = true}, ["Vitória"] = {container = "Espírito Santo", wp = "%l, %c"}, -- 1,870,000 ["Vitoria"] = {alias_of = "Vitória", display = true}, ["Santos"] = {container = "São Paulo", wp = "%l, %c"}, -- 1,760,000 ["São Luís"] = {container = "Maranhão", wp = "%l, %c"}, -- 1,530,000 ["Sao Luis"] = {alias_of = "São Luís", display = true}, ["Natal"] = {container = "Rio Grande do Norte", wp = "%l, %c"}, -- 1,360,000 ["Florianópolis"] = {container = "Santa Catarina"}, -- 1,260,000 ["Florianopolis"] = {alias_of = "Florianópolis", display = true}, ["Maceió"] = {container = "Alagoas"}, -- 1,220,000 ["Maceio"] = {alias_of = "Maceió", display = true}, ["João Pessoa"] = {container = "Paraíba", wp = "%l, %c"}, -- 1,210,000 ["Joao Pessoa"] = {alias_of = "João Pessoa", display = true}, ["São José dos Campos"] = {container = "São Paulo"}, -- 1,090,000 ["Sao Jose dos Campos"] = {alias_of = "São José dos Campos", display = true}, ["Londrina"] = {container = "Paraná"}, -- 1,050,000 ["Teresina"] = {container = "Piauí"}, -- 1,040,000 } export.brazil_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Brazil", "state"), default_placetype = "city", data = export.brazil_cities, } export.canada_cities = { -- Figures from citypopulation.de; retrieved 2025-04-27; reference date 2025-01-01. ["Toronto"] = {container = "Ontario"}, -- 7,850,000 (Consolidated Urban Area; including Hamilton) ["Montreal"] = {container = "Quebec"}, -- 4,500,000 (Consolidated Urban Area) ["Vancouver"] = {container = "British Columbia"}, -- 3,175,000 (Consolidated Urban Area) ["Calgary"] = {container = "Alberta"}, -- 1,510,000 (Consolidated Urban Area) ["Edmonton"] = {container = "Alberta"}, -- 1,460,000 (Consolidated Urban Area) ["Ottawa"] = {container = "Ontario"}, -- 1,390,000 (Consolidated Urban Area) ["Quebec City"] = {container = "Quebec"}, -- 839,311 metro per Wikipedia (2021 census) ["Winnipeg"] = {container = "Manitoba"}, -- 834,678 metro per Wikipedia (2021 census) ["Hamilton"] = {container = "Ontario", wp = "%l, %c"}, -- 785,184 metro per Wikipedia (2021 census) ["Kitchener"] = {container = "Ontario", wp = "%l, %c"}, -- 575,847 metro per Wikipedia (2021 census) } export.canada_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Canada", "province"), default_placetype = "city", data = export.canada_cities, } export.france_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. ["Paris"] = {container = "Île-de-France"}, -- 11,500,000 (Conglomeration) ["Lyon"] = {container = "Auvergne-Rhône-Alpes"}, -- 2,050,000 (Conglomeration) ["Lyons"] = {alias_of = "Lyon", display = true}, ["Marseille"] = {container = "Provence-Alpes-Côte d'Azur"}, -- 1,710,000 (Conglomeration) ["Marseilles"] = {alias_of = "Marseille", display = true}, ["Lille"] = {container = "Hauts-de-France"}, -- 1,320,000 (Conglomeration) ["Bordeaux"] = {container = "Nouvelle-Aquitaine"}, -- 1,160,000 (Conglomeration) ["Toulouse"] = {container = "Occitania"}, -- 1,150,000 (Conglomeration) ["Nice"] = {container = "Provence-Alpes-Côte d'Azur"}, ["Nantes"] = {container = "Pays de la Loire"}, ["Strasbourg"] = {container = "Grand Est"}, ["Rennes"] = {container = "Brittany"}, } export.france_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", France", "region"), default_placetype = "city", data = export.france_cities, } export.germany_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. -- listed under Rhein-Ruhr Area, total population 10,900,000 (Consolidated Urban Area) ["Cologne"] = {container = "North Rhine-Westphalia"}, ["Köln"] = {alias_of = "Cologne", display = true}, ["Düsseldorf"] = {container = "North Rhine-Westphalia"}, ["Dusseldorf"] = {alias_of = "Düsseldorf", display = true}, ["Dortmund"] = {container = "North Rhine-Westphalia"}, ["Essen"] = {container = "North Rhine-Westphalia"}, ["Duisberg"] = {container = "North Rhine-Westphalia"}, ["Berlin"] = {}, -- 4,700,000 ["Frankfurt"] = {container = "Hesse"}, -- 3,225,000 ["Frankfurt am Main"] = {alias_of = "Frankfurt"}, -- not a display alias as it's longer ["Hamburg"] = {}, -- 2,900,000 ["Munich"] = {container = "Bavaria"}, -- 2,300,000 ["Stuttgart"] = {container = "Baden-Württemberg"}, -- 2,300,000 ["Mannheim"] = {container = "Baden-Württemberg"}, -- 1,550,000 ["Nuremberg"] = {container = "Bavaria"}, -- 1,120,000 ["Hanover"] = {"Lower Saxony"}, -- 1,090,000 ["Bielefeld"] = {container = "North Rhine-Westphalia"}, -- 1,080,000 ["Leipzig"] = {container = "Saxony"}, -- 1,080,000 ["Aachen"] = {container = "North Rhine-Westphalia"}, -- 1,000,000 ["Aix-la-Chapelle"] = {alias_of = "Aachen"}, -- historical; not a display alias ["Bremen"] = {}, } export.germany_cities_group = { default_container = "Germany", canonicalize_key_container = make_canonicalize_key_container(", Germany", "state"), default_placetype = "city", data = export.germany_cities, } export.india_cities = { -- This lists the 65 metro areas per Demographia's 2023 estimates, as found in -- [[w:List_of_million-plus_urban_agglomerations_in_India]]. The last census in India (as of April 2025) was -- conducted in 2011, and the results are not accurate any more. ["Delhi"] = {container = {key = "Delhi, India", placetype = "union territory"}}, -- 31,190,000 ["Mumbai"] = {container = "Maharashtra"}, -- 25,189,000 ["Kolkata"] = {container = "West Bengal"}, -- 21,747,000 ["Bangalore"] = {container = "Karnataka", wp = "Bengaluru"}, -- 15,257,000 ["Bengaluru"] = {alias_of = "Bangalore"}, ["Chennai"] = {container = "Tamil Nadu"}, -- 11,570,000 ["Hyderabad"] = {container = "Telangana"}, -- 9,797,000 ["Ahmedabad"] = {container = "Gujarat"}, -- 8,006,000 ["Pune"] = {container = "Maharashtra"}, -- 6,819,000 ["Surat"] = {container = "Gujarat"}, -- 6,601,000 ["Lucknow"] = {container = "Uttar Pradesh"}, -- 4,661,000 ["Jaipur"] = {container = "Rajasthan"}, -- 4,360,000 ["Kanpur"] = {container = "Uttar Pradesh"}, -- 4,350,000 ["Indore"] = {container = "Madhya Pradesh"}, -- 3,765,000 ["Nagpur"] = {container = "Maharashtra"}, -- 3,493,000 ["Patna"] = {container = "Bihar"}, -- 3,331,000 ["Varanasi"] = {container = "Uttar Pradesh"}, -- 3,229,000 ["Kozhikode"] = {container = "Kerala"}, -- 3,049,000 ["Thiruvananthapuram"] = {container = "Kerala"}, -- 2,851,000 ["Agra"] = {container = "Uttar Pradesh"}, -- 2,737,000 ["Bhopal"] = {container = "Madhya Pradesh"}, -- 2,562,000 ["Coimbatore"] = {container = "Tamil Nadu"}, -- 2,551,000 ["Allahabad"] = {container = "Uttar Pradesh", wp = "Prayagraj"}, -- 2,438,000 ["Prayagraj"] = {alias_of = "Allahabad"}, ["Kochi"] = {container = "Kerala"}, -- 2,381,000 ["Ludhiana"] = {container = "Punjab"}, -- 2,205,000 ["Vadodara"] = {container = "Gujarat"}, -- 2,182,000 ["Chandigarh"] = {container = {key = "Chandigarh, India", placetype = "union territory"}}, -- 2,168,000 ["Madurai"] = {container = "Tamil Nadu"}, -- 2,048,000 ["Meerut"] = {container = "Uttar Pradesh"}, -- 2,011,000 ["Visakhapatnam"] = {container = "Andhra Pradesh"}, -- 2,005,000 ["Jamshedpur"] = {container = "Jharkhand"}, -- 1,925,000 ["Malappuram"] = {container = "Kerala"}, -- 1,868,000 ["Nashik"] = {container = "Maharashtra"}, -- 1,810,000 ["Asansol"] = {container = "West Bengal"}, -- 1,720,000 ["Aligarh"] = {container = "Uttar Pradesh"}, -- 1,660,000 ["Ranchi"] = {container = "Jharkhand"}, -- 1,638,000 ["Thrissur"] = {container = "Kerala"}, -- 1,578,000 ["Kollam"] = {container = "Kerala"}, -- 1,576,000 ["Jabalpur"] = {container = "Madhya Pradesh"}, -- 1,533,000 ["Dhanbad"] = {container = "Jharkhand"}, -- 1,503,000 ["Jodhpur"] = {container = "Rajasthan"}, -- 1,497,000 ["Aurangabad"] = {container = "Maharashtra"}, -- 1,490,000 ["Chhatrapati Sambhajinagar"] = {alias_of = "Aurangabad"}, ["Rajkot"] = {container = "Gujarat"}, -- 1,487,000 ["Gwalior"] = {container = "Madhya Pradesh"}, -- 1,477,000 ["Raipur"] = {container = "Chhattisgarh"}, -- 1,429,000 ["Gorakhpur"] = {container = "Uttar Pradesh"}, -- 1,410,000 ["Kannur"] = {container = "Kerala"}, -- 1,360,000 ["Bareilly"] = {container = "Uttar Pradesh"}, -- 1,355,000 ["Guwahati"] = {container = "Assam"}, -- 1,355,000 ["Moradabad"] = {container = "Uttar Pradesh"}, -- 1,345,000 ["Amritsar"] = {container = "Punjab"}, -- 1,313,000 ["Mysore"] = {container = "Karnataka"}, -- 1,296,000 ["Bhilai"] = {container = "Chhattisgarh"}, -- 1,293,000 ["Durg-Bhilainagar"] = {alias_of = "Bhilai"}, ["Durg-Bhilai"] = {alias_of = "Bhilai"}, ["Durg"] = {alias_of = "Bhilai"}, ["Bhilainagar"] = {alias_of = "Bhilai"}, ["Vijayawada"] = {container = "Andhra Pradesh"}, -- 1,232,000 ["Srinagar"] = {container = {key = "Jammu and Kashmir, India", placetype = "union territory"}}, -- 1,212,000 ["Salem"] = {container = "Tamil Nadu", wp = "%l, %c"}, -- 1,189,000 ["Kota"] = {container = "Rajasthan"}, -- 1,172,000 ["Jalandhar"] = {container = "Punjab"}, -- 1,165,000 ["Saharanpur"] = {container = "Uttar Pradesh"}, -- 1,152,000 ["Dehradun"] = {container = "Uttarakhand"}, -- 1,136,000 ["Tiruchirappalli"] = {container = "Tamil Nadu"}, -- 1,131,000 ["Bhubaneswar"] = {container = "Odisha"}, -- 1,112,000 ["Jammu"] = {container = {key = "Jammu and Kashmir, India", placetype = "union territory"}}, -- 1,103,000 ["Solapur"] = {container = "Maharashtra"}, -- 1,082,000 ["Hubli-Dharwad"] = {container = "Karnataka", wp = "Hubli–Dharwad"}, -- 1,062,000; wp with en dash ["Hubli"] = {alias_of = "Hubli-Dharwad"}, ["Dharwad"] = {alias_of = "Hubli-Dharwad"}, ["Puducherry"] = {container = {key = "Puducherry, India", placetype = "union territory"}}, -- 1,024,000 ["Pondicherry"] = {alias_of = "Puducherry", display = true}, -- satellite/secondary cities of metro area (none in citypopulation.de) ["Ghaziabad"] = {container = "Uttar Pradesh"}, -- 1,729,000 city, 2,358,525 urban agglomeration per 2011 census; 3,406,061 2025 estimate from official website; part of Delhi metro area ["Faridabad"] = {container = "Haryana"}, -- 1,414,050 city per 2011 census; part of Delhi metro area ["Thane"] = {container = "Maharashtra"}, -- 1,841,488 city per 2011 census; part of Mumbai metro area ["Kalyan-Dombivli"] = {container = "Maharashtra"}, -- 1,246,381 city per 2011 census; part of Mumbai metro area ["Kalyan-Dombivali"] = {alias_of = "Kalyan-Dombivli", display = true}, ["Kalyan"] = {alias_of = "Kalyan-Dombivli"}, ["Dombivli"] = {alias_of = "Kalyan-Dombivli"}, ["Dombivali"] = {alias_of = "Kalyan-Dombivli"}, ["Vasai-Virar"] = {container = "Maharashtra"}, -- 1,221,233 city per 2011 census; part of Mumbai metro area ["Vasai"] = {alias_of = "Vasai-Virar"}, ["Virar"] = {alias_of = "Vasai-Virar"}, ["Navi Mumbai"] = {container = "Maharashtra"}, -- 1,120,547 city per 2011 census; part of Mumbai metro area ["Howrah"] = {container = "West Bengal"}, -- 1,077,075 city ("metropolis"), 2,811,344 "metro" per 2011 census; part of Kolkata metro area ["Pimpri-Chinchwad"] = {container = "Maharashtra"}, -- 1,727,692 per 2011 census; part of Pune metro area ["Pimpri Chinchwad"] = {alias_of = "Pimpri-Chinchwad", display = true}, } export.india_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", India", "state"), default_placetype = "city", data = export.india_cities, } export.indonesia_cities = { -- cities where the city proper has more than 1,000,000 people as of mid-2023 estimate ["Jakarta"] = {container = "Special Capital Region of Jakarta", divs = { {type = "subdistricts", container_parent_type = false}, }}, ["Surabaya"] = {container = "East Java"}, ["Bekasi"] = {container = "West Java"}, -- part of Jakarta metro area ["Bandung"] = {container = "West Java"}, ["Medan"] = {container = "North Sumatra"}, ["Depok"] = {container = "West Java"}, -- part of Jakarta metro area ["Tangerang"] = {container = "Banten"}, -- part of Jakarta metro area ["Palembang"] = {container = "South Sumatra"}, ["Semarang"] = {container = "Central Java"}, ["Makassar"] = {container = "South Sulawesi"}, ["South Tangerang"] = {container = "Banten"}, -- part of Jakarta metro area ["Batam"] = {container = "Riau Islands"}, ["Bogor"] = {container = "West Java"}, -- part of Jakarta metro area ["Pekanbaru"] = {container = "Riau"}, ["Bandar Lampung"] = {container = "Lampung"}, -- other metro areas over 1,000,000 people ["Padang"] = {container = "West Sumatra"}, ["Samarinda"] = {container = "East Kalimantan"}, ["Malang"] = {container = "East Java"}, ["Yogyakarta"] = {container = "Special Region of Yogyakarta"}, ["Denpasar"] = {container = "Bali"}, ["Cirebon"] = {container = "West Java"}, ["Surakarta"] = {container = "Central Java"}, ["Banjarmasin"] = {container = "South Kalimantan"}, ["Tasikmalaya"] = {container = "West Java"}, } export.indonesia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Indonesia", "province"), default_placetype = "city", data = export.indonesia_cities, } export.italy_cities = { -- Data per [[w:List_of_metropolitan_areas_of_Italy]]. There are several lists given; the most recent one, used -- here, only gives estimates as of Jan 1, 2014. ["Milan"] = {container = "Lombardy"}, -- 6,623,798 ["Naples"] = {container = "Campania"}, -- 5,294,546 ["Rome"] = {container = "Lazio"}, -- 4,447,881 ["Turin"] = {container = "Piedmont"}, -- 1,865,284 ["Venice"] = {container = "Veneto"}, -- 1,645,900 ["Florence"] = {container = "Tuscany"}, -- 1,485,030 ["Bari"] = {container = "Apulia"}, -- 1,257,459 ["Palermo"] = {container = "Sicily"}, -- 1,183,084 -- include a few just below 1,000,000 metro area that may be above it by now (depending on the definition). ["Catania"] = {container = "Sicily"}, -- 988,240 ["Brescia"] = {container = "Lombardy"}, -- 924,090 ["Genoa"] = {container = "Liguria"}, -- 861,318 } export.italy_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Italy", "region"), default_placetype = "city", data = export.italy_cities, } export.japan_cities = { -- Population figures from [[w:List of cities in Japan]]. Metro areas from -- [[w:List of metropolitan areas in Japan]]. ["Tokyo"] = {keydesc = "[[Tokyo]] Metropolis, the [[capital city]] and a [[prefecture]] of [[Japan]] (which is a country in [[Asia]])", placetype = {"city", "prefecture"}, divs = { {type = "special wards", container_parent_type = false}, {type = "cities", prep = "in"}, }, }, ["Yokohama"] = {container = "Kanagawa"}, -- 3,697,894 ["Osaka"] = {container = "Osaka"}, -- 2,668,586 ["Nagoya"] = {container = "Aichi"}, -- 2,283,289 -- FIXME, Hokkaido is handled specially. ["Sapporo"] = {container = "Hokkaido"}, -- 1,918,096 ["Fukuoka"] = {container = "Fukuoka"}, -- 1,581,527 ["Kobe"] = {container = "Hyōgo"}, -- 1,530,847 ["Kyoto"] = {container = "Kyoto"}, -- 1,474,570 ["Kawasaki"] = {container = "Kanagawa", wp = "%l, Kanagawa"}, -- 1,373,630 ["Saitama"] = {container = "Saitama", wp = "%l (city)", commonscat = "%l, %c"}, -- 1,192,418 ["Hiroshima"] = {container = "Hiroshima"}, -- 1,163,806 ["Sendai"] = {container = "Miyagi"}, -- 1,029,552 -- the remaining cities are considered "central cities" in a 1,000,000+ metro area -- (sometimes there is more than one central city in the area). ["Kitakyushu"] = {container = "Fukuoka"}, -- 986,998 ["Chiba"] = {container = "Chiba", wp = "%l (city)", commonscat = "%l, %c"}, -- 938,695 ["Sakai"] = {container = "Osaka"}, -- 835,333 ["Niigata"] = {container = "Niigata", wp = "%l (city)", commonscat = "%l, %c"}, -- 813,053 ["Hamamatsu"] = {container = "Shizuoka"}, -- 811,431 ["Shizuoka"] = {container = "Shizuoka", wp = "%l (city)", commonscat = "%l, %c"}, -- 710,944 ["Sagamihara"] = {container = "Kanagawa"}, -- 706,342 ["Okayama"] = {container = "Okayama"}, -- 701,293 ["Kumamoto"] = {container = "Kumamoto"}, -- 670,348 ["Kagoshima"] = {container = "Kagoshima"}, -- 605,196 -- skipped 6 cities (Funabashi, Hachiōji, Kawaguchi, Himeji, Matsuyama, Higashiōsaka) -- with population in the range 509k - 587k because not central cities in any -- 1,000,000+ metro area. ["Utsunomiya"] = {container = "Tochigi"}, -- 507,833 } export.japan_cities_group = { default_container = "Japan", canonicalize_key_container = make_canonicalize_key_container(" Prefecture, Japan", "prefecture"), default_placetype = "city", data = export.japan_cities, } export.mexico_cities = { ["Mexico City"] = {}, -- its own state ["Monterrey"] = {container = "Nuevo León"}, ["Guadalajara"] = {container = "Jalisco"}, ["Puebla"] = {container = "Puebla", wp = "%l (city)"}, ["Toluca"] = {container = "State of Mexico"}, ["Tijuana"] = {container = "Baja California"}, -- Include the state in the category for León due to possible confusion with León, Spain. ["León, Guanajuato"] = {container = "Guanajuato", wp = "%l, %c"}, ["León"] = {alias_of = "León, Guanajuato"}, ["Leon"] = {alias_of = "León, Guanajuato", display = true}, ["Querétaro"] = {container = "Querétaro", wp = "%l (city)"}, ["Queretaro"] = {alias_of = "Querétaro", display = true}, ["Ciudad Juárez"] = {container = "Chihuahua"}, ["Juárez"] = {alias_of = "Ciudad Juárez"}, ["Juarez"] = {alias_of = "Ciudad Juárez", display = "Juárez"}, ["Torreón"] = {container = "Coahuila"}, ["Torreon"] = {alias_of = "Torreón", display = true}, -- Include the state in the category for Mérida due to possible confusion with Mérida, Spain or -- Mérida, Venezuela. ["Mérida, Yucatán"] = {container = "Yucatán", wp = "%l, %c"}, ["Mérida"] = {alias_of = "Mérida, Yucatán"}, ["Merida"] = {alias_of = "Mérida, Yucatán", display = true}, ["San Luis Potosí"] = {container = "San Luis Potosí", wp = "%l (city)"}, ["San Luis Potosi"] = {alias_of = "San Luis Potosí", display = true}, ["Aguascalientes"] = {container = "Aguascalientes", wp = "%l (city)"}, ["Mexicali"] = {container = "Baja California"}, } export.mexico_cities_group = { default_container = "Mexico", canonicalize_key_container = make_canonicalize_key_container(", Mexico", "state"), default_placetype = "city", data = export.mexico_cities, } export.nigeria_cities = { -- Figures from citypopulation.de unless otherwise indicated; retrieved 2025-04-26; reference date 2025-01-01. ["Lagos"] = {container = "Lagos"}, -- 21,300,000 (unindicated; population of low reliability) ["Kano"] = {container = "Kano", wp = "%l (city)"}, -- 5,350,000 (unindicated; population of low reliability) ["Ibadan"] = {container = "Oyo"}, -- 3,400,000 (unindicated; population of low reliability) ["Abuja"] = {container = {key = "Federal Capital Territory, Nigeria", placetype = "federal territory"}}, -- 3,050,000 (unindicated; population of low reliability) ["Port Harcourt"] = {container = "Rivers"}, -- 2,250,000 (unindicated; population of low reliability) ["Kaduna"] = {container = "Kaduna"}, -- 1,980,000 (unindicated; population of low reliability) ["Benin City"] = {container = "Edo"}, -- 1,790,000 (unindicated; population of low reliability) ["Aba"] = {container = "Abia", wp = "%l, Nigeria"}, -- 1,280,000 (unindicated; population of low reliability) ["Onitsha"] = {container = "Anambra"}, -- 1,230,000 (unindicated; population of low reliability) ["Maiduguri"] = {container = "Borno"}, -- 1,190,000 (unindicated; population of low reliability) ["Ilorin"] = {container = "Kwara"}, -- 1,160,000 (unindicated; population of low reliability) ["Sokoto"] = {container = "Sokoto", wp = "%l (city)"}, -- 1,140,000 (unindicated; population of low reliability) ["Jos"] = {container = "Plateau"}, -- 1,110,000 (unindicated; population of low reliability) ["Zaria"] = {container = "Kaduna"}, -- 1,050,000 (unindicated; population of low reliability) ["Enugu"] = {container = "Enugu", wp = "%l (city)"}, -- 1,010,000 (unindicated; population of low reliability) } export.nigeria_cities_group = { default_container = "Nigeria", canonicalize_key_container = make_canonicalize_key_container(" State, Nigeria", "state"), default_placetype = "city", data = export.nigeria_cities, } export.pakistan_cities = { -- Figures from citypopulation.de; retrieved 2025-04-26; reference date 2025-01-01. ["Karachi"] = {container = "Sindh"}, -- 21,000,000 (Consolidated Urban Area) ["Lahore"] = {container = "Punjab"}, -- 14,600,000 (Consolidated Urban Area) ["Rawalpindi"] = {container = "Punjab"}, -- 5,600,000 (Consolidated Urban Area; including Islamabad) ["Islamabad"] = {container = {key = "Islamabad Capital Territory, Pakistan", placetype = "federal territory"}}, -- 5,600,000 (Consolidated Urban Area; including Rawalpindi) ["Faisalabad"] = {container = "Punjab"}, -- 4,125,000 (Consolidated Urban Area) ["Gujranwala"] = {container = "Punjab"}, -- 3,450,000 (Consolidated Urban Area) -- there is also Hyderabad in India (very confusing) ["Hyderabad, Pakistan"] = {container = "Sindh", wp = "%l, %c"}, -- 2,475,000 (Consolidated Urban Area) ["Hyderabad"] = {alias_of = "Hyderabad, Pakistan"}, ["Multan"] = {container = "Punjab"}, -- 2,425,000 (Consolidated Urban Area) ["Peshawar"] = {container = "Khyber Pakhtunkhwa"}, -- 2,150,000 (Consolidated Urban Area) ["Quetta"] = {container = "Balochistan"}, -- 1,720,000 (Urban Area) ["Sargodha"] = {container = "Punjab"}, -- 1,080,000 (Urban Area) ["Sialkot"] = {container = "Punjab"}, -- 1,050,000 (Consolidated Urban Area) } export.pakistan_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Pakistan", "province"), default_placetype = "city", data = export.pakistan_cities, } export.philippines_cities = { -- Skipped some cities in Metro Manila (Taguig, Pasig) which don't have districts. -- Other cities outside Metro Manila skipped as not central city in their urban area. ["Quezon City"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, -- Don't display-canonicalize Foo to Foo City as it may make the display weird. ["Quezon"] = {alias_of = "Quezon City"}, ["Manila"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, ["Davao City"] = {container = "Davao del Sur"}, ["Davao"] = {alias_of = "Davao City"}, ["Caloocan"] = {container = {key = "Metro Manila, Philippines", placetype = "region"}}, ["Zamboanga City"] = {container = "Zamboanga del Sur"}, ["Zamboanga"] = {alias_of = "Zamboanga City"}, ["Cebu City"] = {container = "Cebu"}, ["Cebu"] = {alias_of = "Cebu City"}, ["Antipolo"] = {container = "Rizal"}, ["Cagayan de Oro"] = {container = "Misamis Oriental"}, ["Dasmariñas"] = {container = "Cavite"}, ["Dasmarinas"] = {alias_of = "Dasmariñas", display = true}, ["General Santos"] = {container = "South Cotabato"}, ["San Jose del Monte"] = {container = "Bulacan"}, ["Bacolod"] = {container = "Negros Occidental"}, ["Calamba"] = {container = "Laguna", wp = "%l, %c"}, ["Angeles"] = {container = "Pampanga", wp = "Angeles City"}, ["Angeles City"] = {alias_of = "Angeles"}, ["Iloilo City"] = {container = "Iloilo"}, ["Iloilo"] = {alias_of = "Iloilo City"}, } export.philippines_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Philippines", "province"), default_placetype = "city", data = export.philippines_cities, } export.russia_cities = { -- Figures from citypopulation.de; retrieved 2025-04-26; reference date 2025-01-01. ["Moscow"] = {}, -- 18,800,000 (Agglomeration) ["Saint Petersburg"] = {}, -- 6,350,000 (Agglomeration) ["Novosibirsk"] = {container = "Novosibirsk Oblast"}, -- 1,820,000 (Agglomeration) ["Yekaterinburg"] = {container = "Sverdlovsk Oblast"}, -- 1,810,000 (Agglomeration) ["Nizhny Novgorod"] = {container = "Nizhny Novgorod Oblast"}, -- 1,620,000 (Agglomeration) ["Kazan"] = {container = {key = "Tatarstan, Russia", placetype = "republic"}}, -- 1,560,000 (Agglomeration) ["Chelyabinsk"] = {container = "Chelyabinsk Oblast"}, -- 1,430,000 (Agglomeration) ["Rostov-on-Don"] = {container = "Rostov Oblast"}, -- 1,390,000 (Agglomeration) ["Rostov-na-Donu"] = {alias_of = "Rostov-on-Don", display = true}, ["Krasnodar"] = {container = {key = "Krasnodar Krai, Russia", placetype = "krai"}}, -- 1,370,000 (Agglomeration) ["Samara"] = {container = "Samara Oblast"}, -- 1,350,000 (Agglomeration) ["Krasnoyarsk"] = {container = {key = "Krasnoyarsk Krai, Russia", placetype = "krai"}}, -- 1,270,000 (Agglomeration) ["Ufa"] = {container = {key = "Bashkortostan, Russia", placetype = "republic"}}, -- 1,230,000 (Agglomeration) ["Saratov"] = {container = "Saratov Oblast"}, -- 1,170,000 (Agglomeration) ["Omsk"] = {container = "Omsk Oblast"}, -- 1,140,000 (Agglomeration) ["Voronezh"] = {container = "Voronezh Oblast"}, -- 1,130,000 (Agglomeration) ["Volgograd"] = {container = "Volgograd Oblast"}, -- 1,080,000 (Agglomeration) ["Perm"] = {container = {key = "Perm Krai, Russia", placetype = "krai"}, wp = "%l, Russia"}, -- 1,070,000 (Agglomeration) } export.russia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Russia", "oblast"), default_container = "Russia", default_placetype = "city", data = export.russia_cities, } export.saudi_arabia_cities = { -- Figures for the first five from [[w:List of cities and towns in Saudi Arabia]] as of 2022. Unclear if these are -- metro, urban or city proper figures. ["Riyadh"] = {container = "Riyadh"}, -- 7,000,100; 7,700,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Jeddah"] = {container = "Mecca"}, -- 3,751,917; 3,950,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Jedda"] = {alias_of = "Jeddah", display = true}, ["Jiddah"] = {alias_of = "Jeddah", display = true}, ["Jidda"] = {alias_of = "Jeddah", display = true}, ["Dammam"] = {container = "Eastern"}, -- 2,638,166; 2,925,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Mecca"] = {container = "Mecca"}, -- 2,385,509; 2,675,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Makkah"] = {alias_of = "Mecca", display = true}, ["Medina"] = {container = "Medina"}, -- 1,477,023; 1,530,000 per citypopulation.de 2025-01-01 (City) ["Hofuf"] = {container = "Eastern"}, -- 1,060,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Khamis Mushait"] = {container = "Aseer"}, -- 1,030,000 per citypopulation.de 2025-01-01 (Agglomeration) ["Khamis Mushayt"] = {alias_of = "Khamis Mushait", display = true}, } export.saudi_arabia_cities_group = { canonicalize_key_container = make_canonicalize_key_container(" Province, Saudi Arabia", "province"), default_placetype = "city", data = export.saudi_arabia_cities, } export.south_korea_cities = { -- All cities listed are not associated with any county. ["Seoul"] = {}, ["Busan"] = {}, ["Incheon"] = {}, ["Daegu"] = {}, ["Daejeon"] = {}, ["Gwangju"] = {}, ["Ulsan"] = {}, } export.south_korea_cities_group = { default_container = "South Korea", canonicalize_key_container = make_canonicalize_key_container(" County, South Korea", "province"), default_placetype = "city", data = export.south_korea_cities, } export.spain_cities = { ["Madrid"] = {container = "Community of Madrid"}, ["Barcelona"] = {container = "Catalonia"}, ["Valencia"] = {container = "Valencia"}, ["Seville"] = {container = "Andalusia"}, ["Bilbao"] = {container = "Basque Country"}, } export.spain_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", Spain", "autonomous community"), default_placetype = "city", data = export.spain_cities, } export.taiwan_cities = { ["New Taipei City"] = {}, ["New Taipei"] = {alias_of = "New Taipei City", display = true}, ["Taichung"] = {}, ["Kaohsiung"] = {wp = "%l, Taiwan"}, ["Taipei"] = {}, ["Taoyuan"] = {}, ["Tainan"] = {}, -- these last three are not special municipalities ["Chiayi"] = {placetype = "city"}, ["Hsinchu"] = {placetype = "city"}, ["Keelung"] = {placetype = "city"}, } export.taiwan_cities_group = { placename_to_key = false, -- don't add ", Taiwan" to make the key canonicalize_key_container = make_canonicalize_key_container(", Taiwan", "county"), default_container = "Taiwan", default_placetype = {"special municipality", "municipality", "city"}, default_is_city = true, default_divs = {"districts"}, data = export.taiwan_cities, } -- NOTE: It's OK to mix cities from different constituent countries; as long as the immediate container is correct, -- everything else will be figured out. export.united_kingdom_cities = { ["London"] = {container = "Greater London"}, ["Manchester"] = {container = "Greater Manchester"}, ["Birmingham"] = {container = "West Midlands"}, ["Liverpool"] = {container = "Merseyside"}, ["Glasgow"] = {container = {key = "City of Glasgow, Scotland", placetype = "council area"}}, ["Leeds"] = {container = "West Yorkshire"}, ["Newcastle upon Tyne"] = {container = "Tyne and Wear"}, ["Newcastle"] = {alias_of = "Newcastle upon Tyne"}, ["Bristol"] = {container = {key = "England", placetype = "constituent country"}}, ["Cardiff"] = {container = {key = "Wales", placetype = "constituent country"}}, ["Portsmouth"] = {container = "Hampshire"}, ["Edinburgh"] = {container = {key = "City of Edinburgh, Scotland", placetype = "council area"}}, -- under 1,000,000 people but principal areas of Wales; requested by [[User:Donnanz]] ["Swansea"] = {container = {key = "Wales", placetype = "constituent country"}}, ["Newport"] = {container = {key = "Wales", placetype = "constituent country"}, wp = "Newport, Wales"}, } export.united_kingdom_cities_group = { canonicalize_key_container = make_canonicalize_key_container(", England", "county"), default_placetype = "city", data = export.united_kingdom_cities, } export.united_states_cities = { -- top 50 CSA's by population, with the top and sometimes 2nd or 3rd city listed ["New York City"] = {container = "New York", wp = "%l", divs = { {type = "boroughs", container_parent_type = false}, }}, -- Don't display-canonicalize as it may make the display weird (e.g. in the context New York, New York). ["New York"] = {alias_of = "New York City"}, ["Newark"] = {container = "New Jersey"}, ["Los Angeles"] = {container = "California", wp = "%l"}, ["Long Beach"] = {container = "California"}, ["Riverside"] = {container = "California"}, ["Chicago"] = {container = "Illinois", wp = "%l"}, ["Washington, D.C."] = {wp = "%l"}, ["Washington, DC"] = {alias_of = "Washington, D.C.", display = true}, ["Washington D.C."] = {alias_of = "Washington, D.C.", display = true}, ["Washington DC"] = {alias_of = "Washington, D.C.", display = true}, -- Don't display-canonicalize as it may make the display weird (e.g. if the holonym is followed by a District of -- Columbia holonym). ["Washington"] = {alias_of = "Washington, D.C."}, ["Baltimore"] = {container = "Maryland", wp = "%l"}, -- to avoid conflict with San Jose in Costa Rica ["San Jose, California"] = {container = "California"}, ["San Jose"] = {alias_of = "San Jose, California"}, ["San Francisco"] = {container = "California", wp = "%l"}, ["Oakland"] = {container = "California"}, ["Boston"] = {container = "Massachusetts", wp = "%l"}, ["Providence"] = {container = "Rhode Island"}, ["Dallas"] = {container = "Texas", wp = "%l", commonscat = "%l, %c"}, ["Fort Worth"] = {container = "Texas"}, ["Philadelphia"] = {container = "Pennsylvania", wp = "%l"}, ["Houston"] = {container = "Texas", wp = "%l"}, ["Miami"] = {container = "Florida", wp = "%l", commonscat = "%l, %c"}, ["Atlanta"] = {container = "Georgia", wp = "%l"}, ["Detroit"] = {container = "Michigan", wp = "%l"}, ["Phoenix"] = {container = "Arizona", wp = "%l", commonscat = "%l, %c"}, ["Mesa"] = {container = "Arizona"}, ["Seattle"] = {container = "Washington", wp = "%l"}, ["Orlando"] = {container = "Florida"}, ["Minneapolis"] = {container = "Minnesota", wp = "%l"}, ["Cleveland"] = {container = "Ohio", wp = "%l", commonscat = "%l, %c"}, ["Denver"] = {container = "Colorado", wp = "%l", commonscat = "%l, %c"}, ["San Diego"] = {container = "California", wp = "%l", commonscat = "%l, %c"}, ["Portland"] = {container = "Oregon"}, ["Tampa"] = {container = "Florida"}, ["St. Louis"] = {container = "Missouri", wp = "%l", commonscat = "%l, %c"}, ["Saint Louis"] = {alias_of = "St. Louis", display = true}, ["Charlotte"] = {container = "North Carolina"}, ["Sacramento"] = {container = "California"}, ["Pittsburgh"] = {container = "Pennsylvania", wp = "%l"}, ["Salt Lake City"] = {container = "Utah", wp = "%l"}, ["San Antonio"] = {container = "Texas", wp = "%l", commonscat = "%l, %c"}, ["Columbus"] = {container = "Ohio"}, ["Kansas City"] = {container = "Missouri", wp = "%l metropolitan area", commonscat = "%l, %c"}, ["Indianapolis"] = {container = "Indiana", wp = "%l"}, ["Las Vegas"] = {container = "Nevada", wp = "%l"}, ["Cincinnati"] = {container = "Ohio", wp = "%l", commonscat = "%l, %c"}, ["Austin"] = {container = "Texas"}, ["Milwaukee"] = {container = "Wisconsin", wp = "%l", commonscat = "%l, %c"}, ["Raleigh"] = {container = "North Carolina"}, ["Nashville"] = {container = "Tennessee"}, ["Virginia Beach"] = {container = "Virginia"}, ["Norfolk"] = {container = "Virginia"}, ["Greensboro"] = {container = "North Carolina"}, ["Winston-Salem"] = {container = "North Carolina"}, ["Jacksonville"] = {container = "Florida"}, ["New Orleans"] = {container = "Louisiana", wp = "%l"}, ["Louisville"] = {container = "Kentucky"}, ["Greenville"] = {container = "South Carolina"}, ["Hartford"] = {container = "Connecticut"}, ["Oklahoma City"] = {container = "Oklahoma", wp = "%l"}, ["Grand Rapids"] = {container = "Michigan"}, ["Memphis"] = {container = "Tennessee"}, ["Birmingham, Alabama"] = {container = "Alabama"}, ["Birmingham"] = {alias_of = "Birmingham, Alabama"}, ["Fresno"] = {container = "California"}, ["Richmond"] = {container = "Virginia"}, ["Harrisburg"] = {container = "Pennsylvania"}, -- any major city of top 50 MSA's that's missed by previous ["Buffalo"] = {container = "New York"}, -- any of the top 50 city by city population that's missed by previous ["El Paso"] = {container = "Texas"}, ["Albuquerque"] = {container = "New Mexico"}, ["Tucson"] = {container = "Arizona"}, ["Colorado Springs"] = {container = "Colorado"}, ["Omaha"] = {container = "Nebraska"}, ["Tulsa"] = {container = "Oklahoma"}, -- skip Arlington, Texas; too obscure and likely to be interpreted as Arlington, Virginia } export.united_states_cities_group = { default_container = "United States", canonicalize_key_container = make_canonicalize_key_container(", USA", "state"), default_placetype = "city", default_wp = "%l, %c", data = export.united_states_cities, } export.new_york_boroughs = { ["Bronx"] = {the = true, wp = "The Bronx"}, ["Brooklyn"] = {}, ["Manhattan"] = {}, ["Queens"] = {}, ["Staten Island"] = {}, } export.new_york_boroughs_group = { default_container = {key = "New York City", placetype = "city"}, default_placetype = "borough", default_is_city = true, data = export.new_york_boroughs, } export.vietnam_cities = { -- Figures from citypopulation.de (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated. ["Ho Chi Minh City"] = {}, -- 14,300,000 (Agglomeration; inclunding Bien Hoa) ["Saigon"] = {alias_of = "Ho Chi Minh City"}, ["Hanoi"] = {}, -- 7,350,000 (Agglomeration) ["Da Nang"] = {}, -- 1,500,000 (Agglomeration) ["Danang"] = {alias_of = "Da Nang", display = true}, ["Haiphong"] = {}, -- 1,450,000 (Agglomeration) ["Hai Phong"] = {alias_of = "Haiphong", display = true}, -- This is the one entry in this list that is not a province-level municipality; instead it's a "provincial city" -- meaning it is directly under its province as opposed to being contained in a district. ["Bien Hoa"] = {placetype = "city", container = "Đồng Nai", wp = "Biên Hòa"}, -- 1,272,235 (2022 city population per Wikipedia) ["Biên Hòa"] = {alias_of = "Bien Hoa", display = true}, ["Biên Hoà"] = {alias_of = "Bien Hoa", display = true}, -- These two not in citypopulation.de because the urban population may be slightly under 1,000,000, but they are -- both province-level municipalities and close to the 1,000,000 mark. ["Can Tho"] = {wp = "Cần Thơ"}, -- 1,456,000 municipality (2019 census), 994,704 urban (2022 General Statistics Office of Vietnam estimate); capital [[Ninh Kiều district]] ["Cần Thơ"] = {alias_of = "Can Tho", display = true}, ["Hue"] = {wp = "Huế"}, -- 1,257,000 municipality (2019 census), 840,000 urban (2022 General Statistics Office of Vietnam estimate); -- capital [[Thuận Hóa district]] ["Huế"] = {alias_of = "Hue", display = true}, } export.vietnam_cities_group = { placename_to_key = false, -- don't add ", Vietnam" to make the key default_container = "Vietnam", canonicalize_key_container = make_canonicalize_key_container(" Province, Vietnam", "province"), -- Most of the cities listed are province-level municipalities in addition, which contain a certain amount of -- rural territory surrounding the city, but not enough to separate the municipality from the city as distinct -- known locations. default_placetype = {"municipality", "city"}, default_is_city = true, -- There may not be enough districts to subcategorize like this. -- default_divs = "districts", data = export.vietnam_cities, } export.misc_cities = { ------------------ Africa ------------------- -- Sorted by country and then within the country, by decreasing population; figures from citypopulation.de -- (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated; combined with data from -- [[w:List of urban areas in Africa by population]]. ["Algiers"] = {container = "Algeria"}, -- 4,325,000 (Consolidated Urban Area) ["Oran"] = {container = "Algeria"}, -- 1,640,000 (Consolidated Urban Area) ["Luanda"] = {container = "Angola"}, -- 9,650,000 (Urban Area) ["Benguela"] = {container = "Angola"}, -- 1,420,000 (Urban Area) ["Cotonou"] = {container = "Benin"}, -- 2,150,000 (Agglomeration) ["Ouagadougou"] = {container = "Burkina Faso"}, -- 3,425,000 (Agglomeration) ["Bobo-Dioulasso"] = {container = "Burkina Faso"}, -- 1,100,000 (Agglomeration) ["Bujumbura"] = {container = "Burundi"}, -- 1,143,202 (Urban Area 2023 per PopulationStat, cited in Wikipedia) ["Yaoundé"] = {container = "Cameroon"}, -- 3,975,000 (City) ["Yaounde"] = {alias_of = "Yaoundé", display = true}, ["Douala"] = {container = "Cameroon"}, -- 3,900,000 (City) ["Bangui"] = {container = "Central African Republic"}, -- 1,680,000 (Agglomeration) ["N'Djamena"] = {container = "Chad"}, -- 1,950,000 (City) ["Ndjamena"] = {alias_of = "N'Djamena", display = true}, ["Kinshasa"] = {container = "Democratic Republic of the Congo"}, -- 16,300,000 (City; population of low reliability) ["Lubumbashi"] = {container = "Democratic Republic of the Congo"}, -- 2,875,000 (City; population of low reliability) ["Mbuji-Mayi"] = {container = "Democratic Republic of the Congo"}, -- 2,500,000 (City; population of low reliability) ["Kananga"] = {container = "Democratic Republic of the Congo"}, -- 1,370,000 (City; population of low reliability) ["Kisangani"] = {container = "Democratic Republic of the Congo"}, -- 1,300,000 (City; population of low reliability) ["Bukavu"] = {container = "Democratic Republic of the Congo"}, -- 1,100,000 (City; population of low reliability) ["Goma"] = {container = "Democratic Republic of the Congo"}, -- 1,010,000 (City; population of low reliability) ["Tshikapa"] = {container = "Democratic Republic of the Congo"}, -- 1,020,468 (2023 Wikipedia [[w:List of cities with over one million inhabitants]] from populationstat.com; not in citypopulation.de) ["Cairo"] = {container = "Egypt"}, -- 22,800,000 (Agglomeration, including Giza and Subhra El Kheima) ["Alexandria"] = {container = "Egypt"}, -- 6,250,000 (Agglomeration) ["Giza"] = {container = "Egypt"}, -- 4,458,135 (2023 from citypopulation.de) ["Shubra El Kheima"] = {container = "Egypt"}, -- 1,240,239 (2021 from citypopulation.de) ["Asmara"] = {container = "Eritrea"}, -- 1,090,000 (City; population of low reliability) ["Asmera"] = {alias_of = "Asmara", display = true}, ["Addis Ababa"] = {container = "Ethiopia"}, -- 4,825,000 (Agglomeration) ["Banjul"] = {container = "Gambia"}, -- 1,170,000 (Agglomeration) ["Accra"] = {container = "Ghana"}, -- 6,800,000 (Agglomeration) ["Kumasi"] = {container = "Ghana"}, -- 2,900,000 (Agglomeration) ["Conakry"] = {container = "Guinea"}, -- 2,975,000 (Consolidated Urban Area) ["Abidjan"] = {container = "Ivory Coast"}, -- 7,050,000 (Agglomeration) ["Nairobi"] = {container = "Kenya"}, -- 6,900,000 (unindicated) ["Mombasa"] = {container = "Kenya"}, -- 1,370,000 (City) ["Monrovia"] = {container = "Liberia"}, -- 1,940,000 (Urban Area) ["Tripoli"] = {container = "Libya", wp = "%l, %c"}, -- 1,870,000 (unindicated) ["Antananarivo"] = {container = "Madagascar"}, -- 3,150,000 (Agglomeration) ["Lilongwe"] = {container = "Malawi"}, -- 1,210,000 (City) ["Bamako"] = {container = "Mali"}, -- 5,700,000 (Agglomeration) ["Nouakchott"] = {container = "Mauritania"}, -- 1,500,000 (City) ["Casablanca"] = {container = {key = "Casablanca-Settat, Morocco", placetype = "region"}}, -- 4,450,000 (Municipality (urban population)) ["Rabat"] = {container = {key = "Rabat-Sale-Kenitra, Morocco", placetype = "region"}}, -- 2,125,000 (Municipality (urban population)) ["Tangier"] = {container = {key = "Tangier-Tetouan-Al Hoceima, Morocco", placetype = "region"}}, -- 1,410,000 (Municipality (urban population)) ["Tanger"] = {alias_of = "Tangier", display = true}, ["Tangiers"] = {alias_of = "Tangier", display = true}, ["Fez"] = {container = {key = "Fez-Meknes, Morocco", placetype = "region"}, wp = "%l, Morocco"}, -- 1,310,000 (Municipality (urban population)) ["Fes"] = {alias_of = "Fez", display = true}, ["Fès"] = {alias_of = "Fez", display = true}, ["Agadir"] = {container = {key = "Souss-Massa, Morocco", placetype = "region"}}, -- 1,270,000 (Municipality (urban population)) ["Marrakesh"] = {container = {key = "Marrakesh-Safi, Morocco", placetype = "region"}}, -- 1,140,000 (Municipality (urban population)) ["Marrakech"] = {alias_of = "Marrakesh", display = true}, ["Maputo"] = {container = "Mozambique"}, -- 2,575,000 (Agglomeration) ["Niamey"] = {container = "Niger"}, -- 1,530,000 (City) ["Brazzaville"] = {container = "Republic of the Congo"}, -- 2,475,000 (Agglomeration) ["Pointe-Noire"] = {container = "Republic of the Congo"}, -- 1,480,000 (City) ["Kigali"] = {container = "Rwanda"}, -- 1,960,000 (Municipality (urban population)) ["Dakar"] = {container = "Senegal"}, -- 4,225,000 (Agglomeration) ["Touba"] = {container = "Senegal"}, -- 1,320,000 (Agglomeration) ["Freetown"] = {container = "Sierra Leone"}, -- 1,420,000 (Agglomeration) ["Mogadishu"] = {container = "Somalia"}, -- 2,250,000 (unindicated; population of low reliability) ["Johannesburg"] = {container = {key = "Gauteng, South Africa", placetype = "province"}}, -- 14,800,000 (Consolidated Urban Area; including Pretoria, Soweto, etc.) ["Cape Town"] = {container = {key = "Western Cape, South Africa", placetype = "province"}}, -- 5,100,000 (Consolidated Urban Area) ["Durban"] = {container = {key = "KwaZulu-Natal, South Africa", placetype = "province"}}, -- 3,900,000 (Consolidated Urban Area) ["Pretoria"] = {container = {key = "Gauteng, South Africa", placetype = "province"}}, -- 2,921,488 (2011 census) ["Port Elizabeth"] = {container = {key = "Eastern Cape, South Africa", placetype = "province"}, wp = "Gqeberha"}, -- 1,200,000 (Consolidated Urban Area) ["Gqeberha"] = {alias_of = "Port Elizabeth"}, -- official name; not a display alias ["Khartoum"] = {container = "Sudan"}, -- 7,200,000 (unindicated; population of low reliability) ["Dar es Salaam"] = {container = "Tanzania"}, -- 6,650,000 (Agglomeration) ["Mwanza"] = {container = "Tanzania"}, -- 1,340,000 (Agglomeration) ["Mwanza City"] = {alias_of = "Mwanza", display = true}, ["Arusha"] = {container = "Tanzania"}, -- 1,190,000 (Agglomeration) ["Zanzibar"] = {container = "Tanzania"}, -- 1,030,000 (Agglomeration) ["Lomé"] = {container = "Togo"}, -- 2,625,000 (unindicated) ["Lome"] = {alias_of = "Lomé", display = true}, ["Tunis"] = {container = "Tunisia"}, -- 2,725,000 (Municipality (urban population)) ["Sousse"] = {container = "Tunisia"}, -- 1,180,000 (Municipality (urban population)) ["Soussa"] = {alias_of = "Sousse", display = true}, ["Kampala"] = {container = "Uganda"}, -- 4,300,000 (unindicated) ["Lusaka"] = {container = "Zambia"}, -- 3,000,000 (Consolidated Urban Area) ["Harare"] = {container = "Zimbabwe"}, -- 2,675,000 (Agglomeration) ------------------ Asia ------------------- -- sorted by country and then within the country, by decreasing population; figures from citypopulation.de -- (retrieved 2025-04-26; reference date 2025-01-01) unless otherwise indicated. ["Kabul"] = {container = "Afghanistan"}, -- 5,250,000 (Agglomeration) ["Baku"] = {container = "Azerbaijan"}, -- 3,725,000 (Administrative Area (urban population)) ["Manama"] = {container = "Bahrain"}, -- 1,560,000 (unindicated) ["Dhaka"] = {container = {key = "Dhaka Division, Bangladesh", placetype = "division"}}, -- 23,100,000 (Agglomeration) ["Dacca"] = {alias_of = "Dhaka", display = true}, ["Chittagong"] = {container = {key = "Chittagong Division, Bangladesh", placetype = "division"}}, -- 5,050,000 (Agglomeration) ["Gazipur"] = {container = {key = "Dhaka Division, Bangladesh", placetype = "division"}}, -- 2,674,697 (City per 2022; countied in citypopulation.de as part of Dhaka metro area) ["Khulna"] = {container = {key = "Khulna Division, Bangladesh", placetype = "division"}}, -- 1,210,000 (Agglomeration) ["Phnom Penh"] = {container = "Cambodia"}, -- 2,925,000 (Agglomeration) ["Tehran"] = {container = {key = "Tehran Province, Iran", placetype = "province"}}, -- 16,800,000 (Agglomeration) ["Teheran"] = {alias_of = "Tehran", display = true}, ["Mashhad"] = {container = {key = "Razavi Khorasan Province, Iran", placetype = "province"}}, -- 3,475,000 (Agglomeration) ["Mashad"] = {alias_of = "Mashhad", display = true}, ["Meshhed"] = {alias_of = "Mashhad", display = true}, ["Meshed"] = {alias_of = "Mashhad", display = true}, ["Isfahan"] = {container = {key = "Isfahan Province, Iran", placetype = "province"}}, -- 3,425,000 (Agglomeration) ["Esfahan"] = {alias_of = "Isfahan", display = true}, ["Tabriz"] = {container = {key = "East Azerbaijan Province, Iran", placetype = "province"}}, -- 1,970,000 (Agglomeration) ["Shiraz"] = {container = {key = "Fars Province, Iran", placetype = "province"}}, -- 1,950,000 (Agglomeration) ["Ahvaz"] = {container = {key = "Khuzestan Province, Iran", placetype = "province"}}, -- 1,550,000 (Agglomeration) ["Qom"] = {container = {key = "Qom Province, Iran", placetype = "province"}}, -- 1,450,000 (City) ["Kermanshah"] = {container = {key = "Kermanshah Province, Iran", placetype = "province"}}, -- 1,130,000 (City) ["Baghdad"] = {container = "Iraq"}, -- 7,800,000 (Administrative Area (urban population)) ["Basra"] = {container = "Iraq"}, -- 1,710,000 (Administrative Area (urban population)) ["Mosul"] = {container = "Iraq"}, -- 1,550,000 (Administrative Area (urban population)) ["Erbil"] = {container = "Iraq"}, -- 1,220,000 (Administrative Area (urban population)) ["Kirkuk"] = {container = "Iraq"}, -- 1,160,000 (Administrative Area (urban population)) ["Najaf"] = {container = "Iraq"}, -- 1,050,000 (Administrative Area (urban population)) ["Tel Aviv"] = {container = "Israel"}, -- 3,000,000 (Agglomeration) -- Jerusalem is not recognized internationally as part of either Israel or Palestine, but as a -- [[w:corpus separatum]], so put the container as "Asia" and list Israel and Palestine as additional parents for -- categorization purposes. ["Jerusalem"] = {container = {key = "Asia", placetype = "continent"}, addl_parents = {"Israel", "Palestine"}}, -- 1,080,000 (Agglomeration) ["Amman"] = {container = "Jordan"}, -- 6,150,000 (unindicated) ["Irbid"] = {container = "Jordan"}, -- 1,070,000 (unindicated) ["Almaty"] = {container = "Kazakhstan"}, -- 2,700,000 (Agglomeration) ["Alma-Ata"] = {alias_of = "Almaty"}, -- former name, sometimes still used; don't display-canonicalize ["Astana"] = {container = "Kazakhstan"}, -- 1,600,000 (Agglomeration) ["Shymkent"] = {container = "Kazakhstan"}, -- 1,370,000 (Agglomeration) ["Kuwait City"] = {container = "Kuwait"}, -- 5,050,000 (Agglomeration) ["Bishkek"] = {container = "Kyrgyzstan"}, -- 1,540,000 (Agglomeration) ["Beirut"] = {container = "Lebanon"}, -- 1,930,000 (unindicated; population of low reliability) -- Kuala Lumpur is a federal capital city, not in any state ["Kuala Lumpur"] = {container = "Malaysia"}, -- 9,550,000 (Agglomeration) -- there are various George Towns and Georgetowns ["George Town, Malaysia"] = {container = {key = "Penang, Malaysia", placetype = "state"}, wp = "%l, %c"}, -- 2,075,000 (Agglomeration) ["George Town"] = {alias_of = "George Town, Malaysia"}, ["Ulaanbaatar"] = {container = "Mongolia"}, -- 1,610,000 (City) ["Ulan Bator"] = {alias_of = "Ulaanbaatar", display = true}, ["Yangon"] = {container = "Myanmar"}, -- 5,650,000 (Municipality (urban population)) ["Rangoon"] = {alias_of = "Yangon", display = true}, ["Mandalay"] = {container = "Myanmar"}, -- 1,600,000 (Municipality (urban population)) ["Kathmandu"] = {container = "Nepal"}, -- 3,175,000 (Agglomeration) -- Pyongyang is a directly governed city, not in any province ["Pyongyang"] = {container = "North Korea"}, -- 3,025,000 (Administrative Area (urban population)) ["Muscat"] = {container = "Oman"}, -- 1,620,000 (Agglomeration) ["Gaza"] = {container = "Palestine", wp = "Gaza City"}, -- 2,275,000 (unindicated) ["Gaza City"] = {alias_of = "Gaza"}, ["Doha"] = {container = "Qatar"}, -- 2,650,000 (Agglomeration) ["Colombo"] = {container = "Sri Lanka"}, -- 4,975,000 (unindicated) ["Damascus"] = {container = "Syria"}, -- 3,975,000 (unindicated; population of low reliability) ["Aleppo"] = {container = "Syria"}, -- 1,980,000 (unindicated; population of low reliability) ["Dushanbe"] = {container = "Tajikistan"}, -- 1,270,000 (City) ["Bangkok"] = {container = "Thailand"}, -- 21,800,000 (Agglomeration) -- Chiang Mai not in citypopulation.de, but 1,198,000 urban population in 2021 per Wikipedia -- [[w:List_of_municipalities_in_Thailand#Largest_cities_by_urban_population]] ["Chiang Mai"] = {container = {key = "Chiang Mai Province, Thailand", placetype = "province"}}, ["Chonburi"] = {container = {key = "Chonburi Province, Thailand", placetype = "province"}}, -- 1,570,000 (Agglomeration; including Pattaya) -- metro area population stats from https://www.statista.com/statistics/255483/biggest-cities-in-turkey/ as of 2021; -- second source is citypopulation.de reference date 2025-01-01. ["Istanbul"] = {placetype = {"city", "province"}, divs = {"districts"}, container = "Turkey"}, -- 15.2 million; 16,000,000 (Agglomeration) ["İstanbul"] = {alias_of = "Istanbul", display = true}, ["Ankara"] = {container = {key = "Ankara Province, Turkey", placetype = "province"}}, -- 5.15 million; 5,200,000 (Agglomeration) ["Izmir"] = {container = {key = "İzmir Province, Turkey", placetype = "province"}, wp = "İzmir"}, -- 2.95 million; 3,025,000 (Agglomeration) ["İzmir"] = {alias_of = "Izmir", display = true}, ["Bursa"] = {container = {key = "Bursa Province, Turkey", placetype = "province"}}, -- 2.02 million; 2,200,000 (Agglomeration) ["Adana"] = {container = {key = "Adana Province, Turkey", placetype = "province"}}, -- 1.77 million; 1,780,000 (Agglomeration) ["Gaziantep"] = {container = {key = "Gaziantep Province, Turkey", placetype = "province"}}, -- 1.71 million; 1,750,000 (Agglomeration) ["Antalya"] = {container = {key = "Antalya Province, Turkey", placetype = "province"}}, -- 1.3 million; 1,400,000 (Agglomeration) ["Konya"] = {container = {key = "Konya Province, Turkey", placetype = "province"}}, -- 1.35 million; 1,390,000 (Agglomeration) ["Diyarbakır"] = {container = {key = "Diyarbakır Province, Turkey", placetype = "province"}}, -- 1.07 million; 1,100,000 (Agglomeration) -- Diyarbakır is more common per Ngrams and Google Scholar, but Diyarbakir is the Kurdish form, so we should not -- display-canonicalize to the Turkish form Diyarbakır. ["Diyarbakir"] = {alias_of = "Diyarbakır"}, ["Mersin"] = {container = {key = "Mersin Province, Turkey", placetype = "province"}}, -- 1.03 million; 1,060,000 (Agglomeration) ["Ashgabat"] = {container = "Turkmenistan"}, -- 1,150,000 (Agglomeration) ["Dubai"] = {container = "United Arab Emirates"}, -- 6,050,000 (Agglomeration; including Sharjah) ["Abu Dhabi"] = {container = "United Arab Emirates"}, -- 1,850,000 (City) ["Sharjah"] = {container = "United Arab Emirates"}, -- 1,800,000 (Metro area 2022-2023 per Wikipedia; separate from Dubai) ["Tashkent"] = {container = "Uzbekistan"}, -- 3,850,000 (unindicated) ["Sanaa"] = {container = "Yemen"}, -- 3,275,000 (City; population of low reliability) ["Sana'a"] = {alias_of = "Sanaa", display = true}, ["Aden"] = {container = "Yemen"}, -- 1,079,060 (?; 2023 estimate from World Population Review per Wikipedia) ------------------ Europe or Europe-like (Caucasus etc.) --------------------- ["Yerevan"] = {container = "Armenia"}, -- 1,520,000 (Agglomeration) ["Vienna"] = {container = "Austria"}, -- 2,375,000 (Agglomeration) ["Minsk"] = {container = "Belarus"}, -- 2,100,000 (unindicated) ["Brussels"] = {container = "Belgium"}, -- 2,800,000 (Consolidated Urban Area) ["Antwerp"] = {container = "Belgium"}, -- 1,270,000 (Consolidated Urban Area) ["Sofia"] = {container = "Bulgaria"}, -- 1,260,000 (Agglomeration) ["Zagreb"] = {container = "Croatia"}, ["Prague"] = {container = "Czech Republic"}, -- 1,470,000 (Agglomeration) ["Brno"] = {container = "Czech Republic"}, -- 729,405 (metro area per Wikipedia as of 2024-01-01 Czech Statistical Office) ["Olomouc"] = {container = "Czech Republic"}, -- 102,293 (city; included only because someone went crazy creating Olomouc-related terms) ["Copenhagen"] = {container = "Denmark"}, -- 1,800,000 (Consolidated Urban Area) ["Helsinki"] = {container = {key = "Uusimaa, Finland", placetype = "region"}}, -- 1,560,000 (Consolidated Urban Area) ["Tbilisi"] = {container = "Georgia"}, -- 1,430,000 (Agglomeration) ["Athens"] = {container = "Greece"}, ["Thessaloniki"] = {container = "Greece"}, ["Budapest"] = {container = "Hungary"}, -- FIXME, per Wikipedia "County Dublin" is now the "Dublin Region" ["Dublin"] = {container = {key = "County Dublin, Ireland", placetype = "county"}}, ["Riga"] = {container = "Latvia"}, ["Amsterdam"] = {container = {key = "North Holland, Netherlands", placetype = "province"}}, ["Rotterdam"] = {container = {key = "South Holland, Netherlands", placetype = "province"}}, ["The Hague"] = {container = {key = "South Holland, Netherlands", placetype = "province"}}, -- Christchurch (metro 546,600) and Wellington (metro 439,800) are too small to make it. ["Auckland"] = {container = {key = "Auckland, New Zealand", placetype = "region"}}, ["Oslo"] = {container = {key = "Oslo, Norway", placetype = "county"}}, ["Warsaw"] = {container = {key = "Masovian Voivodeship, Poland", placetype = "voivodeship"}}, ["Katowice"] = {container = {key = "Silesian Voivodeship, Poland", placetype = "voivodeship"}}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Krakow" without accent. ["Krakow"] = {container = {key = "Lesser Poland Voivodeship, Poland", placetype = "voivodeship"}, wp = "Kraków"}, ["Kraków"] = {alias_of = "Krakow", display = true}, ["Cracow"] = {alias_of = "Krakow", display = true}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirm "Gdańsk" and "Poznań" with accent. ["Gdańsk"] = {container = {key = "Pomeranian Voivodeship, Poland", placetype = "voivodeship"}}, ["Gdansk"] = {alias_of = "Gdańsk", display = true}, ["Poznań"] = {container = {key = "Greater Poland Voivodeship, Poland", placetype = "voivodeship"}}, ["Poznan"] = {alias_of = "Poznań", display = true}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Lodz" without accents. ["Lodz"] = {container = {key = "Lodz Voivodeship, Poland", placetype = "voivodeship"}, wp = "Łódź"}, ["Łódź"] = {alias_of = "Lodz", display = true}, ["Lisbon"] = {container = {key = "Lisbon District, Portugal", placetype = "district"}}, ["Porto"] = {container = {key = "Porto District, Portugal", placetype = "district"}}, ["Oporto"] = {alias_of = "Porto", display = true}, ["Bucharest"] = {container = "Romania"}, ["Belgrade"] = {container = "Serbia"}, ["Stockholm"] = {container = "Sweden"}, ["Zurich"] = {container = "Switzerland"}, --- Ngrams (up through 2022) and Google Scholar (>= 2024) confirms the common form "Zurich" without umlaut. --- Even Wikipedia uses the form without umlaut. ["Zürich"] = {alias_of = "Zurich", display = true}, ["Kyiv"] = {container = "Ukraine"}, -- not in Kyiv Oblast -- Don't display-canonicalize Kiev -> Kyiv because in ancient contexts, Kiev is still more common. ["Kiev"] = {alias_of = "Kyiv"}, ["Kharkiv"] = {container = {key = "Kharkiv Oblast, Ukraine", placetype = "oblast"}}, ["Odessa"] = {container = {key = "Odesa Oblast, Ukraine", placetype = "oblast"}, wp = "Odesa"}, -- Don't display-canonicalize Odesa -> Odessa because it may be interpreted as a political statement. ["Odesa"] = {alias_of = "Odessa"}, ------------------ North America, South America --------------------- -- Primary figures from citypopulation.de retrieved on 2025-04-26 (reference date 2025-01-01); -- Wikipedia metropolitan figures from [[w:List of metropolitan areas in the Americas]] based on per-country data; -- Wikipedia city limits figures from [[w:List of largest cities in the Americas]]. ["Buenos Aires"] = {container = "Argentina"}, -- 16,800,000 (Consolidated Urban Area; 13,985,794 metropolitan area per Wikipedia) ["Córdoba, Argentina"] = {container = "Argentina", wp = "%l, %c"}, -- 1,810,000 (Consolidated Urban Area; 1,505,25 city limits per Wikipedia) -- to avoid confusion with Córdoba in Spain ["Córdoba"] = {alias_of = "Córdoba, Argentina"}, ["Cordoba"] = {alias_of = "Córdoba, Argentina", display = "Córdoba"}, ["Rosario"] = {container = "Argentina", wp = "%l, Santa Fe"}, -- 1,510,000 (Consolidated Urban Area; 1,348,725 metropolitan area per Wikipedia) ["Mendoza"] = {container = "Argentina", wp = "%l, %c"}, -- 1,180,000 (Consolidated Urban Area) ["San Miguel de Tucumán"] = {container = "Argentina"}, -- 1,110,000 (Consolidated Urban Area) ["Tucumán"] = {alias_of = "San Miguel de Tucumán"}, ["Tucuman"] = {alias_of = "San Miguel de Tucumán", display = "Tucumán"}, ["Santa Cruz de la Sierra"] = {container = "Bolivia"}, -- 1,960,000 (Consolidated Urban Area); 1,606,671 (city limits per Wikipedia) ["Santa Cruz"] = {alias_of = "Santa Cruz de la Sierra"}, ["La Paz"] = {container = "Bolivia"}, -- 1,870,000 (Consolidated Urban Area; composed of El Alto, now slightly larger, and La Paz) ["El Alto"] = {container = "Bolivia"}, ["Cochabamba"] = {container = "Bolivia"}, -- 1,280,000 (Consolidated Urban Area) ["Santiago"] = {container = "Chile"}, -- 8,400,000 (Consolidated Urban Area; 6,903,479 city limits? per Wikipedia) ["Valparaíso"] = {container = "Chile"}, -- 1,060,000 (Consolidated Urban Area) ["Valparaiso"] = {alias_of = "Valparaíso"}, -- 1,060,000 (Consolidated Urban Area) ["Bogotá"] = {container = "Colombia"}, -- 10,600,000 (Agglomeration; 12,772,828 metropolitan area per Wikipedia) ["Bogota"] = {alias_of = "Bogotá", display = true}, ["Medellín"] = {container = "Colombia"}, -- 4,350,000 (Agglomeration; 4,068,000 metropolitan area per Wikipedia) ["Medellin"] = {alias_of = "Medellín", display = true}, ["Cali"] = {container = "Colombia"}, -- 2,975,000 (Agglomeration; 2,837,000 metropolitan area per Wikipedia) ["Barranquilla"] = {container = "Colombia"}, -- 2,375,000 (Agglomeration; 1,341,160 city limits per Wikipedia) ["Bucaramanga"] = {container = "Colombia"}, -- 1,380,000 (Agglomeration) ["Cartagena, Colombia"] = {container = "Colombia", wp = "%l, %c"}, -- 1,250,000 (Agglomeration) -- to avoid confusion with Cartagena, Spain ["Cartagena"] = {alias_of = "Cartagena, Colombia"}, ["Cúcuta"] = {container = "Colombia"}, -- 1,130,000 (Agglomeration) ["Cucuta"] = {alias_of = "Cúcuta", display = true}, -- to avoid conflict with San Jose, California ["San José, Costa Rica"] = {container = "Costa Rica", wp = "%l, %c"}, -- 2,450,000 (Municipality (urban population); 3,160,000 metropolitan area per Wikipedia) ["San José"] = {alias_of = "San José, Costa Rica"}, ["San Jose"] = {alias_of = "San José, Costa Rica"}, -- display = "San José"; causes error due to San Jose alias for California city; FIXME ["Havana"] = {container = "Cuba"}, -- 2,150,000 (City; 2,137,847 city limits? per Wikipedia) ["Santo Domingo"] = {container = "Dominican Republic"}, -- 3,900,000 (Municipality (urban population); 4,274,651 ??? per Wikipedia) ["Guayaquil"] = {container = "Ecuador"}, -- 3,350,000 (Agglomeration; 3,092,000 metro area? per Wikipedia) ["Quito"] = {container = "Ecuador"}, -- 2,875,000 (Agglomeration; 2,889,703 metro area? per Wikipedia) ["San Salvador"] = {container = "El Salvador"}, -- 1,580,000 (Municipality (urban population)) ["Guatemala City"] = {container = "Guatemala"}, -- 3,375,000 (Municipality (urban population); 3,160,000 metro area? per Wikipedia) ["Port-au-Prince"] = {container = "Haiti"}, -- 3,050,000 (Agglomeration; population of low reliability; 2,915,000 metro area? per Wikipedia) ["San Pedro Sula"] = {container = "Honduras"}, -- 1,330,000 (Consolidated Urban Area) ["Tegucigalpa"] = {container = "Honduras"}, -- 1,220,000 (Urban Area) ["Managua"] = {container = "Nicaragua"}, -- 1,400,000 (Consolidated Urban Area) ["Panama City"] = {container = "Panama"}, -- 1,430,000 (Urban Area) ["Asunción"] = {container = "Paraguay"}, -- 2,350,000 (Municipality (urban population)) ["Lima"] = {container = "Peru"}, -- 12,000,000 (Agglomeration; 11,283,787 ??? per Wikipedia) ["Arequipa"] = {container = "Peru"}, -- 1,210,000 (Agglomeration) ["San Juan"] = {container = {key = "Puerto Rico", placetype = "commonwealth"}, wp = "%l, %c"}, -- 1,910,000 (Consolidated Urban Area) ["Montevideo"] = {container = "Uruguay"}, -- 1,810,000 (Agglomeration; 1,302,954 ??? per Wikipedia) ["Caracas"] = {container = "Venezuela"}, -- 3,850,000 (Consolidated Urban Area; 5,243,301 ??? per Wikipedia) ["Maracaibo"] = {container = "Venezuela"}, -- 2,825,000 (Consolidated Urban Area; 5,278,448 ??? per Wikipedia) -- to avoid confusion with Valencia (city and autonomous community of Spain) ["Valencia, Venezuela"] = {container = "Venezuela", wp = "%l, %c"}, -- 2,100,000 (Consolidated Urban Area) ["Valencia"] = {alias_of = "Valencia, Venezuela"}, ["Maracay"] = {container = "Venezuela"}, -- 1,480,000 (Consolidated Urban Area) ["Barquisimeto"] = {container = "Venezuela"}, -- 1,360,000 (Consolidated Urban Area) } export.misc_cities_group = { canonicalize_key_container = make_canonicalize_key_container(nil, "country"), default_placetype = "city", data = export.misc_cities, } --[==[ var: List of all known locations, in groups. The first group lists continents and continental regions, followed by three groups listing top-level locations: countries, "country-like entities" (de-facto/unrecognized/etc. countries and dependent territories) and former polities (countries, empires, etc.). After that come first-level subpolities (administrative divisions) of several, mostly large, countries, followed by groups of cities. China and the United Kingdom include second-level subpolities (in the case of China, only the largest ones as the full list runs in the hundreds). ]==] export.locations = { export.continents_group, export.countries_group, export.country_like_entities_group, export.former_countries_group, export.australia_group, export.austria_group, export.bangladesh_group, export.brazil_group, export.bulgaria_group, export.canada_group, export.china_group, export.china_prefecture_level_cities_group, export.china_prefecture_level_cities_group_2, export.egypt_group, export.finland_group, export.france_group, export.france_departments_group, export.germany_group, export.greece_group, export.india_group, export.indonesia_group, export.iran_group, export.ireland_group, export.italy_group, export.japan_group, export.laos_group, export.lebanon_group, export.malaysia_group, export.malta_group, export.mexico_group, export.moldova_group, export.morocco_group, export.netherlands_group, export.new_zealand_group, export.nigeria_group, export.north_korea_group, export.norway_group, export.pakistan_group, export.philippines_group, export.poland_group, export.portugal_group, export.romania_group, export.russia_group, export.saudi_arabia_group, export.south_africa_group, export.south_korea_group, export.spain_group, export.taiwan_group, export.thailand_group, export.turkey_group, export.ukraine_group, export.united_kingdom_group, export.united_states_group, export.england_group, export.northern_ireland_group, export.scotland_group, export.wales_group, export.vietnam_group, export.australia_cities_group, export.brazil_cities_group, export.canada_cities_group, export.france_cities_group, export.germany_cities_group, export.india_cities_group, export.indonesia_cities_group, export.italy_cities_group, export.japan_cities_group, export.mexico_cities_group, export.nigeria_cities_group, export.pakistan_cities_group, export.philippines_cities_group, export.russia_cities_group, export.saudi_arabia_cities_group, export.south_korea_cities_group, export.spain_cities_group, export.taiwan_cities_group, export.united_kingdom_cities_group, export.united_states_cities_group, export.new_york_boroughs_group, export.vietnam_cities_group, export.misc_cities_group, } return export dws9ii25xu6ehccq914gw62b8c7d56n Mòideal:place/placetypes 828 17897 88792 2026-07-31T01:41:42Z en>Polomo 0 link separately to "state capital" 88792 Scribunto text/plain local export = {} export.force_cat = false -- set to true for testing local m_locations = require("Module:place/locations") local m_links = require("Module:links") local m_table = require("Module:table") local m_strutils = require("Module:string utilities") local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local dump = mw.dumpObject local insert = table.insert local concat = table.concat local internal_error = m_locations.internal_error export.internal_error = internal_error local process_error = m_locations.process_error export.process_error = process_error local unpack = unpack or table.unpack -- Lua 5.2 compatibility local ucfirst = m_strutils.ucfirst local ulower = m_strutils.lower local rmatch = m_strutils.match local split = m_strutils.split --[==[ intro: This module contains placetype data used by [[Module:place]] and {{tl|place}}, along with a significant amount of code to work with both placetypes and locations, as well as some placename-related info (FIXME: Consider moving it to [[Module:place/locations]]). See also [[Module:place/locations]], which has definitions of all known locations. You must currently load this module using {{cd|require()}}, not using {{cd|mw.loadData()}}. In particular, it contains two fundamental and tricky functions: # `get_placetype_equivs`, which finds the equivalent placetypes to look under in order to find a given property, and in the process correctly handles placetypes with qualifiers (including qualifiers that act similar to "type-raising" operators in that they do something non-trivial to the placetype to their right) as well as form-of directives and fallbacks. # `find_matching_holonym_location`, which looks up a holonym to find a matching known location, but in the process checks holonyms to the right to make sure there isn't a clash between the user-specified containing holonyms and the containers of the known location being considered. This is done to prevent overcategorizing when either there are two known locations with the same name (e.g. Birmingham in England and Birmingham, Alabama in the US), or more generally two locations with the same name, one of which is a known location but where the other is not (e.g. we're processing non-known-location Mérida, Spain and don't want it categorized like known location Mérida, Yucatán, Mexico). Both of these functions are invoked repeatedly, and probably are invoked several times on the same inputs and as a result are candidates for memoization to speed up the operation of {{tl|place}}. ]==] ------------------------------------------------------------------------------------------ -- Basic utilities -- ------------------------------------------------------------------------------------------ --[==[ Return true if `force_cat` is set either in this module or in [[Module:place/locations]]. ]==] function export.get_force_cat() return export.force_cat or m_locations.force_cat end -- Add the page to a tracking "category". To see the pages in the "category", -- go to [[Wiktionary:Tracking/place/PAGE]] and click on "What links here". local function track(page) require(debug_track_module)("place/" .. page) return true end function export.remove_links_and_html(text) text = m_links.remove_links(text) return text:gsub("<.->", "") end --[==[ Return the singular version of a maybe-plural placetype, or nil if not plural. This correctly handles placetypes with irregular plurals such as `kibbutzim` plural of `kibbutz` by looking up in a table constructed from the `plural` values specified in `placetype_data`. If a special plural value is not found, the regular singularization algorithm in [[Module:en-utilities]] is invoked, which reverses the y -> ies change after vowels and the 'es' addition after sh/ch/x, and otherwise just subtracts a final 's' (which will incorrectly generate 'passe' for plural 'passes'; FIXME: consider changing this for words ending in '-sses'). If the generated singular is the same as the passed-in value, nil is returned. ]==] function export.maybe_singularize_placetype(placetype) if not placetype then return nil end if export.plural_placetype_to_singular[placetype] then return export.plural_placetype_to_singular[placetype] end local retval = require(en_utilities_module).singularize(placetype) if retval == placetype then return nil end return retval end -- Return the correct plural of a placetype, and (if `do_ucfirst` is given) make the first letter uppercase. We first -- look up the plural in `placetype_data`, falling back to pluralize() in [[Module:en-utilities]], which is almost -- always correct. function export.pluralize_placetype(placetype, do_ucfirst) local ptdata = export.placetype_data[placetype] if ptdata and ptdata.plural then placetype = ptdata.plural else placetype = require(en_utilities_module).pluralize(placetype) end if do_ucfirst then return ucfirst(placetype) else return placetype end end --[==[ Get the data associated with a placetype, which may be in its singular or plural form. If `from_category` is specified, we also look for category-only placetypes (generally plural) followed by `!`. Return three values: (a) the placetype under which the data can be looked up (i.e. in its singular form if the passed-in `placetype` is plural and did not match a category-only placetype followed by `!`); (b) the placetype data structure; (c) the type of `placetype` match that occurred, one of `"direct"` if the canonical placetype is the same as the passed-in `placetype` and also the same as the key under which `ptdata` was looked up, or `"direct-category"` if the `ptdata` was looked up under a key formed from the passed-in `placetype` by adding `!`, or `"plural"` if the `ptdata` was looked up under the singularized version of the plural passed-in `placetype`. ]==] function export.get_placetype_data(placetype, from_category) local ptdata = export.placetype_data[placetype] if ptdata then return placetype, ptdata, "direct" end if from_category then ptdata = export.placetype_data[placetype .. "!"] if ptdata then return placetype .. "!", ptdata, "direct-category" end end local sg_placetype = export.maybe_singularize_placetype(placetype) if sg_placetype then ptdata = export.placetype_data[sg_placetype] if ptdata then return sg_placetype, ptdata, "plural" end end return nil end --[==[ Check for special pseudo-placetypes that should be ignored for categorization purposes. ]==] function export.placetype_is_ignorable(placetype) return placetype == "and" or placetype == "or" or placetype:find("^%(") end function export.resolve_placetype_aliases(placetype) return export.placetype_aliases[placetype] or placetype end --[==[ Return a property from `placetype_data` for a given placetype. If the placetype isn't found in `placetype_data`, or the key isn't found in the placetype's entry in `placetype_data`, return nil. ]==] function export.get_placetype_prop(placetype, key) -- Usually we are called on equivalent placetypes returned from `get_placetype_equivs`, in which case placetype -- aliases have been resolved, but sometimes not, e.g. when fetching the indefinite article in -- get_placetype_article(). `resolve_placetype_aliases` is just a simple lookup and it doesn't hurt to do it twice. placetype = export.resolve_placetype_aliases(placetype) if export.placetype_data[placetype] then return export.placetype_data[placetype][key] else return nil end end --[==[ Given a placetype, split the placetype into one or more potential ''splits'', each consisting of a three-element list { {``prev_qualifiers``, ``this_qualifier``, ``reduced_placetype``}}, i.e. # the concatenation of zero or more previously-recognized qualifiers on the left, normally canonicalized (if there are zero such qualifiers, the value will be nil); # a single recognized qualifier, normally canonicalized (if there is no qualifier, the value will be nil); # the "reduced placetype" on the right. Splitting between the qualifier in (2) and the reduced placetype in (3) happens at each space character, proceeding from left to right, and stops if a qualifier isn't recognized. All placetypes are canonicalized by checking for aliases in `placetype_aliases`, but no other checks are made as to whether the reduced placetype is recognized. Canonicalization of qualifiers does not happen if `no_canon_qualifiers` is specified. For example, given the placetype `"small beachside unincorporated community"`, the return value will be { { {nil, nil, "small beachside unincorporated community"}, {nil, "small", "beachside unincorporated community"}, {"small", "[[beachfront]]", "unincorporated community"}, {"small [[beachfront]]", "[[unincorporated]]", "community"}, }} Here, `"beachside"` is canonicalized to `"[[beachfront]]"` and `"unincorporated"` is canonicalized to `"[[unincorporated]]"`, in both cases according to the entry in `placetype_qualifiers`. On the other hand, if given `"small former haunted community"`, the return value will be { { {nil, nil, "small former haunted community"}, {nil, "small", "former haunted community"}, {"small", "former", "haunted community"}, }} because `"small"` and `"former"` but not `"haunted"` are recognized as qualifiers. Finally, if given `"former adr"`, the return value will be { { {nil, nil, "former adr"}, {nil, "former", "administrative region"}, }} because `"adr"` is a recognized placetype alias for `"administrative region"`. ]==] function export.split_qualifiers_from_placetype(placetype, no_canon_qualifiers) local splits = {{nil, nil, export.resolve_placetype_aliases(placetype)}} local prev_qualifier = nil while true do local qualifier, reduced_placetype = placetype:match("^(.-) (.*)$") if qualifier then local canon = export.placetype_qualifiers[qualifier] if canon == nil then break end local new_qualifier = qualifier if type(canon) == "table" then canon = canon.link end if not no_canon_qualifiers and canon ~= false then if canon == true then new_qualifier = "[[" .. qualifier .. "]]" else new_qualifier = canon end end insert(splits, {prev_qualifier, new_qualifier, export.resolve_placetype_aliases(reduced_placetype)}) prev_qualifier = prev_qualifier and prev_qualifier .. " " .. new_qualifier or new_qualifier placetype = reduced_placetype else break end end return splits end --[==[ Given a `placetype` (which may be pluralized), return an ordered list of equivalent placetypes to look under to find the placetype's properties (such as the category or categories to be inserted). The return value is actually an ordered list of objects of the form `{qualifier=``qualifier``, placetype=``equiv_placetype``}` where ``equiv_placetype`` is a placetype whose properties to look up, derived from the passed-in placetype or from a contiguous subsequence of the words in the passed-in placetype (always including the rightmost word in the placetype, i.e. we successively chop off qualifier words from the left and use the remainder to find equivalent placetypes). ``qualifier`` is the remaining words not part of the subsequence used to find ``equiv_placetype``; or nil if all words in the passed-in placetype were used to find ``equiv_placetype``. (FIXME: This qualifier is not currently used anywhere.) Only placetypes for which there is an entry in `placetype_data` are included. The placetype passed in is always checked first, and will form the first entry if it exists in `placetype_data`. '''NOTE:''' This is a tricky function as it implements handling of (a) qualifiers, (b) fallback logic, (c) "type-raising" qualifiers such as `former`/`ancient`/etc. as well as `fictional` and `mythological`, and (d) form-of directives, which act somewhat similarly to `former`, and allows interaction between more than one of these simultaneously (e.g. official names of former places, which have their own categorization). If {{tl|place}} gets too slow, one potential speedup is to memoize the results of this function, as it appears to be getting called more than once on the same inputs. Another similar potential speedup is to memoize the results of `iterate_matching_holonym_location()`. For example, given the placetype `left tributary`, the following placetype/qualifier combinations are checked in turn: ``` {qualifier = nil, placetype="left tributary"} {qualifier = "left", placetype="tributary"} {qualifier = "left", placetype="river"} ``` and the return value will be { { {qualifier = "left", placetype="tributary"}, {qualifier = "left", placetype="river"}, }} The algorithm first enters the placetype itself into the list, then checks for `left tributary` as a recognized placetype in `placetype_data` and doesn't find it, so it doesn't enter it into the returned list (if it found it, it would add it as well as any fallbacks directly after it). It then splits off the recognized qualifier `left` to form the ''reduced placetype'' `tributary`, which is entered into the list because it is found in `placetype_data`. Then, because it has a fallback `river`, which exists in `placetype_data`, the fallback is entered next. Another example is `small rural fraziones` (where a ''frazione'' is type of subdivision of a ''comune'' or municipality, often specifically an outlying hamlet). the placetype/qualifier combinations checked are: ``` {qualifier = nil, placetype="small rural fraziones"} {qualifier = nil, placetype="small rural frazione"} {qualifier = "small", placetype="rural fraziones"} {qualifier = "small", placetype="rural frazione"} {qualifier = "small [[rural]]", placetype="fraziones"} {qualifier = "small [[rural]]", placetype="frazione"} {qualifier = "small [[rural]]", placetype="hamlet"} {qualifier = "small [[rural]]", placetype="village"} ``` The return value ends up as {qualifier = "small [[rural]]", placetype="frazione"}, {qualifier = "small [[rural]]", placetype="hamlet"}, {qualifier = "small [[rural]]", placetype="village"}, }} Here, because the result of singularizing `fraziones` returns a different value from the placetype itself, that singularized value is checked after the original plural value. Also, in the process of splitting off qualifiers, they are canonicalized if the entry in `placetype_qualifiers` says to do so; in this case, links are placed around `rural`. Finally, `frazione` has `hamlet` as its fallback, which in turn has `village` as its fallback, so both fallbacks end up being returned. `no_fallback`, if set, disables returning equivalent placetypes based on the `fallback` setting for a placetype. This is used in the first of two loops in find_placetype_cat_specs() in [[Module:place]] to prefer exact matches for placetypes such as barangays with later holonyms to matches based on a fallback such as `neighborhood` with an earlier holonym. See the comment in that function in [[Module:place]] for a more detailed explanation of why this is needed. Only the placetype itself, and any reduced placetypes created by chopping off recognized qualifiers at the beginning, are returned; but we do not return reduced placetypes if a containing placetype exists in `placetype_data`. (For example, `"overseas territory"` has a fallback `"dependent territory"`, and `"overseas"` is also a recognized qualifier. When `no_fallback` is in place, without the above proviso, we would return `"overseas territory"` followed by `"territory"` with the incorrect effect of classifying an `"overseas territory"` of the United Kingdom such as `"Gibraltar"` under [[:Category:Territories of the United Kingdom]] instead of [[:Category:Dependent territories of the United Kingdom]].) As an exception, if `historical`, `ancient`, `former` or the like are found, they proceed ignoring `no_fallback`, because it seems tricky to handle them correctly in the presence of `no_fallback`, and historical/former placetypes rarely occur with exact match category specs anyway. `no_split_qualifiers` prevents splitting off recognized qualifiers and returning the remainder of the placetype as an equivalent placetype. Only the passed-in placetype, and any fallbacks, will be returned. This is used in [[Module:category tree/topic cat/data/Places]] when looking up placetypes found in categories. Such placetypes won't have qualifiers and so it doesn't make sense to try and look for them. `from_category`, if set, causes category-only placetypes (those ending in `!`) to also be checked. `form_of_directive`, if set, causes the specified form-of directive (e.g. `FORMER_NAME_OF`) to be prepended to checked placetypes, their directive-specific type (e.g. `FORMER_NAME_OF_type`), and their classes (`class`) to get the appropriate placetypes to check for form-of-directive categories. It falls back to the prepended generic `place` as a placetype, e.g. `FORMER_NAME_OF place`, if nothing else matches. `no_check_for_inherently_former` is used internally to prevent an infinite loop when checking for `inherently_former`. `register_former_as_non_former` is a major hack used in `get_bare_categories` to deal with the mismatch between e.g. known location `Yugoslavia` declaring itself a `country` but definitions of it declaring it a `former country`. It causes the non-former version of the specified placetype to be included in the returned equivalents along with the former placetypes. [FIXME: This should apply only to the entries in `former_countries` but it's tricky to do that now; fix this in the known-location refactor. -- The known-location refactor is already done but we haven't yet fixed this.] ]==] function export.get_placetype_equivs(placetype, props) local no_fallback, no_split_qualifiers, no_check_for_inherently_former, from_category, register_former_as_non_former local form_of_directive if props then no_fallback, no_split_qualifiers, no_check_for_inherently_former, from_category, register_former_as_non_former = props.no_fallback, props.no_split_qualifiers, props.no_check_for_inherently_former, props.from_category, props.register_former_as_non_former form_of_directive = props.form_of_directive end local equivs = {} -- Insert `placetype` into `equivs`, along with any fallback placetypes listed in `placetype_data`. `qualifier` is -- the preceding qualifier to insert into `equivs` along with the placetype (see comment at top of function). If -- `from_category` is given, we also check for a category-specific entry consisting of the placetype followed by -- `!`, and in all cases we also check to see if `placetype` is plural, and if so, insert the singularized version -- along with its fallbacks (if any) in `placetype_data`. `form_of_prefix` is a form-of prefix such as -- `OFFICIAL_NAME_OF`. If specified, we check the fallbacks of `placetype` without the prefix but then insert into -- `equivs` the prefixed placetype. This way, if the user says e.g. {{tl|place|pt|@official name of:Cuba|island country|r/Caribbean}}, -- we will correctly categorize into [[:Category:Official names of countries]], rather than only trying to look up -- `OFFICIAL_NAME_OF island country` and failing, falling back ultimately to [[:Category:Official names of places]]. local function insert_placetype_and_fallbacks(qualifier, placetype, form_of_prefix) local function insert_equiv(pt) if form_of_prefix then -- Let's say the user says {{tl|place|pt|@official name of:Cuba|island country|r/Caribbean}} and we have -- no entry for `OFFICIAL_NAME_OF island country` but we do for `OFFICIAL_NAME_OF country` (which we end -- up processing because `island country` falls back to `country`), and that entry in turn is defined -- using a fallback. We have to insert that fallback-of-fallback, and the easiest/cleanest way of -- handling this is by calling ourselves recursively. insert_placetype_and_fallbacks(qualifier, form_of_prefix .. " " .. pt) else insert(equivs, {qualifier=qualifier, placetype=pt}) end end -- Insert the placetype, along with any fallbacks. local canon_placetype, ptdata, ptmatch = export.get_placetype_data(placetype, from_category) if ptdata then insert_equiv(canon_placetype) if no_fallback then return end local first_placetype = #equivs + 1 local prev_placetype = nil while true do local pt_value = export.placetype_data[canon_placetype] if not pt_value then internal_error("Fallback value %s specified for placetype %s but is not in `placetype_data`", canon_placetype, prev_placetype) end if pt_value.fallback then insert_equiv(pt_value.fallback) local last_placetype = #equivs if last_placetype - first_placetype >= 10 then local fallback_loop = {} for i = first_placetype, last_placetype do insert(fallback_loop, equivs[i].placetype) end internal_error("Apparent loop in fallback chain: %s", table.concat(fallback_loop, " -> ")) end prev_placetype = canon_placetype canon_placetype = pt_value.fallback else break end end end end -- Insert `placetype` into `equivs`, along with any fallback placetypes listed in `placetype_data`. This is a -- wrapper around the more basic `insert_placetype_and_fallbacks()` which handles form-of directives. If there is no -- form-of directive, this function directly calls `insert_placetype_and_fallbacks()`. We do things this way so that -- form-of directives correctly combine with `former`-type qualifiers. Note that we also have special backups for -- form-of directives that check `DIRECTIVE place` (and before that, `DIRECTIVE FORMER/ANCIENT place` is there's a -- `former`-type directive); these backups live outside this function because we want them done once, late, rather -- than in each invocation of `process_and_insert_placetype()`. local function process_and_insert_placetype(qualifier, reduced_placetype) if form_of_directive then -- First check for e.g. `OFFICIAL_NAME_OF island country` and its fallbacks; then we look for fallbacks of -- `island country` and check e.g. `OFFICIAL_NAME_OF country` and its fallbacks. All of this is handled by -- `insert_placetype_and_fallbacks()` with appropriate parameters. After that, check the general class of -- the directive, e.g. `subpolity` if something like `district` is given. (Eventually, we check for -- `OFFICIAL_NAME_OF place` as a backup, but this happens at the end outside the loop over qualifiers.) insert_placetype_and_fallbacks(qualifier, reduced_placetype, form_of_directive) if not no_fallback then local reduced_placetype_equivs = export.get_placetype_equivs(reduced_placetype) local directive_type = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.get_placetype_prop(pt, form_of_directive .. "_type") or export.get_placetype_prop(pt, "class") end ) if not directive_type then local pt_data = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.placetype_data[pt] end ) if pt_data then internal_error("For placetype %s in conjunction with form-of directive %s, placetype data " .. 'located but directive-specific type property %s missing, and so is "class"; ' .. "placetypes searched are %s", reduced_placetype, form_of_directive, form_of_directive .. "_type", reduced_placetype_equivs) else -- This should be allowed, as we allow unrecognized placetypes in general. end elseif directive_type ~= "!" then insert_placetype_and_fallbacks(qualifier, directive_type, form_of_directive) end end else insert_placetype_and_fallbacks(qualifier, reduced_placetype) end end -- Successively split off recognized qualifiers and loop over successively greater sets of qualifiers from the left -- (unless `no_split_qualifiers` is specified, in which case we don't check for qualifiers). local splits if no_split_qualifiers then splits = {{nil, nil, export.resolve_placetype_aliases(placetype)}} else splits = export.split_qualifiers_from_placetype(placetype) end for _, split in ipairs(splits) do local prev_qualifier, this_qualifier, reduced_placetype = unpack(split, 1, 3) -- If a special "former" qualifier like `former` or `historical` isn't present, and -- `no_check_for_inherently_former` is not given (this flag is used to avoid infinite loops), check for -- "inherently former" placetypes like `satrapy` and `treaty port` that always refer to no-longer-existing -- placetypes, and handle accordingly. local unlinked_this_qualifier if this_qualifier and this_qualifier:find("%[") then unlinked_this_qualifier = export.remove_links_and_html(this_qualifier) else unlinked_this_qualifier = this_qualifier end local former_qualifiers = this_qualifier and export.former_qualifiers[unlinked_this_qualifier] or nil if not former_qualifiers and not no_check_for_inherently_former then former_qualifiers = export.get_equiv_placetype_prop(reduced_placetype, function(pt) return export.get_placetype_prop(pt, "inherently_former") end, {no_check_for_inherently_former = true}) end -- If a special "former" qualifier like `former` or `historical` is present, map it to the appropriate internal -- qualifiers (`ANCIENT` and/or `FORMER`, which are written in all-caps to distinguish them from user-specified -- qualifiers), fetch the `former_type` property, and treat the placetype as if a concatenation of the mapped -- qualifier(s) and the value of `former_type`. For example, if `medieval village` is given, we map `medieval` -- to `ANCIENT` and `FORMER`, and `village` to its `former_type` of `settlement`, and enter the placetypes -- `ANCIENT settlement` and `FORMER settlement` (in that order) into `equivs`. If the placetype following the -- "former" qualifier is recognized in `placetype_data` but has no `former_type` and no fallback with a -- `former_type` specified, it is an internal error; but if the placetype isn't recognized (e.g. something like -- `former greenhouse` is specified and we don't have an entry for `greenhouse`), just track the occurrence and -- don't enter anything into `equivs`. if former_qualifiers then -- FIXME: Should we respect `no_fallback` here? My instinct says no. local reduced_placetype_equivs = export.get_placetype_equivs(reduced_placetype, { no_check_for_inherently_former = true }) local former_type = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.get_placetype_prop(pt, "former_type") or export.get_placetype_prop(pt, "class") end ) if not former_type then local pt_data = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.placetype_data[pt] end ) if pt_data then internal_error("For placetype %s, placetype data located but `former_type` missing; " .. "placetypes searched are %s", reduced_placetype, reduced_placetype_equivs) else -- Enable error when we've verified there aren't any examples. track("bad-former-placetype") track("bad-former-placetype/" .. reduced_placetype) --process_error("For placetype '%s', unrecognized placetype following 'former'-type " .. -- "qualifier; searched placetype(s) %s", reduced_placetype, dump(reduced_placetype_equivs)) end elseif former_type ~= "!" then -- First check directly for `ANCIENT/FORMER` + the original following placetype. This makes it possible -- for (e.g.) former provinces of the Roman empire to be categorized specially. for _, former_qualifier in ipairs(former_qualifiers) do process_and_insert_placetype(prev_qualifier, former_qualifier .. " " .. reduced_placetype) end for _, former_qualifier in ipairs(former_qualifiers) do process_and_insert_placetype(prev_qualifier, former_qualifier .. " " .. former_type) end -- HACK! See explanation above for `register_former_as_non_former`. if register_former_as_non_former then process_and_insert_placetype(prev_qualifier, reduced_placetype) end -- If we're processing a form-of directive, after doing everything else we do -- `DIRECTIVE ANCIENT/FORMER place` e.g. `OFFICIAL_NAME_OF FORMER place` as a backup. if form_of_directive and not no_fallback then for _, former_qualifier in ipairs(former_qualifiers) do insert_placetype_and_fallbacks(prev_qualifier, form_of_directive .. " " .. former_qualifier .. " place") end end -- Don't continue processing equivs. The reason is probably the same as the `break` below for -- qualifier_to_placetype_equivs[]; categories for `former BLAH` are set using `default`, and -- non-former equivs will otherwise take precedence. break end end -- Then see if the rightmost split-off qualifier is in qualifier_to_placetype_equivs -- (e.g. 'fictional *' -> 'fictional location'). If so, add the mapping. if this_qualifier and export.qualifier_to_placetype_equivs[unlinked_this_qualifier] then insert(equivs, { qualifier=prev_qualifier, placetype=export.qualifier_to_placetype_equivs[unlinked_this_qualifier] }) -- Don't continue processing equivs; otherwise, if we specify 'mythological city', even though the -- equivalent entry for 'mythological location' gets inserted ahead of the entry for 'city', the -- latter ends up generating the category because the category for 'mythological location' is set as -- the default value, which is used only when no non-default category can be found. break end -- Finally, join the rightmost split-off qualifier to the previously split-off qualifiers to form a combined -- qualifier, and add it along with reduced_placetype and any mapping in placetype_data for reduced_placetype. -- NOTE: The first time through this loop, both `prev_qualifier` and `this_qualifier` are nil, and this inserts -- the full placetype into `equivs`. local qualifier = prev_qualifier and prev_qualifier .. " " .. this_qualifier or this_qualifier process_and_insert_placetype(qualifier, reduced_placetype) -- If `no_fallback` and there's an entry in `placetype_data` for this placetype, don't include any reduced -- placetypes to avoid the "overseas territory treated as a territory" issue describe above. if no_fallback then local canon_placetype, ptdata, ptmatch = export.get_placetype_data(reduced_placetype, from_category) if canon_placetype then break end end end -- If we're processing a form-of directive, after doing everything else we do `DIRECTIVE place` e.g. -- `OFFICIAL_NAME_OF place` as a backup; but only if either the placetype as a whole is recognized or the placetype -- begins with a recognized qualifier. This latter check is to avoid categorizing into e.g. -- [[Category:en:Former names of places]] in an invocation like -- {{place|en|@former name of:Democratic Republic of the Congo|country|r/Central Africa|;|used from 1971–1997}}; -- the `used from 1971–1997` gets treated as a placetype and we're called on it. if form_of_directive and not no_fallback and (splits[2] or export.get_placetype_data(placetype, from_category)) then insert_placetype_and_fallbacks(nil, form_of_directive .. " place") end return equivs end function export.get_equiv_placetype_prop_from_equivs(equivs, fun, continue_on_nil_only) for _, equiv in ipairs(equivs) do local retval = fun(equiv.placetype) if continue_on_nil_only and retval ~= nil or not continue_on_nil_only and retval then return retval, equiv end end return nil, nil end --[==[ Given a placetype `placetype` and a function `fun` of one argument, iteratively call the function on equivalent placetypes fetched from `get_placetype_equivs` until the function returns a non-falsy value (i.e. not {nil} or {false}); but if `continue_on_nil_only` is specified, the iterations continue until the function returns non non-{nil} value. FIXME: We should make `continue_on_nil_only` the default; but this requires changing some callers.) When `fun` returns a non-falsy or non-{nil} value, `get_equiv_placetype_prop` returns two values: the value returned by `fun` and the equivalent placetype that triggered the non-falsy (or non-{nil}) return value. If `fun` never returns a non-falsy (or non-{nil}) value, `get_equiv_placetype_prop` returns {nil} for both return values. If `placetype` is passed in as {nil}, the return value is the result of calling `fun` on {nil} (whatever it is) with {nil} for the second return value. ]==] function export.get_equiv_placetype_prop(placetype, fun, props) if not placetype then return fun(nil), nil end return export.get_equiv_placetype_prop_from_equivs(export.get_placetype_equivs(placetype, props), fun, props and props.continue_on_nil_only) end --[==[ Return the article that is used with an entry placetype. We proceed as follows: # See if there is a recognized qualifier at the beginning that specifies an article (including `false` for no article). This takes precedence over anything else, so that e.g. `various capitals` gets no article rather than "`the"`. # Then check the placetype or any equivalent placetype for the `entry_placetype_use_the` property, indicating that `"the"` should be used. # Otherwise we look to see if the placetype itself (not any equivalents, even those involving deleting a qualifier from the beginning) has an entry in `placetype_data` that specifies the indefinite article using `entry_placetype_use_the` (principally for use with placetypes like `union territory`). # Otherwise, we use [[Module:en-utilities]] to apply the standard algorithm to generate `"an"` for words beginning with a vowel and `"a"` otherwise. If `ucfirst` is true, the first letter of the article is made upper-case. ]==] function export.get_placetype_article(placetype, ucfirst) local art local qualifier, reduced_placetype = placetype:match("^(.-) (.*)$") if qualifier then local canon = export.placetype_qualifiers[qualifier] if type(canon) == "table" then art = canon.article end end if art == false then return art end if art == nil then local placetype_use_the = export.get_equiv_placetype_prop(placetype, function(pt) return export.get_placetype_prop(pt, "entry_placetype_use_the") end) if placetype_use_the then art = "the" else art = export.get_placetype_prop(placetype, "entry_placetype_indefinite_article") if not art then art = require(en_utilities_module).get_indefinite_article(placetype) end end end if ucfirst then art = m_strutils.ucfirst(art) end return art end --[==[ Return the preposition that should be used after `placetype` when occurring as an entry placetype or in categories (e.g. `city >in< France` but `country >of< South America`). The preposition defaults to `"in"` if not specified. ]==] function export.get_placetype_entry_preposition(placetype) local pt_prep = export.get_equiv_placetype_prop(placetype, function(pt) return export.get_placetype_prop(pt, "preposition") end ) return pt_prep or "in" end --[==[ Given a place desc (see top of file) and a holonym object (see top of file), add a key/value into the place desc's `holonyms_by_placetype` field corresponding to the placetype and placename of the holonym. For example, corresponding to the holonym "c/Italy", a key "country" with the list value {"Italy"} will be added to the place desc's `holonyms_by_placetype` field. If there is already a key with that place type, the new placename will be added to the end of the value's list. ]==] function export.key_holonym_into_place_desc(place_desc, holonym) if not holonym.placetype then return end -- Key in equivalent placetypes, so that e.g. `cities/San Francisco` gets keyed under `city`; but don't do -- fallbacks, as it doesn't seem correct for the "do other holonyms of the same placetype" algorithm to do holonyms -- of different types just because they have the same fallback. local equiv_placetypes = export.get_placetype_equivs(holonym.placetype, {no_fallback = true}) local unlinked_placename = holonym.unlinked_placename for _, equiv in ipairs(equiv_placetypes) do local placetype = equiv.placetype if not place_desc.holonyms_by_placetype then place_desc.holonyms_by_placetype = {} end if not place_desc.holonyms_by_placetype[placetype] then place_desc.holonyms_by_placetype[placetype] = {unlinked_placename} else insert(place_desc.holonyms_by_placetype[placetype], unlinked_placename) end end end --[=[ Construct a formatted link from the raw link spec `link` given the canonical singular placetype `sg_placetype`. If the placetype was originally plural, `orig_placetype` should contain this plural value; otherwise it should be nil. This will construct the appropriate type of link that displays as `orig_placetype` (or otherwise `sg_placetype`) but links to whatever the `link` spec specifies (which may be `sg_placetype`, a Wikipedia article, etc.). `ptdata` is the placetype data structure for the placetype, and `from_category` indicates that we are generating the description of a category (otherwise we are generating the display form of an entry placetype). ]=] local function make_placetype_link(link, sg_placetype, orig_placetype, ptdata, from_category, noerror) if not from_category and ptdata.disallow_in_entries then if noerror then return "[not meant to be specified directly, with warning: " .. ptdata.disallow_in_entries .. "]" else process_error("Placetype %s is not meant to be specified directly: " .. ptdata.disallow_in_entries, sg_placetype) end end if link == nil then internal_error("Placetype data present for placetype %s but no link= setting given", sg_placetype) elseif link == true then if orig_placetype then return ("[[%s|%s]]"):format(sg_placetype, orig_placetype) else return ("[[%s]]"):format(sg_placetype) end elseif link == false then process_error("Placetype %s is not meant to be specified directly, but is only for internal use", sg_placetype) elseif link == "w" then return ("[[w:%s|%s]]"):format(sg_placetype, orig_placetype or sg_placetype) elseif link == "separately" then if orig_placetype then local sg_words = split(sg_placetype, " ") local orig_words = split(orig_placetype, " ") if #sg_words ~= #orig_words then internal_error("Can't construct 'separately' link for plural placetype %s as original placetype %s " .. "has different number of words", orig_placetype, sg_placetype) else for i = 1, #sg_words do if sg_words[i] == orig_words[i] then sg_words[i] = ("[[%s]]"):format(sg_words[i]) else sg_words[i] = ("[[%s|%s]]"):format(sg_words[i], orig_words[i]) end end return concat(sg_words, " ") end else return (sg_placetype:gsub("([^ ]+)", "[[%1]]")) end elseif link:find("^%+") then link = link:sub(2) -- discard initial + return ("[[%s|%s]]"):format(link, orig_placetype or sg_placetype) elseif not orig_placetype then return link else return require(en_utilities_module).pluralize(link) end end --[==[ Get the display form of a placetype by looking it up in `placetype_data`. If the placetype is recognized, or is the plural of a recognized placetype, the corresponding linked display form is returned (with plural placetypes displaying as plural but linked to the singular form of the placetype). Otherwise, return nil. If we're generating the description of a category, `category_type` should be set to one of `"top-level"` (for top-level categories like [[:Category:Neighborhoods]]), `"noncity"` (for non-city categories like [[:Category:Neighborhoods in Illinois, USA]]) or `"city"` (for city categories like [[:Category:Neighborhoods of Chicago]]). Otherwise, we're generating the description for use in formatting a {{tl|place}} call, and category-only placetypes ending in `!` will be ignored, along with special `category_link*` settings. `return_full` is used along with `category_type` and will preferably return the "full" variant of category link settings, i.e. `full_category_link*`; if they don't exist, the `category_link*` value is prepended with `"names of"`. `noerror` says to not throw an error when encountering entry placetypes that would be disallowed. ]==] function export.get_placetype_display_form(placetype, category_type, return_full, noerror) local from_category = not not category_type local canon_placetype, ptdata, ptmatch = export.get_placetype_data(placetype, from_category) if canon_placetype then local raw_link local function is_linked_string(str) return type(str) == "string" and str:find("%[%[") end if category_type then local fetched_full local function fetch_maybe_full(prop) local retval = ptdata["full_" .. prop] if retval ~= nil then if return_full then return retval, true else internal_error("Saw full_" .. prop .. "=%s but `return_full` not set, can't handle", retval) end end return ptdata[prop], false end local function maybe_prefix(str) if return_full and not fetched_full then return "names of " .. str else return str end end -- Careful with `false` as possible value. if category_type == "top-level" then raw_link, fetched_full = fetch_maybe_full("category_link_top_level") elseif category_type == "noncity" then raw_link, fetched_full = fetch_maybe_full("category_link_before_noncity") elseif category_type == "city" then raw_link, fetched_full = fetch_maybe_full("category_link_before_city") else internal_error('Unrecognized value for `category_type` %s, should be "top-level", "noncity" or "city"', category_type) end if type(raw_link) == "string" then return maybe_prefix(raw_link), ptdata elseif raw_link ~= nil then return raw_link, ptdata end raw_link, fetched_full = fetch_maybe_full("category_link") if raw_link == false then return raw_link, ptdata end if is_linked_string(raw_link) then return maybe_prefix(raw_link), ptdata end if ptmatch == "plural" then raw_link, fetched_full = fetch_maybe_full("plural_link") if raw_link == false then return raw_link, ptdata end if is_linked_string(raw_link) then return maybe_prefix(raw_link), ptdata end end if raw_link == nil then raw_link, fetched_full = fetch_maybe_full("link") end if raw_link == false then return raw_link, ptdata end return maybe_prefix(make_placetype_link(raw_link, canon_placetype, placetype ~= canon_placetype and placetype or nil, ptdata, from_category, noerror)), ptdata else if ptmatch == "plural" then raw_link = ptdata.plural_link if raw_link == false then process_error("Placetype %s cannot appear plural", placetype) end if is_linked_string(raw_link) then return raw_link, ptdata end end if raw_link == nil then raw_link = ptdata.link end return make_placetype_link(raw_link, canon_placetype, placetype ~= canon_placetype and placetype or nil, ptdata, from_category, noerror), ptdata end end return nil end local function resolve_unlinked_placename_display_aliases(placetype, placename) local equiv_placetypes = export.get_placetype_equivs(placetype) for i, equiv in ipairs(equiv_placetypes) do equiv_placetypes[i] = equiv.placetype end local all_display_aliases_found = {} local all_others_found = {} for group, key, spec in m_locations.iterate_matching_location { placetypes = equiv_placetypes, placename = placename, alias_resolution = "display", } do if spec.alias_of and spec.display then insert(all_display_aliases_found, {group, key, spec, spec.display_as_full}) else insert(all_others_found, {group, key, spec}) end end if not all_display_aliases_found[1] then return placename elseif all_display_aliases_found[2] then internal_error("Found multiple matching display aliases for placename %s, placetype %s: " .. "all_display_aliases_found=%s, all_others_found=%s", placename, placetype, all_display_aliases_found, all_others_found) elseif all_others_found[1] then internal_error("Found a display alias along with other possible meanings for placename %s, placetype %s: " .. "all_display_aliases_found=%s, all_others_found=%s", placename, placetype, all_display_aliases_found, all_others_found) else local group, key, spec, as_full = unpack(all_display_aliases_found[1]) local full, elliptical = m_locations.key_to_placename(group, key) return as_full and full or elliptical end end --[==[ If `placename` of type `placetype` is a display alias, convert it to its canonical form; otherwise, return unchanged. Display aliases transform certain placenames into canonical displayed forms. For example, if any of `country/US`, `country/USA` or `country/United States of America` (or `c/US`, etc.) are given, the result will be displayed as `United States`. '''NOTE''': Display aliases change what is displayed from what the editor wrote in the Wikitext. As a result, they should (a) be non-political in nature, and (b) not involve a change where the word `the` needs to be added or removed. For example, normalizing `US` and `USA` to `United States` for display purposes is OK but normalizing `Burma` to `Myanmar` is not (instead a cat alias should be used) because the terms `Burma` and `Myanmar` have clear political connotations. Similarly, we have a display alias that maps the old name of `Macedonia` as a country (but not a region!) to `North Macedonia`, but `Republic of Macedonia` is mapped to `North Macedonia` only as a cat alias because the two terms differ in their use of `the`. (For example, if we had a display alias mapping `Republic of Macedonia` to `North Macedonia`, the call {{tl|place|en|the <<capital city>> of the <<c/Republic of Macedonia>>}} would wrongly display as `the [[capital city]] of the [[North Macedonia]]`.) Generally, display normalizations tend to involve alternative forms (e.g. abbreviations, ellipses, foreign spellings) where the normalization improves clarity and consistency. ]==] function export.resolve_placename_display_aliases(placetype, placename) -- If the placename is a link, apply the alias inside the link. -- This pattern matches both piped and unpiped links. If the link is not piped, the second capture (linktext) will -- be empty. local link, linktext = rmatch(placename, "^%[%[([^|%[%]]+)|?([^|%[%]]-)%]%]$") if link then if linktext ~= "" then local alias = resolve_unlinked_placename_display_aliases(placetype, linktext) return "[[" .. link .. "|" .. alias .. "]]" else local alias = resolve_unlinked_placename_display_aliases(placetype, link) return "[[" .. alias .. "]]" end else return resolve_unlinked_placename_display_aliases(placetype, placename) end end --[==[ Generate the "prefixed" version of a bare key, i.e. prefix it with `the` if correct for this key. ]==] function export.get_prefixed_key(key, spec) if spec.the then return "the " .. key else return key end end -- Necessary for use by [[Module:place]]. FIXME: Reorganize the modules so this isn't necessary. export.iterate_matching_location = m_locations.iterate_matching_location --[=[ Iterator that iterates over holonyms in `place_desc`. If `first_holonym_index` is given, start iterating at the specified holonym and stop either when there are no more holonyms or a holonym with modifier `:also` is found. If `first_holonym_index` is nil or omitted, iterate over all holonyms regardless. If `include_raw_text_holonyms` is specified, raw text holonyms (those not of the form `placetype/placename`) are returned as well; they can be identified by the fact that the `placetype` field in the holonym structure is nil. Two values are returned at each iteration, the holonym index and holonym structure, similar to `ipairs()`. ]=] function export.get_holonyms_to_check(place_desc, first_holonym_index, include_raw_text_holonyms) local stop_at_also = not not first_holonym_index return function(place_desc, index) while true do index = index + 1 local this_holonym = place_desc.holonyms[index] -- If we were passed in a starting holonym index, go up to but not including a holonym marked with `:also` -- (continue_cat_loop); the categorization code will then restart the loop at that holonym. That holonym -- will have `:also` marked on it, so make sure not to stop immediately if the first holonym is marked with -- `:also`. if not this_holonym or stop_at_also and index > first_holonym_index and this_holonym.continue_cat_loop then return nil end -- If not placetype, we're processing raw text, which we normally want to skip. if include_raw_text_holonyms or this_holonym.placetype then return index, this_holonym end end end, place_desc, first_holonym_index and first_holonym_index - 1 or 0 end --[==[ If the holonym in `data` (in the format as passed to a category handler) refers to a known location, iterate over all such known locations, returning for each location the corresponding key, spec and group as well as the trail of ancestral containers. Unlike `iterate_matching_location()`, this specifically checks that there is no mismatch between the location's containers at any level and any of the following holonyms in the {{tl|place}} spec. The fields in `data` are: * `holonym_placetype`: The placetype of the holonym. It can actually be a list of possible placetypes, as with `iterate_matching_location()`. * `holonym_placename`: The placename of the holonym. * `holonym_index`: The index of the holonym among the holonyms in `place_desc`, or nil if the holonym is not among the holonyms in `place_desc`. (If a holonym index is given, we check for container mismatches among the holonyms following the specified index, stopping either when encountering a holonym marked with modifier `:also` or, if none exist, when we run out of holonyms. If no holonym index is given, we check all holonyms for container mismatches.) * `place_desc`: Description of the place; used for the holonyms, to check for container mismatches. Returns four values: the location group, the canonical key by which the location is known, the spec object describing the location and the trail of ancestral containers for the location. The first three values are the same as for `iterate_matching_location`. ]==] function export.iterate_matching_holonym_location(data) local holonym_placetype, holonym_placename, holonym_index, place_desc = data.holonym_placetype, data.holonym_placename, data.holonym_index, data.place_desc local matching_location_iterator = m_locations.iterate_matching_location { placetypes = holonym_placetype, placename = holonym_placename, } return function() while true do local group, key, spec = matching_location_iterator() if not group then return nil end local container_trail = {} -- For each level of container, check that there are no mismatches (i.e. other location of the same -- placetype) mentioned. We allow a mismatch at a given level if there's also a match with the container -- at that level. For example, in the case of Kansas City, defined in [[Module:place/locations]] as a city -- in Missouri, if we define it as {{tl|place|city|s/Missouri,Kansas}}, we ignore the mismatching state of -- Kansas because the correct state of Missouri was also mentioned. But imagine we are defining Newark, -- Delaware as {{tl|place|city|s/Delaware|c/US}} and (as is the case) we have an entry for Newark, New -- Jersey in [[Module:place/locations]]. Just because the containing location `US` matches isn't enough, -- because Newark, NJ also has New Jersey as a containing location and there's a mismatch at that level. If -- there are no mismatches at any level we assume we're dealing with the right known location. -- -- If at a given level there are multiple containing locations, we count a match if any holonym matches any -- containing location, and a mismatch only if a holonym exists of the same placetype that doesn't match any -- containing location. local containers_mismatch = false for containers in m_locations.iterate_containers(group, key, spec) do insert(container_trail, containers) local match_at_level = false local mismatch_at_level = false for other_holonym_index, other_holonym in export.get_holonyms_to_check(place_desc, holonym_index and holonym_index + 1 or nil) do local other_source_holonym = other_holonym.augmented_from_holonym if other_source_holonym and other_source_holonym.placetype == holonym_placetype and other_source_holonym.unlinked_placename ~= holonym_placename then -- Ignore holonyms added during the augmentation process for other holonyms of the same -- placetype as the placetype of the holonym we're considering. See comment in -- augment_holonyms_with_container() for why we do this. -- continue; grrr, no 'continue' in Lua else local holonym_matches_at_level = false local holonym_exists_with_same_placetype = false for _, container in ipairs(containers) do if not container.spec.no_check_holonym_mismatch then local full_container_placename, elliptical_container_placename = m_locations.key_to_placename(container.group, container.key) local placetypes = container.spec.placetype if type(placetypes) ~= "table" then placetypes = {placetypes} end local placetype_equivs = {} for _, pt in ipairs(placetypes) do m_table.extend(placetype_equivs, export.get_placetype_equivs(pt)) end local this_holonym_matches = export.get_equiv_placetype_prop_from_equivs( placetype_equivs, function(placetype) return other_holonym.placetype == placetype and (other_holonym.unlinked_placename == full_container_placename or other_holonym.unlinked_placename == elliptical_container_placename) end ) if this_holonym_matches then holonym_matches_at_level = true break end local this_holonym_exists_with_same_placetype = export.get_equiv_placetype_prop_from_equivs( placetype_equivs, function(placetype) return other_holonym.placetype == placetype end ) if this_holonym_exists_with_same_placetype then -- We seem to have a mismatch at this level. But before we decide conclusively that this -- is the case, check to see whether the putative mismatch is an alias and matches when -- we resolve the alias. for oh_group, oh_key, oh_spec, oh_container_trail in export.iterate_matching_holonym_location { holonym_placetype = other_holonym.placetype, holonym_placename = other_holonym.unlinked_placename, holonym_index = other_holonym_index, place_desc = place_desc, } do local oh_full_placename, oh_elliptical_placename = m_locations.key_to_placename(oh_group, oh_key) if oh_full_placename == full_container_placename or oh_elliptical_placename == elliptical_container_placename then -- Alias matched when resolved. this_holonym_matches = true break end end if this_holonym_matches then -- Alias matched above when resolved. holonym_matches_at_level = true break else -- Not an alias, or doesn't match when resolved. We have a true mismatch. holonym_exists_with_same_placetype = true end end end end if holonym_matches_at_level then match_at_level = true break end if holonym_exists_with_same_placetype then mismatch_at_level = true end end end if not match_at_level and mismatch_at_level then containers_mismatch = true break end end if not containers_mismatch then return group, key, spec, container_trail end end end end --[==[ If the holonym in `data` (in the format as passed to a category handler) refers to a known location, find and return the corresponding key, spec and group as well as the trail of ancestral containers. This is like `iterate_matching_holonym_location()` but throws an error if more than one location matches. (An example where this would happen is {{tl|place|en|neighborhood|city/Newcastle}}, because there are two known locations named Newcastle. To fix this, specify additional following disambiguating holonyms, e.g. {{tl|place|en|neighborhood|city/Newcastle|s/New South Wales}}. ]==] function export.find_matching_holonym_location(data) local all_found = {} for group, key, spec, container_trail in export.iterate_matching_holonym_location(data) do insert(all_found, {group, key, spec, container_trail}) end if not all_found[1] then return nil elseif all_found[2] then local holonym_placetype = data.holonym_placetype if type(holonym_placetype) == "table" then holonym_placetype = concat(holonym_placetype, ",") end local found_keys = {} for _, found in ipairs(all_found) do local _, key, _, _ = unpack(found) insert(found_keys, key) end error(("Found multiple matching locations for holonym '%s/%s'; specify disambiguating context in the " .. "containing holonyms: %s"):format(holonym_placetype, data.holonym_placename, dump(found_keys))) else return unpack(all_found[1]) end end ------------------------------------------------------------------------------------------ -- Placename and placetype data -- ------------------------------------------------------------------------------------------ --[==[ var: This is a map from aliases to their canonical forms. Any placetypes appearing as keys here will be mapped to their canonical forms in all respects, including the display form. Contrast entries in 'placetype_data' with a fallback, which applies to categorization and other processes but not to display. The most important aliases are for holonym placetypes, particularly those that occur often such as "country", "state", "province" and the like. Particularly long placetypes that mostly occur as entry placetypes (e.g. "census-designated place") can be given abbreviations, but it is generally preferred to spell out the entry placetype. Note also that we purposely avoid certain abbreviations that would be ambiguous (e.g. "d", which could variously be interpreted as "department", "district" or "division"). ]==] export.placetype_aliases = { ["acomm"] = "autonomous community", ["adr"] = "administrative region", ["adterr"] = "administrative territory", -- Pakistan ["aobl"] = "autonomous oblast", ["aokr"] = "autonomous okrug", ["ap"] = "autonomous province", ["apref"] = "autonomous prefecture", ["aprov"] = "autonomous province", ["ar"] = "autonomous region", ["arch"] = "archipelago", ["arep"] = "autonomous republic", ["aterr"] = "autonomous territory", ["atu"] = "autonomous territorial unit", ["bor"] = "borough", ["c"] = "country", ["can"] = "canton", ["carea"] = "council area", ["cc"] = "constituent country", ["cdblock"] = "community development block", ["cdep"] = "Crown dependency", ["CDP"] = "census-designated place", ["cdp"] = "census-designated place", ["clcity"] = "county-level city", ["co"] = "county", ["cobor"] = "county borough", ["colcity"] = "county-level city", ["coll"] = "collectivity", ["comm"] = "community", ["cont"] = "continent", ["contr"] = "continental region", ["contregion"] = "continental region", ["cpar"] = "civil parish", ["damun"] = "direct-administered municipality", ["dep"] = "dependency", ["department capital"] = "departmental capital", ["dept"] = "department", ["depterr"] = "dependent territory", ["dist"] = "district", ["distmun"] = "district municipality", ["div"] = "division", ["emp"] = "empire", ["fpref"] = "French prefecture", ["gov"] = "governorate", ["govnat"] = "governorate", ["home-rule city"] = "home rule city", ["home-rule municipality"] = "home rule municipality", ["inner-city area"] = "inner city area", ["ires"] = "Indian reservation", ["isl"] = "island", ["lbor"] = "London borough", ["lga"] = "local government area", ["lgarea"] = "local government area", ["lgd"] = "local government district", ["lgdist"] = "local government district", ["metbor"] = "metropolitan borough", ["metcity"] = "metropolitan city", ["metmun"] = "metropolitan municipality", ["mtn"] = "mountain", ["mun"] = "municipality", ["mundist"] = "municipal district", ["nonmetropolitan county"] = "non-metropolitan county", ["obl"] = "oblast", ["okr"] = "okrug", ["p"] = "province", ["par"] = "parish", ["parmun"] = "parish municipality", ["pen"] = "peninsula", ["plcity"] = "prefecture-level city", ["plcolony"] = "Polish colony", ["pref"] = "prefecture", ["prefcity"] = "prefecture-level city", ["preflcity"] = "prefecture-level city", ["prov"] = "province", ["r"] = "region", ["range"] = "mountain range", ["rcm"] = "regional county municipality", ["rcomun"] = "regional county municipality", ["rdist"] = "regional district", ["rep"] = "republic", ["rhrom"] = "rural hromada", ["riv"] = "river", ["rmun"] = "regional municipality", ["robor"] = "royal borough", ["romp"] = "Roman province", ["runit"] = "regional unit", ["rurmun"] = "rural municipality", ["s"] = "state", ["sar"] = "special administrative region", ["shrom"] = "settlement hromada", ["spref"] = "subprefecture", ["sprefcity"] = "sub-prefectural city", ["sprovcity"] = "subprovincial city", ["submet city"] = "sub-metropolitan city", ["submetropolitan city"] = "sub-metropolitan city", ["sub-prefecture-level city"] = "sub-prefectural city", ["sub-provincial city"] = "subprovincial city", ["sub-provincial district"] = "subprovincial district", ["terr"] = "territory", ["terrauth"] = "territorial authority", ["twp"] = "township", ["twpmun"] = "township municipality", ["uauth"] = "unitary authority", ["ucomm"] = "unincorporated community", ["udist"] = "unitary district", ["uhrom"] = "urban hromada", ["uterr"] = "union territory", ["utwpmun"] = "united township municipality", ["val"] = "valley", ["vdc"] = "village development committee", ["vil"] = "village", ["voi"] = "voivodeship", ["wcomm"] = "Welsh community", } local no_link_def_article = {link = false, article = "the"} local no_link_no_article = {link = false, article = false} --[==[ var: These qualifiers can be prepended onto any placetype and will be handled correctly. For example, the placetype `large city` will be displayed as `large <nowiki>[[city]]</nowiki>` and categorized as if `city` were specified. If the value in the following table is a string, the qualifier will display according to the string. If the value is `true`, the qualifier will be linked to its corresponding Wiktionary entry. If the value is `false`, the qualifier will not be linked but will appear as-is. Note that these qualifiers do not override placetypes with entries elsewhere that contain those same qualifiers. For example, the entry for `inland sea` in `placetype_data` will apply in preference to treating `inland sea` as equivalent to `sea`. ]==] export.placetype_qualifiers = { -- generic qualifiers ["huge"] = false, ["tiny"] = false, ["large"] = false, ["big"] = false, ["mid-size"] = false, ["mid-sized"] = false, ["small"] = false, ["sizable"] = false, ["important"] = false, ["long"] = false, ["short"] = false, ["major"] = false, ["minor"] = false, ["high"] = false, ["tall"] = false, ["low"] = false, ["left"] = false, -- left tributary ["right"] = false, -- right tributary ["modern"] = false, -- for use in opposition to "ancient" in another definition -- "former" qualifiers ["abandoned"] = true, ["ancient"] = true, ["deserted"] = true, ["extinct"] = true, ["former"] = false, ["historic"] = "historical", ["historical"] = true, ["medieval"] = true, ["mediaeval"] = true, ["ruined"] = true, ["traditional"] = true, -- sea qualifiers ["coastal"] = true, ["inland"] = true, -- note, we also have an entry in placetype_data for 'inland sea' to get a link to [[inland sea]] ["maritime"] = true, ["overseas"] = true, ["seaside"] = true, ["beachfront"] = true, ["beachside"] = true, ["riverside"] = true, -- lake qualifiers ["freshwater"] = true, ["saltwater"] = true, ["endorheic"] = true, ["oxbow"] = true, ["ox-bow"] = "[[oxbow]]", -- [[ox-bow]] is a red link ["tidal"] = true, -- land qualifiers ["hilltop"] = true, ["hilly"] = true, ["insular"] = true, ["peninsular"] = true, ["chalk"] = true, ["karst"] = true, ["limestone"] = true, ["mountainous"] = true, ["mountaintop"] = true, ["alpine"] = true, ["volcanic"] = true, -- for an island -- political status qualifiers ["autonomous"] = true, ["incorporated"] = true, ["special"] = true, ["unincorporated"] = true, ["coterminous"] = true, -- monetary status/etc. qualifiers ["fashionable"] = true, ["wealthy"] = true, ["affluent"] = true, ["declining"] = true, -- city vs. rural qualifiers ["urban"] = true, ["suburban"] = true, ["exurban"] = true, ["outlying"] = true, ["remote"] = true, ["rural"] = true, ["outback"] = true, ["inner"] = false, ["inner-city"] = true, ["central"] = false, ["outer"] = false, -- land use qualifiers ["residential"] = true, ["agricultural"] = true, ["business"] = true, ["commercial"] = true, ["industrial"] = true, -- business use qualifiers ["railroad"] = true, ["railway"] = true, ["farming"] = true, ["fishing"] = true, ["mining"] = true, ["logging"] = true, ["cattle"] = true, -- tourism use qualifiers ["resort"] = true, -- note, we also have 'resort city' and 'resort town', that take precedecne ["spa"] = true, -- note, we also have 'spa city' and 'spa town', that take precedecne ["ski"] = true, -- note, we also have 'ski resort city' and 'ski resort town', that take precedecne -- religious qualifiers ["holy"] = true, ["sacred"] = true, ["religious"] = true, ["secular"] = true, -- qualifiers for nonexistent places ["claimed"] = false, ["fictional"] = true, ["legendary"] = true, ["mythical"] = true, ["mythological"] = true, -- directional qualifiers ["northern"] = false, ["southern"] = false, ["eastern"] = false, ["western"] = false, ["north"] = false, ["south"] = false, ["east"] = false, ["west"] = false, ["northeastern"] = false, ["southeastern"] = false, ["northwestern"] = false, ["southwestern"] = false, ["northeast"] = false, ["southeast"] = false, ["northwest"] = false, ["southwest"] = false, -- seasonal qualifiers ["summer"] = true, -- e.g. for 'summer capital' ["winter"] = true, -- legal status qualifiers -- FIXME: Two-word qualifiers don't work yet. But you can enter "de-facto" and it's canonicalized to [[de facto]]. ["official"] = true, ["unofficial"] = true, ["de facto"] = true, -- 'de facto capital' ["de-facto"] = "[[de facto]]", -- [[de-facto]] is a red link ["de jure"] = true, -- 'de jure capital' ["de-jure"] = "[[de jure]]", -- [[de-jure]] is a red link -- NOTE: 'unrecognized/unrecognised' are handled as placetypes 'unrecognized country', 'unrecognized state' -- misc. qualifiers ["planned"] = true, ["chartered"] = true, ["landlocked"] = true, ["uninhabited"] = true, -- superlative qualifiers ["first"] = no_link_def_article, ["second"] = no_link_def_article, -- for "second largest" etc. ["third"] = no_link_def_article, ["fourth"] = no_link_def_article, ["last"] = no_link_def_article, ["only"] = no_link_def_article, ["sole"] = no_link_def_article, ["main"] = no_link_def_article, ["largest"] = no_link_def_article, ["biggest"] = no_link_def_article, ["smallest"] = no_link_def_article, ["shortest"] = no_link_def_article, ["longest"] = no_link_def_article, ["tallest"] = no_link_def_article, ["highest"] = no_link_def_article, ["lowest"] = no_link_def_article, ["leftmost"] = no_link_def_article, ["rightmost"] = no_link_def_article, ["innermost"] = no_link_def_article, ["outermost"] = no_link_def_article, ["northernmost"] = no_link_def_article, ["southernmost"] = no_link_def_article, ["westernmost"] = no_link_def_article, ["easternmost"] = no_link_def_article, ["northwesternmost"] = no_link_def_article, ["southwesternmost"] = no_link_def_article, ["northeasternmost"] = no_link_def_article, ["southeasternmost"] = no_link_def_article, -- several/various ["several"] = no_link_no_article, ["various"] = no_link_no_article, ["numerous"] = no_link_no_article, ["multiple"] = no_link_no_article, ["many"] = no_link_no_article, ["other"] = no_link_no_article, } --[==[ var: In this table, the key qualifiers should be treated the same as the value qualifiers for categorization purposes. This is overridden by `placetype_data` and `qualifier_to_placetype_equivs`. ]==] export.former_qualifiers = { ["abandoned"] = {"FORMER"}, ["ancient"] = {"ANCIENT", "FORMER"}, ["former"] = {"FORMER"}, ["extinct"] = {"FORMER"}, ["historic"] = {"FORMER"}, ["historical"] = {"FORMER"}, ["medieval"] = {"ANCIENT", "FORMER"}, ["mediaeval"] = {"ANCIENT", "FORMER"}, ["ruined"] = {"ANCIENT", "FORMER"}, ["traditional"] = {"FORMER"}, } --[==[ var: In this table, any placetypes containing these qualifiers that do not occur in `placetype_data` should be mapped to the specified placetypes for categorization purposes. Entries here are overridden by `placetype_data`. ]==] export.qualifier_to_placetype_equivs = { ["fictional"] = "fictional location", ["legendary"] = "mythological location", ["mythical"] = "mythological location", ["mythological"] = "mythological location", -- For e.g. Taiwan as a "claimed province" of China; parts of Belize as claimed by Guatemala; various islands -- claimed by various parties in East Asia. FIXME: We should conditionalize on what is being claimed since there are -- also claimed capitals, e.g. Israel and Palestine claim Jerusalem as their capital. ["claimed"] = "claimed political division", } --[==[ var: Mapping from placetypes to the corresponding plural category-only placetype for a capital of that placetype. The reverse mapping also exists. ]==] export.placetype_to_capital_cat = { ["autonomous community"] = "autonomous community capitals", ["canton"] = "cantonal capitals", ["comarca"] = "comarca capitals", ["country"] = "national capitals", -- The following are not obviously different from 'county seats' but the latte terminology is used in the US. ["county"] = "county capitals", ["department"] = "departmental capitals", ["district"] = "district capitals", ["division"] = "division capitals", ["emirate"] = "emirate capitals", ["governorate"] = "governorate capitals", ["hromada"] = "hromada capitals", ["krai"] = "krai capitals", ["metropolitan city"] = "metropolitan city capitals", ["municipality"] = "municipal capitals", ["oblast"] = "oblast capitals", ["okrug"] = "okrug capitals", ["prefecture"] = "prefectural capitals", ["province"] = "provincial capitals", ["raion"] = "raion capitals", ["regency"] = "regency capitals", ["region"] = "regional capitals", ["regional unit"] = "regional unit capitals", ["republic"] = "republic capitals", ["state"] = "state capitals", ["territory"] = "territorial capitals", ["voivodeship"] = "voivodeship capitals", } --[==[ var: This contains placenames that should be preceded by an article (almost always "the"). '''NOTE''': There are multiple ways that placenames can come to be preceded by "the": # Listed here. # Given in [[Module:place/locations]] with an initial "the". All such placenames are added to this map by the code just below the map. # The placetype of the placename has `holonym_use_the = true` in its placetype_data. # A regex in placename_the_re matches the placename. Note that "the" is added only before the first holonym in a place description. ]==] export.placename_article = { -- This should only contain info that can't be inferred from [[Module:place/locations]]. ["archipelago"] = { ["Cyclades"] = "the", ["Dodecanese"] = "the", }, ["country"] = { ["Holy Roman Empire"] = "the", }, ["empire"] = { ["Holy Roman Empire"] = "the", }, ["island"] = { ["North Island"] = "the", ["South Island"] = "the", }, ["region"] = { ["Balkans"] = "the", ["Russian Far East"] = "the", ["Caribbean"] = "the", ["Caucasus"] = "the", ["Middle East"] = "the", ["New Territories"] = "the", ["North Caucasus"] = "the", ["South Caucasus"] = "the", ["West Bank"] = "the", ["Gaza Strip"] = "the", }, ["valley"] = { ["San Fernando Valley"] = "the", }, } --[==[ var: Regular expressions to apply to determine whether we need to put 'the' before a holonym. The key "*" applies to all holonyms, otherwise only the regexes for the holonym's placetype apply. ]==] export.placename_the_re = { -- We don't need entries for peninsulas, seas, oceans, gulfs or rivers -- because they have holonym_use_the = true. ["*"] = {"^Isle of ", " Islands$", " Mountains$", " Empire$", " Country$", " Region$", " District$", "^City of "}, ["bay"] = {"^Bay of "}, ["lake"] = {"^Lake of "}, ["country"] = {"^Republic of ", " Republic$"}, ["republic"] = {"^Republic of ", " Republic$"}, ["region"] = {" [Rr]egion$"}, ["river"] = {" River$"}, ["local government area"] = {"^Shire of "}, ["county"] = {"^Shire of "}, ["Indian reservation"] = {" Reservation", " Nation"}, ["tribal jurisdictional area"] = {" Reservation", " Nation"}, } --[==[ var: If any of the following holonyms are present, the associated holonyms are automatically added to the end of the list of holonyms for categorization (but not display) purposes. ]==] export.cat_implications = { ["region"] = { ["Eastern Europe"] = {"continent/Europe"}, ["Central Europe"] = {"continent/Europe"}, ["Western Europe"] = {"continent/Europe"}, ["South Europe"] = {"continent/Europe"}, ["Southern Europe"] = {"continent/Europe"}, ["Northern Europe"] = {"continent/Europe"}, ["Northeast Europe"] = {"continent/Europe"}, ["Northeastern Europe"] = {"continent/Europe"}, ["Southeast Europe"] = {"continent/Europe"}, ["Southeastern Europe"] = {"continent/Europe"}, ["North Caucasus"] = {"continent/Europe"}, ["South Caucasus"] = {"continent/Asia"}, ["South Asia"] = {"continent/Asia"}, ["Southern Asia"] = {"continent/Asia"}, ["East Asia"] = {"continent/Asia"}, ["Eastern Asia"] = {"continent/Asia"}, ["Central Asia"] = {"continent/Asia"}, ["West Asia"] = {"continent/Asia"}, ["Western Asia"] = {"continent/Asia"}, ["Southeast Asia"] = {"continent/Asia"}, ["North Asia"] = {"continent/Asia"}, ["Northern Asia"] = {"continent/Asia"}, ["Anatolia"] = {"continent/Asia"}, ["Asia Minor"] = {"continent/Asia"}, ["Mesopotamia"] = {"continent/Asia"}, ["North Africa"] = {"continent/Africa"}, ["Central Africa"] = {"continent/Africa"}, ["West Africa"] = {"continent/Africa"}, ["East Africa"] = {"continent/Africa"}, ["Southern Africa"] = {"continent/Africa"}, ["Central America"] = {"continent/Central America"}, ["Caribbean"] = {"continent/North America"}, ["Polynesia"] = {"continent/Oceania"}, ["Micronesia"] = {"continent/Oceania"}, ["Melanesia"] = {"continent/Oceania"}, ["Siberia"] = {"country/Russia", "continent/Asia"}, ["Russian Far East"] = {"country/Russia", "continent/Asia"}, ["South Wales"] = {"constituent country/Wales", "continent/Europe"}, ["Balkans"] = {"continent/Europe"}, ["West Bank"] = {"country/Palestine", "continent/Asia"}, ["Gaza"] = {"country/Palestine", "continent/Asia"}, ["Gaza Strip"] = {"country/Palestine", "continent/Asia"}, } } ------------------------------------------------------------------------------------------ -- Category and display handlers -- ------------------------------------------------------------------------------------------ local function city_type_cat_handler(data) local entry_placetype = data.entry_placetype local generic_before_non_cities = export.get_placetype_prop(entry_placetype, "generic_before_non_cities") if not generic_before_non_cities then internal_error("city_type_cat_handler called on placetype %s that doesn't have a `generic_before_non_cities`" .. " setting", entry_placetype) end local plural_entry_placetype = export.pluralize_placetype(entry_placetype) local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and not spec.is_former_place and not spec.is_city then -- Categorize both in key, and in the larger polity that the key is part of, e.g. [[Hirakata]] goes in both -- "Cities in Osaka Prefecture" and "Cities in Japan". (But don't do the latter if no_container_cat is set.) local cap_plural_entry_placetype = ucfirst(plural_entry_placetype) local retcats = {("%s %s %s"):format(cap_plural_entry_placetype, generic_before_non_cities, export.get_prefixed_key(key, spec))} if container_trail[1] and not spec.no_container_cat then for _, container in ipairs(container_trail[1]) do insert(retcats, ("%s %s %s"):format(cap_plural_entry_placetype, generic_before_non_cities, export.get_prefixed_key(container.key, container.spec))) end end return retcats end end local function capital_city_cat_handler(data, non_city) local holonym_placetype, holonym_placename, holonym_index, place_desc = data.holonym_placetype, data.holonym_placename, data.holonym_index, data.place_desc -- The first time we're called we want to return something; otherwise we will be called for later-mentioned -- holonyms, which can result in wrongly classifying into e.g. `National capitals`. Simulate the loop in -- find_placetype_cat_specs() over holonyms so we get the proper `Cities in ...` categories as well as the capital -- category/categories we add below. local retcats if not non_city and place_desc.holonyms then for h_index, holonym in export.get_holonyms_to_check(place_desc, holonym_index) do local h_placetype, h_placename = holonym.placetype, holonym.unlinked_placename retcats = city_type_cat_handler { entry_placetype = "city", holonym_placetype = h_placetype, holonym_placename = h_placename, holonym_index = h_index, place_desc = place_desc, } if retcats then break end end end if not retcats then retcats = {} end -- Now find the appropriate capital-type category for the placetype of the holonym, e.g. 'State capitals'. If we -- recognize the holonym among the known holonyms in [[Module:place/locations]], also add a category like 'State -- capitals of the United States'. Truncate e.g. 'autonomous region' to 'region', 'union territory' to 'territory' -- when looking up the type of capital category, if we can't find an entry for the holonym placetype itself (there's -- an entry for 'autonomous community'). local capital_cat = export.placetype_to_capital_cat[holonym_placetype] if not capital_cat then capital_cat = export.placetype_to_capital_cat[holonym_placetype:gsub("^.* ", "")] end if capital_cat then capital_cat = ucfirst(capital_cat) local inserted_specific_variant_cat = false if holonym_index then -- Now find the first recognized holonym location. We don't stop when :also is seen because of the common pattern -- where we use :also to specify that a given city is the capital at multiple surrounding levels. local matching_group, matching_key, matching_spec, matching_container_trail, matching_holonym_index for h_index = holonym_index, #place_desc.holonyms do if place_desc.holonyms[h_index].placetype then matching_group, matching_key, matching_spec, matching_container_trail = export.find_matching_holonym_location { holonym_placetype = place_desc.holonyms[h_index].placetype, holonym_placename = place_desc.holonyms[h_index].unlinked_placename, holonym_index = h_index, place_desc = place_desc, } if matching_group then matching_holonym_index = h_index break end end end if matching_holonym_index == holonym_index then if matching_container_trail[1] and not matching_spec.no_container_cat then for _, container in ipairs(matching_container_trail[1]) do insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(container.key, container.spec))) inserted_specific_variant_cat = true end end elseif matching_holonym_index then -- Check to make sure that the holonym placetype we were called on is listed among the -- divtypes of the location we found. local function insert_specific_variant_if_possible(key, spec) return export.get_equiv_placetype_prop(holonym_placetype, function(pt) local plural_holonym_placetype = export.pluralize_placetype(pt) local saw_matching_div if spec.divs then local divs = spec.divs if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) ~= "table" then div = {type = div} end if plural_holonym_placetype == div.type then saw_matching_div = true break end end end if saw_matching_div then insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(key, spec))) return true end return false end) end if insert_specific_variant_if_possible(matching_key, matching_spec) then inserted_specific_variant_cat = true elseif not matching_spec.no_container_cat then for _, containers in ipairs(matching_container_trail) do local saw_no_container_cat = false for _, container in ipairs(containers) do if insert_specific_variant_if_possible(container.key, container.spec) then inserted_specific_variant_cat = true break end saw_no_container_cat = saw_no_container_cat or container.spec.no_container_cat end if inserted_specific_variant_cat or saw_no_container_cat then break end end end end else -- This happens when in an invocation like {{place|en|capital city|s/Haryana,Punjab}} for -- [[Chandigarh]]. We fall back to older code that doesn't depend on the holonym index existing. -- FIXME: This may not be necessary. In the example just given, when processing Haryana we add to -- [[:Category:en:State capitals of India]], and nothing extra gets added when processing Punjab. -- Possibly we can just skip this case entirely. local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and container_trail[1] and not spec.no_container_cat then for _, container in ipairs(container_trail[1]) do insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(container.key, container.spec))) inserted_specific_variant_cat = true end end end if not inserted_specific_variant_cat then insert(retcats, capital_cat) end else -- We didn't recognize the holonym placetype; just put in 'Capital cities'. insert(retcats, "Capital cities") end return retcats end --[=[ This is invoked specially for all placetypes (see the `*` placetype key at the bottom of `placetype_data`). This is used in two ways: # To add pages to generic holonym categories like [[:Category:en:Places in Merseyside, England]] (and [[:Category:en:Places in England]]) for any pages that have `co/Merseyside` as their holonym. # To categorize demonyms in bare placename categories like [[:Category:en:Merseyside, England]] if the demonym description mentions `co/Merseyside` and doesn't mention a more specific placename that also has a category. (In this case there are none, but we can have demonyms at multiple levels, e.g. in France for individual villages, departments, administrative regions, and for the entire country, and for example we only want to categorize a demonym into [[:Category:France]] if no more specific category applies.) Unlike when invoked from {{tl|place}}, a demonym invocation only adds the most specific holonym category and not the category of any containing polity (hence if we add [[:Category:en:Merseyside, England]] we won't also add [[:Category:England]]). This code also handles cities; e.g. for the first use case above, it would be used to add a page that has `city/Boston` as a holonym to [[:Category:en:Places in Boston]], along with [[:Category:en:Places in Massachusetts, USA]] and [[:Category:en:Places in the United States]]. The city handler tries to deal with the possibility of multiple cities having the same name. For example, the code in [[Module:place/locations]] knows about the city of [[Columbus]], [[Ohio]], which has containing polities `Ohio` (a state) and `the United States` (a country). If either containing polity is mentioned, the handler proceeds to return the key `Columbus` (along with `Ohio, USA` and `the United States`). Otherwise, if any other state or country is mentioned, the handler returns nothing, and otherwise it assumes the mentioned city is the one we're considering and returns `Columbus` etc. This works correctly if the place only mentions Ohio and a holonym for a Columbus in a different country is encountered, because of the function `augment_holonyms_with_container`, which adds the US as a holonym when Ohio is encountered. The single parameter `data` is as in category handlers. The return value is a list of categories (without the preceding language code). ]=] local function generic_place_cat_handler(data) local from_demonym = data.from_demonym local retcats = {} local function insert_retkey(key, spec) if from_demonym then insert(retcats, key) else insert(retcats, ("Places in %s"):format(export.get_prefixed_key(key, spec))) end end local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group then if not spec.no_generic_place_cat then -- This applies to continents and continental regions. insert_retkey(key, spec) end -- Categorize both in key, and in the larger location(s) that the key is part of, e.g. [[Hirakata]] goes in -- both [[Category:Places in Osaka Prefecture, Japan]] and [[Category:Places in Japan]]. But not when -- no_container_cat is set (e.g. for 'United Kingdom'). if not spec.no_container_cat then for _, container_set in ipairs(container_trail) do local stop_adding_containers = false for _, container in ipairs(container_set) do if not container.spec.no_generic_place_cat then insert_retkey(container.key, container.spec) end if container.spec.no_container_cat then stop_adding_containers = true end end if stop_adding_containers then break end end end return retcats end end --[==[ Special category handler run for all placetypes that checks for specified division placetypes of known locations and categorizes appropriately. ]==] function export.political_division_cat_handler(data) if data.from_demonym then return end local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group then local divlists = {} if spec.divs then insert(divlists, spec.divs) end if spec.addl_divs then insert(divlists, spec.addl_divs) end for _, divlist in ipairs(divlists) do if type(divlist) ~= "table" then divlist = {divlist} end for _, div in ipairs(divlist) do if type(div) == "string" then div = {type = div} end local sgdiv = export.maybe_singularize_placetype(div.type) or div.type local prep = div.prep or "of" local cat_as = div.cat_as or div.type if type(cat_as) ~= "table" then cat_as = {cat_as} end if not export.placetype_data[sgdiv] then internal_error("Placetype %s associated with known location key %s and data %s not found in " .. "`placetype_data`", sgdiv, key, spec) end if sgdiv == data.entry_placetype then local retcats = {} for _, pt_cat in ipairs(cat_as) do if type(pt_cat) == "string" then pt_cat = {type = pt_cat} end local pt_prep = pt_cat.prep or prep insert(retcats, ucfirst(pt_cat.type) .. " " .. pt_prep .. " " .. export.get_prefixed_key(key, spec)) end return retcats end end end end end --[==[ This is used to add pages to "bare" categories like [[:Category:en:Georgia, USA]] for `[[Georgia]]` and any foreign-language terms that are translations of the state of Georgia. We look at the page title (or its overridden value in {{para|pagename}}) as well as the glosses in {{para|t}}/{{para|t2}} etc., various extra-info values such as the modern names in {{para|modern}}, and any values specified using a form-of directive. We need to pay attention to the entry placetypes specified so we don't overcategorize; e.g. the US state of Georgia is `[[Джорджия]]` in Russian but the country of Georgia is `[[Грузия]]`, and if we just looked for matching names, we'd get both Russian terms categorized into both [[:Category:ru:Georgia, USA]] and [[:Category:ru:Georgia]]. We also need to check the containing holonyms to make sure there isn't a mismatch (so we don't e.g. categorize Newark, Delaware in [[:Category:en:Newark]], which is intended for Newark, New Jersey). ]==] function export.get_bare_categories(args, overall_place_spec) local bare_cats = {} local place_descs = overall_place_spec.descs local possible_placetypes_by_place_desc = {} for i, place_desc in ipairs(place_descs) do possible_placetypes_by_place_desc[i] = {} for _, placetype in ipairs(place_desc.placetypes) do if not export.placetype_is_ignorable(placetype) then local equivs = export.get_placetype_equivs(placetype, {register_former_as_non_former = true}) for _, equiv in ipairs(equivs) do insert(possible_placetypes_by_place_desc[i], equiv.placetype) end end end end local function check_term(term) -- Treat Wikipedia links like local ones. term = term:gsub("%[%[w:", "[["):gsub("%[%[wikipedia:", "[[") term = export.remove_links_and_html(term) term = term:gsub("^the ", "") for i, place_desc in ipairs(place_descs) do -- Iterate over all matching locations in case there are multiple, as with Delhi defined as -- {{place|en|megacity/and/union territory|c/India|containing the national capital [[New Delhi]]}}. for group, key, spec, container_trail in export.iterate_matching_holonym_location { holonym_placetype = possible_placetypes_by_place_desc[i], holonym_placename = term, place_desc = place_desc, } do insert(bare_cats, key) end end end -- FIXME: Should we only do the following if the language is English (requires that the lang is passed in)? -- We should always do it if `pagename` is given (as it is with {{tcl}}) but maybe not otherwise unless 1=en. There -- are cases like [[Ankara]] = English name for capital of Turkey, but also the name in various languages for the -- capital of Ghana (= English [[Accra]]). But this should get caught by mismatching the containing country. The -- advantage of checking when the language isn't English is we catch those places that fail to give an English -- translation but where the translation happens to be the same as the other-language spelling. However, I don't -- know how often this situation occurs. check_term(args.pagename or mw.loadData("Module:headword/data").pagename) for _, t in ipairs(args.t) do check_term(t) end local function check_termobj_list(terms) for _, term in ipairs(terms) do if term.eq then check_term(term.eq) end if term.alt or term.term then check_term(term.alt or term.term) end end end for _, extra_info_terms in ipairs(overall_place_spec.extra_info) do local arg = extra_info_terms.arg if arg == "modern" or arg == "now" or arg == "full" or arg == "short" then check_termobj_list(extra_info_terms.terms) end end for _, directive in ipairs(overall_place_spec.directives) do check_termobj_list(directive.terms) end return bare_cats end --[==[ This is used to augment the holonyms associated with a place description with the containing polities. For example, given the following: `# {{tl|place|en|subprefecture|pref/Hokkaido}}.` We auto-add Japan as another holonym so that the term gets categorized into [[:Category:Subprefectures of Japan]]. To avoid over-categorizing we need to check to make sure no other countries are specified as holonyms. ]==] function export.augment_holonyms_with_container(place_descs) for _, place_desc in ipairs(place_descs) do if place_desc.holonyms then -- This ends up containing a copy of the original holonyms, with the augmented holonyms inserted in their -- appropriate position. We don't just put them at the end because some holonyms have use the `:also` -- modifier, which causes category processing to restart at that point after generating categories for a -- preceding holonym, and we don't want the preceding holonym's augmented holonyms interfering with -- categorization of a later holonym. We proceed from right to left, and each time we augment, we copy -- the holonyms with the augmented holonym(s) inserted appropriately and replace the place description's -- holonyms with the augmented ones before the next iteration. The reason for this is so that e.g. -- {{place|neighborhood|city/Birmingham|co/West Midlands|cc/England}} doesn't throw an error during the -- augmentation process due to 'Birmingham' referring to two known locations (in England and Alabama). If -- we go left to right, we will throw an ambiguity error on `city/Birmingham` because code to exclude -- Birmingham, Alabama needs `c/United Kingdom` present (to cause a mismatch with `c/United States`), -- which isn't yet present as the augmentation code hasn't gotten to `cc/England` yet. For similar -- reasons, we need to include the augmented holonyms in the holonyms considered in the next iteration -- rather than modifying the place description once at athe end. for i = #place_desc.holonyms, 1, -1 do local holonym = place_desc.holonyms[i] if holonym.placetype and not export.placetype_is_ignorable(holonym.placetype) then local group, key, spec, container_trail = export.find_matching_holonym_location { holonym_placetype = holonym.placetype, holonym_placename = holonym.unlinked_placename, holonym_index = i, place_desc = place_desc, } if group and container_trail[1] and not spec.no_auto_augment_container then local augmented_holonyms = {} for j = 1, i do insert(augmented_holonyms, place_desc.holonyms[j]) end for _, containers in ipairs(container_trail) do local any_no_auto_augment_container = false for _, container in ipairs(containers) do any_no_auto_augment_container = any_no_auto_augment_container or container.spec.no_auto_augment_container local containing_type = container.spec.placetype if type(containing_type) == "table" then -- If the containing type is a list, use the first element as the canonical variant. containing_type = containing_type[1] end local full_container_placename, elliptical_container_placename = m_locations.key_to_placename(container.group, container.key) -- Don't side-effect holonyms while processing them. local new_holonym = { -- By the time we run, the display has already been generated so we don't need to -- set display_placename. placetype = containing_type, -- placename_to_key() for the group should correctly handle both full and elliptical -- placenames, but the full placename seems less likely to be ambiguous. FIXME: We -- should just store the key directly and use it when available to avoid having to -- convert key to placename and back to key. unlinked_placename = full_container_placename, -- Indicate that this is an augmented holonym, and was derived from the specified -- holonym. In iterate_matching_holonym_location(), we ignore augmented holonyms -- derived from holonyms that are different from the holonym we're searching for but -- of the same placetype. This is to correctly handle a situation like -- {{place|river|dept/Ardèche,Gard,Vaucluse,Bouches-du-Rhône|c/France}}. Here, -- `Ardèche` is in `r/Auvergne-Rhône-Alpes`, while `Gard` is in `r/Occitania` and -- the other two are in `r/Provence-Alpes-Côte d'Azur`. Augmenting proceeds from -- right to left, so after it adds `r/Provence-Alpes-Côte d'Azur` to -- `Bouches-du-Rhône`, Vaucluse gets augmented correctly but `Gard` fails to match -- in find_matching_holonym_location() because of the mismatch between augmented -- `r/Provence-Alpes-Côte d'Azur` and actual `r/Occitania`. Similarly, all later -- calls to find_matching_holonym_location() fail to match `Gard` (and likewise -- `Ardèche`) against any known location. To deal with this, we mark augmented -- holoynms as being augmented due to a source holonym, and when processing a given -- holonym, ignore augmented holonyms from other holonyms of the same placetype. -- The restriction to the same placetype is so that `Birmingham` still gets -- correctly disambiguated to Birmingham, England in the example given above near -- the top of this function, using the augmented holonym `c/United Kingdom` added by -- the specified `cc/England` (whose placetype `constituent country` differs from -- the placetype `city` of Birmingham). augmented_from_holonym = holonym, } insert(augmented_holonyms, new_holonym) -- But it is safe to modify other parts of the place_desc. export.key_holonym_into_place_desc(place_desc, new_holonym) end if any_no_auto_augment_container then break end end for j = i + 1, #place_desc.holonyms do insert(augmented_holonyms, place_desc.holonyms[j]) end place_desc.holonyms = augmented_holonyms end end end end end end -- Cat handler for district, areas, neighborhoods and suburbs. Districts are tricky because they can either be political -- divisions or city neighborhoods. Areas similarly can be political divisions (rarely; specifically, in Kuwait), city -- neighborhoods or larger geographical areas/regions. We handle this as follows: -- (1) `placetype_data` cat entries for specific countries or country divisions take precedence over cat_handlers, so if -- the user says {{tl|place|district|s/Maharashtra|c/India}}, we won't even be called because there is an entry that -- categorizes into [[:Category|Districts of Maharashtra, India]]. -- (2) If we're called, we check the holonym we're called on to see if it is a recognized city, e.g. if we're called -- using {{tl|place|district|city/Mumbai|s/Maharashtra|c/India}}. If so, we categorize under e.g. -- [[:Category:Neighbourhoods of Mumbai]]. (Choosing the spelling "neighbourhoods" because we're in India.) -- (3) If we're called and the holonym is not a recognized city, we check if the placetype has has_neighborhoods set. -- If so, it's "city-like" and we categorize under the first containing polity that we recognize. For example, if -- we're called using {{tl|place|district|town/Northampton|co/Hampshire|s/Massachusetts|c/US}}, we should recognize -- town as "city-like" and categorize under [[:Category:Neighborhoods in Massachusetts]]. (Note "in" not "of", and -- note the spelling "neighborhoods" because we're in the US.) -- (4) If the holonym is not city-like, we do nothing. If there's a city or city-like placetype farther up (e.g. we're -- called as {{tl|place|district|ward/Foo|mun/Bar|...}}), we will handle the city-like entity according to (2) or -- (3) when called on that holonym. Otherwise either the categorization in (1) takes place or there's no -- categorization. local function district_neighborhood_cat_handler(data) local function get_plural_entry_placetype(location_spec, container_trail) if data.entry_placetype == "suburb" then return "Suburbs" else -- Check for `british_spelling` setting on the spec itself or any container. local uses_british_spelling = location_spec.british_spelling if uses_british_spelling == nil and container_trail then for _, container_set in ipairs(container_trail) do local must_outer_break = false for _, container in ipairs(container_set) do if container.spec.british_spelling ~= nil then uses_british_spelling = container.spec.british_spelling must_outer_break = true break end end if must_outer_break then break end end end return uses_british_spelling and "Neighbourhoods" or "Neighborhoods" end end -- First check the immediate holonym to see if it's a city or a city-like top-level entity (Hong Kong, Bonaire, -- etc.) local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and not spec.is_former_place and spec.is_city then return {get_plural_entry_placetype(spec, container_trail) .. " of " .. export.get_prefixed_key(key, spec)} end -- If the entry placetype is neighbo(u)rhood, assume it is a neighborhood even if there isn't a city-like -- entity father up the chain. (E.g. due to a mistaken use of m/ instead of mun/ for municipality.) local has_neighborhoods local entry_placetype = data.entry_placetype if entry_placetype == "neighborhood" or entry_placetype == "neighbourhood" or entry_placetype == "suburb" then has_neighborhoods = true else -- Otherwise, make sure the current holonym is city-like. has_neighborhoods = export.get_equiv_placetype_prop(data.holonym_placetype, function(pt) return export.get_placetype_prop(pt, "has_neighborhoods") end, {continue_on_nil_only = true}) end if has_neighborhoods then -- Loop up the holonyms, looking for city and city-like entities in case of e.g. [[Sepulveda]] written -- {{place|en|neighborhood|valley/San Fernando Valley|city/Los Angeles|s/California|c/USA}} -- but also look for a recognizable poldiv, and if so categorize as "Neighborhoods in POLDIV". We need -- to start with the current holonym, which is especially important for neighborhoods and suburbs that -- may have the first holonym be a recognizable province, etc. but can't hurt otherwise. (Previously -- we skipped the first/current holonym.) for other_holonym_index, other_holonym in export.get_holonyms_to_check(data.place_desc, data.holonym_index) do local other_holonym_data = { holonym_placetype = other_holonym.placetype, holonym_placename = other_holonym.unlinked_placename, holonym_index = other_holonym_index, place_desc = data.place_desc, } local group, key, spec, container_trail = export.find_matching_holonym_location(other_holonym_data) if group and not spec.is_former_place then return {get_plural_entry_placetype(spec, container_trail) .. (spec.is_city and " of " or " in ") .. export.get_prefixed_key(key, spec)} end end end end function export.check_already_seen_string(holonym_placename, already_seen_strings) local canon_placename = ulower(m_links.remove_links(holonym_placename)) if type(already_seen_strings) ~= "table" then already_seen_strings = {already_seen_strings} end for _, already_seen_string in ipairs(already_seen_strings) do if canon_placename:find(already_seen_string) then return true end end return false end -- Prefix display handler that adds a prefix such as "Metropolitan Borough of " to the display -- form of holonyms. We make sure the holonym doesn't contain the prefix or some variant already. -- We do this by checking if any of the strings in ALREADY_SEEN_STRINGS, either a single string or -- a list of strings, or the prefix if ALREADY_SEEN_STRINGS is omitted, are found in the holonym -- placename, ignoring case and links. If the prefix isn't already present, we create a link that -- uses the raw form as the link destination but the prefixed form as the display form, unless the -- holonym already has a link in it, in which case we just add the prefix. local function prefix_display_handler(prefix, holonym_placename, already_seen_strings) if export.check_already_seen_string(holonym_placename, already_seen_strings or ulower(prefix)) then return holonym_placename end if holonym_placename:find("%[%[") then return prefix .. " " .. holonym_placename end return prefix .. " [[" .. holonym_placename .. "]]" end -- Suffix display handler that adds a suffix such as " parish" to the display form of holonyms. -- Works identically to prefix_display_handler but for suffixes instead of prefixes. local function suffix_display_handler(suffix, holonym_placename, already_seen_strings, include_suffix_in_link) if export.check_already_seen_string(holonym_placename, already_seen_strings or ulower(suffix)) then return holonym_placename end if holonym_placename:find("%[%[") then return holonym_placename .. " " .. suffix end if include_suffix_in_link then return "[[" .. holonym_placename .. " " .. suffix .. "]]" else return "[[" .. holonym_placename .. "]] " .. suffix end end -- Display handler for boroughs. New York City boroughs are display as-is. Others are suffixed -- with "borough". local function borough_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.new_york_boroughs[unlinked_placename] then -- Hack: don't display "borough" after the names of NYC boroughs return holonym_placename end return suffix_display_handler("borough", holonym_placename) end local function county_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) -- Display handler for Irish counties. Irish counties are displayed as e.g. "County [[Cork]]". if m_locations.ireland_counties["County " .. unlinked_placename .. ", Ireland"] or m_locations.northern_ireland_counties["County " .. unlinked_placename .. ", Northern Ireland"] then return prefix_display_handler("County", holonym_placename) end -- Display handler for Taiwanese counties. Taiwanese counties are displayed as e.g. "[[Chiayi]] County". if m_locations.taiwan_counties[unlinked_placename .. " County, Taiwan"] then return suffix_display_handler("County", holonym_placename) end -- Display handler for Romanian counties. Romanian counties are displayed as e.g. "[[Cluj]] County". if m_locations.romania_counties[unlinked_placename .. " County, Romania"] then return suffix_display_handler("County", holonym_placename) end -- FIXME, we need the same for US counties but need to key off the country, not the specific county. -- Others are displayed as-is. return holonym_placename end -- Display handler for prefectures. Japanese prefectures are displayed as e.g. "[[Fukushima]] Prefecture". -- Others are displayed as e.g. "[[Fthiotida]] prefecture". local function prefecture_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) local suffix = m_locations.japan_prefectures[unlinked_placename .. " Prefecture, Japan"] and "Prefecture" or "prefecture" return suffix_display_handler(suffix, holonym_placename) end -- Display handler for provinces of Bulgaria, Iran, Laos, North and South Korea, Thailand, Turkey and Vietnam. Recognized -- provinces are displayed as e.g. "[[Gyeonggi]] Province" or "[[Antalya]] Province". Others are displayed as-is. local function province_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.bulgaria_provinces[unlinked_placename .. "Province, Bulgaria"] or m_locations.iran_provinces[unlinked_placename .. " Province, Iran"] or m_locations.laos_provinces[unlinked_placename .. " Province, Laos"] or m_locations.north_korea_provinces[unlinked_placename .. " Province, North Korea"] or m_locations.south_korea_provinces[unlinked_placename .. " Province, South Korea"] or m_locations.thailand_provinces[unlinked_placename .. " Province, Thailand"] or m_locations.turkey_provinces[unlinked_placename .. " Province, Turkey"] or m_locations.vietnam_provinces[unlinked_placename .. " Province, Vietnam"] then return suffix_display_handler("Province", holonym_placename) end return holonym_placename end -- Display handler for Nigerian states. Nigerian states are display as "[[Kano]] State". Others are displayed as-is. local function state_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.nigeria_states[unlinked_placename .. " State, Nigeria"] then return suffix_display_handler("State", holonym_placename) end return holonym_placename end -- Display handler for voivodeships. Display as e.g. [[Subcarpathian Voivodeship]]. local function voivodesip_display_handler(holonym_placetype, holonym_placename) return suffix_display_handler("Voivodeship", holonym_placename, nil, "include_suffix_in_link") end ------------------------------------------------------------------------------------------ -- Placetype data -- ------------------------------------------------------------------------------------------ --[==[ var: Main placetype data structure. This specifies, for each canonicalized placetype, various properties. The keys are placetypes (in the singular, except for category-only placetypes, which are plural and followed by `!`), and the value is a table of properties. The `"*"` key is special and is used for adding "generic" categories of the form `Places in ``location`` `; it runs for all entry placetypes. Keys in the form of plural placetypes followed by `!` are used only in [[Module:category tree/topic cat/data/Places]] for specifying the properties of categories containing the specified placetype, esp. bare categories like [[:Category:States and territories]] (rather than qualified categories like [[:Category:States and territories of Australia]]). Keys under the value table for a given placetype of are two types: ''property keys'' (which specify the value of specific properties) and ''categorization keys'' (which tell how to categorize certain sorts of holonyms if the placetype in question occurs as an entry placetype). Categorization keys are either the special value `default` or are wildcard strings with a slash in them, such as `"country/*"`. Note that only wildcard strings are currently allowed directly in the placetype data; everything else is handled through category handlers, either per-placetype or special (such as `political_division_cat_handler`). The algorithm for how category keys and handlers are used to generate categories is described at the top of [[Module:place]]. There are several recognized property keys, of various types: 1. The following link-related property keys are recognized: * `link`: '''Required''' except in category-only placetypes ending in `!`. Describes how to link and display the placetype in the formatted description when occurring as an entry placetype. Also used for formatting pluralized placetypes (which may occur in entry placetypes, esp. new-format ones, such as `two <<islands>>`) and may occur in categories). The possible values are: *# `true`: Link to the same-named Wiktionary entry. This creates a raw link, e.g. `<nowiki>[[city]]</nowiki>`, which is converted to an English-specific link by JavaScript postprocessing. If the placetype is plural, this creates a two-part raw link e.g. `<nowiki>[[city|cities]]</nowiki>`. *# `"w"`: Link to the same-named Wikipedia entry. This creates a two-part link, e.g. `<nowiki>[[w:census town|census town]]</nowiki>`, or `<nowiki>[[w:census town|census towns]]</nowiki>` if the placetype is given plural. *# `"+..."`: Create a two-part link to the entry following the `+` sign. For example, if `cercle` specifies `"+w:cercles of Mali"`, a two-part link `<nowiki>[[w:cercles of Mali|cercle]]</nowiki>` will be generated, or `<nowiki>[[w:cercles of Mali|cercles]]</nowiki>` if plural `cercles` is specified. *# `"separately"`: Link each word separately. For example, if `administrative territory` specifies `"separately"`, it will be linked as `<nowiki>[[administrative]] [[territory]]</nowiki>`, or as `<nowiki>[[administrative]] [[territory|territories]]</nowiki>` if plural `administrative territories` is given. *# another string: Use that string directly. If the placetype is plural, `pluralize()` in [[Module:en-utilities]] is called on the string, which will correctly pluralize most strings, including those with links in them. (If there are multiple links, the display form of the last link is pluralized.) *# `false`: This placetype is not allowed as an entry placetype. An error will be thrown if this placetype is given as an entry placetype. This is specified for internal-use placetypes, especially placetypes used in conjunction with the qualifiers `former`, `ancient`, `historical` and such. * `plural_link`: If specified and the placetype is plural, use the value in place of generating a pluralized version of the link spec in `link`. Most commonly, this is either a string with links in it (which is used directly) or the value `false`, indicating that the placetype cannot occur plural. (This is used for example by `caplc`, which displays as `<nowiki>[[capital]] and [[large]]st [[city]]</nowiki>`, where a plural version doesn't make sense.) Generally if this is specified, `plural` also needs to be specified to give a special placetype plural; this situation occurs especially with multiword placetypes where something other than the last word is pluralized. An example is `town with bystatus`, whose plural is `towns with bystatus`, which needs to be explicitly given. This example uses `link = <nowiki>"[[town]] with [[bystatus#Norwegian Bokmål|bystatus]]"</nowiki>` ({{m|nb|bystatus}}) is a Norwegian Bokmål word, and template calls aren't currently permitted in link strings), along with `plural_link = <nowiki>"[[town]]s with [[bystatus#Norwegian Bokmål|bystatus]]"</nowiki>`. * `category_link`: Spec indicating how to display the placetype when occurring in category descriptions. Defaults to the value of `link`, and in turn is overridden by more specific `category_link_*` keys; see below. Category-only placetypes (which are plural and end in `!`) usually use `category_link` in preference to `link`. The value of `category_link` can be any of the types of specs given above, but most commonly is a plural string with links in it, spelling out the description; in this case it is used directly. When both `category_link` and `link` are given, the value in `category_link` is typically longer and more descriptive. For example, `polity` uses `link = true`, which just generates a link `<nowiki>[[polity]]</nowiki>` or plural `<nowiki>[[polity|polities]]</nowiki>`, but specifies a separate `category_link = <nowiki>"[[independent]] or [[semi-]][[independent]] [[polity|polities]]"</nowiki>`, which clarifies in the category description what a polity is. * `category_link_top_level`: Spec indicating how to display top-level (bare/unqualified) categories, i.e. categories where the placetype is not followed by `in ``location`` ` or `of ``location`` `. If given, this overrides `category_link` for this type of category. * `category_link_before_noncity`: Spec indicating how to display qualified categories of the form ` ``placetypes`` in/of ``location`` ` where ``location`` does not refer to a city. If given, this overrides `category_link` for this type of category. * `category_link_before_city`: Spec indicating how to display qualified categories of the form ` ``placetypes`` in/of ``location`` ` where ``location`` refer to a city. If given, this overrides `category_link` for this type of category. An example where this is given is `neighborhood`, which uses the following specs:<ol> <li>`link = true`</li> <li>`category_link = <nowiki>"[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]]"</nowiki>`</li> <li>`category_link_before_city = <nowiki>"[[neighborhood]]s, [[district]]s and other subportions"</nowiki>`</li> </ol> This has the effect of making the entry placetype `neighborhood` display as just `<nowiki>[[neighborhood]]</nowiki>`, while e.g. a category like `Neighborhoods of Chicago` displays as `<nowiki>[[neighborhood]]s, [[district]]s and other subportions of [[Chicago]], ...</nowiki>` and a category like `Neighborhoods in Illinois, USA` displays as `<nowiki>[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]] in [[Illinois]], ...</nowiki>`. * `disallow_in_entries`: If specified, this placetype cannot occur as an entry placetype, and the specified value (a message indicating what to use instead) is displayed in the error message. * `disallow_in_holonyms`: If specified, this placetype cannot occur as a holonym placetype, and the specified value (a message indicating what to use instead) is displayed in the error message. 2. There is currently one fallback-related property key recognized: * `fallback`: If specified, its value is a placetype which will be used for categorization purposes if no categories get added using the placetype itself. As an example, `branch` sets a fallback of `river` but also sets `preposition = "of"`, meaning that {{tl|place|en|branch|riv/Mississippi}} displays as `a branch of the Mississippi` (whereas `river` itself uses the preposition `in`), but otherwise categorizes the same as `river`. A more complex example is `area`, which sets a fallback of `geographic and cultural area` and also sets a category handler that checks for cities or city-like entities (e.g. boroughs) occurring as holonyms and categorizes the toponym under [[:Category:Neighborhoods of CITY]] (for recognized cities) or otherwise [[:Category:Neighborhoods of POLDIV]] (for the nearest containing recognized location). In addition, `area` is set as a political division of Kuwait, meaning if `c/Kuwait` occurs as holonym, the toponym is categorized under [[:Category:Areas of Kuwait]]. If none of these categories trigger, the fallback of `geographic and cultural area` will take effect, and the toponym will be categorized as e.g. [[:Category:Geographic and cultural areas of England]]. 3. There is currently one property to control irregular plurals of placetypes: * `plural`: If specified, its value is the plural of the placetype. Otherwise, the default pluralization algorithm in [[Module:en-utilities]] applies (which correctly pluralizes most words, including those ending in `-y`, `-ch`, `-sh`, `-x`, etc.). The value of `plural` is also used when converting a pluralized placetype into its singular equivalent; for example, since the placetype `kibbutz` has `plural = "kibbutzim"`, the placetype `kibbutzim` will be recognized as a plural and singularized to `kibbutz`. For this reason, it's occasionally necessary to specify a `plural` value even when the default pluralization algorithm works correctly, if the default singularization algorithm won't correctly reverse the pluralization (as with `pass` and other terms ending in `-ss`). 4. The following property keys relate to generating categories for entry placetypes and specifying the parents of those categories: * `class`: The general class of placetype. This is used for various purposes: (a) to categorize placetypes preceded by a qualifier such as `former`, `ancient`, `medieval` or `historical` (note that these placetypes are not all treated alike); (b) to determine the parent category of bare placetype categories (e.g. [[:Category:Villages]] for placetype `village`); (c) to determine whether to add a parent category `political divisions of specific countries` to qualified placetype categories (e.g. [[:Category:Villages in Mali]]). The possible values are: *# `polity`: a more-or-less sovereign/independent polity, such as a country, kingdom or empire. *# `subpolity`: a non-sovereign division of a polity, above the level of an individual settlement. *# `settlement`: a city or smaller equivalent, such as a village. This also includes administrative divisions of a settlement, such as wards and barangays. *# `non-admin settlement`: similar to a settlement but without administrative or political significance, such as an unincorporated community, farm or neighborhood. *# `capital`: a settlement that is a capital. A former capital is generally still in existence, just not the capital any more. *# `natural feature`: any non-man-made feature, such as a lake, mountain, island, ocean, etc. *# `man-made structure`: a man-made feature below the level of a neighborhood, such as a house, airport, university, metro station, park or the like. *# `geographic region`: a geographic or cultural region or area that has no administrative significance. These may vary greatly in size but typically have some sort of cultural significance (possibly historical). The `former`, `ancient`, etc. qualifier has no effect on the category of these placetypes. *# `generic place`: a place that isn't further qualified into any specific subtype. * `former_type`: The class of placetype used for categorizing placetypes preceded by a qualifier such as `former`, `ancient`, `medieval` or `historical`. The possible values are the same as for `class` but with the addition of `dependent territory` (for colonies, protectorates and the like) and `!` (ignore the historical/former/ancient/etc. qualifier; used e.g. with `fictional location` and `mythological location`). If not specified, the value of `class` is used. When a qualifier such as `former`, `ancient`, `medieval` or `historical` is encountered (specifically, those in `former_qualifiers`), it is mapped using `former_qualifiers` to the appropriate internal qualifier or qualifiers (one or both of `ANCIENT` and/or `FORMER`, which are written in all-caps to distinguish them from user-specified qualifiers), which is prepended to the value of `former_type` or `class` to form a placetype whose properties are looked up to determine how to categorize the toponym in question. For example, if `medieval village` is given, we map `medieval` to `ANCIENT` and `FORMER`, and `village` to its `class` of `settlement`, and enter the placetypes `ANCIENT settlement` and `FORMER settlement` (in that order) into the list of equivalent placetypes returned by `get_placetype_equivs`. In this case, there is an entry in `placetype_data` for `ANCIENT settlement`, so its default category spec `Ancient settlements` is used as the category. If on the other hand `medieval kingdom` is given, where `kingdom` has a `class` value `polity`, we first look up `ANCIENT polity`, see there is no entry in `placetype_data` for it, and then look up `FORMER polity`, which exists and has a default category spec `Former polities`, which is used as the category. Note that if the placetype following the "former" qualifier is recognized in `placetype_data` but has no `former_type` or `class` and no fallback with a `former_type` or `class` specified, it is an internal error; but if the placetype isn't recognized (e.g. something like `former greenhouse` is specified and we don't have an entry for `greenhouse`), we just track the occurrence and end up not categorizing. * `bare_category_parent`: This specifies the first parent category of a bare placetype category named according to the placetype in question (e.g. [[:Category:Atolls]] for placetype `atoll`, or [[:Category:Named buildings]] for placetype `named buildings!`). If not specified, the first parent category is determined by the value of `class`, using the mapping `class_to_bare_category_parent` in [[Module:category tree/topic cat/data/Places]]. * `addl_bare_category_parents`: Extra parent categories to add a bare placetype category to (see `bare_category_parent` just above). * `bare_category_breadcrumb`: Breadcrumb for bare placetype categories. Also used as the sort key of `bare_category_parent` if it is a string. * `inherently_former`: If specified and the given placetype is used as an entry placetype, act as if `former` or `ancient` (depending on the value of `inherently_former`) were prefixed to the placetype. This is for placetypes that always refer to no-longer-existing entities, such as `satrapy` and `treaty port`. The value of `inherently_former` is a list of internal qualifiers (one or more of `ANCIENT` and/or `FORMER`), just as for `former_qualifiers`, and the implementation is the same. * `cat_handler`: Handler used to generate the categories to add a given toponym to, if its entry placetype is the placetype in question. Generally the `cat_handler` function checks the holonyms specified in order to determine which category or categories to generate. For example, `district_neighborhood_cat_handler` handles placetypes `district`, `neighborhood`, `subdivision`, `suburb` and the like, and either adds the toponym to a category like `Neighborhoods of ``city`` ` (if a recognized city is given as a holonym), or otherwise a category like `Neighborhoods in ``location`` ` (for the first recognized non-city location given as a holonym, if an unrecognized city or city-like entity is given before the recognized non-city). The algorithm that runs the category handlers iterates over holonyms from left to right, running the `cat_handler` function on each holonym in turn until one or more categories are returned; see below for more specifics. (Note that countries for which e.g. a `district` is a political division do not get the corresponding category added by the `district_neighborhood_cat_handler` function but by `political_division_cat_handler`.) `cat_handler` functions are called with one argument, `data`, describing the resolved entry placetype (i.e. after resolving placetype aliases and fallbacks) and the holonym being processed. The return value should be a list of category specs (categories minus the langcode prefix, with `+++` standing for the holonym key, or the value `true`, which stands for ` ``Placetypes`` in/of ``Holonym`` `, i.e. the pluralized placetype with the appropriate preposition as specified in `placetype_data`). `data` contains the following fields: ** `entry_placetype`: the resolved entry placetype for the entry placetype being processed (i.e. it will always have an entry in `placetype_data` but may not be the original placetype given by the user); ** `holonym_placetype` and `holonym_placename`: the holonym placetype and placename being processed; ** `holonym_index`: the index of the holonym being processed, or {nil} if we're handling an overriding holonym (FIXME: we will change the overriding holonym algorithm so there will be an index even when processing overriding holonyms); ** `place_desc`: a full description of the {{tl|place}} call, as specified at the top of [[Module:place]]; ** `from_demonym`: If set, we are called from [[Module:demonym]], triggered by {{tl|demonym-adj}} or {{tl|demonym-noun}}, instead of being triggered by {{tl|place}}. * `has_neighborhoods`: If `true`, the specified placetype is city-like. This is used in the `district_neighborhood_cat_handler` to determine whether to add a category such as `Neighborhoods in ``location`` `; see the section just above on `cat_handler`. 5. The following preposition-related property keys are recognized: * `preposition`: The preposition used after this placetype when it occurs as an entry placetype. Defaults to `"in"`. * `generic_before_non_cities`: If specified, the appropriate category description handler in [[Module:category tree/topic cat/data/Places]] will recognize categories of the form ` ``Placetype`` in/of ``location`` ` for the specified placetype and preposition, if ``location`` is a non-city. This is used to generate descriptions for categories added by category handlers and by explicit category specs in the placetype data. All placetypes that specify `generic_before_non_cities` or `generic_before_cities` *MUST* also specify a value for `class` so that the category tree code can determine whether it's a political or non-political division. * `generic_before_cities`: Like `generic_before_non_cities` but for locations referring to cities. 6. The following property keys control the auto-addition of affixes when formatting holonyms of a particular placetype: * `affix_type`: If specified, add the placetype as an affix before or after holonyms of this placetype. Possible values are: *# `"pref"` (the holonym will display as `(the) placetype of Holonym`, where `the` appears when the holonym directly follows an entry placetype); *# `"Pref"` (same as `"pref"` but the placetype is capitalized; each word is capitalized if there are multiple); *# `"suf"` (the holonym will display as `Holonym placetype`); *# `"Suf"` (the holonym will display as `Holonym Placetype`, i.e. same as `"suf"` but the placetype is capitalized). * `suffix`: String to use in place of the placetype itself when the placetype is displayed as a suffix after a holonym. Note that `suffix` can be used independently of `affix_type` because the user can also request a suffix explicitly using a syntax like `adr:suf/Occitania`, which will display as `Occitania region` because the placetype `administrative region` specifies `suffix = "region"`. * `prefix`: Like `suffix` but for use when the placetype is displayed as a prefix before the holonym. * `affix`: Like `suffix` and `prefix` but for use when the placetype is displayed as an affix either before or after the holonym. If both `suffix` or `prefix` and `affix` are given for a single placetype, `suffix` or `prefix` take precedence. * `no_affix_strings`: String or list of strings that, if they occur in the holonym, suppress the addition of any affix requested using `affix_type`. Defaults to the placetype itself. For example, `autonomous okrug` specifies `affix_type = "Suf"` so that `aokr/Nenets` displays as `Nenets Autonomous Okrug`, but also specifies `no_affix_strings = "okrug"` so that `aokr/Nenets Okrug` or `aokr/Nenets Autonomous Okrug` displays as specified, without a redundant `Autonomous Okrug` added. Matching is case-insensitive but whole-word. * `display_handler`: A function of two arguments, `holonym_placetype` and `holonym_placename` (specifying a holonym). Its return value is a string specifying the display form of the holonym. 7. The following property keys control the indefinite and definite articles used before entry placetypes and/or holonyms of the specified placetype. * `entry_placetype_use_the`: Use `"the"` before this placetype when it occurs as an entry placetype. * `entry_placetype_indefinite_article`: Indefinite article used before this placetype when it occurs as an entry placetype (usually `"a"`, specifically for placetypes beginning with u- that don't take the indefinite article `"an"`). Defaults to the appropriate indefinite article (`"a"` or `"an"` depending on whether the placetype begins with a vowel). Overridden by `entry_placetype_use_the`, and unlike for most properties, does not apply to equivalent placetypes (i.e. fallbacks or those formed by removing a qualifier from the beginning); only to the exact placetype specified. * `holonym_use_the`: Use `"the"` before holonyms of this placetype. '''NOTE:''' # The `link` property must be specified on all placetypes, except those ending in `!` (category-only placetypes), which must have either `link` or `category_link` specified. # Either the `class` or `former_type` property must be specified on all placetypes not ending in `!` that do not have a fallback (if a placetype has a fallback and omits the `class` and `former_type` properties, they are taken from the fallback). An internal error will result if a placetype has no `class` or `former_type` property derivable either directly or through a fallback, if an attempt is made to categorize a former/ancient/historical/etc. entity of this placetype. # It is possible to have multiple levels of fallback (e.g. `frazione` falls back to `hamlet`, which falls back to `village`). Fallback loops will cause an internal error. All placetypes specified as fallbacks must exist in `placetype_data` or an internal error occurs. ]==] export.placetype_data = { --[=[ If you need to sort the following, do this (using Vim): 1. Make sure all full-line comments are within the { ... } table, or are moved after and on the same line as single-line entries. 2. Make sure the table uses tabs everywhere for indent, and not spaces. 3. Mark the top of the table with `ma`, go to the bottom and execute the following two lines in sequence: :'a,.s/\n/\\n/g :s/\\n\(\t\[\)/\r\1/g The first command converts every newline to a literal `\n` sequence, so the whole thing becomes a single line, while the second command restores the newlines before the beginning of each entry. The effect is to convert all entries to a single line while not losing any information. (Potentially a negative lookahead could be used to do it all in one command.) 4. Execute the following to sort: :'a,.!perl -pe 's/^(\t\[")(.*?)(".*)$/$2 @@@ $1$2$3/' | sort -f | perl -pe 's/.*? @@@ //' Note that a simple `sort -f` (where `-f` means case-insensitive) would almost work, but it would sort "hill station" before "hill" and "county borough" before "county" because the space after e.g. "hill station" sorts before the quotation mark after e.g. "hill". The above command deals with this by extracting the key, prepending it followed by ` @@@ `, sorting, and then removing key (the classic decorate-sort-undecorate pattern). 5. Put the table back to multi-line format by marking the top of the table with `ma`, going to the bottom and executing :'a,.s/\\n/\r/g Note that for some reason, in order to get a match a newline in the left side of a replacement, you must use \n, but to insert a newline in the right sode of a replacement you must use \r. ]=] ["*"] = { link = false, cat_handler = generic_place_cat_handler, }, ["administrative atoll"] = { -- Maldives link = "+w:administrative divisions of the Maldives", preposition = "of", class = "subpolity", }, ["administrative capital"] = { link = "w", fallback = "capital city", }, ["administrative center"] = { link = "w", fallback = "non-city capital", }, ["administrative centre"] = { link = "w", fallback = "administrative center", }, ["administrative county"] = { link = "w", fallback = "county", }, ["administrative district"] = { link = "w", fallback = "district", }, ["administrative headquarters"] = { link = "separately", fallback = "administrative centre", }, ["administrative region"] = { link = true, preposition = "of", suffix = "region", -- but prefix is still "administrative region (of)" fallback = "region", class = "subpolity", }, ["administrative seat"] = { link = "w", fallback = "administrative centre", }, ["administrative territory"] = { link = "separately", preposition = "of", suffix = "territory", -- but prefix is still "administrative territory (of)" fallback = "territory", class = "subpolity", }, ["administrative unit"] = { -- Grrr, it's difficult to generalize about "administrative units". In Albania, "administrative unit" is an -- official term for a city-level division of municipalities; Wikipedia renders it using the more practical term -- "commune". In Pakistan, "administrative unit" is a collective term used to refer to all the different types -- of first-level divisions (four provinces, one federal territory, and two "disputed territories", i.e. Azad -- Kashmir and Gilgit-Balistan, that are variously described). For this reason, we set no fallback, but we need -- to include this so that it can be used as a placetype for Albania, categorizing as communes. link = "w", class = "subpolity", }, ["administrative village"] = { link = "w", preposition = "of", has_neighborhoods = true, class = "settlement", }, ["aimag"] = { -- used in Mongolia, Russia and China (Inner Mongolia); in Mongolia, equivalent to a province; -- in China, equivalent to a prefecture (below a province); in Russia, equivalent to a municipal district. link = "w", fallback = "prefecture", }, ["airport"] = { link = true, class = "man-made structure", default = {true}, }, ["alliance"] = { link = true, fallback = "confederation", }, ["archipelago"] = { link = true, fallback = "island", }, ["area"] = { link = true, preposition = "of", fallback = "geographic and cultural area", -- Areas can either be administrative divisions (specifically of Kuwait) or geographic areas. Assume the former -- when categorizing 'Areas' but the latter when handling e.g. 'historical area'. class = "subpolity", former_type = "geographic region", cat_handler = district_neighborhood_cat_handler, }, ["arm"] = { link = true, preposition = "of", class = "natural feature", default = {"Seas"}, }, ["arrondissement"] = { link = true, preposition = "of", -- FIXME!!! Grrrrr!!! In some countries, arrondissements are divisions of cities; in others, they are divisions -- of departments or provinces. Need to conditionalize on the country for both of the following. class = "subpolity", has_neighborhoods = true, }, ["associated province"] = { link = "separately", fallback = "province", }, ["atoll"] = { -- FIXME! Atolls are administrative divisions of the Maldives but natural features elsewhere. Need to -- conditionalize `class` on the country. See also `administrative atoll`. link = true, class = "natural feature", bare_category_parent = "islands", default = {true}, }, ["autonomous city"] = { link = "w", preposition = "of", fallback = "city", has_neighborhoods = true, }, ["autonomous community"] = { -- Spain; refers to regional entities, not village-like entities, as might be expected from "community" link = true, preposition = "of", class = "subpolity", }, ["autonomous island"] = { -- Comoros; seems like an administrative atoll of the Maldives. link = "+w:autonomous islands of Comoros", preposition = "of", class = "subpolity", }, ["autonomous oblast"] = { link = true, preposition = "of", affix_type = "Suf", no_affix_strings = "oblast", class = "subpolity", }, ["autonomous okrug"] = { link = true, preposition = "of", affix_type = "Suf", no_affix_strings = "okrug", class = "subpolity", }, ["autonomous prefecture"] = { link = true, fallback = "prefecture", }, ["autonomous province"] = { link = "w", fallback = "province", }, ["autonomous region"] = { link = "w", preposition = "of", fallback = "administrative region", -- "administrative region" sets an affix of "region" but we want to display as "Tibet Autonomous Region" -- if the user writes 'ar:Suf/Tibet'. affix = "autonomous region", }, ["autonomous republic"] = { link = "w", preposition = "of", class = "subpolity", }, ["autonomous territorial unit"] = { -- Moldova; only two of them, one for Gagauzia and one for Transnistria. link = "w", preposition = "of", class = "subpolity", }, ["autonomous territory"] = { link = "w", fallback = "dependent territory", }, ["bailiwick"] = { -- Jersey, etc. link = true, fallback = "polity", }, ["barangay"] = { -- Philippines link = true, class = "settlement", -- Barangays are formal administrative divisions of a city rather than informal neighborhoods, but can use -- some of the properties of a neighborhood. fallback = "neighborhood", }, ["barrio"] = { -- Spanish-speaking countries; Philippines link = true, -- FIXME: Not completely correct, in some countries barrios are formal administrative divisions of a city. -- `class` will need to conditionalize on the country to be completely correct. fallback = "neighborhood", }, ["basin"] = { link = true, fallback = "lake", }, ["bay"] = { link = true, preposition = "of", class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["beach"] = { link = true, class = "natural feature", addl_bare_category_parents = {"water"}, default = {true}, }, ["beach resort"] = { link = "w", fallback = "resort town", }, ["bishopric"] = { link = true, fallback = "polity", }, ["bodies of water!"] = { -- FIXME: This is (maybe?) a type category not a name category. There should be an option for this. We need to -- straighten out the type vs. name vs. related-to issue. category_link = "[[body of water|bodies of water]]", class = "natural feature", addl_bare_category_parents = {"landforms", "ecosystems", "water"}, }, ["borough"] = { link = true, preposition = "of", display_handler = borough_display_handler, has_neighborhoods = true, -- "former borough" could be a former settlement or a former part of a city but seems more likely to -- be a former subpolity, particularly in England. FIXME, we really need a handler to take care of this -- properly. class = "subpolity", -- Grr, some boroughs are city-like but some (e.g. in Britain) may be larger. }, ["borough seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["branch"] = { link = true, preposition = "of", fallback = "river", }, ["bridge"] = { link = true, class = "man-made structure", default = {"Named bridges"}, }, ["building"] = { link = true, class = "man-made structure", default = {"Named buildings"}, }, ["built-up area"] = { link = "w", fallback = "area", }, ["burgh"] = { link = true, fallback = "borough", }, ["business park"] = { link = true, fallback = "park", }, ["caliphate"] = { link = true, fallback = "polity", }, ["canton"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["cape"] = { link = true, fallback = "headland", }, ["capital"] = { link = true, fallback = "capital city", }, ["capital city"] = { link = true, category_link = "[[capital city|capital cities]]: the [[seat of government|seats of government]] for a country or [[political]] [[division]] of a country", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", bare_category_parent = "cities", cat_handler = capital_city_cat_handler, default = {true}, -- The following is necessary so that e.g. [[Melbourne]] defined as {{place|en|capital city|s/Victoria|c/Australia}} -- gets categorized in the bare category [[Category:en:Melbourne]]; otherwise placetype 'capital city' wouldn't -- match against the placetype 'city' of Melbourne. fallback = "city", }, ["caplc"] = { link = "[[capital]] and [[large]]st [[city]]", plural_link = false, fallback = "capital city", }, ["captaincy"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["caravan city"] = { link = "w", fallback = "city", class = "settlement", inherently_former = {"ANCIENT", "FORMER"}, }, ["castle"] = { link = true, fallback = "building", }, ["cathedral city"] = { link = true, fallback = "city", }, ["cattle station"] = { -- Australia link = true, fallback = "farm", }, ["census area"] = { link = true, affix_type = "Suf", has_neighborhoods = true, class = "non-admin settlement", }, ["census-designated place"] = { -- United States link = true, class = "non-admin settlement", }, ["census division"] = { -- Canada link = "w", preposition = "of", class = "subpolity", }, ["census town"] = { link = "w", fallback = "town", }, ["central business district"] = { link = true, fallback = "neighborhood", }, ["cercle"] = { -- Mali link = "+w:cercles of Mali", preposition = "of", class = "subpolity", }, ["ceremonial county"] = { link = true, fallback = "county", }, ["chain of islands"] = { link = "[[chain]] of [[island]]s", plural = "chains of islands", plural_link = "[[chain]]s of [[island]]s", fallback = "island", }, ["channel"] = { link = true, fallback = "strait", }, ["charter community"] = { -- Northwest Territories, Canada link = "w", fallback = "village", }, ["chiwog"] = { -- Bhutan link = true, preposition = "of", class = "subpolity", }, ["city"] = { link = true, generic_before_non_cities = "in", has_neighborhoods = true, class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["city-state"] = { link = true, category_link = "[[sovereign]] [[microstate]]s consisting of a single [[city]] and [[w:dependent territory|dependent territories]]", has_neighborhoods = true, class = "settlement", ["continent/*"] = {"City-states", "Cities in +++", "Countries in +++", "National capitals"}, default = {"City-states", "Cities", "Countries", "National capitals"}, }, ["civil parish"] = { -- Mostly England; similar to municipalities link = true, preposition = "of", affix_type = "suf", has_neighborhoods = true, class = "subpolity", }, ["claimed political division"] = { link = "[[claim]]ed [[political]] [[division]]", class = "subpolity", default = {true}, }, ["co-capital"] = { link = "[[co-]][[capital]]", fallback = "capital city", }, ["coal city"] = { link = "+w:coal town", fallback = "city", }, ["coal town"] = { link = "w", fallback = "town", }, ["collectivity"] = { link = "w", preposition = "of", -- No default; these are weird one-off governmental divisions in France (esp. for overseas collectivities) class = "subpolity", }, ["colony"] = { link = true, fallback = "dependent territory", }, ["comarca"] = { -- per Wikipedia: traditional region or local administrative division found in Portugal, Spain, and some of -- their former colonies, like Brazil, Nicaragua, and Panama. In the Valencian Community, for example, it -- sits between municipalities and provinces, something like a county or district. link = true, preposition = "of", class = "subpolity", }, ["commandery"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"ANCIENT", "FORMER"}, }, ["commonwealth"] = { link = true, preposition = "of", -- No default; applies specifically to Puerto Rico class = "subpolity", }, ["commune"] = { link = true, fallback = "municipality", }, ["community"] = { link = true, category_link = "[[community|communities]] of all sizes", fallback = "village", }, ["community development block"] = { -- in India; appears to be similar to a rural municipality; groups several villages, unclear if there will be -- neighborhoods so I'm not setting `has_neighborhoods` for now link = "w", affix_type = "suf", no_affix_strings = "block", class = "subpolity", }, ["comune"] = { -- Italy, Switzerland link = true, fallback = "municipality", }, ["condominium"] = { link = true, fallback = "polity", }, ["confederacy"] = { link = true, fallback = "confederation", }, ["confederation"] = { link = true, fallback = "polity", }, ["constituency"] = { -- currently we have them as political divisions of Namibia but many countries have them link = true, preposition = "of", class = "subpolity", }, ["constituent country"] = { link = true, preposition = "of", class = "subpolity", }, ["constituent part"] = { link = "separately", preposition = "of", class = "subpolity", }, ["constituent republic"] = { -- Of Russia, Yugoslavia, etc. link = "separately", preposition = "of", class = "subpolity", }, ["counties and county-level cities!"] = { -- This is used when grouping counties and county-level cities under prefecture-level cities in China. category_link = "[[county|counties]] and [[county-level city|county-level cities]]", class = "subpolity", }, ["continent"] = { link = true, category_link = false, -- can't occur as a bare category class = "natural feature", default = {"Continents and continental regions"}, }, ["continental region"] = { link = "separately", category_link = false, -- can't occur as a bare category class = "geographic region", fallback = "continent", }, ["continents and continental regions!"] = { category_link = "[[continent]]s and [[continent]]-[[level]] [[region]]s (e.g. [[Polynesia]])", class = "geographic region", }, ["council area"] = { link = true, -- in Scotland; similar to a county preposition = "of", affix_type = "suf", class = "subpolity", }, ["country"] = { link = true, class = "polity", ["continent/*"] = {true, "Countries"}, default = {true}, }, ["country-like entities!"] = { category_link = "[[polity|polities]] not normally considered [[country|countries]] but treated similarly for categorization purposes; typically, [[unrecognized]] [[de-facto]] countries or [[w:dependent territory|dependent territories]]", class = "polity", }, ["county"] = { link = true, preposition = "of", display_handler = county_display_handler, class = "subpolity", }, ["county borough"] = { link = true, -- in Wales; similar to a county preposition = "of", affix_type = "suf", fallback = "borough", class = "subpolity", }, ["county seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["county town"] = { link = true, entry_placetype_use_the = true, preposition = "of", fallback = "town", has_neighborhoods = true, class = "capital", }, ["county-administered city"] = { -- In Taiwan, per Wikipedia similar to a Taiwanese township or district, which is a small city. -- NOT anything like a "county-level city" in PR China, which is a county masquerading as a city. link = "w", fallback = "city", has_neighborhoods = true, class = "settlement", }, ["county-controlled city"] = { -- Taiwan link = "w", fallback = "county-administered city", }, ["county-level city"] = { -- PR China link = "w", fallback = "prefecture-level city", }, ["crater lake"] = { link = true, fallback = "lake", }, ["creek"] = { link = true, fallback = "stream", }, ["Crown colony"] = { link = "+crown colony", fallback = "crown colony", }, ["crown colony"] = { link = true, fallback = "colony", }, ["Crown dependency"] = { link = true, fallback = "dependent territory", }, ["crown dependency"] = { link = true, fallback = "dependent territory", }, ["cultural area"] = { link = "w", fallback = "geographic and cultural area", }, ["cultural region"] = { link = "w", fallback = "geographic and cultural area", }, ["delegation"] = { -- Tunisia link = "+w:delegations of Tunisia", preposition = "of", class = "subpolity", }, ["department"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["departmental capital"] = { link = "separately", fallback = "capital city", }, ["dependency"] = { link = true, fallback = "dependent territory", }, ["dependent territory"] = { link = "w", preposition = "of", class = "subpolity", former_type = "dependent territory", bare_category_parent = "political divisions", ["country/*"] = {true}, default = {true}, }, ["desert"] = { link = true, class = "natural feature", addl_bare_category_parents = {"ecosystems"}, default = {true}, }, ["deserted mediaeval village"] = { link = "w", fallback = "deserted medieval village", }, ["deserted medieval village"] = { link = "w", fallback = "ANCIENT settlement", }, ["direct-administered municipality"] = { -- China link = "+w:direct-administered municipalities of China", fallback = "municipality", }, ["direct-controlled municipality"] = { -- several countries link = "w", fallback = "municipality", }, ["distributary"] = { link = true, preposition = "of", fallback = "river", }, ["district"] = { link = true, preposition = "of", affix_type = "suf", -- Grrr! FIXME! Here is where we need handlers for `class`. Using similar logic to -- district_neighborhood_cat_handler, we need to check if we're below or above a city to determine if the class -- is "settlement" or "subpolity". class = "subpolity", cat_handler = district_neighborhood_cat_handler, -- No default. Countries for which districts are political divisions will get entries. }, ["districts and autonomous regions!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Portugal. category_link = "[[district]]s and [[autonomous region]]s", class = "subpolity", }, ["districts and autonomous territorial units!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Moldova. category_link = "[[district]]s and [[w:autonomous territorial unit|autonomous territorial unit]]s", class = "subpolity", }, ["district capital"] = { link = "separately", fallback = "capital city", }, ["district headquarters"] = { link = "separately", fallback = "administrative centre", }, ["district municipality"] = { -- In Canada, a district municipality is equivalent to a rural municipality and won't have neighborhoods; in -- South Africa, district municipalities group local municipalities and hence won't have neighborhoods. link = "w", preposition = "of", affix_type = "suf", no_affix_strings = {"district", "municipality"}, fallback = "municipality", class = "subpolity", }, ["division"] = { link = true, preposition = "of", class = "subpolity", }, ["division capital"] = { link = "separately", fallback = "capital city", }, ["dome"] = { link = true, fallback = "mountain", }, ["dormant volcano"] = { link = true, fallback = "volcano", }, ["duchy"] = { link = true, fallback = "polity", }, ["emirate"] = { link = true, preposition = "of", -- FIXME: Can be subpolities (of the United Arab Emirates). fallback = "polity", }, ["empire"] = { link = true, fallback = "polity", }, ["enclave"] = { link = true, preposition = "of", -- Enclaves can theoretically be any size but assume a subpolity. class = "subpolity", }, ["entity"] = { -- Bosnia and Herzegovina link = "+w:entities of Bosnia and Herzegovina", preposition = "of", class = "subpolity", }, ["escarpment"] = { link = true, fallback = "mountain", }, ["ethnographic region"] = { -- used in Lithuania link = "+w:ethnographic regions of Lithuania", fallback = "geographic and cultural area", }, ["exclave"] = { link = true, preposition = "of", -- exclaves can theoretically be any size but assume a subpolity. class = "subpolity", }, ["external territory"] = { link = "separately", fallback = "dependent territory", }, ["farm"] = { link = true, class = "non-admin settlement", default = {"Farms and ranches"}, }, ["farms and ranches!"] = { category_link = "[[farm]]s and [[ranch]]es", class = "non-admin settlement", }, ["federal city"] = { link = "w", preposition = "of", fallback = "city", }, ["federal district"] = { link = true, preposition = "of", -- Might have neighborhoods as federal districts are often cities (e.g. Mexico City) has_neighborhoods = true, class = "settlement", }, ["federal subject"] = { -- In Russia; a generic term for first-level administrative divisions (republics, oblasts, okrugs, krais, -- autonomous okrugs and autonomous oblasts). link = "w", preposition = "of", class = "subpolity", }, ["federal territory"] = { link = "w", fallback = "territory", }, ["fictional location"] = { link = "separately", former_type = "!", class = "hypothetical location", bare_category_parent = "places", default = {true}, }, ["First Nations reserve"] = { -- Canada link = "[[First Nations]] [[w:Indian reserve|reserve]]", -- Wikipedia uses "Indian reserve"; presumably that is the legal term fallback = "Indian reserve", class = "subpolity", }, ["fjord"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["footpath"] = { link = true, fallback = "road", }, ["forest"] = { link = true, class = "natural feature", addl_bare_category_parents = {"ecosystems", "forestry"}, default = {true}, }, ["fort"] = { link = true, fallback = "building", }, ["fortress"] = { link = true, -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- fortresses -> fortresse, so put an entry here to ensure we singularize correctly. plural = "fortresses", fallback = "building", }, ["frazione"] = { link = "w", fallback = "hamlet", }, ["freeway"] = { link = true, fallback = "road", }, ["French prefecture"] = { link = "[[w:prefectures in France|prefecture]]", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["geographic and cultural area"] = { link = "+w:cultural area", -- `generic_before_non_cities` is used when generating the category description of categories of the format -- `Geographic and cultural areas of PLACE`. `preposition` is used when generating {{place}} description and -- categories for any placetype that falls back to `geographic and cultural area`. generic_before_non_cities = "of", preposition = "of", class = "geographic region", bare_category_parent = "places", ["country/*"] = {true}, ["constituent country/*"] = {true}, ["continent/*"] = {true}, default = {true}, }, ["geographic area"] = { link = "+w:geographic region", fallback = "geographic and cultural area", }, ["geographic region"] = { link = "w", fallback = "geographic and cultural area", }, ["geographical area"] = { link = "w", fallback = "geographic and cultural area", }, ["geographical region"] = { link = "w", fallback = "geographic and cultural area", }, ["geopolitical zone"] = { -- Nigeria link = true, preposition = "of", class = "subpolity", }, ["gewog"] = { -- Bhutan link = true, preposition = "of", class = "subpolity", }, ["ghost town"] = { link = true, generic_before_non_cities = "in", class = "non-admin settlement", bare_category_parent = "former settlements", cat_handler = city_type_cat_handler, default = {true}, }, ["glen"] = { link = true, fallback = "valley", }, ["governorate"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["greater administrative region"] = { -- China (former division) link = "w", preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["gromada"] = { -- Poland (former division) link = "w", preposition = "of", affix_type = "Pref", class = "subpolity", inherently_former = {"FORMER"}, }, ["group of islands"] = { link = "[[group]] of [[island]]s", plural = "groups of islands", plural_link = "[[group]]s of [[island]]s", fallback = "island group", }, ["gulf"] = { link = true, preposition = "of", holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["hamlet"] = { link = true, fallback = "village", }, ["harbor city"] = { link = "separately", fallback = "city", }, ["harbor town"] = { link = "separately", fallback = "town", }, ["harbour city"] = { link = "separately", fallback = "city", }, ["harbour town"] = { link = "separately", fallback = "town", }, ["headland"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["headquarters"] = { link = "w", fallback = "administrative centre", }, ["heath"] = { link = true, fallback = "moor", }, ["hemisphere"] = { link = true, entry_placetype_use_the = true, fallback = "continental region", }, ["highway"] = { link = true, fallback = "road", }, ["hill"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["hill station"] = { link = "w", fallback = "town", }, ["hill town"] = { link = "w", fallback = "town", }, ["historic region"] = { -- provided only for the link link = "+w:historical region", fallback = "FORMER geographic region", }, ["historical county"] = { -- needed for historical counties of England/etc. link = "+w:historic county", fallback = "FORMER subpolity", }, ["historical region"] = { -- provided only for the link link = "w", fallback = "FORMER geographic region", }, ["home rule city"] = { link = "w", fallback = "city", }, ["home rule municipality"] = { link = "w", fallback = "municipality", }, ["hot spring"] = { link = true, fallback = "spring", }, ["house"] = { link = true, fallback = "building", }, ["housing estate"] = { -- not the same as a housing project (i.e. public housing) link = true, -- not exactly the case but approximately fallback = "neighborhood", }, ["hromada"] = { -- Ukraine link = "w", disallow_in_entries = "Use placetype 'urban hromada', 'rural hromada' or 'settlement hromada' in place of bare 'hromada'", disallow_in_holonyms = "Use placetype 'urban hromada'/'uhrom', 'rural hromada'/'rhrom' or 'settlement hromada'/'shrom' in place of bare 'hromada'", preposition = "of", affix_type = "suf", class = "subpolity", }, ["inactive volcano"] = { link = "w", fallback = "dormant volcano", }, ["independent city"] = { link = true, fallback = "city", }, ["independent town"] = { link = "+independent city", fallback = "town", }, ["Indian reservation"] = { link = "w", -- In the US. Also known as "Native American reservation" or "domestic dependent nation", and the reservations -- themselves often use the term "nation" in their official name (e.g. the "Navajo Nation"). But Wikipedia puts -- the article at [[w:Indian reservation]] and uses that term when describing e.g. what the Navajo Nation is, -- so this must still be the legal term. preposition = "of", class = "subpolity", default = {true}, }, ["Indian reserve"] = { link = "w", -- In Canada. "First Nations reserve" sounds more modern/PC but Wikipedia uses "Indian reserve"; presumably that -- is still the legal term. preposition = "of", class = "subpolity", default = {true}, }, ["inland sea"] = { -- note, we also have 'inland' as a qualifier link = true, fallback = "sea", }, ["inner city area"] = { link = "[[inner city]] [[area]]", fallback = "neighborhood", }, ["island"] = { link = true, preposition = "of", class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["island country"] = { -- FIXME: The following should map to both 'island' and 'country'. link = "w", fallback = "country", }, ["island group"] = { link = "separately", fallback = "island", }, ["island municipality"] = { link = "w", fallback = "municipality", }, ["islet"] = { link = "w", fallback = "island", }, ["Israeli settlement"] = { link = "w", class = "settlement", default = {true}, }, ["judicial capital"] = { link = "w", fallback = "capital city", }, ["khanate"] = { link = true, fallback = "polity", }, ["kibbutz"] = { link = true, plural = "kibbutzim", class = "non-admin settlement", default = {true}, }, ["kingdom"] = { link = true, fallback = "monarchy", }, ["krai"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["lake"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["landforms!"] = { category_link = "[[landform]]s", bare_category_parent = "places", addl_bare_category_parents = {"Earth"}, }, ["largest city"] = { link = "[[large]]st [[city]]", entry_placetype_use_the = true, fallback = "city", has_neighborhoods = true, }, ["league"] = { link = true, fallback = "confederation", }, ["legislative capital"] = { link = "separately", fallback = "capital city", }, ["library"] = { link = true, fallback = "building", }, ["lieutenancy area"] = { -- used in the United Kingdom; per Wikipedia: -- In England, lieutenancy areas are colloquially known as the ceremonial counties, although this phrase does -- not appear in any legislation referring to them. The lieutenancy areas of Scotland are subdivisions of -- Scotland that are more or less based on the counties of Scotland, making use of the major cities as separate -- entities.[2] In Wales, the lieutenancy areas are known as the preserved counties of Wales and are based on -- those used for lieutenancy and local government between 1974 and 1996. The lieutenancy areas of Northern -- Ireland correspond to the six counties and two former county boroughs.[3] link = "w", fallback = "ceremonial county", }, ["local authority district"] = { link = "w", fallback = "local government district", }, ["local government area"] = { -- Australia link = "w", preposition = "of", class = "subpolity", }, ["local council"] = { -- Malta; similar to municipalities link = "+w:local councils of Malta", preposition = "of", fallback = "municipality", }, ["local government district"] = { link = "w", preposition = "of", affix_type = "suf", affix = "district", class = "subpolity", }, ["local government district with borough status"] = { link = "[[w:local government district|local government district]] with [[w:borough status|borough status]]", plural = "local government districts with borough status", plural_link = "[[w:local government district|local government districts]] with [[w:borough status|borough status]]", preposition = "of", affix_type = "suf", affix = "district", class = "subpolity", }, ["local urban district"] = { link = "w", fallback = "unincorporated community", }, ["locality"] = { link = "+w:locality (settlement)", -- not necessarily true, but usually is the case fallback = "village", }, ["London borough"] = { link = "w", preposition = "of", affix_type = "pref", affix = "borough", fallback = "local government district with borough status", has_neighborhoods = true, }, ["macroregion"] = { link = true, fallback = "region", }, ["man-made structures!"] = { category_link = "[[w:geographical feature#Engineered constructs|man-made structures]] such as [[airport]]s, [[university|universities]] and [[metro station]]s", bare_category_parent = "places", }, ["manor"] = { -- FIXME: or is this more like a farm? link = true, fallback = "building", }, ["marginal sea"] = { link = true, preposition = "of", fallback = "sea", }, ["market city"] = { link = "+market town", fallback = "city", }, ["market town"] = { link = true, fallback = "town", }, ["massif"] = { link = true, fallback = "mountain", }, ["megacity"] = { link = true, fallback = "city", }, ["metro station"] = { link = true, class = "man-made structure", }, ["metropolitan borough"] = { link = true, preposition = "of", affix_type = "Pref", no_affix_strings = {"borough", "city"}, fallback = "local government district", has_neighborhoods = true, }, ["metropolitan city"] = { -- These exist e.g. in Italy and are more like municipalities or even provinces than cities. link = true, preposition = "of", affix_type = "Pref", no_affix_strings = {"metropolitan", "city"}, class = "subpolity", }, ["metropolitan county"] = { link = true, fallback = "county", }, ["metropolitan municipality"] = { -- In South Africa, metropolitan municipalities group local municipalities and are like districts, between -- provinces and municipalities. -- In Turkey, metropolitan municipalities are provinces-level. link = "w", preposition = "of", affix_type = "Suf", no_affix_strings = {"metropolitan", "municipality"}, fallback = "municipality", class = "subpolity", }, ["microdistrict"] = { -- residential complex in post-Soviet states link = true, fallback = "neighborhood", }, ["micronations!"] = { -- FIXME, merge with microstate category_link = "[[micronation]]s", bare_category_parent = "countries", }, ["microstate"] = { link = true, fallback = "country", }, ["military base"] = { link = "w", class = "settlement", -- or "man-made structure"? default = {true}, }, ["minster town"] = { -- England link = "separately", fallback = "town", }, ["monarchy"] = { link = true, fallback = "polity", }, ["moor"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms", "ecosystems"}, default = {true}, }, ["moorland"] = { link = true, fallback = "moor", }, ["motorway"] = { link = true, fallback = "road", }, ["mountain"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["mountain indigenous district"] = { -- Taiwan link = "+w:district (Taiwan)", fallback = "district", }, ["mountain indigenous township"] = { -- Taiwan link = "+w:township (Taiwan)", fallback = "township", }, ["mountain pass"] = { link = true, -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- passes -> passe, so put an entry here to ensure we singularize correctly. plural = "mountain passes", class = "natural feature", addl_bare_category_parents = {"mountains"}, default = {true}, }, ["mountain range"] = { link = true, fallback = "mountain", }, ["mountainous region"] = { link = "separately", fallback = "region", }, ["mukim"] = { -- Malaysia, Brunei, Indonesia, Singapore link = true, preposition = "of", class = "subpolity", }, ["municipal district"] = { link = "w", -- meaning varies depending on the country; for now, assume no neighborhoods. -- FIXME: has_neighborhoods might have to be a function that looks at the containing holonyms. preposition = "of", affix_type = "Pref", no_affix_strings = "district", fallback = "municipality", }, ["municipality"] = { link = true, preposition = "of", has_neighborhoods = true, class = "subpolity", }, ["municipality with city status"] = { link = "[[municipality]] with [[w:city status|city status]]", plural = "municipalities with city status", plural_link = "[[municipality|municipalities]] with [[w:city status|city status]]", fallback = "municipality", }, ["museum"] = { link = true, fallback = "building", }, ["mythological location"] = { link = "separately", former_type = "!", class = "hypothetical location", bare_category_parent = "places", default = {true}, }, ["named bridges!"] = { category_link = "notable [[bridge]]s", bare_category_parent = "man-made structures", addl_bare_category_parents = {"bridges"}, }, ["named buildings!"] = { category_link = "notable [[house]]s, [[library|libraries]] and other [[building]]s", bare_category_parent = "man-made structures", addl_bare_category_parents = {"buildings"}, }, ["named roads!"] = { category_link = "notable [[road]]s, [[highway]]s, [[trail]]s and similar linear structures", bare_category_parent = "man-made structures", addl_bare_category_parents = {"roads"}, }, ["national capital"] = { link = "w", fallback = "capital city", }, ["national park"] = { link = true, fallback = "park", }, ["natural features!"] = { category_link = "[[w:geographical feature#Natural features|natural features]] such as [[lake]]s, [[mountain]]s, [[island]]s and [[ocean]]s", bare_category_parent = "places", }, ["neighborhood"] = { -- The majority of the properties here apply to both `neighborhoods` and `neighbourhoods`; the choice of which -- one to use is made by district_neighborhood_cat_handler() based on the value of `british_spelling` for the -- location (city, political division, etc.) of the holonym that follows the word "neighbo(u)hoods" in the -- category name. It does *NOT* depend on whether the {{place}} call uses "neighborhoods" or "neighbourhoods". -- (In general it can't, because other things like "urban areas", "districts", "subdivisions" and the like also -- categorize as neighbo(u)rhoods.) link = true, -- See below. These are used by category handlers in [[Module:category tree/topic cat/data/Places]]. generic_before_non_cities = "in", generic_before_cities = "of", -- The following text is suitable for the top-level description of a neighborhood as well as categories of the -- form `Neighborhoods in POLDIV` e.g. `Neighborhoods in Illinois, USA` but not for categories of the form -- `Neighborhoods of Chicago`, where we'd get "... and other subportions of [[city|cities]] of [[Chicago]]". category_link = "[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]]", category_link_before_city = "[[neighborhood]]s, [[district]]s and other subportions", -- NOTE: This setting is needed for administrative divisions like barangays that fall back to `neighborhood`, -- when set in [[Module:place/locations]] for a specific country (e.g. the Philippines). The above settings -- for `generic_before_non_cities` and `generic_before_cities` are used by category handlers in -- [[Module:category tree/topic cat/data/Places]] for `Neighborhoods in POLDIV` and `Neighborhoods of CITY` -- categories. In fact, district_neighborhood_cat_handler() does not currently pay attention to them, but -- generates "of" before cities and "in" before non-cities regardless. (FIXME: We should change that.) preposition = "of", class = "non-admin settlement", cat_handler = district_neighborhood_cat_handler, }, ["neighbourhood"] = { link = true, category_link = "[[neighbourhood]]s, [[district]]s and other subportions of [[city|cities]]", category_link_before_city = "[[neighbourhood]]s, [[district]]s and other subportions", fallback = "neighborhood", }, ["new area"] = { -- China (type of economic development zone, varying greatly in size) link = "w", preposition = "in", class = "subpolity", --? }, ["new town"] = { link = true, fallback = "town", }, ["non-city capital"] = { link = "[[capital]]", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", cat_handler = function(data) return capital_city_cat_handler(data, "non-city") end, -- FIXME, do we need the following? default = {true}, }, ["non-metropolitan county"] = { link = "w", fallback = "county", }, ["non-metropolitan district"] = { link = "w", fallback = "local government district", }, ["non-sovereign kingdom"] = { -- especially in Africa and Asia link = "+w:non-sovereign monarchy", generic_before_non_cities = "in", class = "subpolity", ["country/*"] = {true}, ["continent/*"] = {true}, default = {true}, }, ["non-sovereign monarchy"] = { link = "w", fallback = "non-sovereign kingdom", }, ["oblast"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["oblasts and autonomous republics!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Ukraine. category_link = "[[oblast]]s and [[w:autonomous republic|autonomous republic]]s", class = "subpolity", }, ["ocean"] = { link = true, holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"seas", "bodies of water"}, default = {true}, }, ["okrug"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["overseas collectivity"] = { link = "w", fallback = "collectivity", }, ["overseas department"] = { link = "w", fallback = "department", }, ["overseas territory"] = { link = "w", fallback = "dependent territory", }, ["parish"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["parish municipality"] = { -- in Quebec, often similar to a rural village; the famous [[Saint-Louis-du-Ha! Ha!]] is one of them. link = "+w:parish municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, }, ["parish seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", class = "capital", has_neighborhoods = true, }, ["park"] = { link = true, class = "man-made structure", default = {true}, }, ["pass"] = { link = "+mountain pass", -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- passes -> passe, so put an entry here to ensure we singularize correctly. plural = "passes", fallback = "mountain pass", }, ["path"] = { link = true, fallback = "road", }, ["peak"] = { link = true, fallback = "mountain", }, ["peninsula"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["periphery"] = { link = true, preposition = "of", class = "subpolity", }, ["places!"] = { generic_before_non_cities = "in", generic_before_cities = "in", class = "generic place", category_link = "[[place]]s of all sorts", -- `category_link_top_level` control the description used in the top-level [[Category:Places]] and -- language-specific variants such as [[Category:en:Places]]. The actual text for a language-spefic variant is -- "{{{langname}}} names of [[geographical]] [[place]]s of all sorts; [[toponym]]s." where the "names of" -- portion is automatically generated by the appropriate handler in -- [[Module:category tree/topic cat/data/Places]]. category_link_top_level = "[[geographical]] [[place]]s of all sorts; [[toponym]]s", bare_category_parent = "names", }, ["planned community"] = { -- Include this so we don't categorize 'planned community' into villages, as 'community' does. link = true, class = "settlement", has_neighborhoods = true, }, ["plateau"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, -- FIXME: Should generate both "Plateaus" and the appropriate 'geographic and cultural area' category }, ["Polish colony"] = { link = "[[w:colony (Poland)|colony]]", affix_type = "suf", affix = "colony", fallback = "village", has_neighborhoods = true, }, ["political divisions!"] = { category_link = "[[political]] [[division]]s and [[subdivision]]s, such as [[state]]s, [[province]]s, [[county|counties]] or [[district]]s", bare_category_parent = "places", }, ["polity"] = { link = true, category_link = "[[independent]] or [[semi-]][[independent]] [[polity|polities]]", class = "polity", bare_category_parent = "places", default = {true}, }, ["populated place"] = { link = "+w:populated place", -- not necessarily true, but usually is the case fallback = "village", }, ["port"] = { link = true, class = "man-made structure", default = {true}, }, ["port city"] = { -- FIXME: should categorize into "Ports" as well as "Cities" link = true, fallback = "city", }, ["port town"] = { -- FIXME: should categorize into "Ports" as well as "Towns" link = "w", fallback = "town", }, ["prefecture"] = { -- FIXME! `prefecture` is like a county in Japan and elsewhere but a department capital city in France. -- May need `has_neighborhoods` to be a function. link = true, preposition = "of", display_handler = prefecture_display_handler, class = "subpolity", }, ["prefecture-level city"] = { -- China; they are huge entities with a central city; not cities themselves. link = "w", preposition = "of", class = "subpolity", }, ["preserved county"] = { -- In Wales; they are former counties enshrined in law; there are 8 of them and each consists of one or more -- "principal areas" (styled as "counties" or "county boroughs"), of which there are 22. link = "w", preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["primary area"] = { -- a grouping of "districts" (neighborhoods) in Gothenburg, Sweden link = "+w:sv:primärområde", fallback = "neighborhood", }, ["principality"] = { link = true, fallback = "monarchy", }, ["promontory"] = { link = true, fallback = "headland", }, ["protectorate"] = { link = true, fallback = "dependent territory", }, ["province"] = { link = true, preposition = "of", display_handler = province_display_handler, class = "subpolity", }, ["provinces and autonomous regions!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case China. category_link = "[[province]]s and [[autonomous region]]s", class = "subpolity", }, ["provinces and territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Canada and Pakistan. category_link = "[[province]]s and [[territory|territories]]", class = "subpolity", }, ["provincial capital"] = { link = "separately", fallback = "capital city", }, ["raion"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["ranch"] = { link = true, fallback = "farm", }, ["range"] = { -- FIXME: Where is this used? Is it a mountain range? link = true, holonym_use_the = true, class = "natural feature", }, ["regency"] = { link = true, preposition = "of", class = "subpolity", }, ["region"] = { link = true, preposition = "of", -- If 'region' isn't a specific administrative division, fall back to 'geographic and cultural area' fallback = "geographic and cultural area", -- "former region" is a subpolity but traditional/historic(al)/ancient/medieval/etc. is a geographic region class = "geographic region", }, ["regional capital"] = { link = "separately", fallback = "capital city", }, ["regional county municipality"] = { -- Quebec link = "w", preposition = "of", affix_type = "Suf", no_affix_strings = {"municipality", "county"}, fallback = "municipality", }, ["regional district"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "district", fallback = "district", }, ["regional municipality"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "municipality", fallback = "municipality", }, ["regional unit"] = { link = "w", preposition = "of", affix_type = "suf", class = "subpolity", }, ["registration county"] = { -- Used in Scotland for land registration purposes; formerly used in England, Wales and Ireland for statistical -- purposes (registration of births, deaths and marriages, and for the output of census information). link = "w", fallback = "county", }, ["republic"] = { -- Of Russia, Yugoslavia, etc. "Republics" in general are sovereign but we use "country" in that case. link = true, fallback = "constituent republic", }, ["research base"] = { link = "+w:research station", fallback = "research station", }, ["research station"] = { link = "w", class = "non-admin settlement", -- or "man-made structure"? default = {true}, }, ["reservoir"] = { link = true, fallback = "lake", }, ["residential area"] = { link = "separately", fallback = "neighborhood", }, ["resort city"] = { link = "w", fallback = "city", }, ["resort town"] = { link = "w", fallback = "town", }, ["river"] = { link = true, generic_before_non_cities = "in", holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, cat_handler = city_type_cat_handler, ["continent/*"] = {true}, default = {true}, }, ["river island"] = { link = "w", fallback = "island", }, ["road"] = { link = true, class = "man-made structure", default = {"Named roads"}, }, ["Roman province"] = { -- FIXME! Eliminate this in favor of 'former province|emp/Roman Empire' link = "w", default = {"Provinces of the Roman Empire"}, class = "subpolity", }, ["royal borough"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = {"royal", "borough"}, fallback = "local government district with borough status", has_neighborhoods = true, }, ["royal burgh"] = { link = true, fallback = "borough", }, ["royal capital"] = { link = "w", fallback = "capital city", }, ["rural committee"] = { -- Hong Kong; a group of villages link = "w", affix_type = "Suf", has_neighborhoods = true, class = "settlement", }, ["rural community"] = { -- New Brunswick link = "+w:list of municipalities in New_Brunswick#Rural communities", fallback = "municipality", }, ["rural hromada"] = { link = "[[rural]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["rural municipality"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "municipality", fallback = "municipality", has_neighborhoods = true, --? }, ["rural township"] = { -- Taiwan link = "+w:rural township (Taiwan)", fallback = "township", }, ["sanctuary"] = { link = true, fallback = "temple", }, ["satrapy"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"ANCIENT", "FORMER"}, }, ["sea"] = { link = true, holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["seaport"] = { link = true, fallback = "port", }, ["seat"] = { link = true, fallback = "administrative centre", }, ["self-administered area"] = { -- Myanmar (groups self-administered divisions and zones) link = "+w:self-administered zone", preposition = "of", class = "subpolity", }, ["self-administered division"] = { -- Myanmar (only one of them: Wa Self-Administered Division) link = "w", fallback = "self-administered area", }, ["self-administered zone"] = { -- Myanmar (five of them) link = "w", fallback = "self-administered area", }, ["separatist state"] = { link = "separately", fallback = "unrecognized country", }, ["settlement"] = { link = true, category_link = "[[settlement]]s such as [[city|cities]], [[village]]s and [[farm]]s", bare_category_parent = "places", -- not necessarily true, but usually is the case fallback = "village", }, ["settlement hromada"] = { link = "[[w:Populated places in Ukraine#Rural settlements|settlement]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["sheading"] = { -- Isle of Man link = true, fallback = "district", }, ["sheep station"] = { -- Australia link = true, fallback = "farm", }, ["shire"] = { link = true, fallback = "county", }, ["shire county"] = { link = "w", fallback = "county", }, ["shire town"] = { link = true, fallback = "county seat", }, ["ski resort city"] = { link = "[[ski resort]] [[city]]", fallback = "city", }, ["ski resort town"] = { link = "[[ski resort]] [[town]]", fallback = "town", }, ["spa city"] = { link = "+w:spa town", fallback = "city", }, ["spa town"] = { link = "w", fallback = "town", }, ["space station"] = { link = true, fallback = "research station", }, ["special administrative region"] = { -- in China; in practice they are city-like (Hong Kong, Macau); also [[Oecusse]] in East Timor is formally a -- "special administrative region"; North Korea had one such region planned (Sinuiju) but abandoned; Indonesia -- has similar "special regions" of Jakarta, Yogyakarta and Aceh; and South Sudan has three "special -- administrative areas" link = "+w:special administrative regions of China", preposition = "of", class = "subpolity", has_neighborhoods = true, --? -- no suffix since places in Hong Kong or Macau are listed without China, except Hong Kong and Macau themselves -- they also contain regions (or areas), e.g. [[Kowloon]], so it would be confusing suffix = "", }, ["special collectivity"] = { link = "w", fallback = "collectivity", }, ["special municipality"] = { -- formerly linked to the Taiwan article but there are also special municipalities of the Netherlands link = "w", fallback = "municipality", }, ["special ward"] = { -- Tokyo link = true, fallback = "municipality", }, ["spit"] = { link = true, fallback = "peninsula", }, ["spring"] = { link = true, class = "natural feature", default = {true}, }, ["star"] = { link = true, class = "natural feature", default = {true}, }, ["state"] = { link = true, preposition = "of", class = "subpolity", -- 'former/historical state' could refer either to a state of a country (a division) or a state = sovereign -- entity. The latter appears more common (e.g. in various "ancient states" of East Asia). former_type = "polity", }, ["states and territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Australia. category_link = "[[state]]s and [[territory|territories]]", class = "subpolity", }, ["states and union territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case India. category_link = "[[state]]s and [[union territory|union territories]]", class = "subpolity", }, ["state capital"] = { link = "separately", fallback = "capital city", }, ["state park"] = { link = true, fallback = "park", }, ["state-level new area"] = { -- China (type of economic development zone, varying greatly in size) link = "w", fallback = "new area", }, ["statistical region"] = { -- Slovenia link = true, fallback = "administrative region", }, ["statutory city"] = { link = "w", fallback = "city", }, ["statutory town"] = { link = "w", fallback = "town", }, ["strait"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["stream"] = { link = true, fallback = "river", }, ["street"] = { link = true, fallback = "road", }, ["strip"] = { link = true, fallback = "geographic region", }, ["strip of land"] = { link = "[[strip]] of [[land]]", plural = "strips of land", plural_link = "[[strip]]s of [[land]]", fallback = "geographic region", }, ["sub-metropolitan city"] = { link = "+w:List of cities in Nepal#Sub-metropolitan cities", fallback = "city", }, ["sub-prefectural city"] = { link = "w", fallback = "subprovincial city", }, ["subdistrict"] = { link = true, preposition = "of", has_neighborhoods = true, --? -- FIXME: subdistricts can be neighborhood-like (of Jakarta) or larger (in China); need a handler class = "subpolity", default = {true}, }, ["subdivision"] = { link = true, preposition = "of", affix_type = "suf", -- FIXME: subdivisions can be neighborhood-like or larger; need a handler class = "subpolity", cat_handler = district_neighborhood_cat_handler, }, ["submerged ghost town"] = { -- FIXME: Consider just having "submerged" as a qualifier. link = "[[submerged]] [[ghost town]]", fallback = "ghost town", }, ["subnational kingdom"] = { link = "+w:subnational monarchy", fallback = "non-sovereign kingdom", }, ["subnational monarchy"] = { link = "w", fallback = "non-sovereign kingdom", }, ["subprefecture"] = { link = true, affix_type = "suf", preposition = "of", class = "subpolity", }, ["subprovince"] = { link = true, preposition = "of", class = "subpolity", }, ["subprovincial city"] = { link = "w", -- China; special status given to certain prefecture-level cities fallback = "prefecture-level city", }, ["subprovincial district"] = { link = "w", -- China; special status given to Binhai New Area and Pudong New Area, which are county-level districts preposition = "of", class = "subpolity", }, ["subregion"] = { link = true, fallback = "geographic region", }, ["suburb"] = { link = true, -- The following text is suitable for the top-level description of a suburb as well as categories of the form -- 'Suburbs in POLDIV' e.g. 'Suburbs in Illinois, USA' but not for categories of the form 'Suburbs of Chicago', -- where we'd get "[[suburb]]s of [[city|cities]] of [[Chicago]]". category_link = "[[suburb]]s of [[city|cities]]", category_link_before_city = "[[suburb]]s", -- See comments under "neighborhood" for the following three settings. They are used by -- [[Module:category tree/topic cat/data/Places]] for generating the text of 'Suburbs in/of PLACE' categories -- but currently ignored by district_neighborhood_cat_handler (which actually generates the categories for a -- given page), which hardcodes "in" for non-cities and "of" for cities. (FIXME: Change this.) generic_before_non_cities = "in", generic_before_cities = "of", preposition = "of", has_neighborhoods = true, --? class = "non-admin settlement", --? cat_handler = district_neighborhood_cat_handler, }, ["suburban area"] = { link = "w", fallback = "suburb", }, ["subway station"] = { link = "w", fallback = "metro station", }, ["sum"] = { -- In China, Mongolia, Russia; something like a county in Mongolia but a township in China (Inner Mongolia), -- and equivalent to a [[selsoviet]] in the parts of Russia where it's in use (a rural council, below a raion). link = "+w:sum (administrative division)", -- This fallback is somewha arbitrary. We could use "county" but that has a display handler -- which we don't want to be active (FIXME: If the display handler would be active, that's a bug). fallback = "division", }, ["supercontinent"] = { link = true, fallback = "continent", }, ["tehsil"] = { link = true, affix_type = "suf", no_affix_strings = {"tehsil", "tahsil"}, class = "subpolity", }, ["temple"] = { link = true, fallback = "building", }, ["territorial authority"] = { link = "w", fallback = "district", }, ["territory"] = { link = true, preposition = "of", class = "subpolity", }, ["theme"] = { link = "+w:theme (Byzantine district)", preposition = "of", class = "subpolity", }, ["town"] = { link = true, generic_before_non_cities = "in", has_neighborhoods = true, class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["town with bystatus"] = { -- can't use templates in links currently link = "[[town]] with [[bystatus#Norwegian Bokmål|bystatus]]", plural = "towns with bystatus", plural_link = "[[town]]s with [[bystatus#Norwegian Bokmål|bystatus]]", fallback = "town", }, ["township"] = { link = true, has_neighborhoods = true, class = "settlement", --? default = {true}, }, ["township municipality"] = { -- Quebec link = "+w:township municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, --? }, ["traditional county"] = { link = true, fallback = "county", }, ["traditional region"] = { -- FIXME: Verify this works. Same for 'historic(al) region'. -- provided only for the link link = "w", fallback = "FORMER geographic region", }, ["trail"] = { link = true, fallback = "road", }, ["treaty port"] = { link = "w", fallback = "city", class = "settlement", inherently_former = {"FORMER"}, }, ["tributary"] = { link = true, preposition = "of", fallback = "river", }, ["underground station"] = { link = "w", fallback = "metro station", }, ["unincorporated area"] = { link = "w", -- I don't know if this fallback makes sense everywhere. fallback = "unincorporated community", }, ["unincorporated community"] = { link = true, generic_before_non_cities = "in", class = "non-admin settlement", }, ["unincorporated territory"] = { link = "w", fallback = "territory", }, ["union territory"] = { -- India link = true, preposition = "of", entry_placetype_indefinite_article = "a", class = "subpolity", }, ["unitary authority"] = { -- UK, New Zealand link = true, entry_placetype_indefinite_article = "a", fallback = "local government district", }, ["unitary district"] = { link = "w", entry_placetype_indefinite_article = "a", fallback = "local government district", }, ["united township municipality"] = { -- Quebec link = "+w:united township municipality (Quebec)", entry_placetype_indefinite_article = "a", fallback = "township municipality", has_neighborhoods = true, --? }, ["university"] = { link = true, entry_placetype_indefinite_article = "a", class = "man-made structure", default = {true}, }, ["unrecognised country"] = { link = "w", fallback = "unrecognized country", }, ["unrecognized and nearly unrecognized countries!"] = { category_link = "[[de facto]] [[independent]] [[state]]s with little or no {{w|international recognition}}", bare_category_parent = "country-like entities", }, ["unrecognized country"] = { link = "w", class = "polity", default = {"Unrecognized and nearly unrecognized countries"}, }, ["unrecognised state"] = { link = "w", fallback = "unrecognized country", }, ["unrecognized state"] = { link = "w", fallback = "unrecognized country", }, ["urban area"] = { link = "separately", fallback = "neighborhood", }, ["urban hromada"] = { link = "[[urban]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["urban service area"] = { -- A strange beast existing in Alberta; technically a type of hamlet but in practice used for much larger -- cities and treated equivalent to a city. (There are only two of them, [[Fort McMurray]] and [[Sherwood Park]]). link = "w", fallback = "city", }, ["urban township"] = { link = "w", fallback = "township", }, ["urban-type settlement"] = { -- appears to be a particular type of small urban settlement in post-Soviet states, -- had an administrative function. link = "w", fallback = "town", }, ["valley"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms", "water"}, default = {true}, }, ["viceroyalty"] = { -- in essence, a type of colony link = true, fallback = "dependent territory", }, ["village"] = { link = true, generic_before_non_cities = "in", category_link = "[[village]]s, [[hamlet]]s, and other small [[community|communities]] and [[settlement]]s", class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["village development committee"] = { -- former administrative structure in Nepal; also exists in India but not as a formal unit link = "+w:village development committee (Nepal)", inherently_former = {"FORMER"}, fallback = "village", }, ["village municipality"] = { -- Quebec link = "+w:village municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, --? }, ["voivodeship"] = { -- Poland link = true, display_handler = voivodeship_display_handler, preposition = "of", class = "subpolity", }, ["volcano"] = { link = true, plural = "volcanoes", class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true, "Mountains"}, }, ["ward"] = { link = true, class = "settlement", -- Wards are formal administrative divisions of a city but have some properties of neighborhoods. fallback = "neighborhood", }, ["watercourse"] = { link = true, fallback = "channel", }, ["Welsh community"] = { -- Wales link = "[[w:community (Wales)|community]]", preposition = "of", affix_type = "suf", affix = "community", has_neighborhoods = true, class = "settlement", }, ["zone"] = { -- administrative division of Ethiopia, Qatar, Nepal, India link = "+w:zone#Place names", preposition = "of", class = "subpolity", }, ---------------------------------------------------------------------------------------------- -- Categories for former places -- ---------------------------------------------------------------------------------------------- ["ANCIENT capital"] = { link = false, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", -- FIXME: Consider removing 'ancient settlements' here. Ancient capitals, like former capitals, often still -- exist but just aren't the capital any more. Maybe we should have an 'Ancient capitals' category. default = {"Ancient settlements", "Former capitals"}, }, ["ANCIENT non-admin settlement"] = { link = false, class = "non-admin settlement", fallback = "ANCIENT settlement", }, ["ANCIENT settlement"] = { link = false, has_neighborhoods = true, class = "settlement", default = {"Ancient settlements"}, }, ["ancient settlements!"] = { category_link = "former [[city|cities]], [[town]]s and [[village]]s that existed in [[antiquity]]", bare_category_parent = "former settlements", }, ["FORMER capital"] = { link = false, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", default = {"Former capitals"}, }, ["former capitals!"] = { category_link = "former [[capital]] [[city|cities]] and [[town]]s", bare_category_parent = "settlements", }, ["former counties and county-level cities!"] = { -- For categorizing former counties and county-level cities of China category_link = "no-longer existing [[county|counties]] and [[county-level city|county-level cities]]", bare_category_breadcrumb = "counties and county-level cities", bare_category_parent = "former political divisions", }, ["FORMER county"] = { -- For categorizing former counties and county-level cities of China link = false, fallback = "FORMER subpolity", }, ["FORMER county-level city"] = { -- For categorizing former counties and county-level cities of China link = false, fallback = "FORMER subpolity", }, ["former countries and country-like entities!"] = { category_link = "[[country|countries]] and similar [[polity|polities]] that no longer exist", bare_category_breadcrumb = "countries and country-like entities", bare_category_parent = "former polities", }, ["FORMER country"] = { link = false, class = "polity", default = {"Former countries and country-like entities"}, }, ["former dependent territories!"] = { category_link = "[[w:dependent territory|dependent territories]] (colonies, dependencies, protectorates, etc.) that no longer exist", bare_category_breadcrumb = "dependent territories", bare_category_parent = "former political divisions", }, ["FORMER dependent territory"] = { link = false, preposition = "of", class = "subpolity", default = {"Former dependent territories"}, }, ["former districts!"] = { -- For categorizing former districts of China category_link = "no-longer-existing [[district]]s", bare_category_breadcrumb = "districts", bare_category_parent = "former political divisions", }, ["FORMER district"] = { -- For categorizing former districts of China link = false, fallback = "FORMER subpolity", }, ["FORMER geographic region"] = { link = false, fallback = "geographic and cultural area", }, ["FORMER man-made structure"] = { link = false, class = "man-made structure", default = {"Former man-made structures"}, }, ["former man-made structures!"] = { category_link = "man-made structures such as [[airport]]s and [[park]]s that no longer exist", bare_category_breadcrumb = "man-made structures", bare_category_parent = "former places", }, ["former municipalities!"] = { -- For categorizing former municipalities of the Netherlands category_link = "no-longer-existing [[municipality|municipalities]]", bare_category_breadcrumb = "municipalities", bare_category_parent = "former political divisions", }, ["FORMER municipality"] = { -- For categorizing former municipalities of the Netherlands link = false, fallback = "FORMER subpolity", }, ["FORMER natural feature"] = { link = false, class = "natural feature", default = {"Former natural features"}, }, ["former natural features!"] = { category_link = "natural features such as [[lake]]s, [[river]]s and [[island]]s that no longer exist", bare_category_breadcrumb = "natural features", bare_category_parent = "former places", }, ["FORMER non-admin settlement"] = { link = false, class = "non-admin settlement", fallback = "FORMER settlement", }, ["former places!"] = { category_link = "[[place]]s of all sorts that no longer exist", bare_category_breadcrumb = "former", bare_category_parent = "places", }, ["former political divisions!"] = { category_link = "[[political]] [[division]]s (states, provinces, counties, etc.) that no longer exist", bare_category_breadcrumb = "political divisions", bare_category_parent = "former places", }, ["former polities!"] = { category_link = "[[polity|polities]] (countries, kingdoms, empires, etc.) that no longer exist", bare_category_breadcrumb = "polities", bare_category_parent = "former places", }, ["FORMER polity"] = { link = false, class = "polity", default = {"Former polities"}, }, ["former prefectures!"] = { -- For categorizing former prefectures of China category_link = "no-longer-existing [[prefecture]]s", bare_category_breadcrumb = "prefectures", bare_category_parent = "former political divisions", }, ["FORMER prefecture"] = { -- For categorizing former prefectures of China link = false, fallback = "FORMER subpolity", }, ["former provinces!"] = { -- For categorizing former provinces of China, etc. category_link = "no-longer-existing [[province]]s", bare_category_breadcrumb = "provinces", bare_category_parent = "former political divisions", }, ["FORMER province"] = { -- For categorizing ancient/historical/former provinces of the Roman Empire link = false, fallback = "FORMER subpolity", }, ["former region"] = { -- A former region is considered a former political division, but not a 'historical/traditional/etc.' region. link = "separately", preposition = "of", inherently_former = {"FORMER"}, class = "subpolity", }, ["FORMER settlement"] = { link = false, has_neighborhoods = true, class = "settlement", default = {"Former settlements"}, }, ["former settlements!"] = { category_link = "[[city|cities]], [[town]]s and [[village]]s that no longer exist or have been merged or reclassified", bare_category_breadcrumb = "settlements", bare_category_parent = "former political divisions", }, ["FORMER subpolity"] = { link = false, preposition = "of", class = "subpolity", default = {"Former political divisions"}, }, ---------------------------------------------------------------------------------------------- -- form-of categories -- ---------------------------------------------------------------------------------------------- ---------- Abbreviations ---------- ["abbreviations of counties!"] = { -- For categorizing abbreviations of counties of e.g. England full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[county|counties]]", bare_category_breadcrumb = "counties", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of countries!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "abbreviations of places", }, ["abbreviations of departments!"] = { -- For categorizing abbreviations of departments of e.g. France full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[department]]s", bare_category_breadcrumb = "departments", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of districts!"] = { -- For categorizing abbreviations of districts of e.g. ??? full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[district]]s", bare_category_breadcrumb = "districts", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of divisions!"] = { -- For categorizing abbreviations of divisions of e.g. Bangladesh full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[division]]s", bare_category_breadcrumb = "divisions", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of former countries!"] = { full_category_link = "{{glossary|abbreviation}}s of [[country|countries]] that no longer [[exist]]", bare_category_breadcrumb = "countries", bare_category_parent = "abbreviations of former places", }, ["abbreviations of former places!"] = { full_category_link = "{{glossary|abbreviation}}s of [[place]]s that no longer [[exist]]", bare_category_breadcrumb = "abbreviations", bare_category_parent = "former places", addl_bare_category_parents = {{name = "abbreviations of places", sort = "former"}}, }, ["abbreviations of places!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[place]]s", bare_category_breadcrumb = "abbreviations", bare_category_parent = "places", }, ["abbreviations of political divisions!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[political]] [[division]]s", bare_category_breadcrumb = "political divisions", bare_category_parent = "abbreviations of places", }, ["abbreviations of prefectures!"] = { -- For categorizing abbreviations of prefectures of e.g. Japan full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[prefecture]]s", bare_category_breadcrumb = "prefectures", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of provinces!"] = { -- For categorizing abbreviations of provinces of e.g. Canada full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[province]]s", bare_category_breadcrumb = "provinces", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of provinces and territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[province]]s and [[territory|territories]]", bare_category_breadcrumb = "provinces and territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of regions!"] = { -- For categorizing abbreviations of regions of e.g. Italy full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[administrative region]]s", bare_category_breadcrumb = "regions", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states!"] = { -- For categorizing abbreviations of states of e.g. the United States full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states and territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s and [[territory|territories]]", bare_category_breadcrumb = "states and territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states and union territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s and [[union territory|union territories]]", bare_category_breadcrumb = "states and union territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[territory|territories]]", bare_category_breadcrumb = "territories", bare_category_parent = "abbreviations of political divisions", }, ["ABBREVIATION_OF country"] = { link = false, default = {"Abbreviations of countries"}, }, ["ABBREVIATION_OF county"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF department"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF district"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF division"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF FORMER country"] = { link = false, default = {"Abbreviations of former countries"}, }, ["ABBREVIATION_OF FORMER place"] = { link = false, default = {"Abbreviations of former places"}, }, ["ABBREVIATION_OF place"] = { link = false, default = {"Abbreviations of places"}, }, ["ABBREVIATION_OF prefecture"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF province"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF region"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF state"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF subpolity"] = { link = false, default = {"Abbreviations of political divisions"}, }, ["ABBREVIATION_OF territory"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF union territory"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ---------- Archaic forms ---------- ["archaic forms of places!"] = { full_category_link = "{{glossary|archaic}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "archaic forms", bare_category_parent = "places", }, ["ARCHAIC_FORM_OF place"] = { link = false, default = {"Archaic forms of places"}, }, ---------- Clippings ---------- ["clippings of places!"] = { full_category_link = "{{glossary|clipping}}s of [[name]]s of [[place]]s", bare_category_breadcrumb = "clippings", bare_category_parent = "places", }, ["CLIPPING_OF place"] = { link = false, default = {"Clippings of places"}, }, ---------- Dated forms ---------- ["dated forms of places!"] = { full_category_link = "{{glossary|dated}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "dated forms", bare_category_parent = "places", }, ["DATED_FORM_OF place"] = { link = false, default = {"Dated forms of places"}, }, ---------- Derogatory names ---------- ["derogatory names for cities!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[city|cities]]", bare_category_breadcrumb = "cities", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for cities"}, }, ["derogatory names for continents!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[continent]]s", bare_category_breadcrumb = "continents", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for continents"}, }, ["derogatory names for countries!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for countries"}, }, ["derogatory names for places!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[place]]s", bare_category_breadcrumb = "derogatory names", bare_category_parent = "nicknames for places", }, ["derogatory names for states!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for states"}, }, ["DEROGATORY_NAME_FOR capital"] = { link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR city"] = { link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR continent"] = { link = false, default = {"Derogatory names for continents"}, }, ["DEROGATORY_NAME_FOR country"] = { link = false, default = {"Derogatory names for countries"}, }, ["DEROGATORY_NAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR place"] = { link = false, default = {"Derogatory names for places"}, }, ["DEROGATORY_NAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR state"] = { link = false, default = {"Derogatory names for states"}, }, ["DEROGATORY_NAME_FOR town"] = { link = false, default = {"Derogatory names for cities"}, }, ---------- Ellipses ---------- ["ellipses of places!"] = { full_category_link = "{{glossary|ellipsis|ellipses}} of [[name]]s of [[place]]s", bare_category_breadcrumb = "ellipses", bare_category_parent = "places", }, ["ELLIPSIS_OF place"] = { link = false, default = {"Ellipses of places"}, }, ---------- Former long-form names ---------- ["former long-form names of countries!"] = { full_category_link = "no-longer-[[use]]d [[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "former long-form names of places", addl_bare_category_parents = {{name = "former names of countries", sort = "long-form"}}, }, ["former long-form names of places!"] = { full_category_link = "no-longer-[[use]]d [[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[place]]s", bare_category_breadcrumb = "long-form", bare_category_parent = "former names of places", }, ["FORMER_LONG_FORM_OF country"] = { link = false, default = {"Former long-form names of countries"}, }, ["FORMER_LONG_FORM_OF place"] = { link = false, default = {"Former long-form names of places"}, }, ---------- Former names ---------- ["former names of capitals!"] = { full_category_link = "[[former]] [[name]]s of [[capital city|capital cities]] that generally still exist but under a different name", bare_category_breadcrumb = "capitals", bare_category_parent = "former names of settlements", }, ["former names of countries!"] = { full_category_link = "[[former]] [[name]]s of [[country|countries]] that generally still exist but under a different name", bare_category_breadcrumb = "countries", bare_category_parent = "former names of places", }, ["former names of places!"] = { full_category_link = "[[former]] [[name]]s of [[place]]s that generally still exist but under a different name", bare_category_breadcrumb = "former names", bare_category_parent = "places", }, ["former names of political divisions!"] = { full_category_link = "[[former]] [[name]]s of [[political]] [[division]]s (states, provinces, counties, etc.) that generally still exist but under a different name", bare_category_breadcrumb = "political divisions", bare_category_parent = "former names of places", }, ["former names of polities!"] = { full_category_link = "[[former]] [[name]]s of [[polity|polities]] (e.g. [[country|countries]]) that generally still exist but under a different name", bare_category_breadcrumb = "polities", bare_category_parent = "former names of places", }, ["former names of settlements!"] = { full_category_link = "[[former]] [[name]]s of [[city|cities]], [[town]]s, [[village]]s, etc. that generally still exist but under a different name", bare_category_breadcrumb = "settlements", bare_category_parent = "former names of political divisions", }, ["FORMER_NAME_OF capital"] = { link = false, default = {"Former names of capitals"}, }, ["FORMER_NAME_OF country"] = { link = false, default = {"Former names of countries"}, }, ["FORMER_NAME_OF place"] = { link = false, default = {"Former names of places"}, }, ["FORMER_NAME_OF polity"] = { link = false, default = {"Former names of polities"}, }, ["FORMER_NAME_OF region"] = { link = false, fallback = "FORMER_NAME_OF subpolity", }, ["FORMER_NAME_OF settlement"] = { link = false, default = {"Former names of settlements"}, }, ["FORMER_NAME_OF subpolity"] = { link = false, default = {"Former names of political divisions"}, }, ---------- Former nicknames ---------- ["former nicknames for cities!"] = { full_category_link = "no-longer-used [[nickname]]s for [[city|cities]], e.g. the [[Eternal City]] for [[Kyoto]] during the {{w|Heian period}} ({{circa2|800–1100|short=yes}} {{AD}})", bare_category_breadcrumb = "cities", bare_category_parent = "former nicknames for places", addl_bare_category_parents = {"nicknames for cities"}, }, ["former nicknames for places!"] = { full_category_link = "no-longer-used [[nickname]]s for [[place]]s", bare_category_breadcrumb = "former", bare_category_parent = "nicknames for places", addl_bare_category_parents = {{name = "former names of places", sort = "nicknames"}}, }, ["FORMER_NICKNAME_FOR capital"] = { link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR city"] = { link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR place"] = { link = false, default = {"Former nicknames for places"}, }, ["FORMER_NICKNAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR town"] = { link = false, default = {"Former nicknames for cities"}, }, ---------- Former official names ---------- ["former official names of countries!"] = { full_category_link = "no-longer-[[use]]d [[official]] [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "former official names of places", addl_bare_category_parents = {{name = "former names of countries", sort = "official"}}, }, ["former official names of places!"] = { full_category_link = "no-longer-[[use]]d [[official]] [[name]]s of [[place]]s", bare_category_breadcrumb = "official", bare_category_parent = "former names of places", }, ["FORMER_OFFICIAL_NAME_OF country"] = { link = false, default = {"Former official names of countries"}, }, ["FORMER_OFFICIAL_NAME_OF place"] = { link = false, default = {"Former official names of places"}, }, ---------- Long-form names ---------- ["long-form names of countries!"] = { full_category_link = "[[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "long-form names of places", }, ["long-form names of places!"] = { full_category_link = "[[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[place]]s", bare_category_breadcrumb = "long-form names", bare_category_parent = "places", }, ["LONG_FORM_OF country"] = { link = false, default = {"Long-form names of countries"}, }, ["LONG_FORM_OF place"] = { link = false, default = {"Long-form names of places"}, }, ---------- Nicknames ---------- ["nicknames for cities!"] = { full_category_link = "[[nickname]]s for [[city|cities]], e.g. the [[Big Apple]] for [[New York City]]", bare_category_breadcrumb = "cities", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"cities"}, }, ["nicknames for continents!"] = { full_category_link = "[[nickname]]s for [[continent]]s", bare_category_breadcrumb = "continents", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"continents"}, }, ["nicknames for countries!"] = { full_category_link = "[[nickname]]s for [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"countries"}, }, ["nicknames for places!"] = { full_category_link = "[[nickname]]s for [[place]]s", bare_category_breadcrumb = "places", bare_category_parent = "nicknames", addl_bare_category_parents = {"places"}, }, ["nicknames for states!"] = { -- For categorizing nicknames for states of e.g. the United States full_category_link = "[[nicknames]] for [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"states"}, }, ["NICKNAME_FOR capital"] = { link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR city"] = { link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR continent"] = { link = false, default = {"Nicknames for continents"}, }, ["NICKNAME_FOR country"] = { link = false, default = {"Nicknames for countries"}, }, ["NICKNAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR place"] = { link = false, default = {"Nicknames for places"}, }, ["NICKNAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR state"] = { link = false, default = {"Nicknames for states"}, }, ["NICKNAME_FOR town"] = { link = false, default = {"Nicknames for cities"}, }, ---------- Obsolete forms ---------- ["obsolete forms of places!"] = { full_category_link = "{{glossary|obsolete}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "obsolete forms", bare_category_parent = "places", }, ["OBSOLETE_FORM_OF place"] = { link = false, default = {"Obsolete forms of places"}, }, ---------- Official names ---------- ["official names of countries!"] = { full_category_link = "[[official]] [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "official names of places", }, ["official names of former countries!"] = { full_category_link = "[[official]] [[name]]s of [[country|countries]] that no longer [[exist]]", bare_category_breadcrumb = "countries", bare_category_parent = "official names of former places", }, ["official names of former places!"] = { full_category_link = "[[official]] [[name]]s of [[place]]s that no longer [[exist]]", bare_category_breadcrumb = "official names", bare_category_parent = "former places", addl_bare_category_parents = {{name = "official names of places", sort = "former"}}, }, ["official names of places!"] = { full_category_link = "[[official]] [[name]]s of [[place]]s", bare_category_breadcrumb = "official names", bare_category_parent = "places", }, ["OFFICIAL_NAME_OF country"] = { link = false, default = {"Official names of countries"}, }, ["OFFICIAL_NAME_OF FORMER country"] = { link = false, default = {"Official names of former countries"}, }, ["OFFICIAL_NAME_OF FORMER place"] = { link = false, default = {"Official names of former places"}, }, ["OFFICIAL_NAME_OF place"] = { link = false, default = {"Official names of places"}, }, ---------- Official nicknames ---------- ["official nicknames for places!"] = { full_category_link = "[[official]] [[nickname]]s for [[place]]s", bare_category_breadcrumb = "official", bare_category_parent = "nicknames for places", }, ["official nicknames for states!"] = { -- For categorizing official nicknames for states of e.g. the United States full_category_link = "[[official]] [[nicknames]] for [[state]]s", bare_category_breadcrumb = "official", bare_category_parent = "nicknames for states", addl_bare_category_parents = {"states"}, }, ["OFFICIAL_NICKNAME_FOR place"] = { link = false, default = {"Official nicknames for places"}, }, ["OFFICIAL_NICKNAME_FOR state"] = { link = false, default = {"Official nicknames for states"}, }, } export.plural_placetype_to_singular = {} for sg_placetype, spec in pairs(export.placetype_data) do if spec.plural then export.plural_placetype_to_singular[spec.plural] = sg_placetype end end return export 0i5icp7fj8km7659tytty7f31iboenv 88793 88792 2026-08-06T18:28:27Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:place/placetypes]] 88792 Scribunto text/plain local export = {} export.force_cat = false -- set to true for testing local m_locations = require("Module:place/locations") local m_links = require("Module:links") local m_table = require("Module:table") local m_strutils = require("Module:string utilities") local debug_track_module = "Module:debug/track" local en_utilities_module = "Module:en-utilities" local dump = mw.dumpObject local insert = table.insert local concat = table.concat local internal_error = m_locations.internal_error export.internal_error = internal_error local process_error = m_locations.process_error export.process_error = process_error local unpack = unpack or table.unpack -- Lua 5.2 compatibility local ucfirst = m_strutils.ucfirst local ulower = m_strutils.lower local rmatch = m_strutils.match local split = m_strutils.split --[==[ intro: This module contains placetype data used by [[Module:place]] and {{tl|place}}, along with a significant amount of code to work with both placetypes and locations, as well as some placename-related info (FIXME: Consider moving it to [[Module:place/locations]]). See also [[Module:place/locations]], which has definitions of all known locations. You must currently load this module using {{cd|require()}}, not using {{cd|mw.loadData()}}. In particular, it contains two fundamental and tricky functions: # `get_placetype_equivs`, which finds the equivalent placetypes to look under in order to find a given property, and in the process correctly handles placetypes with qualifiers (including qualifiers that act similar to "type-raising" operators in that they do something non-trivial to the placetype to their right) as well as form-of directives and fallbacks. # `find_matching_holonym_location`, which looks up a holonym to find a matching known location, but in the process checks holonyms to the right to make sure there isn't a clash between the user-specified containing holonyms and the containers of the known location being considered. This is done to prevent overcategorizing when either there are two known locations with the same name (e.g. Birmingham in England and Birmingham, Alabama in the US), or more generally two locations with the same name, one of which is a known location but where the other is not (e.g. we're processing non-known-location Mérida, Spain and don't want it categorized like known location Mérida, Yucatán, Mexico). Both of these functions are invoked repeatedly, and probably are invoked several times on the same inputs and as a result are candidates for memoization to speed up the operation of {{tl|place}}. ]==] ------------------------------------------------------------------------------------------ -- Basic utilities -- ------------------------------------------------------------------------------------------ --[==[ Return true if `force_cat` is set either in this module or in [[Module:place/locations]]. ]==] function export.get_force_cat() return export.force_cat or m_locations.force_cat end -- Add the page to a tracking "category". To see the pages in the "category", -- go to [[Wiktionary:Tracking/place/PAGE]] and click on "What links here". local function track(page) require(debug_track_module)("place/" .. page) return true end function export.remove_links_and_html(text) text = m_links.remove_links(text) return text:gsub("<.->", "") end --[==[ Return the singular version of a maybe-plural placetype, or nil if not plural. This correctly handles placetypes with irregular plurals such as `kibbutzim` plural of `kibbutz` by looking up in a table constructed from the `plural` values specified in `placetype_data`. If a special plural value is not found, the regular singularization algorithm in [[Module:en-utilities]] is invoked, which reverses the y -> ies change after vowels and the 'es' addition after sh/ch/x, and otherwise just subtracts a final 's' (which will incorrectly generate 'passe' for plural 'passes'; FIXME: consider changing this for words ending in '-sses'). If the generated singular is the same as the passed-in value, nil is returned. ]==] function export.maybe_singularize_placetype(placetype) if not placetype then return nil end if export.plural_placetype_to_singular[placetype] then return export.plural_placetype_to_singular[placetype] end local retval = require(en_utilities_module).singularize(placetype) if retval == placetype then return nil end return retval end -- Return the correct plural of a placetype, and (if `do_ucfirst` is given) make the first letter uppercase. We first -- look up the plural in `placetype_data`, falling back to pluralize() in [[Module:en-utilities]], which is almost -- always correct. function export.pluralize_placetype(placetype, do_ucfirst) local ptdata = export.placetype_data[placetype] if ptdata and ptdata.plural then placetype = ptdata.plural else placetype = require(en_utilities_module).pluralize(placetype) end if do_ucfirst then return ucfirst(placetype) else return placetype end end --[==[ Get the data associated with a placetype, which may be in its singular or plural form. If `from_category` is specified, we also look for category-only placetypes (generally plural) followed by `!`. Return three values: (a) the placetype under which the data can be looked up (i.e. in its singular form if the passed-in `placetype` is plural and did not match a category-only placetype followed by `!`); (b) the placetype data structure; (c) the type of `placetype` match that occurred, one of `"direct"` if the canonical placetype is the same as the passed-in `placetype` and also the same as the key under which `ptdata` was looked up, or `"direct-category"` if the `ptdata` was looked up under a key formed from the passed-in `placetype` by adding `!`, or `"plural"` if the `ptdata` was looked up under the singularized version of the plural passed-in `placetype`. ]==] function export.get_placetype_data(placetype, from_category) local ptdata = export.placetype_data[placetype] if ptdata then return placetype, ptdata, "direct" end if from_category then ptdata = export.placetype_data[placetype .. "!"] if ptdata then return placetype .. "!", ptdata, "direct-category" end end local sg_placetype = export.maybe_singularize_placetype(placetype) if sg_placetype then ptdata = export.placetype_data[sg_placetype] if ptdata then return sg_placetype, ptdata, "plural" end end return nil end --[==[ Check for special pseudo-placetypes that should be ignored for categorization purposes. ]==] function export.placetype_is_ignorable(placetype) return placetype == "and" or placetype == "or" or placetype:find("^%(") end function export.resolve_placetype_aliases(placetype) return export.placetype_aliases[placetype] or placetype end --[==[ Return a property from `placetype_data` for a given placetype. If the placetype isn't found in `placetype_data`, or the key isn't found in the placetype's entry in `placetype_data`, return nil. ]==] function export.get_placetype_prop(placetype, key) -- Usually we are called on equivalent placetypes returned from `get_placetype_equivs`, in which case placetype -- aliases have been resolved, but sometimes not, e.g. when fetching the indefinite article in -- get_placetype_article(). `resolve_placetype_aliases` is just a simple lookup and it doesn't hurt to do it twice. placetype = export.resolve_placetype_aliases(placetype) if export.placetype_data[placetype] then return export.placetype_data[placetype][key] else return nil end end --[==[ Given a placetype, split the placetype into one or more potential ''splits'', each consisting of a three-element list { {``prev_qualifiers``, ``this_qualifier``, ``reduced_placetype``}}, i.e. # the concatenation of zero or more previously-recognized qualifiers on the left, normally canonicalized (if there are zero such qualifiers, the value will be nil); # a single recognized qualifier, normally canonicalized (if there is no qualifier, the value will be nil); # the "reduced placetype" on the right. Splitting between the qualifier in (2) and the reduced placetype in (3) happens at each space character, proceeding from left to right, and stops if a qualifier isn't recognized. All placetypes are canonicalized by checking for aliases in `placetype_aliases`, but no other checks are made as to whether the reduced placetype is recognized. Canonicalization of qualifiers does not happen if `no_canon_qualifiers` is specified. For example, given the placetype `"small beachside unincorporated community"`, the return value will be { { {nil, nil, "small beachside unincorporated community"}, {nil, "small", "beachside unincorporated community"}, {"small", "[[beachfront]]", "unincorporated community"}, {"small [[beachfront]]", "[[unincorporated]]", "community"}, }} Here, `"beachside"` is canonicalized to `"[[beachfront]]"` and `"unincorporated"` is canonicalized to `"[[unincorporated]]"`, in both cases according to the entry in `placetype_qualifiers`. On the other hand, if given `"small former haunted community"`, the return value will be { { {nil, nil, "small former haunted community"}, {nil, "small", "former haunted community"}, {"small", "former", "haunted community"}, }} because `"small"` and `"former"` but not `"haunted"` are recognized as qualifiers. Finally, if given `"former adr"`, the return value will be { { {nil, nil, "former adr"}, {nil, "former", "administrative region"}, }} because `"adr"` is a recognized placetype alias for `"administrative region"`. ]==] function export.split_qualifiers_from_placetype(placetype, no_canon_qualifiers) local splits = {{nil, nil, export.resolve_placetype_aliases(placetype)}} local prev_qualifier = nil while true do local qualifier, reduced_placetype = placetype:match("^(.-) (.*)$") if qualifier then local canon = export.placetype_qualifiers[qualifier] if canon == nil then break end local new_qualifier = qualifier if type(canon) == "table" then canon = canon.link end if not no_canon_qualifiers and canon ~= false then if canon == true then new_qualifier = "[[" .. qualifier .. "]]" else new_qualifier = canon end end insert(splits, {prev_qualifier, new_qualifier, export.resolve_placetype_aliases(reduced_placetype)}) prev_qualifier = prev_qualifier and prev_qualifier .. " " .. new_qualifier or new_qualifier placetype = reduced_placetype else break end end return splits end --[==[ Given a `placetype` (which may be pluralized), return an ordered list of equivalent placetypes to look under to find the placetype's properties (such as the category or categories to be inserted). The return value is actually an ordered list of objects of the form `{qualifier=``qualifier``, placetype=``equiv_placetype``}` where ``equiv_placetype`` is a placetype whose properties to look up, derived from the passed-in placetype or from a contiguous subsequence of the words in the passed-in placetype (always including the rightmost word in the placetype, i.e. we successively chop off qualifier words from the left and use the remainder to find equivalent placetypes). ``qualifier`` is the remaining words not part of the subsequence used to find ``equiv_placetype``; or nil if all words in the passed-in placetype were used to find ``equiv_placetype``. (FIXME: This qualifier is not currently used anywhere.) Only placetypes for which there is an entry in `placetype_data` are included. The placetype passed in is always checked first, and will form the first entry if it exists in `placetype_data`. '''NOTE:''' This is a tricky function as it implements handling of (a) qualifiers, (b) fallback logic, (c) "type-raising" qualifiers such as `former`/`ancient`/etc. as well as `fictional` and `mythological`, and (d) form-of directives, which act somewhat similarly to `former`, and allows interaction between more than one of these simultaneously (e.g. official names of former places, which have their own categorization). If {{tl|place}} gets too slow, one potential speedup is to memoize the results of this function, as it appears to be getting called more than once on the same inputs. Another similar potential speedup is to memoize the results of `iterate_matching_holonym_location()`. For example, given the placetype `left tributary`, the following placetype/qualifier combinations are checked in turn: ``` {qualifier = nil, placetype="left tributary"} {qualifier = "left", placetype="tributary"} {qualifier = "left", placetype="river"} ``` and the return value will be { { {qualifier = "left", placetype="tributary"}, {qualifier = "left", placetype="river"}, }} The algorithm first enters the placetype itself into the list, then checks for `left tributary` as a recognized placetype in `placetype_data` and doesn't find it, so it doesn't enter it into the returned list (if it found it, it would add it as well as any fallbacks directly after it). It then splits off the recognized qualifier `left` to form the ''reduced placetype'' `tributary`, which is entered into the list because it is found in `placetype_data`. Then, because it has a fallback `river`, which exists in `placetype_data`, the fallback is entered next. Another example is `small rural fraziones` (where a ''frazione'' is type of subdivision of a ''comune'' or municipality, often specifically an outlying hamlet). the placetype/qualifier combinations checked are: ``` {qualifier = nil, placetype="small rural fraziones"} {qualifier = nil, placetype="small rural frazione"} {qualifier = "small", placetype="rural fraziones"} {qualifier = "small", placetype="rural frazione"} {qualifier = "small [[rural]]", placetype="fraziones"} {qualifier = "small [[rural]]", placetype="frazione"} {qualifier = "small [[rural]]", placetype="hamlet"} {qualifier = "small [[rural]]", placetype="village"} ``` The return value ends up as {qualifier = "small [[rural]]", placetype="frazione"}, {qualifier = "small [[rural]]", placetype="hamlet"}, {qualifier = "small [[rural]]", placetype="village"}, }} Here, because the result of singularizing `fraziones` returns a different value from the placetype itself, that singularized value is checked after the original plural value. Also, in the process of splitting off qualifiers, they are canonicalized if the entry in `placetype_qualifiers` says to do so; in this case, links are placed around `rural`. Finally, `frazione` has `hamlet` as its fallback, which in turn has `village` as its fallback, so both fallbacks end up being returned. `no_fallback`, if set, disables returning equivalent placetypes based on the `fallback` setting for a placetype. This is used in the first of two loops in find_placetype_cat_specs() in [[Module:place]] to prefer exact matches for placetypes such as barangays with later holonyms to matches based on a fallback such as `neighborhood` with an earlier holonym. See the comment in that function in [[Module:place]] for a more detailed explanation of why this is needed. Only the placetype itself, and any reduced placetypes created by chopping off recognized qualifiers at the beginning, are returned; but we do not return reduced placetypes if a containing placetype exists in `placetype_data`. (For example, `"overseas territory"` has a fallback `"dependent territory"`, and `"overseas"` is also a recognized qualifier. When `no_fallback` is in place, without the above proviso, we would return `"overseas territory"` followed by `"territory"` with the incorrect effect of classifying an `"overseas territory"` of the United Kingdom such as `"Gibraltar"` under [[:Category:Territories of the United Kingdom]] instead of [[:Category:Dependent territories of the United Kingdom]].) As an exception, if `historical`, `ancient`, `former` or the like are found, they proceed ignoring `no_fallback`, because it seems tricky to handle them correctly in the presence of `no_fallback`, and historical/former placetypes rarely occur with exact match category specs anyway. `no_split_qualifiers` prevents splitting off recognized qualifiers and returning the remainder of the placetype as an equivalent placetype. Only the passed-in placetype, and any fallbacks, will be returned. This is used in [[Module:category tree/topic cat/data/Places]] when looking up placetypes found in categories. Such placetypes won't have qualifiers and so it doesn't make sense to try and look for them. `from_category`, if set, causes category-only placetypes (those ending in `!`) to also be checked. `form_of_directive`, if set, causes the specified form-of directive (e.g. `FORMER_NAME_OF`) to be prepended to checked placetypes, their directive-specific type (e.g. `FORMER_NAME_OF_type`), and their classes (`class`) to get the appropriate placetypes to check for form-of-directive categories. It falls back to the prepended generic `place` as a placetype, e.g. `FORMER_NAME_OF place`, if nothing else matches. `no_check_for_inherently_former` is used internally to prevent an infinite loop when checking for `inherently_former`. `register_former_as_non_former` is a major hack used in `get_bare_categories` to deal with the mismatch between e.g. known location `Yugoslavia` declaring itself a `country` but definitions of it declaring it a `former country`. It causes the non-former version of the specified placetype to be included in the returned equivalents along with the former placetypes. [FIXME: This should apply only to the entries in `former_countries` but it's tricky to do that now; fix this in the known-location refactor. -- The known-location refactor is already done but we haven't yet fixed this.] ]==] function export.get_placetype_equivs(placetype, props) local no_fallback, no_split_qualifiers, no_check_for_inherently_former, from_category, register_former_as_non_former local form_of_directive if props then no_fallback, no_split_qualifiers, no_check_for_inherently_former, from_category, register_former_as_non_former = props.no_fallback, props.no_split_qualifiers, props.no_check_for_inherently_former, props.from_category, props.register_former_as_non_former form_of_directive = props.form_of_directive end local equivs = {} -- Insert `placetype` into `equivs`, along with any fallback placetypes listed in `placetype_data`. `qualifier` is -- the preceding qualifier to insert into `equivs` along with the placetype (see comment at top of function). If -- `from_category` is given, we also check for a category-specific entry consisting of the placetype followed by -- `!`, and in all cases we also check to see if `placetype` is plural, and if so, insert the singularized version -- along with its fallbacks (if any) in `placetype_data`. `form_of_prefix` is a form-of prefix such as -- `OFFICIAL_NAME_OF`. If specified, we check the fallbacks of `placetype` without the prefix but then insert into -- `equivs` the prefixed placetype. This way, if the user says e.g. {{tl|place|pt|@official name of:Cuba|island country|r/Caribbean}}, -- we will correctly categorize into [[:Category:Official names of countries]], rather than only trying to look up -- `OFFICIAL_NAME_OF island country` and failing, falling back ultimately to [[:Category:Official names of places]]. local function insert_placetype_and_fallbacks(qualifier, placetype, form_of_prefix) local function insert_equiv(pt) if form_of_prefix then -- Let's say the user says {{tl|place|pt|@official name of:Cuba|island country|r/Caribbean}} and we have -- no entry for `OFFICIAL_NAME_OF island country` but we do for `OFFICIAL_NAME_OF country` (which we end -- up processing because `island country` falls back to `country`), and that entry in turn is defined -- using a fallback. We have to insert that fallback-of-fallback, and the easiest/cleanest way of -- handling this is by calling ourselves recursively. insert_placetype_and_fallbacks(qualifier, form_of_prefix .. " " .. pt) else insert(equivs, {qualifier=qualifier, placetype=pt}) end end -- Insert the placetype, along with any fallbacks. local canon_placetype, ptdata, ptmatch = export.get_placetype_data(placetype, from_category) if ptdata then insert_equiv(canon_placetype) if no_fallback then return end local first_placetype = #equivs + 1 local prev_placetype = nil while true do local pt_value = export.placetype_data[canon_placetype] if not pt_value then internal_error("Fallback value %s specified for placetype %s but is not in `placetype_data`", canon_placetype, prev_placetype) end if pt_value.fallback then insert_equiv(pt_value.fallback) local last_placetype = #equivs if last_placetype - first_placetype >= 10 then local fallback_loop = {} for i = first_placetype, last_placetype do insert(fallback_loop, equivs[i].placetype) end internal_error("Apparent loop in fallback chain: %s", table.concat(fallback_loop, " -> ")) end prev_placetype = canon_placetype canon_placetype = pt_value.fallback else break end end end end -- Insert `placetype` into `equivs`, along with any fallback placetypes listed in `placetype_data`. This is a -- wrapper around the more basic `insert_placetype_and_fallbacks()` which handles form-of directives. If there is no -- form-of directive, this function directly calls `insert_placetype_and_fallbacks()`. We do things this way so that -- form-of directives correctly combine with `former`-type qualifiers. Note that we also have special backups for -- form-of directives that check `DIRECTIVE place` (and before that, `DIRECTIVE FORMER/ANCIENT place` is there's a -- `former`-type directive); these backups live outside this function because we want them done once, late, rather -- than in each invocation of `process_and_insert_placetype()`. local function process_and_insert_placetype(qualifier, reduced_placetype) if form_of_directive then -- First check for e.g. `OFFICIAL_NAME_OF island country` and its fallbacks; then we look for fallbacks of -- `island country` and check e.g. `OFFICIAL_NAME_OF country` and its fallbacks. All of this is handled by -- `insert_placetype_and_fallbacks()` with appropriate parameters. After that, check the general class of -- the directive, e.g. `subpolity` if something like `district` is given. (Eventually, we check for -- `OFFICIAL_NAME_OF place` as a backup, but this happens at the end outside the loop over qualifiers.) insert_placetype_and_fallbacks(qualifier, reduced_placetype, form_of_directive) if not no_fallback then local reduced_placetype_equivs = export.get_placetype_equivs(reduced_placetype) local directive_type = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.get_placetype_prop(pt, form_of_directive .. "_type") or export.get_placetype_prop(pt, "class") end ) if not directive_type then local pt_data = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.placetype_data[pt] end ) if pt_data then internal_error("For placetype %s in conjunction with form-of directive %s, placetype data " .. 'located but directive-specific type property %s missing, and so is "class"; ' .. "placetypes searched are %s", reduced_placetype, form_of_directive, form_of_directive .. "_type", reduced_placetype_equivs) else -- This should be allowed, as we allow unrecognized placetypes in general. end elseif directive_type ~= "!" then insert_placetype_and_fallbacks(qualifier, directive_type, form_of_directive) end end else insert_placetype_and_fallbacks(qualifier, reduced_placetype) end end -- Successively split off recognized qualifiers and loop over successively greater sets of qualifiers from the left -- (unless `no_split_qualifiers` is specified, in which case we don't check for qualifiers). local splits if no_split_qualifiers then splits = {{nil, nil, export.resolve_placetype_aliases(placetype)}} else splits = export.split_qualifiers_from_placetype(placetype) end for _, split in ipairs(splits) do local prev_qualifier, this_qualifier, reduced_placetype = unpack(split, 1, 3) -- If a special "former" qualifier like `former` or `historical` isn't present, and -- `no_check_for_inherently_former` is not given (this flag is used to avoid infinite loops), check for -- "inherently former" placetypes like `satrapy` and `treaty port` that always refer to no-longer-existing -- placetypes, and handle accordingly. local unlinked_this_qualifier if this_qualifier and this_qualifier:find("%[") then unlinked_this_qualifier = export.remove_links_and_html(this_qualifier) else unlinked_this_qualifier = this_qualifier end local former_qualifiers = this_qualifier and export.former_qualifiers[unlinked_this_qualifier] or nil if not former_qualifiers and not no_check_for_inherently_former then former_qualifiers = export.get_equiv_placetype_prop(reduced_placetype, function(pt) return export.get_placetype_prop(pt, "inherently_former") end, {no_check_for_inherently_former = true}) end -- If a special "former" qualifier like `former` or `historical` is present, map it to the appropriate internal -- qualifiers (`ANCIENT` and/or `FORMER`, which are written in all-caps to distinguish them from user-specified -- qualifiers), fetch the `former_type` property, and treat the placetype as if a concatenation of the mapped -- qualifier(s) and the value of `former_type`. For example, if `medieval village` is given, we map `medieval` -- to `ANCIENT` and `FORMER`, and `village` to its `former_type` of `settlement`, and enter the placetypes -- `ANCIENT settlement` and `FORMER settlement` (in that order) into `equivs`. If the placetype following the -- "former" qualifier is recognized in `placetype_data` but has no `former_type` and no fallback with a -- `former_type` specified, it is an internal error; but if the placetype isn't recognized (e.g. something like -- `former greenhouse` is specified and we don't have an entry for `greenhouse`), just track the occurrence and -- don't enter anything into `equivs`. if former_qualifiers then -- FIXME: Should we respect `no_fallback` here? My instinct says no. local reduced_placetype_equivs = export.get_placetype_equivs(reduced_placetype, { no_check_for_inherently_former = true }) local former_type = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.get_placetype_prop(pt, "former_type") or export.get_placetype_prop(pt, "class") end ) if not former_type then local pt_data = export.get_equiv_placetype_prop_from_equivs(reduced_placetype_equivs, function(pt) return export.placetype_data[pt] end ) if pt_data then internal_error("For placetype %s, placetype data located but `former_type` missing; " .. "placetypes searched are %s", reduced_placetype, reduced_placetype_equivs) else -- Enable error when we've verified there aren't any examples. track("bad-former-placetype") track("bad-former-placetype/" .. reduced_placetype) --process_error("For placetype '%s', unrecognized placetype following 'former'-type " .. -- "qualifier; searched placetype(s) %s", reduced_placetype, dump(reduced_placetype_equivs)) end elseif former_type ~= "!" then -- First check directly for `ANCIENT/FORMER` + the original following placetype. This makes it possible -- for (e.g.) former provinces of the Roman empire to be categorized specially. for _, former_qualifier in ipairs(former_qualifiers) do process_and_insert_placetype(prev_qualifier, former_qualifier .. " " .. reduced_placetype) end for _, former_qualifier in ipairs(former_qualifiers) do process_and_insert_placetype(prev_qualifier, former_qualifier .. " " .. former_type) end -- HACK! See explanation above for `register_former_as_non_former`. if register_former_as_non_former then process_and_insert_placetype(prev_qualifier, reduced_placetype) end -- If we're processing a form-of directive, after doing everything else we do -- `DIRECTIVE ANCIENT/FORMER place` e.g. `OFFICIAL_NAME_OF FORMER place` as a backup. if form_of_directive and not no_fallback then for _, former_qualifier in ipairs(former_qualifiers) do insert_placetype_and_fallbacks(prev_qualifier, form_of_directive .. " " .. former_qualifier .. " place") end end -- Don't continue processing equivs. The reason is probably the same as the `break` below for -- qualifier_to_placetype_equivs[]; categories for `former BLAH` are set using `default`, and -- non-former equivs will otherwise take precedence. break end end -- Then see if the rightmost split-off qualifier is in qualifier_to_placetype_equivs -- (e.g. 'fictional *' -> 'fictional location'). If so, add the mapping. if this_qualifier and export.qualifier_to_placetype_equivs[unlinked_this_qualifier] then insert(equivs, { qualifier=prev_qualifier, placetype=export.qualifier_to_placetype_equivs[unlinked_this_qualifier] }) -- Don't continue processing equivs; otherwise, if we specify 'mythological city', even though the -- equivalent entry for 'mythological location' gets inserted ahead of the entry for 'city', the -- latter ends up generating the category because the category for 'mythological location' is set as -- the default value, which is used only when no non-default category can be found. break end -- Finally, join the rightmost split-off qualifier to the previously split-off qualifiers to form a combined -- qualifier, and add it along with reduced_placetype and any mapping in placetype_data for reduced_placetype. -- NOTE: The first time through this loop, both `prev_qualifier` and `this_qualifier` are nil, and this inserts -- the full placetype into `equivs`. local qualifier = prev_qualifier and prev_qualifier .. " " .. this_qualifier or this_qualifier process_and_insert_placetype(qualifier, reduced_placetype) -- If `no_fallback` and there's an entry in `placetype_data` for this placetype, don't include any reduced -- placetypes to avoid the "overseas territory treated as a territory" issue describe above. if no_fallback then local canon_placetype, ptdata, ptmatch = export.get_placetype_data(reduced_placetype, from_category) if canon_placetype then break end end end -- If we're processing a form-of directive, after doing everything else we do `DIRECTIVE place` e.g. -- `OFFICIAL_NAME_OF place` as a backup; but only if either the placetype as a whole is recognized or the placetype -- begins with a recognized qualifier. This latter check is to avoid categorizing into e.g. -- [[Category:en:Former names of places]] in an invocation like -- {{place|en|@former name of:Democratic Republic of the Congo|country|r/Central Africa|;|used from 1971–1997}}; -- the `used from 1971–1997` gets treated as a placetype and we're called on it. if form_of_directive and not no_fallback and (splits[2] or export.get_placetype_data(placetype, from_category)) then insert_placetype_and_fallbacks(nil, form_of_directive .. " place") end return equivs end function export.get_equiv_placetype_prop_from_equivs(equivs, fun, continue_on_nil_only) for _, equiv in ipairs(equivs) do local retval = fun(equiv.placetype) if continue_on_nil_only and retval ~= nil or not continue_on_nil_only and retval then return retval, equiv end end return nil, nil end --[==[ Given a placetype `placetype` and a function `fun` of one argument, iteratively call the function on equivalent placetypes fetched from `get_placetype_equivs` until the function returns a non-falsy value (i.e. not {nil} or {false}); but if `continue_on_nil_only` is specified, the iterations continue until the function returns non non-{nil} value. FIXME: We should make `continue_on_nil_only` the default; but this requires changing some callers.) When `fun` returns a non-falsy or non-{nil} value, `get_equiv_placetype_prop` returns two values: the value returned by `fun` and the equivalent placetype that triggered the non-falsy (or non-{nil}) return value. If `fun` never returns a non-falsy (or non-{nil}) value, `get_equiv_placetype_prop` returns {nil} for both return values. If `placetype` is passed in as {nil}, the return value is the result of calling `fun` on {nil} (whatever it is) with {nil} for the second return value. ]==] function export.get_equiv_placetype_prop(placetype, fun, props) if not placetype then return fun(nil), nil end return export.get_equiv_placetype_prop_from_equivs(export.get_placetype_equivs(placetype, props), fun, props and props.continue_on_nil_only) end --[==[ Return the article that is used with an entry placetype. We proceed as follows: # See if there is a recognized qualifier at the beginning that specifies an article (including `false` for no article). This takes precedence over anything else, so that e.g. `various capitals` gets no article rather than "`the"`. # Then check the placetype or any equivalent placetype for the `entry_placetype_use_the` property, indicating that `"the"` should be used. # Otherwise we look to see if the placetype itself (not any equivalents, even those involving deleting a qualifier from the beginning) has an entry in `placetype_data` that specifies the indefinite article using `entry_placetype_use_the` (principally for use with placetypes like `union territory`). # Otherwise, we use [[Module:en-utilities]] to apply the standard algorithm to generate `"an"` for words beginning with a vowel and `"a"` otherwise. If `ucfirst` is true, the first letter of the article is made upper-case. ]==] function export.get_placetype_article(placetype, ucfirst) local art local qualifier, reduced_placetype = placetype:match("^(.-) (.*)$") if qualifier then local canon = export.placetype_qualifiers[qualifier] if type(canon) == "table" then art = canon.article end end if art == false then return art end if art == nil then local placetype_use_the = export.get_equiv_placetype_prop(placetype, function(pt) return export.get_placetype_prop(pt, "entry_placetype_use_the") end) if placetype_use_the then art = "the" else art = export.get_placetype_prop(placetype, "entry_placetype_indefinite_article") if not art then art = require(en_utilities_module).get_indefinite_article(placetype) end end end if ucfirst then art = m_strutils.ucfirst(art) end return art end --[==[ Return the preposition that should be used after `placetype` when occurring as an entry placetype or in categories (e.g. `city >in< France` but `country >of< South America`). The preposition defaults to `"in"` if not specified. ]==] function export.get_placetype_entry_preposition(placetype) local pt_prep = export.get_equiv_placetype_prop(placetype, function(pt) return export.get_placetype_prop(pt, "preposition") end ) return pt_prep or "in" end --[==[ Given a place desc (see top of file) and a holonym object (see top of file), add a key/value into the place desc's `holonyms_by_placetype` field corresponding to the placetype and placename of the holonym. For example, corresponding to the holonym "c/Italy", a key "country" with the list value {"Italy"} will be added to the place desc's `holonyms_by_placetype` field. If there is already a key with that place type, the new placename will be added to the end of the value's list. ]==] function export.key_holonym_into_place_desc(place_desc, holonym) if not holonym.placetype then return end -- Key in equivalent placetypes, so that e.g. `cities/San Francisco` gets keyed under `city`; but don't do -- fallbacks, as it doesn't seem correct for the "do other holonyms of the same placetype" algorithm to do holonyms -- of different types just because they have the same fallback. local equiv_placetypes = export.get_placetype_equivs(holonym.placetype, {no_fallback = true}) local unlinked_placename = holonym.unlinked_placename for _, equiv in ipairs(equiv_placetypes) do local placetype = equiv.placetype if not place_desc.holonyms_by_placetype then place_desc.holonyms_by_placetype = {} end if not place_desc.holonyms_by_placetype[placetype] then place_desc.holonyms_by_placetype[placetype] = {unlinked_placename} else insert(place_desc.holonyms_by_placetype[placetype], unlinked_placename) end end end --[=[ Construct a formatted link from the raw link spec `link` given the canonical singular placetype `sg_placetype`. If the placetype was originally plural, `orig_placetype` should contain this plural value; otherwise it should be nil. This will construct the appropriate type of link that displays as `orig_placetype` (or otherwise `sg_placetype`) but links to whatever the `link` spec specifies (which may be `sg_placetype`, a Wikipedia article, etc.). `ptdata` is the placetype data structure for the placetype, and `from_category` indicates that we are generating the description of a category (otherwise we are generating the display form of an entry placetype). ]=] local function make_placetype_link(link, sg_placetype, orig_placetype, ptdata, from_category, noerror) if not from_category and ptdata.disallow_in_entries then if noerror then return "[not meant to be specified directly, with warning: " .. ptdata.disallow_in_entries .. "]" else process_error("Placetype %s is not meant to be specified directly: " .. ptdata.disallow_in_entries, sg_placetype) end end if link == nil then internal_error("Placetype data present for placetype %s but no link= setting given", sg_placetype) elseif link == true then if orig_placetype then return ("[[%s|%s]]"):format(sg_placetype, orig_placetype) else return ("[[%s]]"):format(sg_placetype) end elseif link == false then process_error("Placetype %s is not meant to be specified directly, but is only for internal use", sg_placetype) elseif link == "w" then return ("[[w:%s|%s]]"):format(sg_placetype, orig_placetype or sg_placetype) elseif link == "separately" then if orig_placetype then local sg_words = split(sg_placetype, " ") local orig_words = split(orig_placetype, " ") if #sg_words ~= #orig_words then internal_error("Can't construct 'separately' link for plural placetype %s as original placetype %s " .. "has different number of words", orig_placetype, sg_placetype) else for i = 1, #sg_words do if sg_words[i] == orig_words[i] then sg_words[i] = ("[[%s]]"):format(sg_words[i]) else sg_words[i] = ("[[%s|%s]]"):format(sg_words[i], orig_words[i]) end end return concat(sg_words, " ") end else return (sg_placetype:gsub("([^ ]+)", "[[%1]]")) end elseif link:find("^%+") then link = link:sub(2) -- discard initial + return ("[[%s|%s]]"):format(link, orig_placetype or sg_placetype) elseif not orig_placetype then return link else return require(en_utilities_module).pluralize(link) end end --[==[ Get the display form of a placetype by looking it up in `placetype_data`. If the placetype is recognized, or is the plural of a recognized placetype, the corresponding linked display form is returned (with plural placetypes displaying as plural but linked to the singular form of the placetype). Otherwise, return nil. If we're generating the description of a category, `category_type` should be set to one of `"top-level"` (for top-level categories like [[:Category:Neighborhoods]]), `"noncity"` (for non-city categories like [[:Category:Neighborhoods in Illinois, USA]]) or `"city"` (for city categories like [[:Category:Neighborhoods of Chicago]]). Otherwise, we're generating the description for use in formatting a {{tl|place}} call, and category-only placetypes ending in `!` will be ignored, along with special `category_link*` settings. `return_full` is used along with `category_type` and will preferably return the "full" variant of category link settings, i.e. `full_category_link*`; if they don't exist, the `category_link*` value is prepended with `"names of"`. `noerror` says to not throw an error when encountering entry placetypes that would be disallowed. ]==] function export.get_placetype_display_form(placetype, category_type, return_full, noerror) local from_category = not not category_type local canon_placetype, ptdata, ptmatch = export.get_placetype_data(placetype, from_category) if canon_placetype then local raw_link local function is_linked_string(str) return type(str) == "string" and str:find("%[%[") end if category_type then local fetched_full local function fetch_maybe_full(prop) local retval = ptdata["full_" .. prop] if retval ~= nil then if return_full then return retval, true else internal_error("Saw full_" .. prop .. "=%s but `return_full` not set, can't handle", retval) end end return ptdata[prop], false end local function maybe_prefix(str) if return_full and not fetched_full then return "names of " .. str else return str end end -- Careful with `false` as possible value. if category_type == "top-level" then raw_link, fetched_full = fetch_maybe_full("category_link_top_level") elseif category_type == "noncity" then raw_link, fetched_full = fetch_maybe_full("category_link_before_noncity") elseif category_type == "city" then raw_link, fetched_full = fetch_maybe_full("category_link_before_city") else internal_error('Unrecognized value for `category_type` %s, should be "top-level", "noncity" or "city"', category_type) end if type(raw_link) == "string" then return maybe_prefix(raw_link), ptdata elseif raw_link ~= nil then return raw_link, ptdata end raw_link, fetched_full = fetch_maybe_full("category_link") if raw_link == false then return raw_link, ptdata end if is_linked_string(raw_link) then return maybe_prefix(raw_link), ptdata end if ptmatch == "plural" then raw_link, fetched_full = fetch_maybe_full("plural_link") if raw_link == false then return raw_link, ptdata end if is_linked_string(raw_link) then return maybe_prefix(raw_link), ptdata end end if raw_link == nil then raw_link, fetched_full = fetch_maybe_full("link") end if raw_link == false then return raw_link, ptdata end return maybe_prefix(make_placetype_link(raw_link, canon_placetype, placetype ~= canon_placetype and placetype or nil, ptdata, from_category, noerror)), ptdata else if ptmatch == "plural" then raw_link = ptdata.plural_link if raw_link == false then process_error("Placetype %s cannot appear plural", placetype) end if is_linked_string(raw_link) then return raw_link, ptdata end end if raw_link == nil then raw_link = ptdata.link end return make_placetype_link(raw_link, canon_placetype, placetype ~= canon_placetype and placetype or nil, ptdata, from_category, noerror), ptdata end end return nil end local function resolve_unlinked_placename_display_aliases(placetype, placename) local equiv_placetypes = export.get_placetype_equivs(placetype) for i, equiv in ipairs(equiv_placetypes) do equiv_placetypes[i] = equiv.placetype end local all_display_aliases_found = {} local all_others_found = {} for group, key, spec in m_locations.iterate_matching_location { placetypes = equiv_placetypes, placename = placename, alias_resolution = "display", } do if spec.alias_of and spec.display then insert(all_display_aliases_found, {group, key, spec, spec.display_as_full}) else insert(all_others_found, {group, key, spec}) end end if not all_display_aliases_found[1] then return placename elseif all_display_aliases_found[2] then internal_error("Found multiple matching display aliases for placename %s, placetype %s: " .. "all_display_aliases_found=%s, all_others_found=%s", placename, placetype, all_display_aliases_found, all_others_found) elseif all_others_found[1] then internal_error("Found a display alias along with other possible meanings for placename %s, placetype %s: " .. "all_display_aliases_found=%s, all_others_found=%s", placename, placetype, all_display_aliases_found, all_others_found) else local group, key, spec, as_full = unpack(all_display_aliases_found[1]) local full, elliptical = m_locations.key_to_placename(group, key) return as_full and full or elliptical end end --[==[ If `placename` of type `placetype` is a display alias, convert it to its canonical form; otherwise, return unchanged. Display aliases transform certain placenames into canonical displayed forms. For example, if any of `country/US`, `country/USA` or `country/United States of America` (or `c/US`, etc.) are given, the result will be displayed as `United States`. '''NOTE''': Display aliases change what is displayed from what the editor wrote in the Wikitext. As a result, they should (a) be non-political in nature, and (b) not involve a change where the word `the` needs to be added or removed. For example, normalizing `US` and `USA` to `United States` for display purposes is OK but normalizing `Burma` to `Myanmar` is not (instead a cat alias should be used) because the terms `Burma` and `Myanmar` have clear political connotations. Similarly, we have a display alias that maps the old name of `Macedonia` as a country (but not a region!) to `North Macedonia`, but `Republic of Macedonia` is mapped to `North Macedonia` only as a cat alias because the two terms differ in their use of `the`. (For example, if we had a display alias mapping `Republic of Macedonia` to `North Macedonia`, the call {{tl|place|en|the <<capital city>> of the <<c/Republic of Macedonia>>}} would wrongly display as `the [[capital city]] of the [[North Macedonia]]`.) Generally, display normalizations tend to involve alternative forms (e.g. abbreviations, ellipses, foreign spellings) where the normalization improves clarity and consistency. ]==] function export.resolve_placename_display_aliases(placetype, placename) -- If the placename is a link, apply the alias inside the link. -- This pattern matches both piped and unpiped links. If the link is not piped, the second capture (linktext) will -- be empty. local link, linktext = rmatch(placename, "^%[%[([^|%[%]]+)|?([^|%[%]]-)%]%]$") if link then if linktext ~= "" then local alias = resolve_unlinked_placename_display_aliases(placetype, linktext) return "[[" .. link .. "|" .. alias .. "]]" else local alias = resolve_unlinked_placename_display_aliases(placetype, link) return "[[" .. alias .. "]]" end else return resolve_unlinked_placename_display_aliases(placetype, placename) end end --[==[ Generate the "prefixed" version of a bare key, i.e. prefix it with `the` if correct for this key. ]==] function export.get_prefixed_key(key, spec) if spec.the then return "the " .. key else return key end end -- Necessary for use by [[Module:place]]. FIXME: Reorganize the modules so this isn't necessary. export.iterate_matching_location = m_locations.iterate_matching_location --[=[ Iterator that iterates over holonyms in `place_desc`. If `first_holonym_index` is given, start iterating at the specified holonym and stop either when there are no more holonyms or a holonym with modifier `:also` is found. If `first_holonym_index` is nil or omitted, iterate over all holonyms regardless. If `include_raw_text_holonyms` is specified, raw text holonyms (those not of the form `placetype/placename`) are returned as well; they can be identified by the fact that the `placetype` field in the holonym structure is nil. Two values are returned at each iteration, the holonym index and holonym structure, similar to `ipairs()`. ]=] function export.get_holonyms_to_check(place_desc, first_holonym_index, include_raw_text_holonyms) local stop_at_also = not not first_holonym_index return function(place_desc, index) while true do index = index + 1 local this_holonym = place_desc.holonyms[index] -- If we were passed in a starting holonym index, go up to but not including a holonym marked with `:also` -- (continue_cat_loop); the categorization code will then restart the loop at that holonym. That holonym -- will have `:also` marked on it, so make sure not to stop immediately if the first holonym is marked with -- `:also`. if not this_holonym or stop_at_also and index > first_holonym_index and this_holonym.continue_cat_loop then return nil end -- If not placetype, we're processing raw text, which we normally want to skip. if include_raw_text_holonyms or this_holonym.placetype then return index, this_holonym end end end, place_desc, first_holonym_index and first_holonym_index - 1 or 0 end --[==[ If the holonym in `data` (in the format as passed to a category handler) refers to a known location, iterate over all such known locations, returning for each location the corresponding key, spec and group as well as the trail of ancestral containers. Unlike `iterate_matching_location()`, this specifically checks that there is no mismatch between the location's containers at any level and any of the following holonyms in the {{tl|place}} spec. The fields in `data` are: * `holonym_placetype`: The placetype of the holonym. It can actually be a list of possible placetypes, as with `iterate_matching_location()`. * `holonym_placename`: The placename of the holonym. * `holonym_index`: The index of the holonym among the holonyms in `place_desc`, or nil if the holonym is not among the holonyms in `place_desc`. (If a holonym index is given, we check for container mismatches among the holonyms following the specified index, stopping either when encountering a holonym marked with modifier `:also` or, if none exist, when we run out of holonyms. If no holonym index is given, we check all holonyms for container mismatches.) * `place_desc`: Description of the place; used for the holonyms, to check for container mismatches. Returns four values: the location group, the canonical key by which the location is known, the spec object describing the location and the trail of ancestral containers for the location. The first three values are the same as for `iterate_matching_location`. ]==] function export.iterate_matching_holonym_location(data) local holonym_placetype, holonym_placename, holonym_index, place_desc = data.holonym_placetype, data.holonym_placename, data.holonym_index, data.place_desc local matching_location_iterator = m_locations.iterate_matching_location { placetypes = holonym_placetype, placename = holonym_placename, } return function() while true do local group, key, spec = matching_location_iterator() if not group then return nil end local container_trail = {} -- For each level of container, check that there are no mismatches (i.e. other location of the same -- placetype) mentioned. We allow a mismatch at a given level if there's also a match with the container -- at that level. For example, in the case of Kansas City, defined in [[Module:place/locations]] as a city -- in Missouri, if we define it as {{tl|place|city|s/Missouri,Kansas}}, we ignore the mismatching state of -- Kansas because the correct state of Missouri was also mentioned. But imagine we are defining Newark, -- Delaware as {{tl|place|city|s/Delaware|c/US}} and (as is the case) we have an entry for Newark, New -- Jersey in [[Module:place/locations]]. Just because the containing location `US` matches isn't enough, -- because Newark, NJ also has New Jersey as a containing location and there's a mismatch at that level. If -- there are no mismatches at any level we assume we're dealing with the right known location. -- -- If at a given level there are multiple containing locations, we count a match if any holonym matches any -- containing location, and a mismatch only if a holonym exists of the same placetype that doesn't match any -- containing location. local containers_mismatch = false for containers in m_locations.iterate_containers(group, key, spec) do insert(container_trail, containers) local match_at_level = false local mismatch_at_level = false for other_holonym_index, other_holonym in export.get_holonyms_to_check(place_desc, holonym_index and holonym_index + 1 or nil) do local other_source_holonym = other_holonym.augmented_from_holonym if other_source_holonym and other_source_holonym.placetype == holonym_placetype and other_source_holonym.unlinked_placename ~= holonym_placename then -- Ignore holonyms added during the augmentation process for other holonyms of the same -- placetype as the placetype of the holonym we're considering. See comment in -- augment_holonyms_with_container() for why we do this. -- continue; grrr, no 'continue' in Lua else local holonym_matches_at_level = false local holonym_exists_with_same_placetype = false for _, container in ipairs(containers) do if not container.spec.no_check_holonym_mismatch then local full_container_placename, elliptical_container_placename = m_locations.key_to_placename(container.group, container.key) local placetypes = container.spec.placetype if type(placetypes) ~= "table" then placetypes = {placetypes} end local placetype_equivs = {} for _, pt in ipairs(placetypes) do m_table.extend(placetype_equivs, export.get_placetype_equivs(pt)) end local this_holonym_matches = export.get_equiv_placetype_prop_from_equivs( placetype_equivs, function(placetype) return other_holonym.placetype == placetype and (other_holonym.unlinked_placename == full_container_placename or other_holonym.unlinked_placename == elliptical_container_placename) end ) if this_holonym_matches then holonym_matches_at_level = true break end local this_holonym_exists_with_same_placetype = export.get_equiv_placetype_prop_from_equivs( placetype_equivs, function(placetype) return other_holonym.placetype == placetype end ) if this_holonym_exists_with_same_placetype then -- We seem to have a mismatch at this level. But before we decide conclusively that this -- is the case, check to see whether the putative mismatch is an alias and matches when -- we resolve the alias. for oh_group, oh_key, oh_spec, oh_container_trail in export.iterate_matching_holonym_location { holonym_placetype = other_holonym.placetype, holonym_placename = other_holonym.unlinked_placename, holonym_index = other_holonym_index, place_desc = place_desc, } do local oh_full_placename, oh_elliptical_placename = m_locations.key_to_placename(oh_group, oh_key) if oh_full_placename == full_container_placename or oh_elliptical_placename == elliptical_container_placename then -- Alias matched when resolved. this_holonym_matches = true break end end if this_holonym_matches then -- Alias matched above when resolved. holonym_matches_at_level = true break else -- Not an alias, or doesn't match when resolved. We have a true mismatch. holonym_exists_with_same_placetype = true end end end end if holonym_matches_at_level then match_at_level = true break end if holonym_exists_with_same_placetype then mismatch_at_level = true end end end if not match_at_level and mismatch_at_level then containers_mismatch = true break end end if not containers_mismatch then return group, key, spec, container_trail end end end end --[==[ If the holonym in `data` (in the format as passed to a category handler) refers to a known location, find and return the corresponding key, spec and group as well as the trail of ancestral containers. This is like `iterate_matching_holonym_location()` but throws an error if more than one location matches. (An example where this would happen is {{tl|place|en|neighborhood|city/Newcastle}}, because there are two known locations named Newcastle. To fix this, specify additional following disambiguating holonyms, e.g. {{tl|place|en|neighborhood|city/Newcastle|s/New South Wales}}. ]==] function export.find_matching_holonym_location(data) local all_found = {} for group, key, spec, container_trail in export.iterate_matching_holonym_location(data) do insert(all_found, {group, key, spec, container_trail}) end if not all_found[1] then return nil elseif all_found[2] then local holonym_placetype = data.holonym_placetype if type(holonym_placetype) == "table" then holonym_placetype = concat(holonym_placetype, ",") end local found_keys = {} for _, found in ipairs(all_found) do local _, key, _, _ = unpack(found) insert(found_keys, key) end error(("Found multiple matching locations for holonym '%s/%s'; specify disambiguating context in the " .. "containing holonyms: %s"):format(holonym_placetype, data.holonym_placename, dump(found_keys))) else return unpack(all_found[1]) end end ------------------------------------------------------------------------------------------ -- Placename and placetype data -- ------------------------------------------------------------------------------------------ --[==[ var: This is a map from aliases to their canonical forms. Any placetypes appearing as keys here will be mapped to their canonical forms in all respects, including the display form. Contrast entries in 'placetype_data' with a fallback, which applies to categorization and other processes but not to display. The most important aliases are for holonym placetypes, particularly those that occur often such as "country", "state", "province" and the like. Particularly long placetypes that mostly occur as entry placetypes (e.g. "census-designated place") can be given abbreviations, but it is generally preferred to spell out the entry placetype. Note also that we purposely avoid certain abbreviations that would be ambiguous (e.g. "d", which could variously be interpreted as "department", "district" or "division"). ]==] export.placetype_aliases = { ["acomm"] = "autonomous community", ["adr"] = "administrative region", ["adterr"] = "administrative territory", -- Pakistan ["aobl"] = "autonomous oblast", ["aokr"] = "autonomous okrug", ["ap"] = "autonomous province", ["apref"] = "autonomous prefecture", ["aprov"] = "autonomous province", ["ar"] = "autonomous region", ["arch"] = "archipelago", ["arep"] = "autonomous republic", ["aterr"] = "autonomous territory", ["atu"] = "autonomous territorial unit", ["bor"] = "borough", ["c"] = "country", ["can"] = "canton", ["carea"] = "council area", ["cc"] = "constituent country", ["cdblock"] = "community development block", ["cdep"] = "Crown dependency", ["CDP"] = "census-designated place", ["cdp"] = "census-designated place", ["clcity"] = "county-level city", ["co"] = "county", ["cobor"] = "county borough", ["colcity"] = "county-level city", ["coll"] = "collectivity", ["comm"] = "community", ["cont"] = "continent", ["contr"] = "continental region", ["contregion"] = "continental region", ["cpar"] = "civil parish", ["damun"] = "direct-administered municipality", ["dep"] = "dependency", ["department capital"] = "departmental capital", ["dept"] = "department", ["depterr"] = "dependent territory", ["dist"] = "district", ["distmun"] = "district municipality", ["div"] = "division", ["emp"] = "empire", ["fpref"] = "French prefecture", ["gov"] = "governorate", ["govnat"] = "governorate", ["home-rule city"] = "home rule city", ["home-rule municipality"] = "home rule municipality", ["inner-city area"] = "inner city area", ["ires"] = "Indian reservation", ["isl"] = "island", ["lbor"] = "London borough", ["lga"] = "local government area", ["lgarea"] = "local government area", ["lgd"] = "local government district", ["lgdist"] = "local government district", ["metbor"] = "metropolitan borough", ["metcity"] = "metropolitan city", ["metmun"] = "metropolitan municipality", ["mtn"] = "mountain", ["mun"] = "municipality", ["mundist"] = "municipal district", ["nonmetropolitan county"] = "non-metropolitan county", ["obl"] = "oblast", ["okr"] = "okrug", ["p"] = "province", ["par"] = "parish", ["parmun"] = "parish municipality", ["pen"] = "peninsula", ["plcity"] = "prefecture-level city", ["plcolony"] = "Polish colony", ["pref"] = "prefecture", ["prefcity"] = "prefecture-level city", ["preflcity"] = "prefecture-level city", ["prov"] = "province", ["r"] = "region", ["range"] = "mountain range", ["rcm"] = "regional county municipality", ["rcomun"] = "regional county municipality", ["rdist"] = "regional district", ["rep"] = "republic", ["rhrom"] = "rural hromada", ["riv"] = "river", ["rmun"] = "regional municipality", ["robor"] = "royal borough", ["romp"] = "Roman province", ["runit"] = "regional unit", ["rurmun"] = "rural municipality", ["s"] = "state", ["sar"] = "special administrative region", ["shrom"] = "settlement hromada", ["spref"] = "subprefecture", ["sprefcity"] = "sub-prefectural city", ["sprovcity"] = "subprovincial city", ["submet city"] = "sub-metropolitan city", ["submetropolitan city"] = "sub-metropolitan city", ["sub-prefecture-level city"] = "sub-prefectural city", ["sub-provincial city"] = "subprovincial city", ["sub-provincial district"] = "subprovincial district", ["terr"] = "territory", ["terrauth"] = "territorial authority", ["twp"] = "township", ["twpmun"] = "township municipality", ["uauth"] = "unitary authority", ["ucomm"] = "unincorporated community", ["udist"] = "unitary district", ["uhrom"] = "urban hromada", ["uterr"] = "union territory", ["utwpmun"] = "united township municipality", ["val"] = "valley", ["vdc"] = "village development committee", ["vil"] = "village", ["voi"] = "voivodeship", ["wcomm"] = "Welsh community", } local no_link_def_article = {link = false, article = "the"} local no_link_no_article = {link = false, article = false} --[==[ var: These qualifiers can be prepended onto any placetype and will be handled correctly. For example, the placetype `large city` will be displayed as `large <nowiki>[[city]]</nowiki>` and categorized as if `city` were specified. If the value in the following table is a string, the qualifier will display according to the string. If the value is `true`, the qualifier will be linked to its corresponding Wiktionary entry. If the value is `false`, the qualifier will not be linked but will appear as-is. Note that these qualifiers do not override placetypes with entries elsewhere that contain those same qualifiers. For example, the entry for `inland sea` in `placetype_data` will apply in preference to treating `inland sea` as equivalent to `sea`. ]==] export.placetype_qualifiers = { -- generic qualifiers ["huge"] = false, ["tiny"] = false, ["large"] = false, ["big"] = false, ["mid-size"] = false, ["mid-sized"] = false, ["small"] = false, ["sizable"] = false, ["important"] = false, ["long"] = false, ["short"] = false, ["major"] = false, ["minor"] = false, ["high"] = false, ["tall"] = false, ["low"] = false, ["left"] = false, -- left tributary ["right"] = false, -- right tributary ["modern"] = false, -- for use in opposition to "ancient" in another definition -- "former" qualifiers ["abandoned"] = true, ["ancient"] = true, ["deserted"] = true, ["extinct"] = true, ["former"] = false, ["historic"] = "historical", ["historical"] = true, ["medieval"] = true, ["mediaeval"] = true, ["ruined"] = true, ["traditional"] = true, -- sea qualifiers ["coastal"] = true, ["inland"] = true, -- note, we also have an entry in placetype_data for 'inland sea' to get a link to [[inland sea]] ["maritime"] = true, ["overseas"] = true, ["seaside"] = true, ["beachfront"] = true, ["beachside"] = true, ["riverside"] = true, -- lake qualifiers ["freshwater"] = true, ["saltwater"] = true, ["endorheic"] = true, ["oxbow"] = true, ["ox-bow"] = "[[oxbow]]", -- [[ox-bow]] is a red link ["tidal"] = true, -- land qualifiers ["hilltop"] = true, ["hilly"] = true, ["insular"] = true, ["peninsular"] = true, ["chalk"] = true, ["karst"] = true, ["limestone"] = true, ["mountainous"] = true, ["mountaintop"] = true, ["alpine"] = true, ["volcanic"] = true, -- for an island -- political status qualifiers ["autonomous"] = true, ["incorporated"] = true, ["special"] = true, ["unincorporated"] = true, ["coterminous"] = true, -- monetary status/etc. qualifiers ["fashionable"] = true, ["wealthy"] = true, ["affluent"] = true, ["declining"] = true, -- city vs. rural qualifiers ["urban"] = true, ["suburban"] = true, ["exurban"] = true, ["outlying"] = true, ["remote"] = true, ["rural"] = true, ["outback"] = true, ["inner"] = false, ["inner-city"] = true, ["central"] = false, ["outer"] = false, -- land use qualifiers ["residential"] = true, ["agricultural"] = true, ["business"] = true, ["commercial"] = true, ["industrial"] = true, -- business use qualifiers ["railroad"] = true, ["railway"] = true, ["farming"] = true, ["fishing"] = true, ["mining"] = true, ["logging"] = true, ["cattle"] = true, -- tourism use qualifiers ["resort"] = true, -- note, we also have 'resort city' and 'resort town', that take precedecne ["spa"] = true, -- note, we also have 'spa city' and 'spa town', that take precedecne ["ski"] = true, -- note, we also have 'ski resort city' and 'ski resort town', that take precedecne -- religious qualifiers ["holy"] = true, ["sacred"] = true, ["religious"] = true, ["secular"] = true, -- qualifiers for nonexistent places ["claimed"] = false, ["fictional"] = true, ["legendary"] = true, ["mythical"] = true, ["mythological"] = true, -- directional qualifiers ["northern"] = false, ["southern"] = false, ["eastern"] = false, ["western"] = false, ["north"] = false, ["south"] = false, ["east"] = false, ["west"] = false, ["northeastern"] = false, ["southeastern"] = false, ["northwestern"] = false, ["southwestern"] = false, ["northeast"] = false, ["southeast"] = false, ["northwest"] = false, ["southwest"] = false, -- seasonal qualifiers ["summer"] = true, -- e.g. for 'summer capital' ["winter"] = true, -- legal status qualifiers -- FIXME: Two-word qualifiers don't work yet. But you can enter "de-facto" and it's canonicalized to [[de facto]]. ["official"] = true, ["unofficial"] = true, ["de facto"] = true, -- 'de facto capital' ["de-facto"] = "[[de facto]]", -- [[de-facto]] is a red link ["de jure"] = true, -- 'de jure capital' ["de-jure"] = "[[de jure]]", -- [[de-jure]] is a red link -- NOTE: 'unrecognized/unrecognised' are handled as placetypes 'unrecognized country', 'unrecognized state' -- misc. qualifiers ["planned"] = true, ["chartered"] = true, ["landlocked"] = true, ["uninhabited"] = true, -- superlative qualifiers ["first"] = no_link_def_article, ["second"] = no_link_def_article, -- for "second largest" etc. ["third"] = no_link_def_article, ["fourth"] = no_link_def_article, ["last"] = no_link_def_article, ["only"] = no_link_def_article, ["sole"] = no_link_def_article, ["main"] = no_link_def_article, ["largest"] = no_link_def_article, ["biggest"] = no_link_def_article, ["smallest"] = no_link_def_article, ["shortest"] = no_link_def_article, ["longest"] = no_link_def_article, ["tallest"] = no_link_def_article, ["highest"] = no_link_def_article, ["lowest"] = no_link_def_article, ["leftmost"] = no_link_def_article, ["rightmost"] = no_link_def_article, ["innermost"] = no_link_def_article, ["outermost"] = no_link_def_article, ["northernmost"] = no_link_def_article, ["southernmost"] = no_link_def_article, ["westernmost"] = no_link_def_article, ["easternmost"] = no_link_def_article, ["northwesternmost"] = no_link_def_article, ["southwesternmost"] = no_link_def_article, ["northeasternmost"] = no_link_def_article, ["southeasternmost"] = no_link_def_article, -- several/various ["several"] = no_link_no_article, ["various"] = no_link_no_article, ["numerous"] = no_link_no_article, ["multiple"] = no_link_no_article, ["many"] = no_link_no_article, ["other"] = no_link_no_article, } --[==[ var: In this table, the key qualifiers should be treated the same as the value qualifiers for categorization purposes. This is overridden by `placetype_data` and `qualifier_to_placetype_equivs`. ]==] export.former_qualifiers = { ["abandoned"] = {"FORMER"}, ["ancient"] = {"ANCIENT", "FORMER"}, ["former"] = {"FORMER"}, ["extinct"] = {"FORMER"}, ["historic"] = {"FORMER"}, ["historical"] = {"FORMER"}, ["medieval"] = {"ANCIENT", "FORMER"}, ["mediaeval"] = {"ANCIENT", "FORMER"}, ["ruined"] = {"ANCIENT", "FORMER"}, ["traditional"] = {"FORMER"}, } --[==[ var: In this table, any placetypes containing these qualifiers that do not occur in `placetype_data` should be mapped to the specified placetypes for categorization purposes. Entries here are overridden by `placetype_data`. ]==] export.qualifier_to_placetype_equivs = { ["fictional"] = "fictional location", ["legendary"] = "mythological location", ["mythical"] = "mythological location", ["mythological"] = "mythological location", -- For e.g. Taiwan as a "claimed province" of China; parts of Belize as claimed by Guatemala; various islands -- claimed by various parties in East Asia. FIXME: We should conditionalize on what is being claimed since there are -- also claimed capitals, e.g. Israel and Palestine claim Jerusalem as their capital. ["claimed"] = "claimed political division", } --[==[ var: Mapping from placetypes to the corresponding plural category-only placetype for a capital of that placetype. The reverse mapping also exists. ]==] export.placetype_to_capital_cat = { ["autonomous community"] = "autonomous community capitals", ["canton"] = "cantonal capitals", ["comarca"] = "comarca capitals", ["country"] = "national capitals", -- The following are not obviously different from 'county seats' but the latte terminology is used in the US. ["county"] = "county capitals", ["department"] = "departmental capitals", ["district"] = "district capitals", ["division"] = "division capitals", ["emirate"] = "emirate capitals", ["governorate"] = "governorate capitals", ["hromada"] = "hromada capitals", ["krai"] = "krai capitals", ["metropolitan city"] = "metropolitan city capitals", ["municipality"] = "municipal capitals", ["oblast"] = "oblast capitals", ["okrug"] = "okrug capitals", ["prefecture"] = "prefectural capitals", ["province"] = "provincial capitals", ["raion"] = "raion capitals", ["regency"] = "regency capitals", ["region"] = "regional capitals", ["regional unit"] = "regional unit capitals", ["republic"] = "republic capitals", ["state"] = "state capitals", ["territory"] = "territorial capitals", ["voivodeship"] = "voivodeship capitals", } --[==[ var: This contains placenames that should be preceded by an article (almost always "the"). '''NOTE''': There are multiple ways that placenames can come to be preceded by "the": # Listed here. # Given in [[Module:place/locations]] with an initial "the". All such placenames are added to this map by the code just below the map. # The placetype of the placename has `holonym_use_the = true` in its placetype_data. # A regex in placename_the_re matches the placename. Note that "the" is added only before the first holonym in a place description. ]==] export.placename_article = { -- This should only contain info that can't be inferred from [[Module:place/locations]]. ["archipelago"] = { ["Cyclades"] = "the", ["Dodecanese"] = "the", }, ["country"] = { ["Holy Roman Empire"] = "the", }, ["empire"] = { ["Holy Roman Empire"] = "the", }, ["island"] = { ["North Island"] = "the", ["South Island"] = "the", }, ["region"] = { ["Balkans"] = "the", ["Russian Far East"] = "the", ["Caribbean"] = "the", ["Caucasus"] = "the", ["Middle East"] = "the", ["New Territories"] = "the", ["North Caucasus"] = "the", ["South Caucasus"] = "the", ["West Bank"] = "the", ["Gaza Strip"] = "the", }, ["valley"] = { ["San Fernando Valley"] = "the", }, } --[==[ var: Regular expressions to apply to determine whether we need to put 'the' before a holonym. The key "*" applies to all holonyms, otherwise only the regexes for the holonym's placetype apply. ]==] export.placename_the_re = { -- We don't need entries for peninsulas, seas, oceans, gulfs or rivers -- because they have holonym_use_the = true. ["*"] = {"^Isle of ", " Islands$", " Mountains$", " Empire$", " Country$", " Region$", " District$", "^City of "}, ["bay"] = {"^Bay of "}, ["lake"] = {"^Lake of "}, ["country"] = {"^Republic of ", " Republic$"}, ["republic"] = {"^Republic of ", " Republic$"}, ["region"] = {" [Rr]egion$"}, ["river"] = {" River$"}, ["local government area"] = {"^Shire of "}, ["county"] = {"^Shire of "}, ["Indian reservation"] = {" Reservation", " Nation"}, ["tribal jurisdictional area"] = {" Reservation", " Nation"}, } --[==[ var: If any of the following holonyms are present, the associated holonyms are automatically added to the end of the list of holonyms for categorization (but not display) purposes. ]==] export.cat_implications = { ["region"] = { ["Eastern Europe"] = {"continent/Europe"}, ["Central Europe"] = {"continent/Europe"}, ["Western Europe"] = {"continent/Europe"}, ["South Europe"] = {"continent/Europe"}, ["Southern Europe"] = {"continent/Europe"}, ["Northern Europe"] = {"continent/Europe"}, ["Northeast Europe"] = {"continent/Europe"}, ["Northeastern Europe"] = {"continent/Europe"}, ["Southeast Europe"] = {"continent/Europe"}, ["Southeastern Europe"] = {"continent/Europe"}, ["North Caucasus"] = {"continent/Europe"}, ["South Caucasus"] = {"continent/Asia"}, ["South Asia"] = {"continent/Asia"}, ["Southern Asia"] = {"continent/Asia"}, ["East Asia"] = {"continent/Asia"}, ["Eastern Asia"] = {"continent/Asia"}, ["Central Asia"] = {"continent/Asia"}, ["West Asia"] = {"continent/Asia"}, ["Western Asia"] = {"continent/Asia"}, ["Southeast Asia"] = {"continent/Asia"}, ["North Asia"] = {"continent/Asia"}, ["Northern Asia"] = {"continent/Asia"}, ["Anatolia"] = {"continent/Asia"}, ["Asia Minor"] = {"continent/Asia"}, ["Mesopotamia"] = {"continent/Asia"}, ["North Africa"] = {"continent/Africa"}, ["Central Africa"] = {"continent/Africa"}, ["West Africa"] = {"continent/Africa"}, ["East Africa"] = {"continent/Africa"}, ["Southern Africa"] = {"continent/Africa"}, ["Central America"] = {"continent/Central America"}, ["Caribbean"] = {"continent/North America"}, ["Polynesia"] = {"continent/Oceania"}, ["Micronesia"] = {"continent/Oceania"}, ["Melanesia"] = {"continent/Oceania"}, ["Siberia"] = {"country/Russia", "continent/Asia"}, ["Russian Far East"] = {"country/Russia", "continent/Asia"}, ["South Wales"] = {"constituent country/Wales", "continent/Europe"}, ["Balkans"] = {"continent/Europe"}, ["West Bank"] = {"country/Palestine", "continent/Asia"}, ["Gaza"] = {"country/Palestine", "continent/Asia"}, ["Gaza Strip"] = {"country/Palestine", "continent/Asia"}, } } ------------------------------------------------------------------------------------------ -- Category and display handlers -- ------------------------------------------------------------------------------------------ local function city_type_cat_handler(data) local entry_placetype = data.entry_placetype local generic_before_non_cities = export.get_placetype_prop(entry_placetype, "generic_before_non_cities") if not generic_before_non_cities then internal_error("city_type_cat_handler called on placetype %s that doesn't have a `generic_before_non_cities`" .. " setting", entry_placetype) end local plural_entry_placetype = export.pluralize_placetype(entry_placetype) local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and not spec.is_former_place and not spec.is_city then -- Categorize both in key, and in the larger polity that the key is part of, e.g. [[Hirakata]] goes in both -- "Cities in Osaka Prefecture" and "Cities in Japan". (But don't do the latter if no_container_cat is set.) local cap_plural_entry_placetype = ucfirst(plural_entry_placetype) local retcats = {("%s %s %s"):format(cap_plural_entry_placetype, generic_before_non_cities, export.get_prefixed_key(key, spec))} if container_trail[1] and not spec.no_container_cat then for _, container in ipairs(container_trail[1]) do insert(retcats, ("%s %s %s"):format(cap_plural_entry_placetype, generic_before_non_cities, export.get_prefixed_key(container.key, container.spec))) end end return retcats end end local function capital_city_cat_handler(data, non_city) local holonym_placetype, holonym_placename, holonym_index, place_desc = data.holonym_placetype, data.holonym_placename, data.holonym_index, data.place_desc -- The first time we're called we want to return something; otherwise we will be called for later-mentioned -- holonyms, which can result in wrongly classifying into e.g. `National capitals`. Simulate the loop in -- find_placetype_cat_specs() over holonyms so we get the proper `Cities in ...` categories as well as the capital -- category/categories we add below. local retcats if not non_city and place_desc.holonyms then for h_index, holonym in export.get_holonyms_to_check(place_desc, holonym_index) do local h_placetype, h_placename = holonym.placetype, holonym.unlinked_placename retcats = city_type_cat_handler { entry_placetype = "city", holonym_placetype = h_placetype, holonym_placename = h_placename, holonym_index = h_index, place_desc = place_desc, } if retcats then break end end end if not retcats then retcats = {} end -- Now find the appropriate capital-type category for the placetype of the holonym, e.g. 'State capitals'. If we -- recognize the holonym among the known holonyms in [[Module:place/locations]], also add a category like 'State -- capitals of the United States'. Truncate e.g. 'autonomous region' to 'region', 'union territory' to 'territory' -- when looking up the type of capital category, if we can't find an entry for the holonym placetype itself (there's -- an entry for 'autonomous community'). local capital_cat = export.placetype_to_capital_cat[holonym_placetype] if not capital_cat then capital_cat = export.placetype_to_capital_cat[holonym_placetype:gsub("^.* ", "")] end if capital_cat then capital_cat = ucfirst(capital_cat) local inserted_specific_variant_cat = false if holonym_index then -- Now find the first recognized holonym location. We don't stop when :also is seen because of the common pattern -- where we use :also to specify that a given city is the capital at multiple surrounding levels. local matching_group, matching_key, matching_spec, matching_container_trail, matching_holonym_index for h_index = holonym_index, #place_desc.holonyms do if place_desc.holonyms[h_index].placetype then matching_group, matching_key, matching_spec, matching_container_trail = export.find_matching_holonym_location { holonym_placetype = place_desc.holonyms[h_index].placetype, holonym_placename = place_desc.holonyms[h_index].unlinked_placename, holonym_index = h_index, place_desc = place_desc, } if matching_group then matching_holonym_index = h_index break end end end if matching_holonym_index == holonym_index then if matching_container_trail[1] and not matching_spec.no_container_cat then for _, container in ipairs(matching_container_trail[1]) do insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(container.key, container.spec))) inserted_specific_variant_cat = true end end elseif matching_holonym_index then -- Check to make sure that the holonym placetype we were called on is listed among the -- divtypes of the location we found. local function insert_specific_variant_if_possible(key, spec) return export.get_equiv_placetype_prop(holonym_placetype, function(pt) local plural_holonym_placetype = export.pluralize_placetype(pt) local saw_matching_div if spec.divs then local divs = spec.divs if type(divs) ~= "table" then divs = {divs} end for _, div in ipairs(divs) do if type(div) ~= "table" then div = {type = div} end if plural_holonym_placetype == div.type then saw_matching_div = true break end end end if saw_matching_div then insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(key, spec))) return true end return false end) end if insert_specific_variant_if_possible(matching_key, matching_spec) then inserted_specific_variant_cat = true elseif not matching_spec.no_container_cat then for _, containers in ipairs(matching_container_trail) do local saw_no_container_cat = false for _, container in ipairs(containers) do if insert_specific_variant_if_possible(container.key, container.spec) then inserted_specific_variant_cat = true break end saw_no_container_cat = saw_no_container_cat or container.spec.no_container_cat end if inserted_specific_variant_cat or saw_no_container_cat then break end end end end else -- This happens when in an invocation like {{place|en|capital city|s/Haryana,Punjab}} for -- [[Chandigarh]]. We fall back to older code that doesn't depend on the holonym index existing. -- FIXME: This may not be necessary. In the example just given, when processing Haryana we add to -- [[:Category:en:State capitals of India]], and nothing extra gets added when processing Punjab. -- Possibly we can just skip this case entirely. local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and container_trail[1] and not spec.no_container_cat then for _, container in ipairs(container_trail[1]) do insert(retcats, ("%s of %s"):format(capital_cat, export.get_prefixed_key(container.key, container.spec))) inserted_specific_variant_cat = true end end end if not inserted_specific_variant_cat then insert(retcats, capital_cat) end else -- We didn't recognize the holonym placetype; just put in 'Capital cities'. insert(retcats, "Capital cities") end return retcats end --[=[ This is invoked specially for all placetypes (see the `*` placetype key at the bottom of `placetype_data`). This is used in two ways: # To add pages to generic holonym categories like [[:Category:en:Places in Merseyside, England]] (and [[:Category:en:Places in England]]) for any pages that have `co/Merseyside` as their holonym. # To categorize demonyms in bare placename categories like [[:Category:en:Merseyside, England]] if the demonym description mentions `co/Merseyside` and doesn't mention a more specific placename that also has a category. (In this case there are none, but we can have demonyms at multiple levels, e.g. in France for individual villages, departments, administrative regions, and for the entire country, and for example we only want to categorize a demonym into [[:Category:France]] if no more specific category applies.) Unlike when invoked from {{tl|place}}, a demonym invocation only adds the most specific holonym category and not the category of any containing polity (hence if we add [[:Category:en:Merseyside, England]] we won't also add [[:Category:England]]). This code also handles cities; e.g. for the first use case above, it would be used to add a page that has `city/Boston` as a holonym to [[:Category:en:Places in Boston]], along with [[:Category:en:Places in Massachusetts, USA]] and [[:Category:en:Places in the United States]]. The city handler tries to deal with the possibility of multiple cities having the same name. For example, the code in [[Module:place/locations]] knows about the city of [[Columbus]], [[Ohio]], which has containing polities `Ohio` (a state) and `the United States` (a country). If either containing polity is mentioned, the handler proceeds to return the key `Columbus` (along with `Ohio, USA` and `the United States`). Otherwise, if any other state or country is mentioned, the handler returns nothing, and otherwise it assumes the mentioned city is the one we're considering and returns `Columbus` etc. This works correctly if the place only mentions Ohio and a holonym for a Columbus in a different country is encountered, because of the function `augment_holonyms_with_container`, which adds the US as a holonym when Ohio is encountered. The single parameter `data` is as in category handlers. The return value is a list of categories (without the preceding language code). ]=] local function generic_place_cat_handler(data) local from_demonym = data.from_demonym local retcats = {} local function insert_retkey(key, spec) if from_demonym then insert(retcats, key) else insert(retcats, ("Places in %s"):format(export.get_prefixed_key(key, spec))) end end local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group then if not spec.no_generic_place_cat then -- This applies to continents and continental regions. insert_retkey(key, spec) end -- Categorize both in key, and in the larger location(s) that the key is part of, e.g. [[Hirakata]] goes in -- both [[Category:Places in Osaka Prefecture, Japan]] and [[Category:Places in Japan]]. But not when -- no_container_cat is set (e.g. for 'United Kingdom'). if not spec.no_container_cat then for _, container_set in ipairs(container_trail) do local stop_adding_containers = false for _, container in ipairs(container_set) do if not container.spec.no_generic_place_cat then insert_retkey(container.key, container.spec) end if container.spec.no_container_cat then stop_adding_containers = true end end if stop_adding_containers then break end end end return retcats end end --[==[ Special category handler run for all placetypes that checks for specified division placetypes of known locations and categorizes appropriately. ]==] function export.political_division_cat_handler(data) if data.from_demonym then return end local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group then local divlists = {} if spec.divs then insert(divlists, spec.divs) end if spec.addl_divs then insert(divlists, spec.addl_divs) end for _, divlist in ipairs(divlists) do if type(divlist) ~= "table" then divlist = {divlist} end for _, div in ipairs(divlist) do if type(div) == "string" then div = {type = div} end local sgdiv = export.maybe_singularize_placetype(div.type) or div.type local prep = div.prep or "of" local cat_as = div.cat_as or div.type if type(cat_as) ~= "table" then cat_as = {cat_as} end if not export.placetype_data[sgdiv] then internal_error("Placetype %s associated with known location key %s and data %s not found in " .. "`placetype_data`", sgdiv, key, spec) end if sgdiv == data.entry_placetype then local retcats = {} for _, pt_cat in ipairs(cat_as) do if type(pt_cat) == "string" then pt_cat = {type = pt_cat} end local pt_prep = pt_cat.prep or prep insert(retcats, ucfirst(pt_cat.type) .. " " .. pt_prep .. " " .. export.get_prefixed_key(key, spec)) end return retcats end end end end end --[==[ This is used to add pages to "bare" categories like [[:Category:en:Georgia, USA]] for `[[Georgia]]` and any foreign-language terms that are translations of the state of Georgia. We look at the page title (or its overridden value in {{para|pagename}}) as well as the glosses in {{para|t}}/{{para|t2}} etc., various extra-info values such as the modern names in {{para|modern}}, and any values specified using a form-of directive. We need to pay attention to the entry placetypes specified so we don't overcategorize; e.g. the US state of Georgia is `[[Джорджия]]` in Russian but the country of Georgia is `[[Грузия]]`, and if we just looked for matching names, we'd get both Russian terms categorized into both [[:Category:ru:Georgia, USA]] and [[:Category:ru:Georgia]]. We also need to check the containing holonyms to make sure there isn't a mismatch (so we don't e.g. categorize Newark, Delaware in [[:Category:en:Newark]], which is intended for Newark, New Jersey). ]==] function export.get_bare_categories(args, overall_place_spec) local bare_cats = {} local place_descs = overall_place_spec.descs local possible_placetypes_by_place_desc = {} for i, place_desc in ipairs(place_descs) do possible_placetypes_by_place_desc[i] = {} for _, placetype in ipairs(place_desc.placetypes) do if not export.placetype_is_ignorable(placetype) then local equivs = export.get_placetype_equivs(placetype, {register_former_as_non_former = true}) for _, equiv in ipairs(equivs) do insert(possible_placetypes_by_place_desc[i], equiv.placetype) end end end end local function check_term(term) -- Treat Wikipedia links like local ones. term = term:gsub("%[%[w:", "[["):gsub("%[%[wikipedia:", "[[") term = export.remove_links_and_html(term) term = term:gsub("^the ", "") for i, place_desc in ipairs(place_descs) do -- Iterate over all matching locations in case there are multiple, as with Delhi defined as -- {{place|en|megacity/and/union territory|c/India|containing the national capital [[New Delhi]]}}. for group, key, spec, container_trail in export.iterate_matching_holonym_location { holonym_placetype = possible_placetypes_by_place_desc[i], holonym_placename = term, place_desc = place_desc, } do insert(bare_cats, key) end end end -- FIXME: Should we only do the following if the language is English (requires that the lang is passed in)? -- We should always do it if `pagename` is given (as it is with {{tcl}}) but maybe not otherwise unless 1=en. There -- are cases like [[Ankara]] = English name for capital of Turkey, but also the name in various languages for the -- capital of Ghana (= English [[Accra]]). But this should get caught by mismatching the containing country. The -- advantage of checking when the language isn't English is we catch those places that fail to give an English -- translation but where the translation happens to be the same as the other-language spelling. However, I don't -- know how often this situation occurs. check_term(args.pagename or mw.loadData("Module:headword/data").pagename) for _, t in ipairs(args.t) do check_term(t) end local function check_termobj_list(terms) for _, term in ipairs(terms) do if term.eq then check_term(term.eq) end if term.alt or term.term then check_term(term.alt or term.term) end end end for _, extra_info_terms in ipairs(overall_place_spec.extra_info) do local arg = extra_info_terms.arg if arg == "modern" or arg == "now" or arg == "full" or arg == "short" then check_termobj_list(extra_info_terms.terms) end end for _, directive in ipairs(overall_place_spec.directives) do check_termobj_list(directive.terms) end return bare_cats end --[==[ This is used to augment the holonyms associated with a place description with the containing polities. For example, given the following: `# {{tl|place|en|subprefecture|pref/Hokkaido}}.` We auto-add Japan as another holonym so that the term gets categorized into [[:Category:Subprefectures of Japan]]. To avoid over-categorizing we need to check to make sure no other countries are specified as holonyms. ]==] function export.augment_holonyms_with_container(place_descs) for _, place_desc in ipairs(place_descs) do if place_desc.holonyms then -- This ends up containing a copy of the original holonyms, with the augmented holonyms inserted in their -- appropriate position. We don't just put them at the end because some holonyms have use the `:also` -- modifier, which causes category processing to restart at that point after generating categories for a -- preceding holonym, and we don't want the preceding holonym's augmented holonyms interfering with -- categorization of a later holonym. We proceed from right to left, and each time we augment, we copy -- the holonyms with the augmented holonym(s) inserted appropriately and replace the place description's -- holonyms with the augmented ones before the next iteration. The reason for this is so that e.g. -- {{place|neighborhood|city/Birmingham|co/West Midlands|cc/England}} doesn't throw an error during the -- augmentation process due to 'Birmingham' referring to two known locations (in England and Alabama). If -- we go left to right, we will throw an ambiguity error on `city/Birmingham` because code to exclude -- Birmingham, Alabama needs `c/United Kingdom` present (to cause a mismatch with `c/United States`), -- which isn't yet present as the augmentation code hasn't gotten to `cc/England` yet. For similar -- reasons, we need to include the augmented holonyms in the holonyms considered in the next iteration -- rather than modifying the place description once at athe end. for i = #place_desc.holonyms, 1, -1 do local holonym = place_desc.holonyms[i] if holonym.placetype and not export.placetype_is_ignorable(holonym.placetype) then local group, key, spec, container_trail = export.find_matching_holonym_location { holonym_placetype = holonym.placetype, holonym_placename = holonym.unlinked_placename, holonym_index = i, place_desc = place_desc, } if group and container_trail[1] and not spec.no_auto_augment_container then local augmented_holonyms = {} for j = 1, i do insert(augmented_holonyms, place_desc.holonyms[j]) end for _, containers in ipairs(container_trail) do local any_no_auto_augment_container = false for _, container in ipairs(containers) do any_no_auto_augment_container = any_no_auto_augment_container or container.spec.no_auto_augment_container local containing_type = container.spec.placetype if type(containing_type) == "table" then -- If the containing type is a list, use the first element as the canonical variant. containing_type = containing_type[1] end local full_container_placename, elliptical_container_placename = m_locations.key_to_placename(container.group, container.key) -- Don't side-effect holonyms while processing them. local new_holonym = { -- By the time we run, the display has already been generated so we don't need to -- set display_placename. placetype = containing_type, -- placename_to_key() for the group should correctly handle both full and elliptical -- placenames, but the full placename seems less likely to be ambiguous. FIXME: We -- should just store the key directly and use it when available to avoid having to -- convert key to placename and back to key. unlinked_placename = full_container_placename, -- Indicate that this is an augmented holonym, and was derived from the specified -- holonym. In iterate_matching_holonym_location(), we ignore augmented holonyms -- derived from holonyms that are different from the holonym we're searching for but -- of the same placetype. This is to correctly handle a situation like -- {{place|river|dept/Ardèche,Gard,Vaucluse,Bouches-du-Rhône|c/France}}. Here, -- `Ardèche` is in `r/Auvergne-Rhône-Alpes`, while `Gard` is in `r/Occitania` and -- the other two are in `r/Provence-Alpes-Côte d'Azur`. Augmenting proceeds from -- right to left, so after it adds `r/Provence-Alpes-Côte d'Azur` to -- `Bouches-du-Rhône`, Vaucluse gets augmented correctly but `Gard` fails to match -- in find_matching_holonym_location() because of the mismatch between augmented -- `r/Provence-Alpes-Côte d'Azur` and actual `r/Occitania`. Similarly, all later -- calls to find_matching_holonym_location() fail to match `Gard` (and likewise -- `Ardèche`) against any known location. To deal with this, we mark augmented -- holoynms as being augmented due to a source holonym, and when processing a given -- holonym, ignore augmented holonyms from other holonyms of the same placetype. -- The restriction to the same placetype is so that `Birmingham` still gets -- correctly disambiguated to Birmingham, England in the example given above near -- the top of this function, using the augmented holonym `c/United Kingdom` added by -- the specified `cc/England` (whose placetype `constituent country` differs from -- the placetype `city` of Birmingham). augmented_from_holonym = holonym, } insert(augmented_holonyms, new_holonym) -- But it is safe to modify other parts of the place_desc. export.key_holonym_into_place_desc(place_desc, new_holonym) end if any_no_auto_augment_container then break end end for j = i + 1, #place_desc.holonyms do insert(augmented_holonyms, place_desc.holonyms[j]) end place_desc.holonyms = augmented_holonyms end end end end end end -- Cat handler for district, areas, neighborhoods and suburbs. Districts are tricky because they can either be political -- divisions or city neighborhoods. Areas similarly can be political divisions (rarely; specifically, in Kuwait), city -- neighborhoods or larger geographical areas/regions. We handle this as follows: -- (1) `placetype_data` cat entries for specific countries or country divisions take precedence over cat_handlers, so if -- the user says {{tl|place|district|s/Maharashtra|c/India}}, we won't even be called because there is an entry that -- categorizes into [[:Category|Districts of Maharashtra, India]]. -- (2) If we're called, we check the holonym we're called on to see if it is a recognized city, e.g. if we're called -- using {{tl|place|district|city/Mumbai|s/Maharashtra|c/India}}. If so, we categorize under e.g. -- [[:Category:Neighbourhoods of Mumbai]]. (Choosing the spelling "neighbourhoods" because we're in India.) -- (3) If we're called and the holonym is not a recognized city, we check if the placetype has has_neighborhoods set. -- If so, it's "city-like" and we categorize under the first containing polity that we recognize. For example, if -- we're called using {{tl|place|district|town/Northampton|co/Hampshire|s/Massachusetts|c/US}}, we should recognize -- town as "city-like" and categorize under [[:Category:Neighborhoods in Massachusetts]]. (Note "in" not "of", and -- note the spelling "neighborhoods" because we're in the US.) -- (4) If the holonym is not city-like, we do nothing. If there's a city or city-like placetype farther up (e.g. we're -- called as {{tl|place|district|ward/Foo|mun/Bar|...}}), we will handle the city-like entity according to (2) or -- (3) when called on that holonym. Otherwise either the categorization in (1) takes place or there's no -- categorization. local function district_neighborhood_cat_handler(data) local function get_plural_entry_placetype(location_spec, container_trail) if data.entry_placetype == "suburb" then return "Suburbs" else -- Check for `british_spelling` setting on the spec itself or any container. local uses_british_spelling = location_spec.british_spelling if uses_british_spelling == nil and container_trail then for _, container_set in ipairs(container_trail) do local must_outer_break = false for _, container in ipairs(container_set) do if container.spec.british_spelling ~= nil then uses_british_spelling = container.spec.british_spelling must_outer_break = true break end end if must_outer_break then break end end end return uses_british_spelling and "Neighbourhoods" or "Neighborhoods" end end -- First check the immediate holonym to see if it's a city or a city-like top-level entity (Hong Kong, Bonaire, -- etc.) local group, key, spec, container_trail = export.find_matching_holonym_location(data) if group and not spec.is_former_place and spec.is_city then return {get_plural_entry_placetype(spec, container_trail) .. " of " .. export.get_prefixed_key(key, spec)} end -- If the entry placetype is neighbo(u)rhood, assume it is a neighborhood even if there isn't a city-like -- entity father up the chain. (E.g. due to a mistaken use of m/ instead of mun/ for municipality.) local has_neighborhoods local entry_placetype = data.entry_placetype if entry_placetype == "neighborhood" or entry_placetype == "neighbourhood" or entry_placetype == "suburb" then has_neighborhoods = true else -- Otherwise, make sure the current holonym is city-like. has_neighborhoods = export.get_equiv_placetype_prop(data.holonym_placetype, function(pt) return export.get_placetype_prop(pt, "has_neighborhoods") end, {continue_on_nil_only = true}) end if has_neighborhoods then -- Loop up the holonyms, looking for city and city-like entities in case of e.g. [[Sepulveda]] written -- {{place|en|neighborhood|valley/San Fernando Valley|city/Los Angeles|s/California|c/USA}} -- but also look for a recognizable poldiv, and if so categorize as "Neighborhoods in POLDIV". We need -- to start with the current holonym, which is especially important for neighborhoods and suburbs that -- may have the first holonym be a recognizable province, etc. but can't hurt otherwise. (Previously -- we skipped the first/current holonym.) for other_holonym_index, other_holonym in export.get_holonyms_to_check(data.place_desc, data.holonym_index) do local other_holonym_data = { holonym_placetype = other_holonym.placetype, holonym_placename = other_holonym.unlinked_placename, holonym_index = other_holonym_index, place_desc = data.place_desc, } local group, key, spec, container_trail = export.find_matching_holonym_location(other_holonym_data) if group and not spec.is_former_place then return {get_plural_entry_placetype(spec, container_trail) .. (spec.is_city and " of " or " in ") .. export.get_prefixed_key(key, spec)} end end end end function export.check_already_seen_string(holonym_placename, already_seen_strings) local canon_placename = ulower(m_links.remove_links(holonym_placename)) if type(already_seen_strings) ~= "table" then already_seen_strings = {already_seen_strings} end for _, already_seen_string in ipairs(already_seen_strings) do if canon_placename:find(already_seen_string) then return true end end return false end -- Prefix display handler that adds a prefix such as "Metropolitan Borough of " to the display -- form of holonyms. We make sure the holonym doesn't contain the prefix or some variant already. -- We do this by checking if any of the strings in ALREADY_SEEN_STRINGS, either a single string or -- a list of strings, or the prefix if ALREADY_SEEN_STRINGS is omitted, are found in the holonym -- placename, ignoring case and links. If the prefix isn't already present, we create a link that -- uses the raw form as the link destination but the prefixed form as the display form, unless the -- holonym already has a link in it, in which case we just add the prefix. local function prefix_display_handler(prefix, holonym_placename, already_seen_strings) if export.check_already_seen_string(holonym_placename, already_seen_strings or ulower(prefix)) then return holonym_placename end if holonym_placename:find("%[%[") then return prefix .. " " .. holonym_placename end return prefix .. " [[" .. holonym_placename .. "]]" end -- Suffix display handler that adds a suffix such as " parish" to the display form of holonyms. -- Works identically to prefix_display_handler but for suffixes instead of prefixes. local function suffix_display_handler(suffix, holonym_placename, already_seen_strings, include_suffix_in_link) if export.check_already_seen_string(holonym_placename, already_seen_strings or ulower(suffix)) then return holonym_placename end if holonym_placename:find("%[%[") then return holonym_placename .. " " .. suffix end if include_suffix_in_link then return "[[" .. holonym_placename .. " " .. suffix .. "]]" else return "[[" .. holonym_placename .. "]] " .. suffix end end -- Display handler for boroughs. New York City boroughs are display as-is. Others are suffixed -- with "borough". local function borough_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.new_york_boroughs[unlinked_placename] then -- Hack: don't display "borough" after the names of NYC boroughs return holonym_placename end return suffix_display_handler("borough", holonym_placename) end local function county_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) -- Display handler for Irish counties. Irish counties are displayed as e.g. "County [[Cork]]". if m_locations.ireland_counties["County " .. unlinked_placename .. ", Ireland"] or m_locations.northern_ireland_counties["County " .. unlinked_placename .. ", Northern Ireland"] then return prefix_display_handler("County", holonym_placename) end -- Display handler for Taiwanese counties. Taiwanese counties are displayed as e.g. "[[Chiayi]] County". if m_locations.taiwan_counties[unlinked_placename .. " County, Taiwan"] then return suffix_display_handler("County", holonym_placename) end -- Display handler for Romanian counties. Romanian counties are displayed as e.g. "[[Cluj]] County". if m_locations.romania_counties[unlinked_placename .. " County, Romania"] then return suffix_display_handler("County", holonym_placename) end -- FIXME, we need the same for US counties but need to key off the country, not the specific county. -- Others are displayed as-is. return holonym_placename end -- Display handler for prefectures. Japanese prefectures are displayed as e.g. "[[Fukushima]] Prefecture". -- Others are displayed as e.g. "[[Fthiotida]] prefecture". local function prefecture_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) local suffix = m_locations.japan_prefectures[unlinked_placename .. " Prefecture, Japan"] and "Prefecture" or "prefecture" return suffix_display_handler(suffix, holonym_placename) end -- Display handler for provinces of Bulgaria, Iran, Laos, North and South Korea, Thailand, Turkey and Vietnam. Recognized -- provinces are displayed as e.g. "[[Gyeonggi]] Province" or "[[Antalya]] Province". Others are displayed as-is. local function province_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.bulgaria_provinces[unlinked_placename .. "Province, Bulgaria"] or m_locations.iran_provinces[unlinked_placename .. " Province, Iran"] or m_locations.laos_provinces[unlinked_placename .. " Province, Laos"] or m_locations.north_korea_provinces[unlinked_placename .. " Province, North Korea"] or m_locations.south_korea_provinces[unlinked_placename .. " Province, South Korea"] or m_locations.thailand_provinces[unlinked_placename .. " Province, Thailand"] or m_locations.turkey_provinces[unlinked_placename .. " Province, Turkey"] or m_locations.vietnam_provinces[unlinked_placename .. " Province, Vietnam"] then return suffix_display_handler("Province", holonym_placename) end return holonym_placename end -- Display handler for Nigerian states. Nigerian states are display as "[[Kano]] State". Others are displayed as-is. local function state_display_handler(holonym_placetype, holonym_placename) local unlinked_placename = m_links.remove_links(holonym_placename) if m_locations.nigeria_states[unlinked_placename .. " State, Nigeria"] then return suffix_display_handler("State", holonym_placename) end return holonym_placename end -- Display handler for voivodeships. Display as e.g. [[Subcarpathian Voivodeship]]. local function voivodesip_display_handler(holonym_placetype, holonym_placename) return suffix_display_handler("Voivodeship", holonym_placename, nil, "include_suffix_in_link") end ------------------------------------------------------------------------------------------ -- Placetype data -- ------------------------------------------------------------------------------------------ --[==[ var: Main placetype data structure. This specifies, for each canonicalized placetype, various properties. The keys are placetypes (in the singular, except for category-only placetypes, which are plural and followed by `!`), and the value is a table of properties. The `"*"` key is special and is used for adding "generic" categories of the form `Places in ``location`` `; it runs for all entry placetypes. Keys in the form of plural placetypes followed by `!` are used only in [[Module:category tree/topic cat/data/Places]] for specifying the properties of categories containing the specified placetype, esp. bare categories like [[:Category:States and territories]] (rather than qualified categories like [[:Category:States and territories of Australia]]). Keys under the value table for a given placetype of are two types: ''property keys'' (which specify the value of specific properties) and ''categorization keys'' (which tell how to categorize certain sorts of holonyms if the placetype in question occurs as an entry placetype). Categorization keys are either the special value `default` or are wildcard strings with a slash in them, such as `"country/*"`. Note that only wildcard strings are currently allowed directly in the placetype data; everything else is handled through category handlers, either per-placetype or special (such as `political_division_cat_handler`). The algorithm for how category keys and handlers are used to generate categories is described at the top of [[Module:place]]. There are several recognized property keys, of various types: 1. The following link-related property keys are recognized: * `link`: '''Required''' except in category-only placetypes ending in `!`. Describes how to link and display the placetype in the formatted description when occurring as an entry placetype. Also used for formatting pluralized placetypes (which may occur in entry placetypes, esp. new-format ones, such as `two <<islands>>`) and may occur in categories). The possible values are: *# `true`: Link to the same-named Wiktionary entry. This creates a raw link, e.g. `<nowiki>[[city]]</nowiki>`, which is converted to an English-specific link by JavaScript postprocessing. If the placetype is plural, this creates a two-part raw link e.g. `<nowiki>[[city|cities]]</nowiki>`. *# `"w"`: Link to the same-named Wikipedia entry. This creates a two-part link, e.g. `<nowiki>[[w:census town|census town]]</nowiki>`, or `<nowiki>[[w:census town|census towns]]</nowiki>` if the placetype is given plural. *# `"+..."`: Create a two-part link to the entry following the `+` sign. For example, if `cercle` specifies `"+w:cercles of Mali"`, a two-part link `<nowiki>[[w:cercles of Mali|cercle]]</nowiki>` will be generated, or `<nowiki>[[w:cercles of Mali|cercles]]</nowiki>` if plural `cercles` is specified. *# `"separately"`: Link each word separately. For example, if `administrative territory` specifies `"separately"`, it will be linked as `<nowiki>[[administrative]] [[territory]]</nowiki>`, or as `<nowiki>[[administrative]] [[territory|territories]]</nowiki>` if plural `administrative territories` is given. *# another string: Use that string directly. If the placetype is plural, `pluralize()` in [[Module:en-utilities]] is called on the string, which will correctly pluralize most strings, including those with links in them. (If there are multiple links, the display form of the last link is pluralized.) *# `false`: This placetype is not allowed as an entry placetype. An error will be thrown if this placetype is given as an entry placetype. This is specified for internal-use placetypes, especially placetypes used in conjunction with the qualifiers `former`, `ancient`, `historical` and such. * `plural_link`: If specified and the placetype is plural, use the value in place of generating a pluralized version of the link spec in `link`. Most commonly, this is either a string with links in it (which is used directly) or the value `false`, indicating that the placetype cannot occur plural. (This is used for example by `caplc`, which displays as `<nowiki>[[capital]] and [[large]]st [[city]]</nowiki>`, where a plural version doesn't make sense.) Generally if this is specified, `plural` also needs to be specified to give a special placetype plural; this situation occurs especially with multiword placetypes where something other than the last word is pluralized. An example is `town with bystatus`, whose plural is `towns with bystatus`, which needs to be explicitly given. This example uses `link = <nowiki>"[[town]] with [[bystatus#Norwegian Bokmål|bystatus]]"</nowiki>` ({{m|nb|bystatus}}) is a Norwegian Bokmål word, and template calls aren't currently permitted in link strings), along with `plural_link = <nowiki>"[[town]]s with [[bystatus#Norwegian Bokmål|bystatus]]"</nowiki>`. * `category_link`: Spec indicating how to display the placetype when occurring in category descriptions. Defaults to the value of `link`, and in turn is overridden by more specific `category_link_*` keys; see below. Category-only placetypes (which are plural and end in `!`) usually use `category_link` in preference to `link`. The value of `category_link` can be any of the types of specs given above, but most commonly is a plural string with links in it, spelling out the description; in this case it is used directly. When both `category_link` and `link` are given, the value in `category_link` is typically longer and more descriptive. For example, `polity` uses `link = true`, which just generates a link `<nowiki>[[polity]]</nowiki>` or plural `<nowiki>[[polity|polities]]</nowiki>`, but specifies a separate `category_link = <nowiki>"[[independent]] or [[semi-]][[independent]] [[polity|polities]]"</nowiki>`, which clarifies in the category description what a polity is. * `category_link_top_level`: Spec indicating how to display top-level (bare/unqualified) categories, i.e. categories where the placetype is not followed by `in ``location`` ` or `of ``location`` `. If given, this overrides `category_link` for this type of category. * `category_link_before_noncity`: Spec indicating how to display qualified categories of the form ` ``placetypes`` in/of ``location`` ` where ``location`` does not refer to a city. If given, this overrides `category_link` for this type of category. * `category_link_before_city`: Spec indicating how to display qualified categories of the form ` ``placetypes`` in/of ``location`` ` where ``location`` refer to a city. If given, this overrides `category_link` for this type of category. An example where this is given is `neighborhood`, which uses the following specs:<ol> <li>`link = true`</li> <li>`category_link = <nowiki>"[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]]"</nowiki>`</li> <li>`category_link_before_city = <nowiki>"[[neighborhood]]s, [[district]]s and other subportions"</nowiki>`</li> </ol> This has the effect of making the entry placetype `neighborhood` display as just `<nowiki>[[neighborhood]]</nowiki>`, while e.g. a category like `Neighborhoods of Chicago` displays as `<nowiki>[[neighborhood]]s, [[district]]s and other subportions of [[Chicago]], ...</nowiki>` and a category like `Neighborhoods in Illinois, USA` displays as `<nowiki>[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]] in [[Illinois]], ...</nowiki>`. * `disallow_in_entries`: If specified, this placetype cannot occur as an entry placetype, and the specified value (a message indicating what to use instead) is displayed in the error message. * `disallow_in_holonyms`: If specified, this placetype cannot occur as a holonym placetype, and the specified value (a message indicating what to use instead) is displayed in the error message. 2. There is currently one fallback-related property key recognized: * `fallback`: If specified, its value is a placetype which will be used for categorization purposes if no categories get added using the placetype itself. As an example, `branch` sets a fallback of `river` but also sets `preposition = "of"`, meaning that {{tl|place|en|branch|riv/Mississippi}} displays as `a branch of the Mississippi` (whereas `river` itself uses the preposition `in`), but otherwise categorizes the same as `river`. A more complex example is `area`, which sets a fallback of `geographic and cultural area` and also sets a category handler that checks for cities or city-like entities (e.g. boroughs) occurring as holonyms and categorizes the toponym under [[:Category:Neighborhoods of CITY]] (for recognized cities) or otherwise [[:Category:Neighborhoods of POLDIV]] (for the nearest containing recognized location). In addition, `area` is set as a political division of Kuwait, meaning if `c/Kuwait` occurs as holonym, the toponym is categorized under [[:Category:Areas of Kuwait]]. If none of these categories trigger, the fallback of `geographic and cultural area` will take effect, and the toponym will be categorized as e.g. [[:Category:Geographic and cultural areas of England]]. 3. There is currently one property to control irregular plurals of placetypes: * `plural`: If specified, its value is the plural of the placetype. Otherwise, the default pluralization algorithm in [[Module:en-utilities]] applies (which correctly pluralizes most words, including those ending in `-y`, `-ch`, `-sh`, `-x`, etc.). The value of `plural` is also used when converting a pluralized placetype into its singular equivalent; for example, since the placetype `kibbutz` has `plural = "kibbutzim"`, the placetype `kibbutzim` will be recognized as a plural and singularized to `kibbutz`. For this reason, it's occasionally necessary to specify a `plural` value even when the default pluralization algorithm works correctly, if the default singularization algorithm won't correctly reverse the pluralization (as with `pass` and other terms ending in `-ss`). 4. The following property keys relate to generating categories for entry placetypes and specifying the parents of those categories: * `class`: The general class of placetype. This is used for various purposes: (a) to categorize placetypes preceded by a qualifier such as `former`, `ancient`, `medieval` or `historical` (note that these placetypes are not all treated alike); (b) to determine the parent category of bare placetype categories (e.g. [[:Category:Villages]] for placetype `village`); (c) to determine whether to add a parent category `political divisions of specific countries` to qualified placetype categories (e.g. [[:Category:Villages in Mali]]). The possible values are: *# `polity`: a more-or-less sovereign/independent polity, such as a country, kingdom or empire. *# `subpolity`: a non-sovereign division of a polity, above the level of an individual settlement. *# `settlement`: a city or smaller equivalent, such as a village. This also includes administrative divisions of a settlement, such as wards and barangays. *# `non-admin settlement`: similar to a settlement but without administrative or political significance, such as an unincorporated community, farm or neighborhood. *# `capital`: a settlement that is a capital. A former capital is generally still in existence, just not the capital any more. *# `natural feature`: any non-man-made feature, such as a lake, mountain, island, ocean, etc. *# `man-made structure`: a man-made feature below the level of a neighborhood, such as a house, airport, university, metro station, park or the like. *# `geographic region`: a geographic or cultural region or area that has no administrative significance. These may vary greatly in size but typically have some sort of cultural significance (possibly historical). The `former`, `ancient`, etc. qualifier has no effect on the category of these placetypes. *# `generic place`: a place that isn't further qualified into any specific subtype. * `former_type`: The class of placetype used for categorizing placetypes preceded by a qualifier such as `former`, `ancient`, `medieval` or `historical`. The possible values are the same as for `class` but with the addition of `dependent territory` (for colonies, protectorates and the like) and `!` (ignore the historical/former/ancient/etc. qualifier; used e.g. with `fictional location` and `mythological location`). If not specified, the value of `class` is used. When a qualifier such as `former`, `ancient`, `medieval` or `historical` is encountered (specifically, those in `former_qualifiers`), it is mapped using `former_qualifiers` to the appropriate internal qualifier or qualifiers (one or both of `ANCIENT` and/or `FORMER`, which are written in all-caps to distinguish them from user-specified qualifiers), which is prepended to the value of `former_type` or `class` to form a placetype whose properties are looked up to determine how to categorize the toponym in question. For example, if `medieval village` is given, we map `medieval` to `ANCIENT` and `FORMER`, and `village` to its `class` of `settlement`, and enter the placetypes `ANCIENT settlement` and `FORMER settlement` (in that order) into the list of equivalent placetypes returned by `get_placetype_equivs`. In this case, there is an entry in `placetype_data` for `ANCIENT settlement`, so its default category spec `Ancient settlements` is used as the category. If on the other hand `medieval kingdom` is given, where `kingdom` has a `class` value `polity`, we first look up `ANCIENT polity`, see there is no entry in `placetype_data` for it, and then look up `FORMER polity`, which exists and has a default category spec `Former polities`, which is used as the category. Note that if the placetype following the "former" qualifier is recognized in `placetype_data` but has no `former_type` or `class` and no fallback with a `former_type` or `class` specified, it is an internal error; but if the placetype isn't recognized (e.g. something like `former greenhouse` is specified and we don't have an entry for `greenhouse`), we just track the occurrence and end up not categorizing. * `bare_category_parent`: This specifies the first parent category of a bare placetype category named according to the placetype in question (e.g. [[:Category:Atolls]] for placetype `atoll`, or [[:Category:Named buildings]] for placetype `named buildings!`). If not specified, the first parent category is determined by the value of `class`, using the mapping `class_to_bare_category_parent` in [[Module:category tree/topic cat/data/Places]]. * `addl_bare_category_parents`: Extra parent categories to add a bare placetype category to (see `bare_category_parent` just above). * `bare_category_breadcrumb`: Breadcrumb for bare placetype categories. Also used as the sort key of `bare_category_parent` if it is a string. * `inherently_former`: If specified and the given placetype is used as an entry placetype, act as if `former` or `ancient` (depending on the value of `inherently_former`) were prefixed to the placetype. This is for placetypes that always refer to no-longer-existing entities, such as `satrapy` and `treaty port`. The value of `inherently_former` is a list of internal qualifiers (one or more of `ANCIENT` and/or `FORMER`), just as for `former_qualifiers`, and the implementation is the same. * `cat_handler`: Handler used to generate the categories to add a given toponym to, if its entry placetype is the placetype in question. Generally the `cat_handler` function checks the holonyms specified in order to determine which category or categories to generate. For example, `district_neighborhood_cat_handler` handles placetypes `district`, `neighborhood`, `subdivision`, `suburb` and the like, and either adds the toponym to a category like `Neighborhoods of ``city`` ` (if a recognized city is given as a holonym), or otherwise a category like `Neighborhoods in ``location`` ` (for the first recognized non-city location given as a holonym, if an unrecognized city or city-like entity is given before the recognized non-city). The algorithm that runs the category handlers iterates over holonyms from left to right, running the `cat_handler` function on each holonym in turn until one or more categories are returned; see below for more specifics. (Note that countries for which e.g. a `district` is a political division do not get the corresponding category added by the `district_neighborhood_cat_handler` function but by `political_division_cat_handler`.) `cat_handler` functions are called with one argument, `data`, describing the resolved entry placetype (i.e. after resolving placetype aliases and fallbacks) and the holonym being processed. The return value should be a list of category specs (categories minus the langcode prefix, with `+++` standing for the holonym key, or the value `true`, which stands for ` ``Placetypes`` in/of ``Holonym`` `, i.e. the pluralized placetype with the appropriate preposition as specified in `placetype_data`). `data` contains the following fields: ** `entry_placetype`: the resolved entry placetype for the entry placetype being processed (i.e. it will always have an entry in `placetype_data` but may not be the original placetype given by the user); ** `holonym_placetype` and `holonym_placename`: the holonym placetype and placename being processed; ** `holonym_index`: the index of the holonym being processed, or {nil} if we're handling an overriding holonym (FIXME: we will change the overriding holonym algorithm so there will be an index even when processing overriding holonyms); ** `place_desc`: a full description of the {{tl|place}} call, as specified at the top of [[Module:place]]; ** `from_demonym`: If set, we are called from [[Module:demonym]], triggered by {{tl|demonym-adj}} or {{tl|demonym-noun}}, instead of being triggered by {{tl|place}}. * `has_neighborhoods`: If `true`, the specified placetype is city-like. This is used in the `district_neighborhood_cat_handler` to determine whether to add a category such as `Neighborhoods in ``location`` `; see the section just above on `cat_handler`. 5. The following preposition-related property keys are recognized: * `preposition`: The preposition used after this placetype when it occurs as an entry placetype. Defaults to `"in"`. * `generic_before_non_cities`: If specified, the appropriate category description handler in [[Module:category tree/topic cat/data/Places]] will recognize categories of the form ` ``Placetype`` in/of ``location`` ` for the specified placetype and preposition, if ``location`` is a non-city. This is used to generate descriptions for categories added by category handlers and by explicit category specs in the placetype data. All placetypes that specify `generic_before_non_cities` or `generic_before_cities` *MUST* also specify a value for `class` so that the category tree code can determine whether it's a political or non-political division. * `generic_before_cities`: Like `generic_before_non_cities` but for locations referring to cities. 6. The following property keys control the auto-addition of affixes when formatting holonyms of a particular placetype: * `affix_type`: If specified, add the placetype as an affix before or after holonyms of this placetype. Possible values are: *# `"pref"` (the holonym will display as `(the) placetype of Holonym`, where `the` appears when the holonym directly follows an entry placetype); *# `"Pref"` (same as `"pref"` but the placetype is capitalized; each word is capitalized if there are multiple); *# `"suf"` (the holonym will display as `Holonym placetype`); *# `"Suf"` (the holonym will display as `Holonym Placetype`, i.e. same as `"suf"` but the placetype is capitalized). * `suffix`: String to use in place of the placetype itself when the placetype is displayed as a suffix after a holonym. Note that `suffix` can be used independently of `affix_type` because the user can also request a suffix explicitly using a syntax like `adr:suf/Occitania`, which will display as `Occitania region` because the placetype `administrative region` specifies `suffix = "region"`. * `prefix`: Like `suffix` but for use when the placetype is displayed as a prefix before the holonym. * `affix`: Like `suffix` and `prefix` but for use when the placetype is displayed as an affix either before or after the holonym. If both `suffix` or `prefix` and `affix` are given for a single placetype, `suffix` or `prefix` take precedence. * `no_affix_strings`: String or list of strings that, if they occur in the holonym, suppress the addition of any affix requested using `affix_type`. Defaults to the placetype itself. For example, `autonomous okrug` specifies `affix_type = "Suf"` so that `aokr/Nenets` displays as `Nenets Autonomous Okrug`, but also specifies `no_affix_strings = "okrug"` so that `aokr/Nenets Okrug` or `aokr/Nenets Autonomous Okrug` displays as specified, without a redundant `Autonomous Okrug` added. Matching is case-insensitive but whole-word. * `display_handler`: A function of two arguments, `holonym_placetype` and `holonym_placename` (specifying a holonym). Its return value is a string specifying the display form of the holonym. 7. The following property keys control the indefinite and definite articles used before entry placetypes and/or holonyms of the specified placetype. * `entry_placetype_use_the`: Use `"the"` before this placetype when it occurs as an entry placetype. * `entry_placetype_indefinite_article`: Indefinite article used before this placetype when it occurs as an entry placetype (usually `"a"`, specifically for placetypes beginning with u- that don't take the indefinite article `"an"`). Defaults to the appropriate indefinite article (`"a"` or `"an"` depending on whether the placetype begins with a vowel). Overridden by `entry_placetype_use_the`, and unlike for most properties, does not apply to equivalent placetypes (i.e. fallbacks or those formed by removing a qualifier from the beginning); only to the exact placetype specified. * `holonym_use_the`: Use `"the"` before holonyms of this placetype. '''NOTE:''' # The `link` property must be specified on all placetypes, except those ending in `!` (category-only placetypes), which must have either `link` or `category_link` specified. # Either the `class` or `former_type` property must be specified on all placetypes not ending in `!` that do not have a fallback (if a placetype has a fallback and omits the `class` and `former_type` properties, they are taken from the fallback). An internal error will result if a placetype has no `class` or `former_type` property derivable either directly or through a fallback, if an attempt is made to categorize a former/ancient/historical/etc. entity of this placetype. # It is possible to have multiple levels of fallback (e.g. `frazione` falls back to `hamlet`, which falls back to `village`). Fallback loops will cause an internal error. All placetypes specified as fallbacks must exist in `placetype_data` or an internal error occurs. ]==] export.placetype_data = { --[=[ If you need to sort the following, do this (using Vim): 1. Make sure all full-line comments are within the { ... } table, or are moved after and on the same line as single-line entries. 2. Make sure the table uses tabs everywhere for indent, and not spaces. 3. Mark the top of the table with `ma`, go to the bottom and execute the following two lines in sequence: :'a,.s/\n/\\n/g :s/\\n\(\t\[\)/\r\1/g The first command converts every newline to a literal `\n` sequence, so the whole thing becomes a single line, while the second command restores the newlines before the beginning of each entry. The effect is to convert all entries to a single line while not losing any information. (Potentially a negative lookahead could be used to do it all in one command.) 4. Execute the following to sort: :'a,.!perl -pe 's/^(\t\[")(.*?)(".*)$/$2 @@@ $1$2$3/' | sort -f | perl -pe 's/.*? @@@ //' Note that a simple `sort -f` (where `-f` means case-insensitive) would almost work, but it would sort "hill station" before "hill" and "county borough" before "county" because the space after e.g. "hill station" sorts before the quotation mark after e.g. "hill". The above command deals with this by extracting the key, prepending it followed by ` @@@ `, sorting, and then removing key (the classic decorate-sort-undecorate pattern). 5. Put the table back to multi-line format by marking the top of the table with `ma`, going to the bottom and executing :'a,.s/\\n/\r/g Note that for some reason, in order to get a match a newline in the left side of a replacement, you must use \n, but to insert a newline in the right sode of a replacement you must use \r. ]=] ["*"] = { link = false, cat_handler = generic_place_cat_handler, }, ["administrative atoll"] = { -- Maldives link = "+w:administrative divisions of the Maldives", preposition = "of", class = "subpolity", }, ["administrative capital"] = { link = "w", fallback = "capital city", }, ["administrative center"] = { link = "w", fallback = "non-city capital", }, ["administrative centre"] = { link = "w", fallback = "administrative center", }, ["administrative county"] = { link = "w", fallback = "county", }, ["administrative district"] = { link = "w", fallback = "district", }, ["administrative headquarters"] = { link = "separately", fallback = "administrative centre", }, ["administrative region"] = { link = true, preposition = "of", suffix = "region", -- but prefix is still "administrative region (of)" fallback = "region", class = "subpolity", }, ["administrative seat"] = { link = "w", fallback = "administrative centre", }, ["administrative territory"] = { link = "separately", preposition = "of", suffix = "territory", -- but prefix is still "administrative territory (of)" fallback = "territory", class = "subpolity", }, ["administrative unit"] = { -- Grrr, it's difficult to generalize about "administrative units". In Albania, "administrative unit" is an -- official term for a city-level division of municipalities; Wikipedia renders it using the more practical term -- "commune". In Pakistan, "administrative unit" is a collective term used to refer to all the different types -- of first-level divisions (four provinces, one federal territory, and two "disputed territories", i.e. Azad -- Kashmir and Gilgit-Balistan, that are variously described). For this reason, we set no fallback, but we need -- to include this so that it can be used as a placetype for Albania, categorizing as communes. link = "w", class = "subpolity", }, ["administrative village"] = { link = "w", preposition = "of", has_neighborhoods = true, class = "settlement", }, ["aimag"] = { -- used in Mongolia, Russia and China (Inner Mongolia); in Mongolia, equivalent to a province; -- in China, equivalent to a prefecture (below a province); in Russia, equivalent to a municipal district. link = "w", fallback = "prefecture", }, ["airport"] = { link = true, class = "man-made structure", default = {true}, }, ["alliance"] = { link = true, fallback = "confederation", }, ["archipelago"] = { link = true, fallback = "island", }, ["area"] = { link = true, preposition = "of", fallback = "geographic and cultural area", -- Areas can either be administrative divisions (specifically of Kuwait) or geographic areas. Assume the former -- when categorizing 'Areas' but the latter when handling e.g. 'historical area'. class = "subpolity", former_type = "geographic region", cat_handler = district_neighborhood_cat_handler, }, ["arm"] = { link = true, preposition = "of", class = "natural feature", default = {"Seas"}, }, ["arrondissement"] = { link = true, preposition = "of", -- FIXME!!! Grrrrr!!! In some countries, arrondissements are divisions of cities; in others, they are divisions -- of departments or provinces. Need to conditionalize on the country for both of the following. class = "subpolity", has_neighborhoods = true, }, ["associated province"] = { link = "separately", fallback = "province", }, ["atoll"] = { -- FIXME! Atolls are administrative divisions of the Maldives but natural features elsewhere. Need to -- conditionalize `class` on the country. See also `administrative atoll`. link = true, class = "natural feature", bare_category_parent = "islands", default = {true}, }, ["autonomous city"] = { link = "w", preposition = "of", fallback = "city", has_neighborhoods = true, }, ["autonomous community"] = { -- Spain; refers to regional entities, not village-like entities, as might be expected from "community" link = true, preposition = "of", class = "subpolity", }, ["autonomous island"] = { -- Comoros; seems like an administrative atoll of the Maldives. link = "+w:autonomous islands of Comoros", preposition = "of", class = "subpolity", }, ["autonomous oblast"] = { link = true, preposition = "of", affix_type = "Suf", no_affix_strings = "oblast", class = "subpolity", }, ["autonomous okrug"] = { link = true, preposition = "of", affix_type = "Suf", no_affix_strings = "okrug", class = "subpolity", }, ["autonomous prefecture"] = { link = true, fallback = "prefecture", }, ["autonomous province"] = { link = "w", fallback = "province", }, ["autonomous region"] = { link = "w", preposition = "of", fallback = "administrative region", -- "administrative region" sets an affix of "region" but we want to display as "Tibet Autonomous Region" -- if the user writes 'ar:Suf/Tibet'. affix = "autonomous region", }, ["autonomous republic"] = { link = "w", preposition = "of", class = "subpolity", }, ["autonomous territorial unit"] = { -- Moldova; only two of them, one for Gagauzia and one for Transnistria. link = "w", preposition = "of", class = "subpolity", }, ["autonomous territory"] = { link = "w", fallback = "dependent territory", }, ["bailiwick"] = { -- Jersey, etc. link = true, fallback = "polity", }, ["barangay"] = { -- Philippines link = true, class = "settlement", -- Barangays are formal administrative divisions of a city rather than informal neighborhoods, but can use -- some of the properties of a neighborhood. fallback = "neighborhood", }, ["barrio"] = { -- Spanish-speaking countries; Philippines link = true, -- FIXME: Not completely correct, in some countries barrios are formal administrative divisions of a city. -- `class` will need to conditionalize on the country to be completely correct. fallback = "neighborhood", }, ["basin"] = { link = true, fallback = "lake", }, ["bay"] = { link = true, preposition = "of", class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["beach"] = { link = true, class = "natural feature", addl_bare_category_parents = {"water"}, default = {true}, }, ["beach resort"] = { link = "w", fallback = "resort town", }, ["bishopric"] = { link = true, fallback = "polity", }, ["bodies of water!"] = { -- FIXME: This is (maybe?) a type category not a name category. There should be an option for this. We need to -- straighten out the type vs. name vs. related-to issue. category_link = "[[body of water|bodies of water]]", class = "natural feature", addl_bare_category_parents = {"landforms", "ecosystems", "water"}, }, ["borough"] = { link = true, preposition = "of", display_handler = borough_display_handler, has_neighborhoods = true, -- "former borough" could be a former settlement or a former part of a city but seems more likely to -- be a former subpolity, particularly in England. FIXME, we really need a handler to take care of this -- properly. class = "subpolity", -- Grr, some boroughs are city-like but some (e.g. in Britain) may be larger. }, ["borough seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["branch"] = { link = true, preposition = "of", fallback = "river", }, ["bridge"] = { link = true, class = "man-made structure", default = {"Named bridges"}, }, ["building"] = { link = true, class = "man-made structure", default = {"Named buildings"}, }, ["built-up area"] = { link = "w", fallback = "area", }, ["burgh"] = { link = true, fallback = "borough", }, ["business park"] = { link = true, fallback = "park", }, ["caliphate"] = { link = true, fallback = "polity", }, ["canton"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["cape"] = { link = true, fallback = "headland", }, ["capital"] = { link = true, fallback = "capital city", }, ["capital city"] = { link = true, category_link = "[[capital city|capital cities]]: the [[seat of government|seats of government]] for a country or [[political]] [[division]] of a country", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", bare_category_parent = "cities", cat_handler = capital_city_cat_handler, default = {true}, -- The following is necessary so that e.g. [[Melbourne]] defined as {{place|en|capital city|s/Victoria|c/Australia}} -- gets categorized in the bare category [[Category:en:Melbourne]]; otherwise placetype 'capital city' wouldn't -- match against the placetype 'city' of Melbourne. fallback = "city", }, ["caplc"] = { link = "[[capital]] and [[large]]st [[city]]", plural_link = false, fallback = "capital city", }, ["captaincy"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["caravan city"] = { link = "w", fallback = "city", class = "settlement", inherently_former = {"ANCIENT", "FORMER"}, }, ["castle"] = { link = true, fallback = "building", }, ["cathedral city"] = { link = true, fallback = "city", }, ["cattle station"] = { -- Australia link = true, fallback = "farm", }, ["census area"] = { link = true, affix_type = "Suf", has_neighborhoods = true, class = "non-admin settlement", }, ["census-designated place"] = { -- United States link = true, class = "non-admin settlement", }, ["census division"] = { -- Canada link = "w", preposition = "of", class = "subpolity", }, ["census town"] = { link = "w", fallback = "town", }, ["central business district"] = { link = true, fallback = "neighborhood", }, ["cercle"] = { -- Mali link = "+w:cercles of Mali", preposition = "of", class = "subpolity", }, ["ceremonial county"] = { link = true, fallback = "county", }, ["chain of islands"] = { link = "[[chain]] of [[island]]s", plural = "chains of islands", plural_link = "[[chain]]s of [[island]]s", fallback = "island", }, ["channel"] = { link = true, fallback = "strait", }, ["charter community"] = { -- Northwest Territories, Canada link = "w", fallback = "village", }, ["chiwog"] = { -- Bhutan link = true, preposition = "of", class = "subpolity", }, ["city"] = { link = true, generic_before_non_cities = "in", has_neighborhoods = true, class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["city-state"] = { link = true, category_link = "[[sovereign]] [[microstate]]s consisting of a single [[city]] and [[w:dependent territory|dependent territories]]", has_neighborhoods = true, class = "settlement", ["continent/*"] = {"City-states", "Cities in +++", "Countries in +++", "National capitals"}, default = {"City-states", "Cities", "Countries", "National capitals"}, }, ["civil parish"] = { -- Mostly England; similar to municipalities link = true, preposition = "of", affix_type = "suf", has_neighborhoods = true, class = "subpolity", }, ["claimed political division"] = { link = "[[claim]]ed [[political]] [[division]]", class = "subpolity", default = {true}, }, ["co-capital"] = { link = "[[co-]][[capital]]", fallback = "capital city", }, ["coal city"] = { link = "+w:coal town", fallback = "city", }, ["coal town"] = { link = "w", fallback = "town", }, ["collectivity"] = { link = "w", preposition = "of", -- No default; these are weird one-off governmental divisions in France (esp. for overseas collectivities) class = "subpolity", }, ["colony"] = { link = true, fallback = "dependent territory", }, ["comarca"] = { -- per Wikipedia: traditional region or local administrative division found in Portugal, Spain, and some of -- their former colonies, like Brazil, Nicaragua, and Panama. In the Valencian Community, for example, it -- sits between municipalities and provinces, something like a county or district. link = true, preposition = "of", class = "subpolity", }, ["commandery"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"ANCIENT", "FORMER"}, }, ["commonwealth"] = { link = true, preposition = "of", -- No default; applies specifically to Puerto Rico class = "subpolity", }, ["commune"] = { link = true, fallback = "municipality", }, ["community"] = { link = true, category_link = "[[community|communities]] of all sizes", fallback = "village", }, ["community development block"] = { -- in India; appears to be similar to a rural municipality; groups several villages, unclear if there will be -- neighborhoods so I'm not setting `has_neighborhoods` for now link = "w", affix_type = "suf", no_affix_strings = "block", class = "subpolity", }, ["comune"] = { -- Italy, Switzerland link = true, fallback = "municipality", }, ["condominium"] = { link = true, fallback = "polity", }, ["confederacy"] = { link = true, fallback = "confederation", }, ["confederation"] = { link = true, fallback = "polity", }, ["constituency"] = { -- currently we have them as political divisions of Namibia but many countries have them link = true, preposition = "of", class = "subpolity", }, ["constituent country"] = { link = true, preposition = "of", class = "subpolity", }, ["constituent part"] = { link = "separately", preposition = "of", class = "subpolity", }, ["constituent republic"] = { -- Of Russia, Yugoslavia, etc. link = "separately", preposition = "of", class = "subpolity", }, ["counties and county-level cities!"] = { -- This is used when grouping counties and county-level cities under prefecture-level cities in China. category_link = "[[county|counties]] and [[county-level city|county-level cities]]", class = "subpolity", }, ["continent"] = { link = true, category_link = false, -- can't occur as a bare category class = "natural feature", default = {"Continents and continental regions"}, }, ["continental region"] = { link = "separately", category_link = false, -- can't occur as a bare category class = "geographic region", fallback = "continent", }, ["continents and continental regions!"] = { category_link = "[[continent]]s and [[continent]]-[[level]] [[region]]s (e.g. [[Polynesia]])", class = "geographic region", }, ["council area"] = { link = true, -- in Scotland; similar to a county preposition = "of", affix_type = "suf", class = "subpolity", }, ["country"] = { link = true, class = "polity", ["continent/*"] = {true, "Countries"}, default = {true}, }, ["country-like entities!"] = { category_link = "[[polity|polities]] not normally considered [[country|countries]] but treated similarly for categorization purposes; typically, [[unrecognized]] [[de-facto]] countries or [[w:dependent territory|dependent territories]]", class = "polity", }, ["county"] = { link = true, preposition = "of", display_handler = county_display_handler, class = "subpolity", }, ["county borough"] = { link = true, -- in Wales; similar to a county preposition = "of", affix_type = "suf", fallback = "borough", class = "subpolity", }, ["county seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["county town"] = { link = true, entry_placetype_use_the = true, preposition = "of", fallback = "town", has_neighborhoods = true, class = "capital", }, ["county-administered city"] = { -- In Taiwan, per Wikipedia similar to a Taiwanese township or district, which is a small city. -- NOT anything like a "county-level city" in PR China, which is a county masquerading as a city. link = "w", fallback = "city", has_neighborhoods = true, class = "settlement", }, ["county-controlled city"] = { -- Taiwan link = "w", fallback = "county-administered city", }, ["county-level city"] = { -- PR China link = "w", fallback = "prefecture-level city", }, ["crater lake"] = { link = true, fallback = "lake", }, ["creek"] = { link = true, fallback = "stream", }, ["Crown colony"] = { link = "+crown colony", fallback = "crown colony", }, ["crown colony"] = { link = true, fallback = "colony", }, ["Crown dependency"] = { link = true, fallback = "dependent territory", }, ["crown dependency"] = { link = true, fallback = "dependent territory", }, ["cultural area"] = { link = "w", fallback = "geographic and cultural area", }, ["cultural region"] = { link = "w", fallback = "geographic and cultural area", }, ["delegation"] = { -- Tunisia link = "+w:delegations of Tunisia", preposition = "of", class = "subpolity", }, ["department"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["departmental capital"] = { link = "separately", fallback = "capital city", }, ["dependency"] = { link = true, fallback = "dependent territory", }, ["dependent territory"] = { link = "w", preposition = "of", class = "subpolity", former_type = "dependent territory", bare_category_parent = "political divisions", ["country/*"] = {true}, default = {true}, }, ["desert"] = { link = true, class = "natural feature", addl_bare_category_parents = {"ecosystems"}, default = {true}, }, ["deserted mediaeval village"] = { link = "w", fallback = "deserted medieval village", }, ["deserted medieval village"] = { link = "w", fallback = "ANCIENT settlement", }, ["direct-administered municipality"] = { -- China link = "+w:direct-administered municipalities of China", fallback = "municipality", }, ["direct-controlled municipality"] = { -- several countries link = "w", fallback = "municipality", }, ["distributary"] = { link = true, preposition = "of", fallback = "river", }, ["district"] = { link = true, preposition = "of", affix_type = "suf", -- Grrr! FIXME! Here is where we need handlers for `class`. Using similar logic to -- district_neighborhood_cat_handler, we need to check if we're below or above a city to determine if the class -- is "settlement" or "subpolity". class = "subpolity", cat_handler = district_neighborhood_cat_handler, -- No default. Countries for which districts are political divisions will get entries. }, ["districts and autonomous regions!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Portugal. category_link = "[[district]]s and [[autonomous region]]s", class = "subpolity", }, ["districts and autonomous territorial units!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Moldova. category_link = "[[district]]s and [[w:autonomous territorial unit|autonomous territorial unit]]s", class = "subpolity", }, ["district capital"] = { link = "separately", fallback = "capital city", }, ["district headquarters"] = { link = "separately", fallback = "administrative centre", }, ["district municipality"] = { -- In Canada, a district municipality is equivalent to a rural municipality and won't have neighborhoods; in -- South Africa, district municipalities group local municipalities and hence won't have neighborhoods. link = "w", preposition = "of", affix_type = "suf", no_affix_strings = {"district", "municipality"}, fallback = "municipality", class = "subpolity", }, ["division"] = { link = true, preposition = "of", class = "subpolity", }, ["division capital"] = { link = "separately", fallback = "capital city", }, ["dome"] = { link = true, fallback = "mountain", }, ["dormant volcano"] = { link = true, fallback = "volcano", }, ["duchy"] = { link = true, fallback = "polity", }, ["emirate"] = { link = true, preposition = "of", -- FIXME: Can be subpolities (of the United Arab Emirates). fallback = "polity", }, ["empire"] = { link = true, fallback = "polity", }, ["enclave"] = { link = true, preposition = "of", -- Enclaves can theoretically be any size but assume a subpolity. class = "subpolity", }, ["entity"] = { -- Bosnia and Herzegovina link = "+w:entities of Bosnia and Herzegovina", preposition = "of", class = "subpolity", }, ["escarpment"] = { link = true, fallback = "mountain", }, ["ethnographic region"] = { -- used in Lithuania link = "+w:ethnographic regions of Lithuania", fallback = "geographic and cultural area", }, ["exclave"] = { link = true, preposition = "of", -- exclaves can theoretically be any size but assume a subpolity. class = "subpolity", }, ["external territory"] = { link = "separately", fallback = "dependent territory", }, ["farm"] = { link = true, class = "non-admin settlement", default = {"Farms and ranches"}, }, ["farms and ranches!"] = { category_link = "[[farm]]s and [[ranch]]es", class = "non-admin settlement", }, ["federal city"] = { link = "w", preposition = "of", fallback = "city", }, ["federal district"] = { link = true, preposition = "of", -- Might have neighborhoods as federal districts are often cities (e.g. Mexico City) has_neighborhoods = true, class = "settlement", }, ["federal subject"] = { -- In Russia; a generic term for first-level administrative divisions (republics, oblasts, okrugs, krais, -- autonomous okrugs and autonomous oblasts). link = "w", preposition = "of", class = "subpolity", }, ["federal territory"] = { link = "w", fallback = "territory", }, ["fictional location"] = { link = "separately", former_type = "!", class = "hypothetical location", bare_category_parent = "places", default = {true}, }, ["First Nations reserve"] = { -- Canada link = "[[First Nations]] [[w:Indian reserve|reserve]]", -- Wikipedia uses "Indian reserve"; presumably that is the legal term fallback = "Indian reserve", class = "subpolity", }, ["fjord"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["footpath"] = { link = true, fallback = "road", }, ["forest"] = { link = true, class = "natural feature", addl_bare_category_parents = {"ecosystems", "forestry"}, default = {true}, }, ["fort"] = { link = true, fallback = "building", }, ["fortress"] = { link = true, -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- fortresses -> fortresse, so put an entry here to ensure we singularize correctly. plural = "fortresses", fallback = "building", }, ["frazione"] = { link = "w", fallback = "hamlet", }, ["freeway"] = { link = true, fallback = "road", }, ["French prefecture"] = { link = "[[w:prefectures in France|prefecture]]", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", }, ["geographic and cultural area"] = { link = "+w:cultural area", -- `generic_before_non_cities` is used when generating the category description of categories of the format -- `Geographic and cultural areas of PLACE`. `preposition` is used when generating {{place}} description and -- categories for any placetype that falls back to `geographic and cultural area`. generic_before_non_cities = "of", preposition = "of", class = "geographic region", bare_category_parent = "places", ["country/*"] = {true}, ["constituent country/*"] = {true}, ["continent/*"] = {true}, default = {true}, }, ["geographic area"] = { link = "+w:geographic region", fallback = "geographic and cultural area", }, ["geographic region"] = { link = "w", fallback = "geographic and cultural area", }, ["geographical area"] = { link = "w", fallback = "geographic and cultural area", }, ["geographical region"] = { link = "w", fallback = "geographic and cultural area", }, ["geopolitical zone"] = { -- Nigeria link = true, preposition = "of", class = "subpolity", }, ["gewog"] = { -- Bhutan link = true, preposition = "of", class = "subpolity", }, ["ghost town"] = { link = true, generic_before_non_cities = "in", class = "non-admin settlement", bare_category_parent = "former settlements", cat_handler = city_type_cat_handler, default = {true}, }, ["glen"] = { link = true, fallback = "valley", }, ["governorate"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["greater administrative region"] = { -- China (former division) link = "w", preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["gromada"] = { -- Poland (former division) link = "w", preposition = "of", affix_type = "Pref", class = "subpolity", inherently_former = {"FORMER"}, }, ["group of islands"] = { link = "[[group]] of [[island]]s", plural = "groups of islands", plural_link = "[[group]]s of [[island]]s", fallback = "island group", }, ["gulf"] = { link = true, preposition = "of", holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["hamlet"] = { link = true, fallback = "village", }, ["harbor city"] = { link = "separately", fallback = "city", }, ["harbor town"] = { link = "separately", fallback = "town", }, ["harbour city"] = { link = "separately", fallback = "city", }, ["harbour town"] = { link = "separately", fallback = "town", }, ["headland"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["headquarters"] = { link = "w", fallback = "administrative centre", }, ["heath"] = { link = true, fallback = "moor", }, ["hemisphere"] = { link = true, entry_placetype_use_the = true, fallback = "continental region", }, ["highway"] = { link = true, fallback = "road", }, ["hill"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["hill station"] = { link = "w", fallback = "town", }, ["hill town"] = { link = "w", fallback = "town", }, ["historic region"] = { -- provided only for the link link = "+w:historical region", fallback = "FORMER geographic region", }, ["historical county"] = { -- needed for historical counties of England/etc. link = "+w:historic county", fallback = "FORMER subpolity", }, ["historical region"] = { -- provided only for the link link = "w", fallback = "FORMER geographic region", }, ["home rule city"] = { link = "w", fallback = "city", }, ["home rule municipality"] = { link = "w", fallback = "municipality", }, ["hot spring"] = { link = true, fallback = "spring", }, ["house"] = { link = true, fallback = "building", }, ["housing estate"] = { -- not the same as a housing project (i.e. public housing) link = true, -- not exactly the case but approximately fallback = "neighborhood", }, ["hromada"] = { -- Ukraine link = "w", disallow_in_entries = "Use placetype 'urban hromada', 'rural hromada' or 'settlement hromada' in place of bare 'hromada'", disallow_in_holonyms = "Use placetype 'urban hromada'/'uhrom', 'rural hromada'/'rhrom' or 'settlement hromada'/'shrom' in place of bare 'hromada'", preposition = "of", affix_type = "suf", class = "subpolity", }, ["inactive volcano"] = { link = "w", fallback = "dormant volcano", }, ["independent city"] = { link = true, fallback = "city", }, ["independent town"] = { link = "+independent city", fallback = "town", }, ["Indian reservation"] = { link = "w", -- In the US. Also known as "Native American reservation" or "domestic dependent nation", and the reservations -- themselves often use the term "nation" in their official name (e.g. the "Navajo Nation"). But Wikipedia puts -- the article at [[w:Indian reservation]] and uses that term when describing e.g. what the Navajo Nation is, -- so this must still be the legal term. preposition = "of", class = "subpolity", default = {true}, }, ["Indian reserve"] = { link = "w", -- In Canada. "First Nations reserve" sounds more modern/PC but Wikipedia uses "Indian reserve"; presumably that -- is still the legal term. preposition = "of", class = "subpolity", default = {true}, }, ["inland sea"] = { -- note, we also have 'inland' as a qualifier link = true, fallback = "sea", }, ["inner city area"] = { link = "[[inner city]] [[area]]", fallback = "neighborhood", }, ["island"] = { link = true, preposition = "of", class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["island country"] = { -- FIXME: The following should map to both 'island' and 'country'. link = "w", fallback = "country", }, ["island group"] = { link = "separately", fallback = "island", }, ["island municipality"] = { link = "w", fallback = "municipality", }, ["islet"] = { link = "w", fallback = "island", }, ["Israeli settlement"] = { link = "w", class = "settlement", default = {true}, }, ["judicial capital"] = { link = "w", fallback = "capital city", }, ["khanate"] = { link = true, fallback = "polity", }, ["kibbutz"] = { link = true, plural = "kibbutzim", class = "non-admin settlement", default = {true}, }, ["kingdom"] = { link = true, fallback = "monarchy", }, ["krai"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["lake"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["landforms!"] = { category_link = "[[landform]]s", bare_category_parent = "places", addl_bare_category_parents = {"Earth"}, }, ["largest city"] = { link = "[[large]]st [[city]]", entry_placetype_use_the = true, fallback = "city", has_neighborhoods = true, }, ["league"] = { link = true, fallback = "confederation", }, ["legislative capital"] = { link = "separately", fallback = "capital city", }, ["library"] = { link = true, fallback = "building", }, ["lieutenancy area"] = { -- used in the United Kingdom; per Wikipedia: -- In England, lieutenancy areas are colloquially known as the ceremonial counties, although this phrase does -- not appear in any legislation referring to them. The lieutenancy areas of Scotland are subdivisions of -- Scotland that are more or less based on the counties of Scotland, making use of the major cities as separate -- entities.[2] In Wales, the lieutenancy areas are known as the preserved counties of Wales and are based on -- those used for lieutenancy and local government between 1974 and 1996. The lieutenancy areas of Northern -- Ireland correspond to the six counties and two former county boroughs.[3] link = "w", fallback = "ceremonial county", }, ["local authority district"] = { link = "w", fallback = "local government district", }, ["local government area"] = { -- Australia link = "w", preposition = "of", class = "subpolity", }, ["local council"] = { -- Malta; similar to municipalities link = "+w:local councils of Malta", preposition = "of", fallback = "municipality", }, ["local government district"] = { link = "w", preposition = "of", affix_type = "suf", affix = "district", class = "subpolity", }, ["local government district with borough status"] = { link = "[[w:local government district|local government district]] with [[w:borough status|borough status]]", plural = "local government districts with borough status", plural_link = "[[w:local government district|local government districts]] with [[w:borough status|borough status]]", preposition = "of", affix_type = "suf", affix = "district", class = "subpolity", }, ["local urban district"] = { link = "w", fallback = "unincorporated community", }, ["locality"] = { link = "+w:locality (settlement)", -- not necessarily true, but usually is the case fallback = "village", }, ["London borough"] = { link = "w", preposition = "of", affix_type = "pref", affix = "borough", fallback = "local government district with borough status", has_neighborhoods = true, }, ["macroregion"] = { link = true, fallback = "region", }, ["man-made structures!"] = { category_link = "[[w:geographical feature#Engineered constructs|man-made structures]] such as [[airport]]s, [[university|universities]] and [[metro station]]s", bare_category_parent = "places", }, ["manor"] = { -- FIXME: or is this more like a farm? link = true, fallback = "building", }, ["marginal sea"] = { link = true, preposition = "of", fallback = "sea", }, ["market city"] = { link = "+market town", fallback = "city", }, ["market town"] = { link = true, fallback = "town", }, ["massif"] = { link = true, fallback = "mountain", }, ["megacity"] = { link = true, fallback = "city", }, ["metro station"] = { link = true, class = "man-made structure", }, ["metropolitan borough"] = { link = true, preposition = "of", affix_type = "Pref", no_affix_strings = {"borough", "city"}, fallback = "local government district", has_neighborhoods = true, }, ["metropolitan city"] = { -- These exist e.g. in Italy and are more like municipalities or even provinces than cities. link = true, preposition = "of", affix_type = "Pref", no_affix_strings = {"metropolitan", "city"}, class = "subpolity", }, ["metropolitan county"] = { link = true, fallback = "county", }, ["metropolitan municipality"] = { -- In South Africa, metropolitan municipalities group local municipalities and are like districts, between -- provinces and municipalities. -- In Turkey, metropolitan municipalities are provinces-level. link = "w", preposition = "of", affix_type = "Suf", no_affix_strings = {"metropolitan", "municipality"}, fallback = "municipality", class = "subpolity", }, ["microdistrict"] = { -- residential complex in post-Soviet states link = true, fallback = "neighborhood", }, ["micronations!"] = { -- FIXME, merge with microstate category_link = "[[micronation]]s", bare_category_parent = "countries", }, ["microstate"] = { link = true, fallback = "country", }, ["military base"] = { link = "w", class = "settlement", -- or "man-made structure"? default = {true}, }, ["minster town"] = { -- England link = "separately", fallback = "town", }, ["monarchy"] = { link = true, fallback = "polity", }, ["moor"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms", "ecosystems"}, default = {true}, }, ["moorland"] = { link = true, fallback = "moor", }, ["motorway"] = { link = true, fallback = "road", }, ["mountain"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["mountain indigenous district"] = { -- Taiwan link = "+w:district (Taiwan)", fallback = "district", }, ["mountain indigenous township"] = { -- Taiwan link = "+w:township (Taiwan)", fallback = "township", }, ["mountain pass"] = { link = true, -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- passes -> passe, so put an entry here to ensure we singularize correctly. plural = "mountain passes", class = "natural feature", addl_bare_category_parents = {"mountains"}, default = {true}, }, ["mountain range"] = { link = true, fallback = "mountain", }, ["mountainous region"] = { link = "separately", fallback = "region", }, ["mukim"] = { -- Malaysia, Brunei, Indonesia, Singapore link = true, preposition = "of", class = "subpolity", }, ["municipal district"] = { link = "w", -- meaning varies depending on the country; for now, assume no neighborhoods. -- FIXME: has_neighborhoods might have to be a function that looks at the containing holonyms. preposition = "of", affix_type = "Pref", no_affix_strings = "district", fallback = "municipality", }, ["municipality"] = { link = true, preposition = "of", has_neighborhoods = true, class = "subpolity", }, ["municipality with city status"] = { link = "[[municipality]] with [[w:city status|city status]]", plural = "municipalities with city status", plural_link = "[[municipality|municipalities]] with [[w:city status|city status]]", fallback = "municipality", }, ["museum"] = { link = true, fallback = "building", }, ["mythological location"] = { link = "separately", former_type = "!", class = "hypothetical location", bare_category_parent = "places", default = {true}, }, ["named bridges!"] = { category_link = "notable [[bridge]]s", bare_category_parent = "man-made structures", addl_bare_category_parents = {"bridges"}, }, ["named buildings!"] = { category_link = "notable [[house]]s, [[library|libraries]] and other [[building]]s", bare_category_parent = "man-made structures", addl_bare_category_parents = {"buildings"}, }, ["named roads!"] = { category_link = "notable [[road]]s, [[highway]]s, [[trail]]s and similar linear structures", bare_category_parent = "man-made structures", addl_bare_category_parents = {"roads"}, }, ["national capital"] = { link = "w", fallback = "capital city", }, ["national park"] = { link = true, fallback = "park", }, ["natural features!"] = { category_link = "[[w:geographical feature#Natural features|natural features]] such as [[lake]]s, [[mountain]]s, [[island]]s and [[ocean]]s", bare_category_parent = "places", }, ["neighborhood"] = { -- The majority of the properties here apply to both `neighborhoods` and `neighbourhoods`; the choice of which -- one to use is made by district_neighborhood_cat_handler() based on the value of `british_spelling` for the -- location (city, political division, etc.) of the holonym that follows the word "neighbo(u)hoods" in the -- category name. It does *NOT* depend on whether the {{place}} call uses "neighborhoods" or "neighbourhoods". -- (In general it can't, because other things like "urban areas", "districts", "subdivisions" and the like also -- categorize as neighbo(u)rhoods.) link = true, -- See below. These are used by category handlers in [[Module:category tree/topic cat/data/Places]]. generic_before_non_cities = "in", generic_before_cities = "of", -- The following text is suitable for the top-level description of a neighborhood as well as categories of the -- form `Neighborhoods in POLDIV` e.g. `Neighborhoods in Illinois, USA` but not for categories of the form -- `Neighborhoods of Chicago`, where we'd get "... and other subportions of [[city|cities]] of [[Chicago]]". category_link = "[[neighborhood]]s, [[district]]s and other subportions of [[city|cities]]", category_link_before_city = "[[neighborhood]]s, [[district]]s and other subportions", -- NOTE: This setting is needed for administrative divisions like barangays that fall back to `neighborhood`, -- when set in [[Module:place/locations]] for a specific country (e.g. the Philippines). The above settings -- for `generic_before_non_cities` and `generic_before_cities` are used by category handlers in -- [[Module:category tree/topic cat/data/Places]] for `Neighborhoods in POLDIV` and `Neighborhoods of CITY` -- categories. In fact, district_neighborhood_cat_handler() does not currently pay attention to them, but -- generates "of" before cities and "in" before non-cities regardless. (FIXME: We should change that.) preposition = "of", class = "non-admin settlement", cat_handler = district_neighborhood_cat_handler, }, ["neighbourhood"] = { link = true, category_link = "[[neighbourhood]]s, [[district]]s and other subportions of [[city|cities]]", category_link_before_city = "[[neighbourhood]]s, [[district]]s and other subportions", fallback = "neighborhood", }, ["new area"] = { -- China (type of economic development zone, varying greatly in size) link = "w", preposition = "in", class = "subpolity", --? }, ["new town"] = { link = true, fallback = "town", }, ["non-city capital"] = { link = "[[capital]]", entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", cat_handler = function(data) return capital_city_cat_handler(data, "non-city") end, -- FIXME, do we need the following? default = {true}, }, ["non-metropolitan county"] = { link = "w", fallback = "county", }, ["non-metropolitan district"] = { link = "w", fallback = "local government district", }, ["non-sovereign kingdom"] = { -- especially in Africa and Asia link = "+w:non-sovereign monarchy", generic_before_non_cities = "in", class = "subpolity", ["country/*"] = {true}, ["continent/*"] = {true}, default = {true}, }, ["non-sovereign monarchy"] = { link = "w", fallback = "non-sovereign kingdom", }, ["oblast"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["oblasts and autonomous republics!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Ukraine. category_link = "[[oblast]]s and [[w:autonomous republic|autonomous republic]]s", class = "subpolity", }, ["ocean"] = { link = true, holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"seas", "bodies of water"}, default = {true}, }, ["okrug"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["overseas collectivity"] = { link = "w", fallback = "collectivity", }, ["overseas department"] = { link = "w", fallback = "department", }, ["overseas territory"] = { link = "w", fallback = "dependent territory", }, ["parish"] = { link = true, preposition = "of", affix_type = "suf", class = "subpolity", }, ["parish municipality"] = { -- in Quebec, often similar to a rural village; the famous [[Saint-Louis-du-Ha! Ha!]] is one of them. link = "+w:parish municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, }, ["parish seat"] = { link = true, entry_placetype_use_the = true, preposition = "of", class = "capital", has_neighborhoods = true, }, ["park"] = { link = true, class = "man-made structure", default = {true}, }, ["pass"] = { link = "+mountain pass", -- The default plural algorithm gets this right but the singularization algorithm incorrectly converts -- passes -> passe, so put an entry here to ensure we singularize correctly. plural = "passes", fallback = "mountain pass", }, ["path"] = { link = true, fallback = "road", }, ["peak"] = { link = true, fallback = "mountain", }, ["peninsula"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, }, ["periphery"] = { link = true, preposition = "of", class = "subpolity", }, ["places!"] = { generic_before_non_cities = "in", generic_before_cities = "in", class = "generic place", category_link = "[[place]]s of all sorts", -- `category_link_top_level` control the description used in the top-level [[Category:Places]] and -- language-specific variants such as [[Category:en:Places]]. The actual text for a language-spefic variant is -- "{{{langname}}} names of [[geographical]] [[place]]s of all sorts; [[toponym]]s." where the "names of" -- portion is automatically generated by the appropriate handler in -- [[Module:category tree/topic cat/data/Places]]. category_link_top_level = "[[geographical]] [[place]]s of all sorts; [[toponym]]s", bare_category_parent = "names", }, ["planned community"] = { -- Include this so we don't categorize 'planned community' into villages, as 'community' does. link = true, class = "settlement", has_neighborhoods = true, }, ["plateau"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true}, -- FIXME: Should generate both "Plateaus" and the appropriate 'geographic and cultural area' category }, ["Polish colony"] = { link = "[[w:colony (Poland)|colony]]", affix_type = "suf", affix = "colony", fallback = "village", has_neighborhoods = true, }, ["political divisions!"] = { category_link = "[[political]] [[division]]s and [[subdivision]]s, such as [[state]]s, [[province]]s, [[county|counties]] or [[district]]s", bare_category_parent = "places", }, ["polity"] = { link = true, category_link = "[[independent]] or [[semi-]][[independent]] [[polity|polities]]", class = "polity", bare_category_parent = "places", default = {true}, }, ["populated place"] = { link = "+w:populated place", -- not necessarily true, but usually is the case fallback = "village", }, ["port"] = { link = true, class = "man-made structure", default = {true}, }, ["port city"] = { -- FIXME: should categorize into "Ports" as well as "Cities" link = true, fallback = "city", }, ["port town"] = { -- FIXME: should categorize into "Ports" as well as "Towns" link = "w", fallback = "town", }, ["prefecture"] = { -- FIXME! `prefecture` is like a county in Japan and elsewhere but a department capital city in France. -- May need `has_neighborhoods` to be a function. link = true, preposition = "of", display_handler = prefecture_display_handler, class = "subpolity", }, ["prefecture-level city"] = { -- China; they are huge entities with a central city; not cities themselves. link = "w", preposition = "of", class = "subpolity", }, ["preserved county"] = { -- In Wales; they are former counties enshrined in law; there are 8 of them and each consists of one or more -- "principal areas" (styled as "counties" or "county boroughs"), of which there are 22. link = "w", preposition = "of", class = "subpolity", inherently_former = {"FORMER"}, }, ["primary area"] = { -- a grouping of "districts" (neighborhoods) in Gothenburg, Sweden link = "+w:sv:primärområde", fallback = "neighborhood", }, ["principality"] = { link = true, fallback = "monarchy", }, ["promontory"] = { link = true, fallback = "headland", }, ["protectorate"] = { link = true, fallback = "dependent territory", }, ["province"] = { link = true, preposition = "of", display_handler = province_display_handler, class = "subpolity", }, ["provinces and autonomous regions!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case China. category_link = "[[province]]s and [[autonomous region]]s", class = "subpolity", }, ["provinces and territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Canada and Pakistan. category_link = "[[province]]s and [[territory|territories]]", class = "subpolity", }, ["provincial capital"] = { link = "separately", fallback = "capital city", }, ["raion"] = { link = true, preposition = "of", affix_type = "Suf", class = "subpolity", }, ["ranch"] = { link = true, fallback = "farm", }, ["range"] = { -- FIXME: Where is this used? Is it a mountain range? link = true, holonym_use_the = true, class = "natural feature", }, ["regency"] = { link = true, preposition = "of", class = "subpolity", }, ["region"] = { link = true, preposition = "of", -- If 'region' isn't a specific administrative division, fall back to 'geographic and cultural area' fallback = "geographic and cultural area", -- "former region" is a subpolity but traditional/historic(al)/ancient/medieval/etc. is a geographic region class = "geographic region", }, ["regional capital"] = { link = "separately", fallback = "capital city", }, ["regional county municipality"] = { -- Quebec link = "w", preposition = "of", affix_type = "Suf", no_affix_strings = {"municipality", "county"}, fallback = "municipality", }, ["regional district"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "district", fallback = "district", }, ["regional municipality"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "municipality", fallback = "municipality", }, ["regional unit"] = { link = "w", preposition = "of", affix_type = "suf", class = "subpolity", }, ["registration county"] = { -- Used in Scotland for land registration purposes; formerly used in England, Wales and Ireland for statistical -- purposes (registration of births, deaths and marriages, and for the output of census information). link = "w", fallback = "county", }, ["republic"] = { -- Of Russia, Yugoslavia, etc. "Republics" in general are sovereign but we use "country" in that case. link = true, fallback = "constituent republic", }, ["research base"] = { link = "+w:research station", fallback = "research station", }, ["research station"] = { link = "w", class = "non-admin settlement", -- or "man-made structure"? default = {true}, }, ["reservoir"] = { link = true, fallback = "lake", }, ["residential area"] = { link = "separately", fallback = "neighborhood", }, ["resort city"] = { link = "w", fallback = "city", }, ["resort town"] = { link = "w", fallback = "town", }, ["river"] = { link = true, generic_before_non_cities = "in", holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, cat_handler = city_type_cat_handler, ["continent/*"] = {true}, default = {true}, }, ["river island"] = { link = "w", fallback = "island", }, ["road"] = { link = true, class = "man-made structure", default = {"Named roads"}, }, ["Roman province"] = { -- FIXME! Eliminate this in favor of 'former province|emp/Roman Empire' link = "w", default = {"Provinces of the Roman Empire"}, class = "subpolity", }, ["royal borough"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = {"royal", "borough"}, fallback = "local government district with borough status", has_neighborhoods = true, }, ["royal burgh"] = { link = true, fallback = "borough", }, ["royal capital"] = { link = "w", fallback = "capital city", }, ["rural committee"] = { -- Hong Kong; a group of villages link = "w", affix_type = "Suf", has_neighborhoods = true, class = "settlement", }, ["rural community"] = { -- New Brunswick link = "+w:list of municipalities in New_Brunswick#Rural communities", fallback = "municipality", }, ["rural hromada"] = { link = "[[rural]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["rural municipality"] = { link = "w", preposition = "of", affix_type = "Pref", no_affix_strings = "municipality", fallback = "municipality", has_neighborhoods = true, --? }, ["rural township"] = { -- Taiwan link = "+w:rural township (Taiwan)", fallback = "township", }, ["sanctuary"] = { link = true, fallback = "temple", }, ["satrapy"] = { link = true, preposition = "of", class = "subpolity", inherently_former = {"ANCIENT", "FORMER"}, }, ["sea"] = { link = true, holonym_use_the = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["seaport"] = { link = true, fallback = "port", }, ["seat"] = { link = true, fallback = "administrative centre", }, ["self-administered area"] = { -- Myanmar (groups self-administered divisions and zones) link = "+w:self-administered zone", preposition = "of", class = "subpolity", }, ["self-administered division"] = { -- Myanmar (only one of them: Wa Self-Administered Division) link = "w", fallback = "self-administered area", }, ["self-administered zone"] = { -- Myanmar (five of them) link = "w", fallback = "self-administered area", }, ["separatist state"] = { link = "separately", fallback = "unrecognized country", }, ["settlement"] = { link = true, category_link = "[[settlement]]s such as [[city|cities]], [[village]]s and [[farm]]s", bare_category_parent = "places", -- not necessarily true, but usually is the case fallback = "village", }, ["settlement hromada"] = { link = "[[w:Populated places in Ukraine#Rural settlements|settlement]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["sheading"] = { -- Isle of Man link = true, fallback = "district", }, ["sheep station"] = { -- Australia link = true, fallback = "farm", }, ["shire"] = { link = true, fallback = "county", }, ["shire county"] = { link = "w", fallback = "county", }, ["shire town"] = { link = true, fallback = "county seat", }, ["ski resort city"] = { link = "[[ski resort]] [[city]]", fallback = "city", }, ["ski resort town"] = { link = "[[ski resort]] [[town]]", fallback = "town", }, ["spa city"] = { link = "+w:spa town", fallback = "city", }, ["spa town"] = { link = "w", fallback = "town", }, ["space station"] = { link = true, fallback = "research station", }, ["special administrative region"] = { -- in China; in practice they are city-like (Hong Kong, Macau); also [[Oecusse]] in East Timor is formally a -- "special administrative region"; North Korea had one such region planned (Sinuiju) but abandoned; Indonesia -- has similar "special regions" of Jakarta, Yogyakarta and Aceh; and South Sudan has three "special -- administrative areas" link = "+w:special administrative regions of China", preposition = "of", class = "subpolity", has_neighborhoods = true, --? -- no suffix since places in Hong Kong or Macau are listed without China, except Hong Kong and Macau themselves -- they also contain regions (or areas), e.g. [[Kowloon]], so it would be confusing suffix = "", }, ["special collectivity"] = { link = "w", fallback = "collectivity", }, ["special municipality"] = { -- formerly linked to the Taiwan article but there are also special municipalities of the Netherlands link = "w", fallback = "municipality", }, ["special ward"] = { -- Tokyo link = true, fallback = "municipality", }, ["spit"] = { link = true, fallback = "peninsula", }, ["spring"] = { link = true, class = "natural feature", default = {true}, }, ["star"] = { link = true, class = "natural feature", default = {true}, }, ["state"] = { link = true, preposition = "of", class = "subpolity", -- 'former/historical state' could refer either to a state of a country (a division) or a state = sovereign -- entity. The latter appears more common (e.g. in various "ancient states" of East Asia). former_type = "polity", }, ["states and territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case Australia. category_link = "[[state]]s and [[territory|territories]]", class = "subpolity", }, ["states and union territories!"] = { -- This and other similar "combined placetypes" are for use in the plural when grouping first-level -- administrative regions of certain countries, in this case India. category_link = "[[state]]s and [[union territory|union territories]]", class = "subpolity", }, ["state capital"] = { link = "separately", fallback = "capital city", }, ["state park"] = { link = true, fallback = "park", }, ["state-level new area"] = { -- China (type of economic development zone, varying greatly in size) link = "w", fallback = "new area", }, ["statistical region"] = { -- Slovenia link = true, fallback = "administrative region", }, ["statutory city"] = { link = "w", fallback = "city", }, ["statutory town"] = { link = "w", fallback = "town", }, ["strait"] = { link = true, class = "natural feature", addl_bare_category_parents = {"bodies of water"}, default = {true}, }, ["stream"] = { link = true, fallback = "river", }, ["street"] = { link = true, fallback = "road", }, ["strip"] = { link = true, fallback = "geographic region", }, ["strip of land"] = { link = "[[strip]] of [[land]]", plural = "strips of land", plural_link = "[[strip]]s of [[land]]", fallback = "geographic region", }, ["sub-metropolitan city"] = { link = "+w:List of cities in Nepal#Sub-metropolitan cities", fallback = "city", }, ["sub-prefectural city"] = { link = "w", fallback = "subprovincial city", }, ["subdistrict"] = { link = true, preposition = "of", has_neighborhoods = true, --? -- FIXME: subdistricts can be neighborhood-like (of Jakarta) or larger (in China); need a handler class = "subpolity", default = {true}, }, ["subdivision"] = { link = true, preposition = "of", affix_type = "suf", -- FIXME: subdivisions can be neighborhood-like or larger; need a handler class = "subpolity", cat_handler = district_neighborhood_cat_handler, }, ["submerged ghost town"] = { -- FIXME: Consider just having "submerged" as a qualifier. link = "[[submerged]] [[ghost town]]", fallback = "ghost town", }, ["subnational kingdom"] = { link = "+w:subnational monarchy", fallback = "non-sovereign kingdom", }, ["subnational monarchy"] = { link = "w", fallback = "non-sovereign kingdom", }, ["subprefecture"] = { link = true, affix_type = "suf", preposition = "of", class = "subpolity", }, ["subprovince"] = { link = true, preposition = "of", class = "subpolity", }, ["subprovincial city"] = { link = "w", -- China; special status given to certain prefecture-level cities fallback = "prefecture-level city", }, ["subprovincial district"] = { link = "w", -- China; special status given to Binhai New Area and Pudong New Area, which are county-level districts preposition = "of", class = "subpolity", }, ["subregion"] = { link = true, fallback = "geographic region", }, ["suburb"] = { link = true, -- The following text is suitable for the top-level description of a suburb as well as categories of the form -- 'Suburbs in POLDIV' e.g. 'Suburbs in Illinois, USA' but not for categories of the form 'Suburbs of Chicago', -- where we'd get "[[suburb]]s of [[city|cities]] of [[Chicago]]". category_link = "[[suburb]]s of [[city|cities]]", category_link_before_city = "[[suburb]]s", -- See comments under "neighborhood" for the following three settings. They are used by -- [[Module:category tree/topic cat/data/Places]] for generating the text of 'Suburbs in/of PLACE' categories -- but currently ignored by district_neighborhood_cat_handler (which actually generates the categories for a -- given page), which hardcodes "in" for non-cities and "of" for cities. (FIXME: Change this.) generic_before_non_cities = "in", generic_before_cities = "of", preposition = "of", has_neighborhoods = true, --? class = "non-admin settlement", --? cat_handler = district_neighborhood_cat_handler, }, ["suburban area"] = { link = "w", fallback = "suburb", }, ["subway station"] = { link = "w", fallback = "metro station", }, ["sum"] = { -- In China, Mongolia, Russia; something like a county in Mongolia but a township in China (Inner Mongolia), -- and equivalent to a [[selsoviet]] in the parts of Russia where it's in use (a rural council, below a raion). link = "+w:sum (administrative division)", -- This fallback is somewha arbitrary. We could use "county" but that has a display handler -- which we don't want to be active (FIXME: If the display handler would be active, that's a bug). fallback = "division", }, ["supercontinent"] = { link = true, fallback = "continent", }, ["tehsil"] = { link = true, affix_type = "suf", no_affix_strings = {"tehsil", "tahsil"}, class = "subpolity", }, ["temple"] = { link = true, fallback = "building", }, ["territorial authority"] = { link = "w", fallback = "district", }, ["territory"] = { link = true, preposition = "of", class = "subpolity", }, ["theme"] = { link = "+w:theme (Byzantine district)", preposition = "of", class = "subpolity", }, ["town"] = { link = true, generic_before_non_cities = "in", has_neighborhoods = true, class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["town with bystatus"] = { -- can't use templates in links currently link = "[[town]] with [[bystatus#Norwegian Bokmål|bystatus]]", plural = "towns with bystatus", plural_link = "[[town]]s with [[bystatus#Norwegian Bokmål|bystatus]]", fallback = "town", }, ["township"] = { link = true, has_neighborhoods = true, class = "settlement", --? default = {true}, }, ["township municipality"] = { -- Quebec link = "+w:township municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, --? }, ["traditional county"] = { link = true, fallback = "county", }, ["traditional region"] = { -- FIXME: Verify this works. Same for 'historic(al) region'. -- provided only for the link link = "w", fallback = "FORMER geographic region", }, ["trail"] = { link = true, fallback = "road", }, ["treaty port"] = { link = "w", fallback = "city", class = "settlement", inherently_former = {"FORMER"}, }, ["tributary"] = { link = true, preposition = "of", fallback = "river", }, ["underground station"] = { link = "w", fallback = "metro station", }, ["unincorporated area"] = { link = "w", -- I don't know if this fallback makes sense everywhere. fallback = "unincorporated community", }, ["unincorporated community"] = { link = true, generic_before_non_cities = "in", class = "non-admin settlement", }, ["unincorporated territory"] = { link = "w", fallback = "territory", }, ["union territory"] = { -- India link = true, preposition = "of", entry_placetype_indefinite_article = "a", class = "subpolity", }, ["unitary authority"] = { -- UK, New Zealand link = true, entry_placetype_indefinite_article = "a", fallback = "local government district", }, ["unitary district"] = { link = "w", entry_placetype_indefinite_article = "a", fallback = "local government district", }, ["united township municipality"] = { -- Quebec link = "+w:united township municipality (Quebec)", entry_placetype_indefinite_article = "a", fallback = "township municipality", has_neighborhoods = true, --? }, ["university"] = { link = true, entry_placetype_indefinite_article = "a", class = "man-made structure", default = {true}, }, ["unrecognised country"] = { link = "w", fallback = "unrecognized country", }, ["unrecognized and nearly unrecognized countries!"] = { category_link = "[[de facto]] [[independent]] [[state]]s with little or no {{w|international recognition}}", bare_category_parent = "country-like entities", }, ["unrecognized country"] = { link = "w", class = "polity", default = {"Unrecognized and nearly unrecognized countries"}, }, ["unrecognised state"] = { link = "w", fallback = "unrecognized country", }, ["unrecognized state"] = { link = "w", fallback = "unrecognized country", }, ["urban area"] = { link = "separately", fallback = "neighborhood", }, ["urban hromada"] = { link = "[[urban]] [[w:hromada|hromada]]", affix_type = "suf", fallback = "hromada", }, ["urban service area"] = { -- A strange beast existing in Alberta; technically a type of hamlet but in practice used for much larger -- cities and treated equivalent to a city. (There are only two of them, [[Fort McMurray]] and [[Sherwood Park]]). link = "w", fallback = "city", }, ["urban township"] = { link = "w", fallback = "township", }, ["urban-type settlement"] = { -- appears to be a particular type of small urban settlement in post-Soviet states, -- had an administrative function. link = "w", fallback = "town", }, ["valley"] = { link = true, class = "natural feature", addl_bare_category_parents = {"landforms", "water"}, default = {true}, }, ["viceroyalty"] = { -- in essence, a type of colony link = true, fallback = "dependent territory", }, ["village"] = { link = true, generic_before_non_cities = "in", category_link = "[[village]]s, [[hamlet]]s, and other small [[community|communities]] and [[settlement]]s", class = "settlement", cat_handler = city_type_cat_handler, default = {true}, }, ["village development committee"] = { -- former administrative structure in Nepal; also exists in India but not as a formal unit link = "+w:village development committee (Nepal)", inherently_former = {"FORMER"}, fallback = "village", }, ["village municipality"] = { -- Quebec link = "+w:village municipality (Quebec)", preposition = "of", fallback = "municipality", has_neighborhoods = true, --? }, ["voivodeship"] = { -- Poland link = true, display_handler = voivodeship_display_handler, preposition = "of", class = "subpolity", }, ["volcano"] = { link = true, plural = "volcanoes", class = "natural feature", addl_bare_category_parents = {"landforms"}, default = {true, "Mountains"}, }, ["ward"] = { link = true, class = "settlement", -- Wards are formal administrative divisions of a city but have some properties of neighborhoods. fallback = "neighborhood", }, ["watercourse"] = { link = true, fallback = "channel", }, ["Welsh community"] = { -- Wales link = "[[w:community (Wales)|community]]", preposition = "of", affix_type = "suf", affix = "community", has_neighborhoods = true, class = "settlement", }, ["zone"] = { -- administrative division of Ethiopia, Qatar, Nepal, India link = "+w:zone#Place names", preposition = "of", class = "subpolity", }, ---------------------------------------------------------------------------------------------- -- Categories for former places -- ---------------------------------------------------------------------------------------------- ["ANCIENT capital"] = { link = false, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", -- FIXME: Consider removing 'ancient settlements' here. Ancient capitals, like former capitals, often still -- exist but just aren't the capital any more. Maybe we should have an 'Ancient capitals' category. default = {"Ancient settlements", "Former capitals"}, }, ["ANCIENT non-admin settlement"] = { link = false, class = "non-admin settlement", fallback = "ANCIENT settlement", }, ["ANCIENT settlement"] = { link = false, has_neighborhoods = true, class = "settlement", default = {"Ancient settlements"}, }, ["ancient settlements!"] = { category_link = "former [[city|cities]], [[town]]s and [[village]]s that existed in [[antiquity]]", bare_category_parent = "former settlements", }, ["FORMER capital"] = { link = false, entry_placetype_use_the = true, preposition = "of", has_neighborhoods = true, class = "capital", default = {"Former capitals"}, }, ["former capitals!"] = { category_link = "former [[capital]] [[city|cities]] and [[town]]s", bare_category_parent = "settlements", }, ["former counties and county-level cities!"] = { -- For categorizing former counties and county-level cities of China category_link = "no-longer existing [[county|counties]] and [[county-level city|county-level cities]]", bare_category_breadcrumb = "counties and county-level cities", bare_category_parent = "former political divisions", }, ["FORMER county"] = { -- For categorizing former counties and county-level cities of China link = false, fallback = "FORMER subpolity", }, ["FORMER county-level city"] = { -- For categorizing former counties and county-level cities of China link = false, fallback = "FORMER subpolity", }, ["former countries and country-like entities!"] = { category_link = "[[country|countries]] and similar [[polity|polities]] that no longer exist", bare_category_breadcrumb = "countries and country-like entities", bare_category_parent = "former polities", }, ["FORMER country"] = { link = false, class = "polity", default = {"Former countries and country-like entities"}, }, ["former dependent territories!"] = { category_link = "[[w:dependent territory|dependent territories]] (colonies, dependencies, protectorates, etc.) that no longer exist", bare_category_breadcrumb = "dependent territories", bare_category_parent = "former political divisions", }, ["FORMER dependent territory"] = { link = false, preposition = "of", class = "subpolity", default = {"Former dependent territories"}, }, ["former districts!"] = { -- For categorizing former districts of China category_link = "no-longer-existing [[district]]s", bare_category_breadcrumb = "districts", bare_category_parent = "former political divisions", }, ["FORMER district"] = { -- For categorizing former districts of China link = false, fallback = "FORMER subpolity", }, ["FORMER geographic region"] = { link = false, fallback = "geographic and cultural area", }, ["FORMER man-made structure"] = { link = false, class = "man-made structure", default = {"Former man-made structures"}, }, ["former man-made structures!"] = { category_link = "man-made structures such as [[airport]]s and [[park]]s that no longer exist", bare_category_breadcrumb = "man-made structures", bare_category_parent = "former places", }, ["former municipalities!"] = { -- For categorizing former municipalities of the Netherlands category_link = "no-longer-existing [[municipality|municipalities]]", bare_category_breadcrumb = "municipalities", bare_category_parent = "former political divisions", }, ["FORMER municipality"] = { -- For categorizing former municipalities of the Netherlands link = false, fallback = "FORMER subpolity", }, ["FORMER natural feature"] = { link = false, class = "natural feature", default = {"Former natural features"}, }, ["former natural features!"] = { category_link = "natural features such as [[lake]]s, [[river]]s and [[island]]s that no longer exist", bare_category_breadcrumb = "natural features", bare_category_parent = "former places", }, ["FORMER non-admin settlement"] = { link = false, class = "non-admin settlement", fallback = "FORMER settlement", }, ["former places!"] = { category_link = "[[place]]s of all sorts that no longer exist", bare_category_breadcrumb = "former", bare_category_parent = "places", }, ["former political divisions!"] = { category_link = "[[political]] [[division]]s (states, provinces, counties, etc.) that no longer exist", bare_category_breadcrumb = "political divisions", bare_category_parent = "former places", }, ["former polities!"] = { category_link = "[[polity|polities]] (countries, kingdoms, empires, etc.) that no longer exist", bare_category_breadcrumb = "polities", bare_category_parent = "former places", }, ["FORMER polity"] = { link = false, class = "polity", default = {"Former polities"}, }, ["former prefectures!"] = { -- For categorizing former prefectures of China category_link = "no-longer-existing [[prefecture]]s", bare_category_breadcrumb = "prefectures", bare_category_parent = "former political divisions", }, ["FORMER prefecture"] = { -- For categorizing former prefectures of China link = false, fallback = "FORMER subpolity", }, ["former provinces!"] = { -- For categorizing former provinces of China, etc. category_link = "no-longer-existing [[province]]s", bare_category_breadcrumb = "provinces", bare_category_parent = "former political divisions", }, ["FORMER province"] = { -- For categorizing ancient/historical/former provinces of the Roman Empire link = false, fallback = "FORMER subpolity", }, ["former region"] = { -- A former region is considered a former political division, but not a 'historical/traditional/etc.' region. link = "separately", preposition = "of", inherently_former = {"FORMER"}, class = "subpolity", }, ["FORMER settlement"] = { link = false, has_neighborhoods = true, class = "settlement", default = {"Former settlements"}, }, ["former settlements!"] = { category_link = "[[city|cities]], [[town]]s and [[village]]s that no longer exist or have been merged or reclassified", bare_category_breadcrumb = "settlements", bare_category_parent = "former political divisions", }, ["FORMER subpolity"] = { link = false, preposition = "of", class = "subpolity", default = {"Former political divisions"}, }, ---------------------------------------------------------------------------------------------- -- form-of categories -- ---------------------------------------------------------------------------------------------- ---------- Abbreviations ---------- ["abbreviations of counties!"] = { -- For categorizing abbreviations of counties of e.g. England full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[county|counties]]", bare_category_breadcrumb = "counties", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of countries!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "abbreviations of places", }, ["abbreviations of departments!"] = { -- For categorizing abbreviations of departments of e.g. France full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[department]]s", bare_category_breadcrumb = "departments", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of districts!"] = { -- For categorizing abbreviations of districts of e.g. ??? full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[district]]s", bare_category_breadcrumb = "districts", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of divisions!"] = { -- For categorizing abbreviations of divisions of e.g. Bangladesh full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[division]]s", bare_category_breadcrumb = "divisions", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of former countries!"] = { full_category_link = "{{glossary|abbreviation}}s of [[country|countries]] that no longer [[exist]]", bare_category_breadcrumb = "countries", bare_category_parent = "abbreviations of former places", }, ["abbreviations of former places!"] = { full_category_link = "{{glossary|abbreviation}}s of [[place]]s that no longer [[exist]]", bare_category_breadcrumb = "abbreviations", bare_category_parent = "former places", addl_bare_category_parents = {{name = "abbreviations of places", sort = "former"}}, }, ["abbreviations of places!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[place]]s", bare_category_breadcrumb = "abbreviations", bare_category_parent = "places", }, ["abbreviations of political divisions!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[political]] [[division]]s", bare_category_breadcrumb = "political divisions", bare_category_parent = "abbreviations of places", }, ["abbreviations of prefectures!"] = { -- For categorizing abbreviations of prefectures of e.g. Japan full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[prefecture]]s", bare_category_breadcrumb = "prefectures", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of provinces!"] = { -- For categorizing abbreviations of provinces of e.g. Canada full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[province]]s", bare_category_breadcrumb = "provinces", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of provinces and territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[province]]s and [[territory|territories]]", bare_category_breadcrumb = "provinces and territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of regions!"] = { -- For categorizing abbreviations of regions of e.g. Italy full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[administrative region]]s", bare_category_breadcrumb = "regions", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states!"] = { -- For categorizing abbreviations of states of e.g. the United States full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states and territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s and [[territory|territories]]", bare_category_breadcrumb = "states and territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of states and union territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[state]]s and [[union territory|union territories]]", bare_category_breadcrumb = "states and union territories", bare_category_parent = "abbreviations of political divisions", }, ["abbreviations of territories!"] = { full_category_link = "{{glossary|abbreviation}}s of [[name]]s of [[territory|territories]]", bare_category_breadcrumb = "territories", bare_category_parent = "abbreviations of political divisions", }, ["ABBREVIATION_OF country"] = { link = false, default = {"Abbreviations of countries"}, }, ["ABBREVIATION_OF county"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF department"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF district"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF division"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF FORMER country"] = { link = false, default = {"Abbreviations of former countries"}, }, ["ABBREVIATION_OF FORMER place"] = { link = false, default = {"Abbreviations of former places"}, }, ["ABBREVIATION_OF place"] = { link = false, default = {"Abbreviations of places"}, }, ["ABBREVIATION_OF prefecture"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF province"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF region"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF state"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF subpolity"] = { link = false, default = {"Abbreviations of political divisions"}, }, ["ABBREVIATION_OF territory"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ["ABBREVIATION_OF union territory"] = { link = false, fallback = "ABBREVIATION_OF subpolity", }, ---------- Archaic forms ---------- ["archaic forms of places!"] = { full_category_link = "{{glossary|archaic}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "archaic forms", bare_category_parent = "places", }, ["ARCHAIC_FORM_OF place"] = { link = false, default = {"Archaic forms of places"}, }, ---------- Clippings ---------- ["clippings of places!"] = { full_category_link = "{{glossary|clipping}}s of [[name]]s of [[place]]s", bare_category_breadcrumb = "clippings", bare_category_parent = "places", }, ["CLIPPING_OF place"] = { link = false, default = {"Clippings of places"}, }, ---------- Dated forms ---------- ["dated forms of places!"] = { full_category_link = "{{glossary|dated}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "dated forms", bare_category_parent = "places", }, ["DATED_FORM_OF place"] = { link = false, default = {"Dated forms of places"}, }, ---------- Derogatory names ---------- ["derogatory names for cities!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[city|cities]]", bare_category_breadcrumb = "cities", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for cities"}, }, ["derogatory names for continents!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[continent]]s", bare_category_breadcrumb = "continents", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for continents"}, }, ["derogatory names for countries!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for countries"}, }, ["derogatory names for places!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[place]]s", bare_category_breadcrumb = "derogatory names", bare_category_parent = "nicknames for places", }, ["derogatory names for states!"] = { full_category_link = "{{glossary|derogatory}} [[name]]s for [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "derogatory names for places", addl_bare_category_parents = {"nicknames for states"}, }, ["DEROGATORY_NAME_FOR capital"] = { link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR city"] = { link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR continent"] = { link = false, default = {"Derogatory names for continents"}, }, ["DEROGATORY_NAME_FOR country"] = { link = false, default = {"Derogatory names for countries"}, }, ["DEROGATORY_NAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR place"] = { link = false, default = {"Derogatory names for places"}, }, ["DEROGATORY_NAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Derogatory names for cities"}, }, ["DEROGATORY_NAME_FOR state"] = { link = false, default = {"Derogatory names for states"}, }, ["DEROGATORY_NAME_FOR town"] = { link = false, default = {"Derogatory names for cities"}, }, ---------- Ellipses ---------- ["ellipses of places!"] = { full_category_link = "{{glossary|ellipsis|ellipses}} of [[name]]s of [[place]]s", bare_category_breadcrumb = "ellipses", bare_category_parent = "places", }, ["ELLIPSIS_OF place"] = { link = false, default = {"Ellipses of places"}, }, ---------- Former long-form names ---------- ["former long-form names of countries!"] = { full_category_link = "no-longer-[[use]]d [[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "former long-form names of places", addl_bare_category_parents = {{name = "former names of countries", sort = "long-form"}}, }, ["former long-form names of places!"] = { full_category_link = "no-longer-[[use]]d [[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[place]]s", bare_category_breadcrumb = "long-form", bare_category_parent = "former names of places", }, ["FORMER_LONG_FORM_OF country"] = { link = false, default = {"Former long-form names of countries"}, }, ["FORMER_LONG_FORM_OF place"] = { link = false, default = {"Former long-form names of places"}, }, ---------- Former names ---------- ["former names of capitals!"] = { full_category_link = "[[former]] [[name]]s of [[capital city|capital cities]] that generally still exist but under a different name", bare_category_breadcrumb = "capitals", bare_category_parent = "former names of settlements", }, ["former names of countries!"] = { full_category_link = "[[former]] [[name]]s of [[country|countries]] that generally still exist but under a different name", bare_category_breadcrumb = "countries", bare_category_parent = "former names of places", }, ["former names of places!"] = { full_category_link = "[[former]] [[name]]s of [[place]]s that generally still exist but under a different name", bare_category_breadcrumb = "former names", bare_category_parent = "places", }, ["former names of political divisions!"] = { full_category_link = "[[former]] [[name]]s of [[political]] [[division]]s (states, provinces, counties, etc.) that generally still exist but under a different name", bare_category_breadcrumb = "political divisions", bare_category_parent = "former names of places", }, ["former names of polities!"] = { full_category_link = "[[former]] [[name]]s of [[polity|polities]] (e.g. [[country|countries]]) that generally still exist but under a different name", bare_category_breadcrumb = "polities", bare_category_parent = "former names of places", }, ["former names of settlements!"] = { full_category_link = "[[former]] [[name]]s of [[city|cities]], [[town]]s, [[village]]s, etc. that generally still exist but under a different name", bare_category_breadcrumb = "settlements", bare_category_parent = "former names of political divisions", }, ["FORMER_NAME_OF capital"] = { link = false, default = {"Former names of capitals"}, }, ["FORMER_NAME_OF country"] = { link = false, default = {"Former names of countries"}, }, ["FORMER_NAME_OF place"] = { link = false, default = {"Former names of places"}, }, ["FORMER_NAME_OF polity"] = { link = false, default = {"Former names of polities"}, }, ["FORMER_NAME_OF region"] = { link = false, fallback = "FORMER_NAME_OF subpolity", }, ["FORMER_NAME_OF settlement"] = { link = false, default = {"Former names of settlements"}, }, ["FORMER_NAME_OF subpolity"] = { link = false, default = {"Former names of political divisions"}, }, ---------- Former nicknames ---------- ["former nicknames for cities!"] = { full_category_link = "no-longer-used [[nickname]]s for [[city|cities]], e.g. the [[Eternal City]] for [[Kyoto]] during the {{w|Heian period}} ({{circa2|800–1100|short=yes}} {{AD}})", bare_category_breadcrumb = "cities", bare_category_parent = "former nicknames for places", addl_bare_category_parents = {"nicknames for cities"}, }, ["former nicknames for places!"] = { full_category_link = "no-longer-used [[nickname]]s for [[place]]s", bare_category_breadcrumb = "former", bare_category_parent = "nicknames for places", addl_bare_category_parents = {{name = "former names of places", sort = "nicknames"}}, }, ["FORMER_NICKNAME_FOR capital"] = { link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR city"] = { link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR place"] = { link = false, default = {"Former nicknames for places"}, }, ["FORMER_NICKNAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Former nicknames for cities"}, }, ["FORMER_NICKNAME_FOR town"] = { link = false, default = {"Former nicknames for cities"}, }, ---------- Former official names ---------- ["former official names of countries!"] = { full_category_link = "no-longer-[[use]]d [[official]] [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "former official names of places", addl_bare_category_parents = {{name = "former names of countries", sort = "official"}}, }, ["former official names of places!"] = { full_category_link = "no-longer-[[use]]d [[official]] [[name]]s of [[place]]s", bare_category_breadcrumb = "official", bare_category_parent = "former names of places", }, ["FORMER_OFFICIAL_NAME_OF country"] = { link = false, default = {"Former official names of countries"}, }, ["FORMER_OFFICIAL_NAME_OF place"] = { link = false, default = {"Former official names of places"}, }, ---------- Long-form names ---------- ["long-form names of countries!"] = { full_category_link = "[[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "long-form names of places", }, ["long-form names of places!"] = { full_category_link = "[[long]]-[[form]] (but typically [[unofficial]]) [[name]]s of [[place]]s", bare_category_breadcrumb = "long-form names", bare_category_parent = "places", }, ["LONG_FORM_OF country"] = { link = false, default = {"Long-form names of countries"}, }, ["LONG_FORM_OF place"] = { link = false, default = {"Long-form names of places"}, }, ---------- Nicknames ---------- ["nicknames for cities!"] = { full_category_link = "[[nickname]]s for [[city|cities]], e.g. the [[Big Apple]] for [[New York City]]", bare_category_breadcrumb = "cities", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"cities"}, }, ["nicknames for continents!"] = { full_category_link = "[[nickname]]s for [[continent]]s", bare_category_breadcrumb = "continents", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"continents"}, }, ["nicknames for countries!"] = { full_category_link = "[[nickname]]s for [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"countries"}, }, ["nicknames for places!"] = { full_category_link = "[[nickname]]s for [[place]]s", bare_category_breadcrumb = "places", bare_category_parent = "nicknames", addl_bare_category_parents = {"places"}, }, ["nicknames for states!"] = { -- For categorizing nicknames for states of e.g. the United States full_category_link = "[[nicknames]] for [[state]]s", bare_category_breadcrumb = "states", bare_category_parent = "nicknames for places", addl_bare_category_parents = {"states"}, }, ["NICKNAME_FOR capital"] = { link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR city"] = { link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR continent"] = { link = false, default = {"Nicknames for continents"}, }, ["NICKNAME_FOR country"] = { link = false, default = {"Nicknames for countries"}, }, ["NICKNAME_FOR metropolitan city"] = { -- "metropolitan city" doesn't fall back to "city" link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR place"] = { link = false, default = {"Nicknames for places"}, }, ["NICKNAME_FOR prefecture-level city"] = { -- "prefecture-level city" doesn't fall back to "city" but things like "county-level city" and -- "subprovincial city" fall back to "prefecture-level city" link = false, default = {"Nicknames for cities"}, }, ["NICKNAME_FOR state"] = { link = false, default = {"Nicknames for states"}, }, ["NICKNAME_FOR town"] = { link = false, default = {"Nicknames for cities"}, }, ---------- Obsolete forms ---------- ["obsolete forms of places!"] = { full_category_link = "{{glossary|obsolete}} [[form]]s of [[name]]s of [[place]]s", bare_category_breadcrumb = "obsolete forms", bare_category_parent = "places", }, ["OBSOLETE_FORM_OF place"] = { link = false, default = {"Obsolete forms of places"}, }, ---------- Official names ---------- ["official names of countries!"] = { full_category_link = "[[official]] [[name]]s of [[country|countries]]", bare_category_breadcrumb = "countries", bare_category_parent = "official names of places", }, ["official names of former countries!"] = { full_category_link = "[[official]] [[name]]s of [[country|countries]] that no longer [[exist]]", bare_category_breadcrumb = "countries", bare_category_parent = "official names of former places", }, ["official names of former places!"] = { full_category_link = "[[official]] [[name]]s of [[place]]s that no longer [[exist]]", bare_category_breadcrumb = "official names", bare_category_parent = "former places", addl_bare_category_parents = {{name = "official names of places", sort = "former"}}, }, ["official names of places!"] = { full_category_link = "[[official]] [[name]]s of [[place]]s", bare_category_breadcrumb = "official names", bare_category_parent = "places", }, ["OFFICIAL_NAME_OF country"] = { link = false, default = {"Official names of countries"}, }, ["OFFICIAL_NAME_OF FORMER country"] = { link = false, default = {"Official names of former countries"}, }, ["OFFICIAL_NAME_OF FORMER place"] = { link = false, default = {"Official names of former places"}, }, ["OFFICIAL_NAME_OF place"] = { link = false, default = {"Official names of places"}, }, ---------- Official nicknames ---------- ["official nicknames for places!"] = { full_category_link = "[[official]] [[nickname]]s for [[place]]s", bare_category_breadcrumb = "official", bare_category_parent = "nicknames for places", }, ["official nicknames for states!"] = { -- For categorizing official nicknames for states of e.g. the United States full_category_link = "[[official]] [[nicknames]] for [[state]]s", bare_category_breadcrumb = "official", bare_category_parent = "nicknames for states", addl_bare_category_parents = {"states"}, }, ["OFFICIAL_NICKNAME_FOR place"] = { link = false, default = {"Official nicknames for places"}, }, ["OFFICIAL_NICKNAME_FOR state"] = { link = false, default = {"Official nicknames for states"}, }, } export.plural_placetype_to_singular = {} for sg_placetype, spec in pairs(export.placetype_data) do if spec.plural then export.plural_placetype_to_singular[spec.plural] = sg_placetype end end return export 0i5icp7fj8km7659tytty7f31iboenv Mòideal:category tree/topic/Nature 828 17898 88794 2026-08-02T00:35:54Z en>Fenakhay 0 88794 Scribunto text/plain local labels = {} local unpack = unpack or table.unpack -- Lua 5.2 compatibility labels["nature"] = { type = "related-to", parents = {"all topics"}, } labels["acids"] = { type = "set", parents = {"matter"}, } labels["actinide series chemical elements"] = { breadcrumb = "actinide series", type = "set", description = "{{{langname}}} terms for those chemical elements in the {{w|f-block}} of the [[periodic table]] with [[atomic number]]s from 89 to 103.", parents = {"chemical elements", "metals", "radioactivity"}, } labels["air"] = { type = "related-to", parents = {"atmosphere"}, } labels["alkali metals"] = { type = "set", description = "{{{langname}}} terms for [[alkali metal]]s, chemical elements in [[w:Group (periodic table)|group]] 1 of the [[periodic table]], which all have one [[valence electron]].", parents = {"chemical elements", "metals"}, } labels["alkaline earth metals"] = { type = "set", description = "{{{langname}}} terms for [[alkaline earth metal]]s, chemical elements in [[w:Group (periodic table)|group]] 2, which all have two [[valence electron]]s.", parents = {"chemical elements", "metals"}, } labels["alkaloids"] = { type = "set", parents = {"organic compounds"}, } labels["alloys"] = { type = "set", parents = {"metals"}, } labels["aluminium"] = { type = "related-to", parents = {"boron group elements"}, } labels["amino acids"] = { type = "set", parents = {"carboxylic acids"}, } labels["animal sounds"] = { type = "set", parents = {"sounds", "vocalizations"}, } labels["animal welfare"] = { type = "related-to", description = "{{{langname}}} terms closely associated with [[animal welfare]].", parents = {"ethics"}, } labels["antimatter"] = { type = "related-to", parents = {"matter"}, } labels["antimony"] = { type = "related-to", parents = {"pnictogens"}, } labels["argon"] = { type = "related-to", parents = {"noble gases"}, } labels["arsenic"] = { type = "related-to", parents = {"pnictogens"}, } labels["astatine"] = { type = "related-to", parents = {"halogens"}, } labels["asteroids"] = { type = "set", parents = {"celestial bodies"}, } labels["atmosphere"] = { type = "related-to", parents = {"nature"}, } labels["atmospheric phenomena"] = { type = "set", parents = {"atmosphere"}, } labels["autumn"] = { type = "related-to", parents = {"seasons"}, } labels["barium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["baryons"] = { type = "set", parents = {"hadrons"}, } labels["beryllium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["birth"] = { type = "related-to", parents = {"reproduction"}, } labels["bismuth"] = { type = "related-to", parents = {"pnictogens"}, } labels["boron"] = { type = "related-to", parents = {"boron group elements"}, } labels["boron group elements"] = { breadcrumb = "boron group", type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 13 of the [[periodic table]], which all have three [[valence electron]]s.", parents = {"chemical elements"}, } labels["bosons"] = { type = "set", parents = {"subatomic particles"}, } labels["bromine"] = { type = "related-to", parents = {"halogens"}, } labels["cadmium"] = { type = "related-to", parents = {"transition metals"}, } labels["calcium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["carbohydrates"] = { type = "set", parents = {"organic compounds"}, } labels["carbon"] = { type = "related-to", parents = {"carbon group elements"}, } labels["carbon group elements"] = { breadcrumb = "carbon group", type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 14 of the [[periodic table]], which all have four [[valence electron]]s.", parents = {"chemical elements"}, } labels["carboxylic acids"] = { type = "set", parents = {"acids", "organic compounds"}, } labels["celestial bodies"] = { type = "set", description = "{{{langname}}} terms for varous [[celestial body|celestial bodies]]; things found in outer space.", parents = {"space"}, } labels["cerium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["cesium"] = { type = "related-to", parents = {"alkali metals"}, } labels["chalcogens"] = { type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 16 of the [[periodic table]], which all have 6 [[valence electron]]s.", parents = {"chemical elements"}, } labels["chemical elements"] = { type = "set", parents = {"matter"}, } for period = 1, 7 do local key = ("Period %d elements"):format(period) if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in period %d of the [[periodic table]]."):format(period), parents = {"chemical elements"}, } end end for group = 1, 12 do local key = ("Group %d elements"):format(group) if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in [[w:Group (periodic table)|group]] %d of the [[periodic table]]."):format(group), parents = {"chemical elements"}, } end end for _, block in ipairs({"s", "p", "d", "f"}) do local key = block:upper() .. "-block elements" if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in the %s-block of the [[periodic table]]."):format(block), parents = {"chemical elements"}, } end end if not labels["Nonmetals"] then labels["Nonmetals"] = { type = "set", description = "{{{langname}}} terms for [[nonmetal]] [[chemical element]]s.", parents = {"chemical elements"}, } end if not labels["Post-transition metals"] then labels["Post-transition metals"] = { type = "set", description = "{{{langname}}} terms for [[post-transition metal]] [[chemical element]]s.", parents = {"chemical elements", "metals"}, } end labels["chemical isomers"] = { type = "related-to", parents = {"matter", "physical chemistry", "shapes"}, } labels["chemical processes"] = { type = "set", description = "=[[chemical]] [[process]]es", parents = {"nature"}, } labels["chlorine"] = { type = "related-to", parents = {"halogens"}, } labels["chromium"] = { type = "related-to", parents = {"transition metals"}, } labels["classical planets"] = { type = "name", description = "{{{langname}}} names for the [[classical planet]]s of our Solar System.", parents = {"celestial bodies"}, } labels["climate change"] = { type = "related-to", description = "=[[anthropogenic]] [[climate change]]", parents = {"nature"}, } labels["clouds"] = { type = "set", parents = {"atmospheric phenomena"}, } labels["coal"] = { type = "related-to", parents = {"fossil fuels"}, } labels["cobalt"] = { type = "related-to", parents = {"transition metals"}, } labels["coenzymes"] = { type = "set", parents = {"enzymes"}, } labels["colors"] = { type = "set", parents = {"light", "vision"}, } for _, color_etc in ipairs { {"black"}, {"blue"}, {"brown"}, {"green"}, {"grey", "[[grey]] ([[gray]])"}, {"orange"}, {"pink"}, {"purple"}, {"red"}, {"violet"}, {"white"}, {"yellow"}, } do local color, desc = unpack(color_etc) desc = desc or ("[[%s]]"):format(color) labels[color .. "s"] = { type = "set", description = ("=shades of the [[color]] %s"):format(desc), parents = {"colors"}, } end labels["colors of the rainbow"] = { type = "set", description = "=[[color]]s of the [[rainbow]]", parents = {"colors"}, } labels["combustion"] = { type = "related-to", parents = {"chemical processes"}, } labels["compass points"] = { type = "set", parents = {"directions", "navigation"}, } labels["copper"] = { type = "related-to", parents = {"transition metals"}, } labels["crystal"] = { type = "related-to", parents = {"matter", "physical chemistry"}, } labels["darkness"] = { type = "related-to", parents = {"light"}, } labels["deuterium"] = { type = "related-to", parents = {"hydrogen", "two", "isotopes"} } labels["directions"] = { type = "set", parents = {"nature"}, } labels["distance"] = { type = "related-to", parents = {"nature"}, } labels["drugs"] = { type = "set", parents = {"matter", "pharmacology"}, } labels["dryness"] = { type = "related-to", parents = {"liquids"}, } labels["dwarf planets of the Solar System"] = { type = "name", description = "=[[dwarf planet]]s of our [[Solar System]]", parents = {"celestial bodies"}, } labels["dyes"] = { type = "set", parents = {"matter", "pigments"}, } labels["energy"] = { type = "related-to", parents = {"nature"}, } labels["enzymes"] = { type = "set", parents = {"proteins", "catalysis"}, } labels["europium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["explosives"] = { type = "set", parents = {"matter", "weapons"}, } labels["eye colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[eye]]s", parents = {"colors", "eye"}, } labels["fatty acids"] = { type = "set", parents = {"carboxylic acids"}, } labels["fermions"] = { type = "set", parents = {"subatomic particles"}, } labels["fictional materials"] = { type = "set", parents = {"science fiction", "materials"}, } labels["fire"] = { type = "related-to", parents = {"combustion", "light sources"}, wp = "Fire", } labels["fluorine"] = { type = "related-to", parents = {"halogens"}, } labels["fog"] = { type = "related-to", parents = {"weather", "water"}, } labels["fossil fuels"] = { type = "set", parents = {"carbon", "energy", "natural resources"}, } labels["francium"] = { type = "related-to", parents = {"alkali metals"}, } labels["gadolinium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["galaxies"] = { type = "set", parents = {"celestial bodies"}, } labels["gallium"] = { type = "related-to", parents = {"boron group elements"}, } labels["gases"] = { type = "set", parents = {"matter"}, } labels["germanium"] = { type = "related-to", parents = {"carbon group elements"}, } labels["gold"] = { type = "related-to", parents = {"transition metals"}, } labels["hadrons"] = { type = "set", parents = {"subatomic particles"}, } labels["hair colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[hair]]", parents = {"colors", "hair"}, } labels["halogens"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 17 of the [[periodic table]], which all have 7 [[valence electron]]s", parents = {"chemical elements"}, } labels["helium"] = { type = "related-to", parents = {"noble gases"}, } labels["heroin"] = { type = "related-to", parents = {"recreational drugs"}, } labels["height"] = { type = "related-to", parents = {"distance"}, } labels["horse colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[horse]]s", parents = {"colors", "horses"}, } labels["hydrogen"] = { type = "related-to", parents = {"chemical elements"}, } labels["hypothetical chemical elements"] = { breadcrumb = "hypothetical", type = "set", description = "{{{langname}}} terms for types or instances of [[chemical element]]s which have been hypothesized to exist, but not (yet) discovered.", parents = {"chemical elements", "fictional materials"}, } labels["ice"] = { type = "related-to", parents = {"water"}, } labels["indium"] = { type = "related-to", parents = {"boron group elements"}, } labels["inorganic compounds"] = { type = "set", parents = {"matter"}, } labels["iodine"] = { type = "related-to", parents = {"halogens"}, } labels["ions"] = { type = "set", parents = {"matter", "chemistry", "electricity"}, } labels["iridium"] = { type = "related-to", parents = {"transition metals"}, } labels["iron"] = { type = "related-to", parents = {"transition metals"}, } labels["isotopes"] = { type = "set", parents = {"chemical elements"}, } labels["krypton"] = { type = "related-to", parents = {"noble gases"}, } labels["lanthanide series chemical elements"] = { breadcrumb = "lanthanide series", type = "set", description = "=[[chemical element]]s in the {{w|f-block}} of the [[periodic table]] with [[atomic number]]s from 57 to 71", parents = {"chemical elements"}, } labels["lanthanum"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["lead"] = { type = "related-to", parents = {"carbon group elements"}, } labels["length"] = { type = "related-to", parents = {"distance"}, } labels["leptons"] = { type = "set", parents = {"fermions"}, } labels["life"] = { type = "related-to", parents = {"nature"}, } labels["light"] = { type = "related-to", parents = {"energy"}, } labels["light sources"] = { type = "set", parents = {"light"}, } labels["lightning"] = { type = "related-to", parents = {"atmospheric phenomena", "weather", "electricity", "light sources"}, } labels["liquids"] = { type = "set", -- description = "default", -- At what temperature? parents = {"matter"}, } labels["lithium"] = { type = "related-to", parents = {"alkali metals"}, } labels["magnesium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["manganese"] = { type = "related-to", parents = {"transition metals"}, } labels["Mars (planet)"] = { type = "related-to", description = "=the planet [[Mars]]", parents = {"planets of the Solar System"}, } labels["marijuana"] = { type = "related-to", parents = {"hemp family plants", "recreational drugs"}, } labels["matter"] = { type = "related-to", description = "=physical [[matter]]", parents = {"nature", "chemistry"}, } labels["mercury (element)"] = { type = "related-to", parents = {"transition metals"}, } labels["mesons"] = { type = "set", parents = {"hadrons"}, } labels["metalloids"] = { type = "set", parents = {"chemical elements"}, } labels["metals"] = { type = "set", parents = {"matter", "metallurgy"}, } labels["minerals"] = { type = "set", parents = {"matter", "mineralogy"}, } labels["molybdenum"] = { type = "related-to", parents = {"transition metals"}, } labels["moon"] = { type = "related-to", description = "=the [[Moon]], Earth's only natural satellite", parents = {"nature", "light", "celestial bodies", "moons"}, } labels["moons"] = { type = "related-to", parents = {"celestial bodies"}, } for _, planet in ipairs {"Mars", "Haumea", "Jupiter", "Saturn", "Neptune", "Uranus", "Pluto"} do labels["moons of " .. planet] = { type = "name", description = ("=[[moon]]s that orbit [[%s]]"):format(planet), parents = {"moons"}, } end labels["natural products (Chemistry)"] = { type = "name", description = "=[[organic compound]]s produced by living [[organism]]s", parents = {"organic compounds"}, } labels["natural resources"] = { type = "set", parents = {"matter"}, } labels["neodymium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["neon"] = { type = "related-to", parents = {"noble gases"}, } labels["neurotoxins"] = { type = "set", parents = {"poisons", "neuroscience"}, } labels["nickel"] = { type = "related-to", parents = {"transition metals"}, } labels["niobium"] = { type = "related-to", parents = {"transition metals"}, } labels["nitrogen"] = { type = "related-to", parents = {"pnictogens"}, } labels["noble gases"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 18 of the [[periodic table]], which all have a full set of [[valence electron]]s: 2 for helium and 8 for the others", parents = {"chemical elements", "gases"}, } labels["organic compounds"] = { type = "set", parents = {"matter"}, } labels["osmium"] = { type = "related-to", parents = {"transition metals"}, } labels["oxygen"] = { type = "related-to", parents = {"chalcogens"}, } labels["palladium"] = { type = "related-to", parents = {"transition metals"}, } labels["petroleum"] = { type = "related-to", parents = {"fossil fuels", "liquids"}, } labels["pharmaceutical drugs"] = { type = "set", description = "{{{langname}}} names for [[pharmaceutical#Adjective|pharmaceutical]] [[drug#Noun|drugs]].", parents = {"drugs"}, } labels["pharmaceutical effects"] = { type = "set", description = "{{{langname}}} names for [[pharmaceutical#Adjective|pharmaceutical]] [[effect#Noun|effects]].", parents = {"pharmacology"}, } labels["phosphorus"] = { type = "related-to", parents = {"pnictogens"}, } labels["pigments"] = { type = "set", parents = {"colors"}, } labels["planetoids"] = { type = "set", parents = {"celestial bodies"}, } labels["planets"] = { type = "set", parents = {"celestial bodies"}, } labels["planets of the Solar System"] = { type = "name", description = "=[[planet]]s of our [[Solar System]]", parents = {"planets"}, } labels["platinum"] = { type = "related-to", parents = {"transition metals"}, } labels["Pluto"] = { type = "related-to", description = "=the dwarf planet [[Pluto]]", parents = {"dwarf planets of the Solar System"}, } labels["pnictogens"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 15 of the [[periodic table]], which all have 5 [[valence electron]]s", parents = {"chemical elements"}, } labels["poisons"] = { type = "set", parents = {"matter"}, } labels["potassium"] = { type = "related-to", parents = {"alkali metals"}, } labels["praseodymium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["promethium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["quarks"] = { type = "set", parents = {"fermions"}, } labels["radiation"] = { type = "related-to", parents = {"energy"}, } labels["radioactivity"] = { type = "related-to", parents = {"radiation", "nuclear physics"}, } labels["radium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["radon"] = { type = "related-to", parents = {"noble gases"}, } labels["rain"] = { type = "related-to", parents = {"weather", "water"}, } labels["recreational drugs"] = { type = "set", parents = {"drugs"}, } labels["rhodium"] = { type = "related-to", parents = {"transition metals"}, } labels["rubidium"] = { type = "related-to", parents = {"alkali metals"}, } labels["ruthenium"] = { type = "related-to", parents = {"transition metals"}, } labels["salt"] = { type = "related-to", parents = {"minerals", "condiments"}, } labels["samarium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["scandium"] = { type = "related-to", parents = {"transition metals"}, } labels["selenium"] = { type = "related-to", parents = {"chalcogens"}, } labels["shadow"] = { type = "related-to", parents = {"darkness"}, } labels["silence"] = { type = "related-to", parents = {"sound"}, } labels["silicon"] = { type = "related-to", parents = {"carbon group elements"}, } labels["silver"] = { type = "related-to", parents = {"transition metals"}, } labels["size"] = { type = "related-to", parents = {"nature"}, } labels["snow"] = { type = "related-to", parents = {"weather", "water"}, } labels["sodium"] = { type = "related-to", parents = {"alkali metals"}, } labels["sound"] = { type = "related-to", parents = {"energy"}, } labels["sounds"] = { type = "set", parents = {"sound"}, } labels["space"] = { type = "related-to", parents = {"nature"}, } labels["spring"] = { type = "related-to", parents = {"seasons"}, } labels["squarks"] = { type = "set", parents = {"fermions"}, } labels["stars"] = { type = "set", description = "{{{langname}}} names of individual [[star]]s, not including the [[Sun]].", parents = {"celestial bodies"}, } labels["steel"] = { type = "related-to", parents = {"iron", "alloys"}, } labels["steroids"] = { type = "set", parents = {"organic compounds"}, } labels["strength"] = { type = "related-to", parents = {"nature", "health"}, } labels["strontium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["subatomic particles"] = { type = "set", parents = {"matter", "particle physics"}, } labels["sugar acids"] = { type = "set", parents = {"carboxylic acids", "carbohydrates"}, } labels["sugars"] = { type = "set", parents = {"carbohydrates"}, } labels["sulfur"] = { type = "related-to", parents = {"chalcogens"}, } labels["summer"] = { type = "related-to", parents = {"seasons"}, } labels["sun"] = { type = "related-to", description = "=the [[Sun]]", parents = {"nature", "light", "celestial bodies"}, } labels["supposed chemical elements"] = { breadcrumb = "supposed", type = "set", description = "{{{langname}}} terms for types or instances of [[chemical element]]s which were erroneously identified.", parents = {"chemical elements", "obsolete scientific theories"}, } labels["tantalum"] = { type = "related-to", parents = {"transition metals"}, } labels["technetium"] = { type = "related-to", parents = {"transition metals"}, } labels["tellurium"] = { type = "related-to", parents = {"chalcogens"}, } labels["temperature"] = { type = "related-to", parents = {"nature", "weather"}, } labels["teratogens"] = { type = "set", parents = {"poisons"}, } labels["thalium"] = { type = "related-to", parents = {"boron group elements"}, } labels["thorium"] = { type = "related-to", parents = {"actinide series chemical elements"}, } labels["tin"] = { type = "related-to", parents = {"carbon group elements"}, } labels["titanium"] = { type = "related-to", parents = {"transition metals"}, } labels["tobacco"] = { type = "related-to", parents = {"nightshades", "recreational drugs", "smoking"}, } labels["transition metals"] = { type = "set", description = "{{{langname}}} terms for [[chemical element]]s in [[w:Group (periodic table)|group]]s 3 to 12 of the [[periodic table]], which are also in the {{w|d-block}} of the [[periodic table]] ", parents = {"chemical elements", "metals"}, } labels["tritium"] = { type = "related-to", parents = {"hydrogen", "three", "isotopes"}, } labels["tungsten"] = { type = "related-to", parents = {"transition metals"}, } labels["types of chemical elements"] = { breadcrumb = "types", type = "type", topic = "chemical elements", description = "=[[chemical element]]s, e.g. metal, nonmetal, noble gas, etc.", parents = {"chemical elements", "chemistry"}, } labels["types of planets"] = { type = "type", topic = "planets", description = "=[[planet]]s", parents = {"planets"}, } labels["uranium"] = { type = "related-to", parents = {"actinide series chemical elements"}, } labels["vanadium"] = { type = "related-to", parents = {"transition metals"}, } labels["vocalizations"] = { type = "set", parents = {"sounds", "communication"}, } labels["water"] = { type = "related-to", parents = {"liquids"}, } labels["waterfalls"] = { type = "related-to", parents = {"water"}, } labels["weather"] = { type = "related-to", parents = {"atmosphere"}, } labels["weight"] = { type = "related-to", parents = {"nature"}, } labels["wetlands"] = { type = "related-to", parents = {"bodies of water", "ecosystems"}, } labels["wetness"] = { type = "related-to", parents = {"liquids"}, } labels["wind"] = { type = "related-to", parents = {"weather"}, } labels["winter"] = { type = "related-to", parents = {"seasons"}, } labels["xenon"] = { type = "related-to", parents = {"noble gases"}, } labels["yttrium"] = { type = "related-to", parents = {"transition metals"}, } labels["zinc"] = { type = "related-to", parents = {"transition metals"}, } labels["zirconium"] = { type = "related-to", parents = {"transition metals"}, } labels["exoplanets"] = { type = "name", parents = {"planets"}, } return labels cu4vnxr2me8qddcpar8xtalgqgmvndj 88795 88794 2026-08-06T20:13:24Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Nature]] 88794 Scribunto text/plain local labels = {} local unpack = unpack or table.unpack -- Lua 5.2 compatibility labels["nature"] = { type = "related-to", parents = {"all topics"}, } labels["acids"] = { type = "set", parents = {"matter"}, } labels["actinide series chemical elements"] = { breadcrumb = "actinide series", type = "set", description = "{{{langname}}} terms for those chemical elements in the {{w|f-block}} of the [[periodic table]] with [[atomic number]]s from 89 to 103.", parents = {"chemical elements", "metals", "radioactivity"}, } labels["air"] = { type = "related-to", parents = {"atmosphere"}, } labels["alkali metals"] = { type = "set", description = "{{{langname}}} terms for [[alkali metal]]s, chemical elements in [[w:Group (periodic table)|group]] 1 of the [[periodic table]], which all have one [[valence electron]].", parents = {"chemical elements", "metals"}, } labels["alkaline earth metals"] = { type = "set", description = "{{{langname}}} terms for [[alkaline earth metal]]s, chemical elements in [[w:Group (periodic table)|group]] 2, which all have two [[valence electron]]s.", parents = {"chemical elements", "metals"}, } labels["alkaloids"] = { type = "set", parents = {"organic compounds"}, } labels["alloys"] = { type = "set", parents = {"metals"}, } labels["aluminium"] = { type = "related-to", parents = {"boron group elements"}, } labels["amino acids"] = { type = "set", parents = {"carboxylic acids"}, } labels["animal sounds"] = { type = "set", parents = {"sounds", "vocalizations"}, } labels["animal welfare"] = { type = "related-to", description = "{{{langname}}} terms closely associated with [[animal welfare]].", parents = {"ethics"}, } labels["antimatter"] = { type = "related-to", parents = {"matter"}, } labels["antimony"] = { type = "related-to", parents = {"pnictogens"}, } labels["argon"] = { type = "related-to", parents = {"noble gases"}, } labels["arsenic"] = { type = "related-to", parents = {"pnictogens"}, } labels["astatine"] = { type = "related-to", parents = {"halogens"}, } labels["asteroids"] = { type = "set", parents = {"celestial bodies"}, } labels["atmosphere"] = { type = "related-to", parents = {"nature"}, } labels["atmospheric phenomena"] = { type = "set", parents = {"atmosphere"}, } labels["autumn"] = { type = "related-to", parents = {"seasons"}, } labels["barium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["baryons"] = { type = "set", parents = {"hadrons"}, } labels["beryllium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["birth"] = { type = "related-to", parents = {"reproduction"}, } labels["bismuth"] = { type = "related-to", parents = {"pnictogens"}, } labels["boron"] = { type = "related-to", parents = {"boron group elements"}, } labels["boron group elements"] = { breadcrumb = "boron group", type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 13 of the [[periodic table]], which all have three [[valence electron]]s.", parents = {"chemical elements"}, } labels["bosons"] = { type = "set", parents = {"subatomic particles"}, } labels["bromine"] = { type = "related-to", parents = {"halogens"}, } labels["cadmium"] = { type = "related-to", parents = {"transition metals"}, } labels["calcium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["carbohydrates"] = { type = "set", parents = {"organic compounds"}, } labels["carbon"] = { type = "related-to", parents = {"carbon group elements"}, } labels["carbon group elements"] = { breadcrumb = "carbon group", type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 14 of the [[periodic table]], which all have four [[valence electron]]s.", parents = {"chemical elements"}, } labels["carboxylic acids"] = { type = "set", parents = {"acids", "organic compounds"}, } labels["celestial bodies"] = { type = "set", description = "{{{langname}}} terms for varous [[celestial body|celestial bodies]]; things found in outer space.", parents = {"space"}, } labels["cerium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["cesium"] = { type = "related-to", parents = {"alkali metals"}, } labels["chalcogens"] = { type = "set", description = "{{{langname}}} terms for chemical elements in [[w:Group (periodic table)|group]] 16 of the [[periodic table]], which all have 6 [[valence electron]]s.", parents = {"chemical elements"}, } labels["chemical elements"] = { type = "set", parents = {"matter"}, } for period = 1, 7 do local key = ("Period %d elements"):format(period) if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in period %d of the [[periodic table]]."):format(period), parents = {"chemical elements"}, } end end for group = 1, 12 do local key = ("Group %d elements"):format(group) if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in [[w:Group (periodic table)|group]] %d of the [[periodic table]]."):format(group), parents = {"chemical elements"}, } end end for _, block in ipairs({"s", "p", "d", "f"}) do local key = block:upper() .. "-block elements" if not labels[key] then labels[key] = { type = "set", description = ("{{{langname}}} terms for [[chemical element]]s in the %s-block of the [[periodic table]]."):format(block), parents = {"chemical elements"}, } end end if not labels["Nonmetals"] then labels["Nonmetals"] = { type = "set", description = "{{{langname}}} terms for [[nonmetal]] [[chemical element]]s.", parents = {"chemical elements"}, } end if not labels["Post-transition metals"] then labels["Post-transition metals"] = { type = "set", description = "{{{langname}}} terms for [[post-transition metal]] [[chemical element]]s.", parents = {"chemical elements", "metals"}, } end labels["chemical isomers"] = { type = "related-to", parents = {"matter", "physical chemistry", "shapes"}, } labels["chemical processes"] = { type = "set", description = "=[[chemical]] [[process]]es", parents = {"nature"}, } labels["chlorine"] = { type = "related-to", parents = {"halogens"}, } labels["chromium"] = { type = "related-to", parents = {"transition metals"}, } labels["classical planets"] = { type = "name", description = "{{{langname}}} names for the [[classical planet]]s of our Solar System.", parents = {"celestial bodies"}, } labels["climate change"] = { type = "related-to", description = "=[[anthropogenic]] [[climate change]]", parents = {"nature"}, } labels["clouds"] = { type = "set", parents = {"atmospheric phenomena"}, } labels["coal"] = { type = "related-to", parents = {"fossil fuels"}, } labels["cobalt"] = { type = "related-to", parents = {"transition metals"}, } labels["coenzymes"] = { type = "set", parents = {"enzymes"}, } labels["colors"] = { type = "set", parents = {"light", "vision"}, } for _, color_etc in ipairs { {"black"}, {"blue"}, {"brown"}, {"green"}, {"grey", "[[grey]] ([[gray]])"}, {"orange"}, {"pink"}, {"purple"}, {"red"}, {"violet"}, {"white"}, {"yellow"}, } do local color, desc = unpack(color_etc) desc = desc or ("[[%s]]"):format(color) labels[color .. "s"] = { type = "set", description = ("=shades of the [[color]] %s"):format(desc), parents = {"colors"}, } end labels["colors of the rainbow"] = { type = "set", description = "=[[color]]s of the [[rainbow]]", parents = {"colors"}, } labels["combustion"] = { type = "related-to", parents = {"chemical processes"}, } labels["compass points"] = { type = "set", parents = {"directions", "navigation"}, } labels["copper"] = { type = "related-to", parents = {"transition metals"}, } labels["crystal"] = { type = "related-to", parents = {"matter", "physical chemistry"}, } labels["darkness"] = { type = "related-to", parents = {"light"}, } labels["deuterium"] = { type = "related-to", parents = {"hydrogen", "two", "isotopes"} } labels["directions"] = { type = "set", parents = {"nature"}, } labels["distance"] = { type = "related-to", parents = {"nature"}, } labels["drugs"] = { type = "set", parents = {"matter", "pharmacology"}, } labels["dryness"] = { type = "related-to", parents = {"liquids"}, } labels["dwarf planets of the Solar System"] = { type = "name", description = "=[[dwarf planet]]s of our [[Solar System]]", parents = {"celestial bodies"}, } labels["dyes"] = { type = "set", parents = {"matter", "pigments"}, } labels["energy"] = { type = "related-to", parents = {"nature"}, } labels["enzymes"] = { type = "set", parents = {"proteins", "catalysis"}, } labels["europium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["explosives"] = { type = "set", parents = {"matter", "weapons"}, } labels["eye colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[eye]]s", parents = {"colors", "eye"}, } labels["fatty acids"] = { type = "set", parents = {"carboxylic acids"}, } labels["fermions"] = { type = "set", parents = {"subatomic particles"}, } labels["fictional materials"] = { type = "set", parents = {"science fiction", "materials"}, } labels["fire"] = { type = "related-to", parents = {"combustion", "light sources"}, wp = "Fire", } labels["fluorine"] = { type = "related-to", parents = {"halogens"}, } labels["fog"] = { type = "related-to", parents = {"weather", "water"}, } labels["fossil fuels"] = { type = "set", parents = {"carbon", "energy", "natural resources"}, } labels["francium"] = { type = "related-to", parents = {"alkali metals"}, } labels["gadolinium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["galaxies"] = { type = "set", parents = {"celestial bodies"}, } labels["gallium"] = { type = "related-to", parents = {"boron group elements"}, } labels["gases"] = { type = "set", parents = {"matter"}, } labels["germanium"] = { type = "related-to", parents = {"carbon group elements"}, } labels["gold"] = { type = "related-to", parents = {"transition metals"}, } labels["hadrons"] = { type = "set", parents = {"subatomic particles"}, } labels["hair colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[hair]]", parents = {"colors", "hair"}, } labels["halogens"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 17 of the [[periodic table]], which all have 7 [[valence electron]]s", parents = {"chemical elements"}, } labels["helium"] = { type = "related-to", parents = {"noble gases"}, } labels["heroin"] = { type = "related-to", parents = {"recreational drugs"}, } labels["height"] = { type = "related-to", parents = {"distance"}, } labels["horse colors"] = { type = "set", description = "=[[color]]s that are mostly or exclusively used of [[horse]]s", parents = {"colors", "horses"}, } labels["hydrogen"] = { type = "related-to", parents = {"chemical elements"}, } labels["hypothetical chemical elements"] = { breadcrumb = "hypothetical", type = "set", description = "{{{langname}}} terms for types or instances of [[chemical element]]s which have been hypothesized to exist, but not (yet) discovered.", parents = {"chemical elements", "fictional materials"}, } labels["ice"] = { type = "related-to", parents = {"water"}, } labels["indium"] = { type = "related-to", parents = {"boron group elements"}, } labels["inorganic compounds"] = { type = "set", parents = {"matter"}, } labels["iodine"] = { type = "related-to", parents = {"halogens"}, } labels["ions"] = { type = "set", parents = {"matter", "chemistry", "electricity"}, } labels["iridium"] = { type = "related-to", parents = {"transition metals"}, } labels["iron"] = { type = "related-to", parents = {"transition metals"}, } labels["isotopes"] = { type = "set", parents = {"chemical elements"}, } labels["krypton"] = { type = "related-to", parents = {"noble gases"}, } labels["lanthanide series chemical elements"] = { breadcrumb = "lanthanide series", type = "set", description = "=[[chemical element]]s in the {{w|f-block}} of the [[periodic table]] with [[atomic number]]s from 57 to 71", parents = {"chemical elements"}, } labels["lanthanum"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["lead"] = { type = "related-to", parents = {"carbon group elements"}, } labels["length"] = { type = "related-to", parents = {"distance"}, } labels["leptons"] = { type = "set", parents = {"fermions"}, } labels["life"] = { type = "related-to", parents = {"nature"}, } labels["light"] = { type = "related-to", parents = {"energy"}, } labels["light sources"] = { type = "set", parents = {"light"}, } labels["lightning"] = { type = "related-to", parents = {"atmospheric phenomena", "weather", "electricity", "light sources"}, } labels["liquids"] = { type = "set", -- description = "default", -- At what temperature? parents = {"matter"}, } labels["lithium"] = { type = "related-to", parents = {"alkali metals"}, } labels["magnesium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["manganese"] = { type = "related-to", parents = {"transition metals"}, } labels["Mars (planet)"] = { type = "related-to", description = "=the planet [[Mars]]", parents = {"planets of the Solar System"}, } labels["marijuana"] = { type = "related-to", parents = {"hemp family plants", "recreational drugs"}, } labels["matter"] = { type = "related-to", description = "=physical [[matter]]", parents = {"nature", "chemistry"}, } labels["mercury (element)"] = { type = "related-to", parents = {"transition metals"}, } labels["mesons"] = { type = "set", parents = {"hadrons"}, } labels["metalloids"] = { type = "set", parents = {"chemical elements"}, } labels["metals"] = { type = "set", parents = {"matter", "metallurgy"}, } labels["minerals"] = { type = "set", parents = {"matter", "mineralogy"}, } labels["molybdenum"] = { type = "related-to", parents = {"transition metals"}, } labels["moon"] = { type = "related-to", description = "=the [[Moon]], Earth's only natural satellite", parents = {"nature", "light", "celestial bodies", "moons"}, } labels["moons"] = { type = "related-to", parents = {"celestial bodies"}, } for _, planet in ipairs {"Mars", "Haumea", "Jupiter", "Saturn", "Neptune", "Uranus", "Pluto"} do labels["moons of " .. planet] = { type = "name", description = ("=[[moon]]s that orbit [[%s]]"):format(planet), parents = {"moons"}, } end labels["natural products (Chemistry)"] = { type = "name", description = "=[[organic compound]]s produced by living [[organism]]s", parents = {"organic compounds"}, } labels["natural resources"] = { type = "set", parents = {"matter"}, } labels["neodymium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["neon"] = { type = "related-to", parents = {"noble gases"}, } labels["neurotoxins"] = { type = "set", parents = {"poisons", "neuroscience"}, } labels["nickel"] = { type = "related-to", parents = {"transition metals"}, } labels["niobium"] = { type = "related-to", parents = {"transition metals"}, } labels["nitrogen"] = { type = "related-to", parents = {"pnictogens"}, } labels["noble gases"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 18 of the [[periodic table]], which all have a full set of [[valence electron]]s: 2 for helium and 8 for the others", parents = {"chemical elements", "gases"}, } labels["organic compounds"] = { type = "set", parents = {"matter"}, } labels["osmium"] = { type = "related-to", parents = {"transition metals"}, } labels["oxygen"] = { type = "related-to", parents = {"chalcogens"}, } labels["palladium"] = { type = "related-to", parents = {"transition metals"}, } labels["petroleum"] = { type = "related-to", parents = {"fossil fuels", "liquids"}, } labels["pharmaceutical drugs"] = { type = "set", description = "{{{langname}}} names for [[pharmaceutical#Adjective|pharmaceutical]] [[drug#Noun|drugs]].", parents = {"drugs"}, } labels["pharmaceutical effects"] = { type = "set", description = "{{{langname}}} names for [[pharmaceutical#Adjective|pharmaceutical]] [[effect#Noun|effects]].", parents = {"pharmacology"}, } labels["phosphorus"] = { type = "related-to", parents = {"pnictogens"}, } labels["pigments"] = { type = "set", parents = {"colors"}, } labels["planetoids"] = { type = "set", parents = {"celestial bodies"}, } labels["planets"] = { type = "set", parents = {"celestial bodies"}, } labels["planets of the Solar System"] = { type = "name", description = "=[[planet]]s of our [[Solar System]]", parents = {"planets"}, } labels["platinum"] = { type = "related-to", parents = {"transition metals"}, } labels["Pluto"] = { type = "related-to", description = "=the dwarf planet [[Pluto]]", parents = {"dwarf planets of the Solar System"}, } labels["pnictogens"] = { type = "set", description = "=[[chemical element]]s in [[w:Group (periodic table)|group]] 15 of the [[periodic table]], which all have 5 [[valence electron]]s", parents = {"chemical elements"}, } labels["poisons"] = { type = "set", parents = {"matter"}, } labels["potassium"] = { type = "related-to", parents = {"alkali metals"}, } labels["praseodymium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["promethium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["quarks"] = { type = "set", parents = {"fermions"}, } labels["radiation"] = { type = "related-to", parents = {"energy"}, } labels["radioactivity"] = { type = "related-to", parents = {"radiation", "nuclear physics"}, } labels["radium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["radon"] = { type = "related-to", parents = {"noble gases"}, } labels["rain"] = { type = "related-to", parents = {"weather", "water"}, } labels["recreational drugs"] = { type = "set", parents = {"drugs"}, } labels["rhodium"] = { type = "related-to", parents = {"transition metals"}, } labels["rubidium"] = { type = "related-to", parents = {"alkali metals"}, } labels["ruthenium"] = { type = "related-to", parents = {"transition metals"}, } labels["salt"] = { type = "related-to", parents = {"minerals", "condiments"}, } labels["samarium"] = { type = "related-to", parents = {"lanthanide series chemical elements"}, } labels["scandium"] = { type = "related-to", parents = {"transition metals"}, } labels["selenium"] = { type = "related-to", parents = {"chalcogens"}, } labels["shadow"] = { type = "related-to", parents = {"darkness"}, } labels["silence"] = { type = "related-to", parents = {"sound"}, } labels["silicon"] = { type = "related-to", parents = {"carbon group elements"}, } labels["silver"] = { type = "related-to", parents = {"transition metals"}, } labels["size"] = { type = "related-to", parents = {"nature"}, } labels["snow"] = { type = "related-to", parents = {"weather", "water"}, } labels["sodium"] = { type = "related-to", parents = {"alkali metals"}, } labels["sound"] = { type = "related-to", parents = {"energy"}, } labels["sounds"] = { type = "set", parents = {"sound"}, } labels["space"] = { type = "related-to", parents = {"nature"}, } labels["spring"] = { type = "related-to", parents = {"seasons"}, } labels["squarks"] = { type = "set", parents = {"fermions"}, } labels["stars"] = { type = "set", description = "{{{langname}}} names of individual [[star]]s, not including the [[Sun]].", parents = {"celestial bodies"}, } labels["steel"] = { type = "related-to", parents = {"iron", "alloys"}, } labels["steroids"] = { type = "set", parents = {"organic compounds"}, } labels["strength"] = { type = "related-to", parents = {"nature", "health"}, } labels["strontium"] = { type = "related-to", parents = {"alkaline earth metals"}, } labels["subatomic particles"] = { type = "set", parents = {"matter", "particle physics"}, } labels["sugar acids"] = { type = "set", parents = {"carboxylic acids", "carbohydrates"}, } labels["sugars"] = { type = "set", parents = {"carbohydrates"}, } labels["sulfur"] = { type = "related-to", parents = {"chalcogens"}, } labels["summer"] = { type = "related-to", parents = {"seasons"}, } labels["sun"] = { type = "related-to", description = "=the [[Sun]]", parents = {"nature", "light", "celestial bodies"}, } labels["supposed chemical elements"] = { breadcrumb = "supposed", type = "set", description = "{{{langname}}} terms for types or instances of [[chemical element]]s which were erroneously identified.", parents = {"chemical elements", "obsolete scientific theories"}, } labels["tantalum"] = { type = "related-to", parents = {"transition metals"}, } labels["technetium"] = { type = "related-to", parents = {"transition metals"}, } labels["tellurium"] = { type = "related-to", parents = {"chalcogens"}, } labels["temperature"] = { type = "related-to", parents = {"nature", "weather"}, } labels["teratogens"] = { type = "set", parents = {"poisons"}, } labels["thalium"] = { type = "related-to", parents = {"boron group elements"}, } labels["thorium"] = { type = "related-to", parents = {"actinide series chemical elements"}, } labels["tin"] = { type = "related-to", parents = {"carbon group elements"}, } labels["titanium"] = { type = "related-to", parents = {"transition metals"}, } labels["tobacco"] = { type = "related-to", parents = {"nightshades", "recreational drugs", "smoking"}, } labels["transition metals"] = { type = "set", description = "{{{langname}}} terms for [[chemical element]]s in [[w:Group (periodic table)|group]]s 3 to 12 of the [[periodic table]], which are also in the {{w|d-block}} of the [[periodic table]] ", parents = {"chemical elements", "metals"}, } labels["tritium"] = { type = "related-to", parents = {"hydrogen", "three", "isotopes"}, } labels["tungsten"] = { type = "related-to", parents = {"transition metals"}, } labels["types of chemical elements"] = { breadcrumb = "types", type = "type", topic = "chemical elements", description = "=[[chemical element]]s, e.g. metal, nonmetal, noble gas, etc.", parents = {"chemical elements", "chemistry"}, } labels["types of planets"] = { type = "type", topic = "planets", description = "=[[planet]]s", parents = {"planets"}, } labels["uranium"] = { type = "related-to", parents = {"actinide series chemical elements"}, } labels["vanadium"] = { type = "related-to", parents = {"transition metals"}, } labels["vocalizations"] = { type = "set", parents = {"sounds", "communication"}, } labels["water"] = { type = "related-to", parents = {"liquids"}, } labels["waterfalls"] = { type = "related-to", parents = {"water"}, } labels["weather"] = { type = "related-to", parents = {"atmosphere"}, } labels["weight"] = { type = "related-to", parents = {"nature"}, } labels["wetlands"] = { type = "related-to", parents = {"bodies of water", "ecosystems"}, } labels["wetness"] = { type = "related-to", parents = {"liquids"}, } labels["wind"] = { type = "related-to", parents = {"weather"}, } labels["winter"] = { type = "related-to", parents = {"seasons"}, } labels["xenon"] = { type = "related-to", parents = {"noble gases"}, } labels["yttrium"] = { type = "related-to", parents = {"transition metals"}, } labels["zinc"] = { type = "related-to", parents = {"transition metals"}, } labels["zirconium"] = { type = "related-to", parents = {"transition metals"}, } labels["exoplanets"] = { type = "name", parents = {"planets"}, } return labels cu4vnxr2me8qddcpar8xtalgqgmvndj Mòideal:category tree/topic/Numbers 828 17899 88796 2026-07-23T19:36:37Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88796 Scribunto text/plain local labels = {} labels["numbers"] = { type = "related-to", parents = {"all topics"}, } for _, number in ipairs { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", "one hundred", "one thousand", } do local bare_number = number:gsub("^one ", "") labels[bare_number] = { type = "related-to", description = ("=the number [[%s]] ([[etymologically]] or [[semantically]])"):format(number), parents = {"numbers"}, } end labels["historical numbers"] = { type = "set", parents = {"numbers"}, } return labels ts3yhwgullub3u9kmik658nnibpnc27 88797 88796 2026-08-06T20:13:42Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Numbers]] 88796 Scribunto text/plain local labels = {} labels["numbers"] = { type = "related-to", parents = {"all topics"}, } for _, number in ipairs { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", "one hundred", "one thousand", } do local bare_number = number:gsub("^one ", "") labels[bare_number] = { type = "related-to", description = ("=the number [[%s]] ([[etymologically]] or [[semantically]])"):format(number), parents = {"numbers"}, } end labels["historical numbers"] = { type = "set", parents = {"numbers"}, } return labels ts3yhwgullub3u9kmik658nnibpnc27 Mòideal:category tree/topic/Philosophy 828 17900 88798 2026-07-23T19:36:40Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88798 Scribunto text/plain local labels = {} labels["philosophy"] = { type = "related-to", parents = {"all topics"}, } labels["aesthetics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["Ancient Greek philosophy"] = { type = "related-to", breadcrumb = "Ancient Greek", parents = {"philosophy", "Ancient Greece"}, } labels["Chinese philosophy"] = { type = "related-to", breadcrumb = "Chinese", parents = {"philosophy", "China"}, } labels["Confucianism"] = { type = "related-to", parents = {"Chinese philosophy", "religion"}, } labels["epistemology"] = { type = "related-to", parents = {"philosophy"}, } labels["ethics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["jurisprudence"] = { type = "related-to", parents = {"law", "philosophy", "humanities"}, } labels["metaphysics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["memetics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["Platonism"] = { type = "related-to", parents = {"Ancient Greek philosophy"}, } labels["theology"] = { type = "related-to", parents = {"philosophy", "religion"}, } labels["transhumanism"] = { type = "related-to", parents = {"philosophy", "technology"}, } labels["virtue"] = { type = "related-to", parents = {"ethics"}, } return labels lar1gs424tu59s579z1k8zr9qdyobor 88799 88798 2026-08-06T20:14:03Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Philosophy]] 88798 Scribunto text/plain local labels = {} labels["philosophy"] = { type = "related-to", parents = {"all topics"}, } labels["aesthetics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["Ancient Greek philosophy"] = { type = "related-to", breadcrumb = "Ancient Greek", parents = {"philosophy", "Ancient Greece"}, } labels["Chinese philosophy"] = { type = "related-to", breadcrumb = "Chinese", parents = {"philosophy", "China"}, } labels["Confucianism"] = { type = "related-to", parents = {"Chinese philosophy", "religion"}, } labels["epistemology"] = { type = "related-to", parents = {"philosophy"}, } labels["ethics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["jurisprudence"] = { type = "related-to", parents = {"law", "philosophy", "humanities"}, } labels["metaphysics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["memetics"] = { type = "related-to", description = "default no singularize", parents = {"philosophy"}, } labels["Platonism"] = { type = "related-to", parents = {"Ancient Greek philosophy"}, } labels["theology"] = { type = "related-to", parents = {"philosophy", "religion"}, } labels["transhumanism"] = { type = "related-to", parents = {"philosophy", "technology"}, } labels["virtue"] = { type = "related-to", parents = {"ethics"}, } return labels lar1gs424tu59s579z1k8zr9qdyobor Mòideal:category tree/topic/Sciences 828 17901 88800 2026-07-23T19:36:47Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88800 Scribunto text/plain local labels = {} labels["sciences"] = { type = "related-to", description = "default with the", parents = {"all topics"}, } labels["acceleration"] = { type = "related-to", parents = {"physics"}, } labels["acoustics"] = { type = "related-to", description = "default no singularize", parents = {"applied sciences", "physics", "sound"}, } labels["adjectives"] = { type = "type", parents = {"parts of speech"}, } labels["aeronautics"] = { type = "related-to", description = "default no singularize", parents = {"sciences"}, } labels["aerospace"] = { type = "related-to", parents = {"sciences", "space", "astronautics", "aeronautics"}, } labels["agriculture"] = { type = "related-to", parents = {"applied sciences"}, } labels["alchemy"] = { type = "related-to", parents = {"paranormal", "pseudoscience", "obsolete scientific theories"}, } labels["alternative medicine"] = { type = "related-to", parents = {"medicine", "pseudoscience"}, } labels["analytical chemistry"] = { type = "related-to", 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", 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", "social sciences"}, } labels["anti-gravity"] = { type = "related-to", parents = {"fictional abilities", "gravity", "science fiction", "space access"}, } labels["applied sciences"] = { type = "related-to", parents = {"sciences"}, } 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", parents = {"anthropology", "sciences"}, commonscat = true, wpcat = true, } labels["architectural elements"] = { type = "set", parents = {"architecture"}, } labels["architecture"] = { type = "related-to", parents = {"applied sciences", "art"}, } 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", parents = {"computer science", "cybernetics"}, } labels["asterisms"] = { type = "name", 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 = {"sciences", "space"}, } labels["astrophysics"] = { type = "related-to", description = "default no singularize", parents = {"physics", "astronomy"}, } labels["aviation"] = { type = "related-to", parents = {"aeronautics", "transport"}, } labels["avionics"] = { type = "related-to", description = "default no singularize", parents = {"aeronautics", "electronics"}, } labels["Ayurveda"] = { type = "related-to", 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", parents = {"chemistry", "biology"}, } labels["biology"] = { type = "related-to", description = "{{{langname}}} terms used in [[biology]], the study of [[life]].", additional = "{{also|Category:{{{langcode}}}:Lifeforms}}", parents = {"sciences"}, } labels["black holes"] = { type = "related-to", 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", parents = {"construction", "woodworking"}, } labels["cartography"] = { type = "related-to", parents = {"geography"}, } labels["catalysis"] = { type = "related-to", parents = {"chemical processes", "chemical reactions", "physical chemistry"}, } labels["chemical engineering"] = { type = "related-to", parents = {"engineering", "chemistry"}, } labels["chemical formulae"] = { type = "name", parents = {"chemical notation"}, } labels["chemical notation"] = { type = "related-to", parents = {"chemistry", "names", "symbols"}, } labels["chemical reactions"] = { type = "related-to,set", parents = {"chemistry"}, } labels["chemical reagents"] = { type = "set", parents = {"chemistry"}, } labels["chemistry"] = { type = "related-to", parents = {"sciences"}, } labels["Chinese astronomy"] = { type = "related-to", 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 = {"linguistics", "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", parents = {"psychology", "pathology"}, } labels["computational linguistics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics", "computer science"}, } labels["computer science"] = { type = "related-to", parents = {"sciences", "computing"}, } labels["conchology"] = { type = "related-to", description = "{{{langname}}} terms used in [[conchology]], the study of mollusc [[shell]]s.", parents = {"malacology"}, } labels["constellations"] = { type = "name", parents = {"astronomy"}, } labels["construction"] = { type = "related-to", parents = {"engineering", "architecture"}, } labels["control theory"] = { type = "related-to", parents = {"sciences", "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", 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", parents = {"physics", "crystal"}, } labels["cultural anthropology"] = { type = "related-to", parents = {"anthropology", "culture"}, } 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", parents = {"information science", "computer science"}, } labels["demarcation lines"] = { type = "name", description = "=political [[demarcation line]]s", parents = {"politics"}, } labels["decision theory"] = { type = "related-to", parents = {"probability theory", "epistemology"}, } labels["demography"] = { type = "related-to", parents = {"sciences", "statistics"}, } labels["dentistry"] = { type = "related-to", 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", parents = {"sciences"}, } labels["earthquake engineering"] = { type = "related-to", 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 = {"social sciences"}, } labels["ecosystems"] = { type = "related-to", 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", parents = {"engineering", "electricity"}, } labels["electricity"] = { type = "related-to", parents = {"electromagnetism"}, } labels["electrocardiography"] = { type = "related-to", parents = {"cardiology"}, } labels["electrodynamics"] = { type = "related-to", description = "default no singularize", parents = {"electromagnetism"}, } labels["electrochemistry"] = { type = "related-to", parents = {"physical chemistry", "electricity"}, } labels["electromagnetism"] = { type = "related-to", parents = {"physics"}, } labels["element nomenclature"] = { type = "related-to", parents = {"chemical notation", "names", "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", 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", parents = {"applied sciences", "technology"}, } labels["enterprise engineering"] = { type = "related-to", 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", 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", 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", parents = {"agriculture", "Malpighiales order plants"}, } labels["fluid dynamics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } labels["forestry"] = { type = "related-to", parents = {"applied sciences"}, } labels["functional group prefixes"] = { type = "set", parents = {"organic chemistry"}, } labels["functional group suffixes"] = { type = "set", 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["geography"] = { 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", 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 = {"geography", "politics"}, } labels["geospatial science"] = { type = "related-to", 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", parents = {"linguistics"}, } labels["grammatical cases"] = { type = "set", parents = {"grammar"}, } labels["grammatical moods"] = { type = "set", parents = {"grammar"}, } labels["gravity"] = { type = "related-to", parents = {"acceleration", "astrophysics", "mechanics"}, } labels["gynaecology"] = { type = "related-to", 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", parents = {"alternative medicine"}, } labels["horticulture"] = { type = "related-to", parents = {"agriculture", "botany"}, } labels["hydroacoustics"] = { type = "related-to", description = "default no singularize", parents = {"acoustics", "hydrology"}, } labels["hydrocarbon chain prefixes"] = { type = "set", parents = {"organic chemistry"}, } labels["hydrocarbon chain suffixes"] = { type = "set", 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", 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 = {"linguistics"}, } labels["information science"] = { type = "related-to", parents = {"applied sciences"}, } labels["inorganic chemistry"] = { type = "related-to", parents = {"chemistry"}, } labels["interdisciplinary fields"] = { type = "related-to", parents = {"sciences"}, } labels["isolines"] = { type = "related-to", parents = {"cartography", "meteorology"}, } labels["Lagrange points"] = { type = "related-to", parents = {"orbits"}, } labels["lexicography"] = { type = "related-to", parents = {"linguistics"}, } labels["library science"] = { type = "related-to", parents = {"sciences", "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", parents = {"linguistics"}, } labels["linguistics"] = { type = "related-to", description = "{{{langname}}} terms used in [[linguistics]], the study and analysis of [[language]].", additional = "{{also|Category:{{{langcode}}}:Language}}", parents = {"language", "social sciences"}, } labels["locksmithing"] = { type = "related-to", parents = {"technology"}, } 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", parents = {"construction"}, } labels["materials science"] = { type = "related-to", parents = {"sciences", "engineering"}, } labels["mechanical engineering"] = { type = "related-to", parents = {"engineering"}, } labels["mechanics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } 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", parents = {"physics"}, } labels["physical constants"] = { type = "set", parents = {"physics"}, } labels["machine learning"] = { type = "related-to", 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", parents = {"surgery", "neurology"}, } labels["neutron"] = { type = "related-to", parents = {"nuclear physics"}, } labels["neutron stars"] = { type = "related-to", parents = {"neutron", "gravity", "astrophysics", "relativity", "stars"}, } labels["nouns"] = { type = "related-to", parents = {"parts of speech"}, } labels["nuclear energy"] = { type = "related-to", parents = {"energy", "nuclear physics", "technology"}, } labels["nuclear fusion"] = { type = "related-to", parents = {"nuclear energy"}, } labels["nuclear physics"] = { type = "related-to", description = "default no singularize", parents = {"physics", "quantum mechanics"}, } labels["nuclear rocketry"] = { type = "related-to", 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", parents = {"sciences"}, } labels["oenology"] = { type = "related-to", description = "{{{langname}}} terms used in [[oenology]], the study of [[wine]] and [[winemaking]].", additional = "{{also|Category:{{{langcode}}}:Wine}}", parents = {"sciences"}, } 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|Category:{{{langcode}}}:Names|Category:{{{langname}}} names}}", parents = {"linguistics", "names"}, } 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 = {"physics"}, } labels["orbits"] = { type = "related-to", parents = {"astronautics", "gravity", "space", "curves"}, } labels["organic chemistry"] = { type = "related-to", 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", parents = {"sciences", "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", parents = {"paranormal", "pseudoscience"}, } labels["parasitology"] = { type = "related-to", 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 = {"physics"}, } 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", 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", parents = {"biochemistry", "medicine"}, } labels["pharmacy"] = { type = "related-to", 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 = {"linguistics"}, } labels["phonology"] = { type = "related-to", description = "{{{langname}}} terms used in [[phonology]], the organisation of [[speech]] sounds within a [[language]].", parents = {"linguistics"}, } labels["photochemistry"] = { type = "related-to", parents = {"physical chemistry", "light"}, } labels["phrenology"] = { type = "related-to", 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", parents = {"chemistry", "physics"}, } labels["physical quantities"] = { type = "set", parents = {"physics"}, } labels["physics"] = { type = "related-to", description = "default no singularize", parents = {"sciences"}, 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", 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", parents = {"surgery"}, } labels["political science"] = { type = "related-to", parents = {"social sciences", "politics"}, } labels["potential theory"] = { type = "related-to", parents = {"mathematics"}, } labels["pragmatics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics"}, } labels["prosody"] = { type = "related-to", description = "{{{langname}}} terms used in [[prosody]], the study of the [[suprasegmental]] aspects of [[speech]].", parents = {"linguistics"}, } labels["pseudoscience"] = { type = "related-to", parents = {"sciences"}, } labels["psychiatry"] = { type = "related-to", 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 = {"social sciences"}, } labels["psychotherapy"] = { type = "related-to", 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 = {"sciences"}, } labels["quantity"] = { type = "related-to", parents = {"mathematics"}, } labels["quantum mechanics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } labels["relativity"] = { type = "related-to", parents = {"physics"}, } labels["rheumatology"] = { type = "related-to", parents = {"medicine"}, } labels["robotics"] = { type = "related-to", description = "default no singularize", parents = {"engineering"}, } labels["rocketry"] = { type = "related-to", parents = {"astronautics"}, } labels["roofing"] = { type = "related-to", parents = {"construction"}, } labels["rosiculture"] = { type = "related-to", parents = {"horticulture"}, } labels["rotation"] = { type = "related-to", 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 = {"linguistics"}, } labels["Semitic linguistics"] = { type = "related-to", description = "{{{langname}}} terms used in the study and analysis of [[Semitic]] [[language]]s.", parents = {"linguistics"}, } labels["semiotics"] = { type = "related-to", description = "default no singularize", parents = {"social sciences", "linguistics"}, } 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", parents = {"applied mathematics", "telecommunications"}, wpcat = true, commonscat = true, } labels["social sciences"] = { type = "related-to", description = "default with the", parents = {"sciences", "society"}, } labels["sociolinguistics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics", "sociology"}, } labels["sociology"] = { type = "related-to", description = "{{{langname}}} terms used in [[sociology]], the study of [[society]].", additional = "{{also|Category:{{{langcode}}}:Society}}", parents = {"social sciences"}, } labels["software engineering"] = { type = "related-to", parents = {"engineering", "computer science", "software"}, wpcat = true, commonscat = true, } labels["soil science"] = { type = "related-to", parents = {"earth sciences"}, } labels["sorting algorithms"] = { type = "set", parents = {"theory of computing"}, } labels["sound engineering"] = { type = "related-to", parents = {"engineering", "sound"}, } labels["space access"] = { type = "related-to", parents = {"astronautics"}, } labels["space sciences"] = { type = "related-to", parents = {"sciences", "space"}, } labels["spectroscopy"] = { type = "related-to", parents = {"analytical chemistry", "optics", "physics"}, } 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", parents = {"medicine"}, } labels["surveying"] = { type = "related-to", parents = {"geography"}, } labels["systems"] = { type = "related-to", parents = {"interdisciplinary fields", "sciences", "society"}, } labels["systems engineering"] = { type = "related-to", parents = {"engineering"}, } labels["systems theory"] = { type = "related-to", parents = {"sciences", "systems"}, } labels["taxonomy"] = { type = "related-to", additional = "For individual [[taxa]], see [[:Category:Taxonomic names]].", parents = {"biology", "evolutionary theory"}, } labels["taxonomic ranks"] = { type = "set", parents = {"taxonomy"}, } labels["tenses"] = { type = "related-to", 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 = {"physics"}, } 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", parents = {"alternative medicine"}, } labels["traffic engineering"] = { type = "related-to", parents = {"engineering", "road transport"}, } labels["translation studies"] = { type = "related-to", description = "default no singularize", parents = {"linguistics"}, } 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", 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["units of volume"] = { type = "set", description = "{{{langname}}} terms that are [[w:unit of volume|units of volume]].", parents = {"units of measure"}, commonscat = true, wpcat = true, } labels["urban studies"] = { type = "related-to", parents = {"applied sciences", "social sciences"}, } labels["urology"] = { type = "related-to", parents = {"medicine"}, } labels["verbs"] = { type = "related-to", parents = {"parts of speech"}, } labels["veterinary medicine"] = { type = "related-to", 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", 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 2b0tabbxbsjqs255dvvkhwnjt8prxx1 88801 88800 2026-08-06T20:14:14Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Sciences]] 88800 Scribunto text/plain local labels = {} labels["sciences"] = { type = "related-to", description = "default with the", parents = {"all topics"}, } labels["acceleration"] = { type = "related-to", parents = {"physics"}, } labels["acoustics"] = { type = "related-to", description = "default no singularize", parents = {"applied sciences", "physics", "sound"}, } labels["adjectives"] = { type = "type", parents = {"parts of speech"}, } labels["aeronautics"] = { type = "related-to", description = "default no singularize", parents = {"sciences"}, } labels["aerospace"] = { type = "related-to", parents = {"sciences", "space", "astronautics", "aeronautics"}, } labels["agriculture"] = { type = "related-to", parents = {"applied sciences"}, } labels["alchemy"] = { type = "related-to", parents = {"paranormal", "pseudoscience", "obsolete scientific theories"}, } labels["alternative medicine"] = { type = "related-to", parents = {"medicine", "pseudoscience"}, } labels["analytical chemistry"] = { type = "related-to", 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", 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", "social sciences"}, } labels["anti-gravity"] = { type = "related-to", parents = {"fictional abilities", "gravity", "science fiction", "space access"}, } labels["applied sciences"] = { type = "related-to", parents = {"sciences"}, } 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", parents = {"anthropology", "sciences"}, commonscat = true, wpcat = true, } labels["architectural elements"] = { type = "set", parents = {"architecture"}, } labels["architecture"] = { type = "related-to", parents = {"applied sciences", "art"}, } 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", parents = {"computer science", "cybernetics"}, } labels["asterisms"] = { type = "name", 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 = {"sciences", "space"}, } labels["astrophysics"] = { type = "related-to", description = "default no singularize", parents = {"physics", "astronomy"}, } labels["aviation"] = { type = "related-to", parents = {"aeronautics", "transport"}, } labels["avionics"] = { type = "related-to", description = "default no singularize", parents = {"aeronautics", "electronics"}, } labels["Ayurveda"] = { type = "related-to", 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", parents = {"chemistry", "biology"}, } labels["biology"] = { type = "related-to", description = "{{{langname}}} terms used in [[biology]], the study of [[life]].", additional = "{{also|Category:{{{langcode}}}:Lifeforms}}", parents = {"sciences"}, } labels["black holes"] = { type = "related-to", 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", parents = {"construction", "woodworking"}, } labels["cartography"] = { type = "related-to", parents = {"geography"}, } labels["catalysis"] = { type = "related-to", parents = {"chemical processes", "chemical reactions", "physical chemistry"}, } labels["chemical engineering"] = { type = "related-to", parents = {"engineering", "chemistry"}, } labels["chemical formulae"] = { type = "name", parents = {"chemical notation"}, } labels["chemical notation"] = { type = "related-to", parents = {"chemistry", "names", "symbols"}, } labels["chemical reactions"] = { type = "related-to,set", parents = {"chemistry"}, } labels["chemical reagents"] = { type = "set", parents = {"chemistry"}, } labels["chemistry"] = { type = "related-to", parents = {"sciences"}, } labels["Chinese astronomy"] = { type = "related-to", 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 = {"linguistics", "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", parents = {"psychology", "pathology"}, } labels["computational linguistics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics", "computer science"}, } labels["computer science"] = { type = "related-to", parents = {"sciences", "computing"}, } labels["conchology"] = { type = "related-to", description = "{{{langname}}} terms used in [[conchology]], the study of mollusc [[shell]]s.", parents = {"malacology"}, } labels["constellations"] = { type = "name", parents = {"astronomy"}, } labels["construction"] = { type = "related-to", parents = {"engineering", "architecture"}, } labels["control theory"] = { type = "related-to", parents = {"sciences", "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", 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", parents = {"physics", "crystal"}, } labels["cultural anthropology"] = { type = "related-to", parents = {"anthropology", "culture"}, } 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", parents = {"information science", "computer science"}, } labels["demarcation lines"] = { type = "name", description = "=political [[demarcation line]]s", parents = {"politics"}, } labels["decision theory"] = { type = "related-to", parents = {"probability theory", "epistemology"}, } labels["demography"] = { type = "related-to", parents = {"sciences", "statistics"}, } labels["dentistry"] = { type = "related-to", 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", parents = {"sciences"}, } labels["earthquake engineering"] = { type = "related-to", 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 = {"social sciences"}, } labels["ecosystems"] = { type = "related-to", 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", parents = {"engineering", "electricity"}, } labels["electricity"] = { type = "related-to", parents = {"electromagnetism"}, } labels["electrocardiography"] = { type = "related-to", parents = {"cardiology"}, } labels["electrodynamics"] = { type = "related-to", description = "default no singularize", parents = {"electromagnetism"}, } labels["electrochemistry"] = { type = "related-to", parents = {"physical chemistry", "electricity"}, } labels["electromagnetism"] = { type = "related-to", parents = {"physics"}, } labels["element nomenclature"] = { type = "related-to", parents = {"chemical notation", "names", "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", 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", parents = {"applied sciences", "technology"}, } labels["enterprise engineering"] = { type = "related-to", 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", 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", 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", parents = {"agriculture", "Malpighiales order plants"}, } labels["fluid dynamics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } labels["forestry"] = { type = "related-to", parents = {"applied sciences"}, } labels["functional group prefixes"] = { type = "set", parents = {"organic chemistry"}, } labels["functional group suffixes"] = { type = "set", 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["geography"] = { 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", 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 = {"geography", "politics"}, } labels["geospatial science"] = { type = "related-to", 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", parents = {"linguistics"}, } labels["grammatical cases"] = { type = "set", parents = {"grammar"}, } labels["grammatical moods"] = { type = "set", parents = {"grammar"}, } labels["gravity"] = { type = "related-to", parents = {"acceleration", "astrophysics", "mechanics"}, } labels["gynaecology"] = { type = "related-to", 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", parents = {"alternative medicine"}, } labels["horticulture"] = { type = "related-to", parents = {"agriculture", "botany"}, } labels["hydroacoustics"] = { type = "related-to", description = "default no singularize", parents = {"acoustics", "hydrology"}, } labels["hydrocarbon chain prefixes"] = { type = "set", parents = {"organic chemistry"}, } labels["hydrocarbon chain suffixes"] = { type = "set", 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", 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 = {"linguistics"}, } labels["information science"] = { type = "related-to", parents = {"applied sciences"}, } labels["inorganic chemistry"] = { type = "related-to", parents = {"chemistry"}, } labels["interdisciplinary fields"] = { type = "related-to", parents = {"sciences"}, } labels["isolines"] = { type = "related-to", parents = {"cartography", "meteorology"}, } labels["Lagrange points"] = { type = "related-to", parents = {"orbits"}, } labels["lexicography"] = { type = "related-to", parents = {"linguistics"}, } labels["library science"] = { type = "related-to", parents = {"sciences", "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", parents = {"linguistics"}, } labels["linguistics"] = { type = "related-to", description = "{{{langname}}} terms used in [[linguistics]], the study and analysis of [[language]].", additional = "{{also|Category:{{{langcode}}}:Language}}", parents = {"language", "social sciences"}, } labels["locksmithing"] = { type = "related-to", parents = {"technology"}, } 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", parents = {"construction"}, } labels["materials science"] = { type = "related-to", parents = {"sciences", "engineering"}, } labels["mechanical engineering"] = { type = "related-to", parents = {"engineering"}, } labels["mechanics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } 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", parents = {"physics"}, } labels["physical constants"] = { type = "set", parents = {"physics"}, } labels["machine learning"] = { type = "related-to", 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", parents = {"surgery", "neurology"}, } labels["neutron"] = { type = "related-to", parents = {"nuclear physics"}, } labels["neutron stars"] = { type = "related-to", parents = {"neutron", "gravity", "astrophysics", "relativity", "stars"}, } labels["nouns"] = { type = "related-to", parents = {"parts of speech"}, } labels["nuclear energy"] = { type = "related-to", parents = {"energy", "nuclear physics", "technology"}, } labels["nuclear fusion"] = { type = "related-to", parents = {"nuclear energy"}, } labels["nuclear physics"] = { type = "related-to", description = "default no singularize", parents = {"physics", "quantum mechanics"}, } labels["nuclear rocketry"] = { type = "related-to", 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", parents = {"sciences"}, } labels["oenology"] = { type = "related-to", description = "{{{langname}}} terms used in [[oenology]], the study of [[wine]] and [[winemaking]].", additional = "{{also|Category:{{{langcode}}}:Wine}}", parents = {"sciences"}, } 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|Category:{{{langcode}}}:Names|Category:{{{langname}}} names}}", parents = {"linguistics", "names"}, } 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 = {"physics"}, } labels["orbits"] = { type = "related-to", parents = {"astronautics", "gravity", "space", "curves"}, } labels["organic chemistry"] = { type = "related-to", 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", parents = {"sciences", "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", parents = {"paranormal", "pseudoscience"}, } labels["parasitology"] = { type = "related-to", 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 = {"physics"}, } 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", 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", parents = {"biochemistry", "medicine"}, } labels["pharmacy"] = { type = "related-to", 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 = {"linguistics"}, } labels["phonology"] = { type = "related-to", description = "{{{langname}}} terms used in [[phonology]], the organisation of [[speech]] sounds within a [[language]].", parents = {"linguistics"}, } labels["photochemistry"] = { type = "related-to", parents = {"physical chemistry", "light"}, } labels["phrenology"] = { type = "related-to", 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", parents = {"chemistry", "physics"}, } labels["physical quantities"] = { type = "set", parents = {"physics"}, } labels["physics"] = { type = "related-to", description = "default no singularize", parents = {"sciences"}, 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", 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", parents = {"surgery"}, } labels["political science"] = { type = "related-to", parents = {"social sciences", "politics"}, } labels["potential theory"] = { type = "related-to", parents = {"mathematics"}, } labels["pragmatics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics"}, } labels["prosody"] = { type = "related-to", description = "{{{langname}}} terms used in [[prosody]], the study of the [[suprasegmental]] aspects of [[speech]].", parents = {"linguistics"}, } labels["pseudoscience"] = { type = "related-to", parents = {"sciences"}, } labels["psychiatry"] = { type = "related-to", 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 = {"social sciences"}, } labels["psychotherapy"] = { type = "related-to", 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 = {"sciences"}, } labels["quantity"] = { type = "related-to", parents = {"mathematics"}, } labels["quantum mechanics"] = { type = "related-to", description = "default no singularize", parents = {"physics"}, } labels["relativity"] = { type = "related-to", parents = {"physics"}, } labels["rheumatology"] = { type = "related-to", parents = {"medicine"}, } labels["robotics"] = { type = "related-to", description = "default no singularize", parents = {"engineering"}, } labels["rocketry"] = { type = "related-to", parents = {"astronautics"}, } labels["roofing"] = { type = "related-to", parents = {"construction"}, } labels["rosiculture"] = { type = "related-to", parents = {"horticulture"}, } labels["rotation"] = { type = "related-to", 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 = {"linguistics"}, } labels["Semitic linguistics"] = { type = "related-to", description = "{{{langname}}} terms used in the study and analysis of [[Semitic]] [[language]]s.", parents = {"linguistics"}, } labels["semiotics"] = { type = "related-to", description = "default no singularize", parents = {"social sciences", "linguistics"}, } 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", parents = {"applied mathematics", "telecommunications"}, wpcat = true, commonscat = true, } labels["social sciences"] = { type = "related-to", description = "default with the", parents = {"sciences", "society"}, } labels["sociolinguistics"] = { type = "related-to", description = "default no singularize", parents = {"linguistics", "sociology"}, } labels["sociology"] = { type = "related-to", description = "{{{langname}}} terms used in [[sociology]], the study of [[society]].", additional = "{{also|Category:{{{langcode}}}:Society}}", parents = {"social sciences"}, } labels["software engineering"] = { type = "related-to", parents = {"engineering", "computer science", "software"}, wpcat = true, commonscat = true, } labels["soil science"] = { type = "related-to", parents = {"earth sciences"}, } labels["sorting algorithms"] = { type = "set", parents = {"theory of computing"}, } labels["sound engineering"] = { type = "related-to", parents = {"engineering", "sound"}, } labels["space access"] = { type = "related-to", parents = {"astronautics"}, } labels["space sciences"] = { type = "related-to", parents = {"sciences", "space"}, } labels["spectroscopy"] = { type = "related-to", parents = {"analytical chemistry", "optics", "physics"}, } 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", parents = {"medicine"}, } labels["surveying"] = { type = "related-to", parents = {"geography"}, } labels["systems"] = { type = "related-to", parents = {"interdisciplinary fields", "sciences", "society"}, } labels["systems engineering"] = { type = "related-to", parents = {"engineering"}, } labels["systems theory"] = { type = "related-to", parents = {"sciences", "systems"}, } labels["taxonomy"] = { type = "related-to", additional = "For individual [[taxa]], see [[:Category:Taxonomic names]].", parents = {"biology", "evolutionary theory"}, } labels["taxonomic ranks"] = { type = "set", parents = {"taxonomy"}, } labels["tenses"] = { type = "related-to", 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 = {"physics"}, } 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", parents = {"alternative medicine"}, } labels["traffic engineering"] = { type = "related-to", parents = {"engineering", "road transport"}, } labels["translation studies"] = { type = "related-to", description = "default no singularize", parents = {"linguistics"}, } 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", 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["units of volume"] = { type = "set", description = "{{{langname}}} terms that are [[w:unit of volume|units of volume]].", parents = {"units of measure"}, commonscat = true, wpcat = true, } labels["urban studies"] = { type = "related-to", parents = {"applied sciences", "social sciences"}, } labels["urology"] = { type = "related-to", parents = {"medicine"}, } labels["verbs"] = { type = "related-to", parents = {"parts of speech"}, } labels["veterinary medicine"] = { type = "related-to", 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", 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 2b0tabbxbsjqs255dvvkhwnjt8prxx1 Mòideal:category tree/topic/Mathematics 828 17902 88802 2026-07-23T19:36:33Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88802 Scribunto text/plain local labels = {} labels["formal sciences"] = { type = "related-to", description = "=the [[formal science]]s, the study of non-physical systems and abstractions", parents = {"sciences"}, } labels["mathematics"] = { type = "related-to", description = "default no singularize", parents = {"formal sciences"}, } labels["actuarial notation"] = { type = "related-to", parents = {"mathematics"}, } labels["algebra"] = { type = "related-to", parents = {"mathematics"}, } labels["algebraic geometry"] = { type = "related-to", parents = {"geometry", "algebra"}, } labels["algebraic topology"] = { type = "related-to", parents = {"topology", "algebra"}, } labels["analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["applied mathematics"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["arithmetic"] = { type = "related-to", parents = {"mathematics", "applied sciences"}, } labels["calculus"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["category theory"] = { type = "related-to", parents = {"mathematics"}, } labels["cellular automata"] = { type = "related-to", parents = {"mathematics", "theory of computing"}, } labels["chaos theory"] = { type = "related-to", parents = {"systems theory", "calculus"}, } labels["circle"] = { type = "related-to", parents = {"curves"}, } labels["coding theory"] = { type = "related-to", parents = {"information theory"}, } labels["combinatorics"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["complex analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["curves"] = { type = "related-to", parents = {"shapes"}, } labels["differential geometry"] = { type = "related-to", parents = {"geometry", "mathematical analysis"}, } labels["functional analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["functions"] = { type = "related-to", parents = {"algebra", "calculus", "geometry", "mathematical analysis"}, } labels["fuzzy logic"] = { type = "related-to", parents = {"logic"}, } labels["game theory"] = { type = "related-to", parents = {"mathematics"}, } labels["geometry"] = { type = "related-to", parents = {"mathematics"}, } labels["graph theory"] = { type = "related-to", parents = {"mathematics", "visualization"}, } labels["group theory"] = { type = "related-to", parents = {"algebra"}, } labels["higher-dimensional geometry"] = { type = "related-to", parents = {"geometry"}, } labels["hyperbolic functions"] = { type = "related-to", parents = {"functions"}, } labels["information theory"] = { type = "related-to", parents = {"applied mathematics"}, } labels["linear algebra"] = { type = "related-to", parents = {"algebra"}, } labels["logic"] = { type = "related-to", parents = {"formal sciences", "philosophy"}, } labels["mathematical analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["measure theory"] = { type = "related-to", parents = {"mathematics"}, } labels["number theory"] = { type = "related-to", parents = {"mathematics"}, } labels["numerical analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["order theory"] = { type = "related-to", parents = {"mathematics"}, } labels["polygons"] = { type = "related-to", parents = {"shapes"}, } labels["polyhedra"] = { type = "related-to", description = "=[[polyhedron|polyhedra]], i.e. solid figures with straight edges and flat faces", parents = {"shapes"}, } labels["probability theory"] = { type = "related-to", parents = {"mathematical analysis"}, } labels["ring theory"] = { type = "related-to", parents = {"algebra"}, } labels["set theory"] = { type = "related-to", parents = {"mathematics"}, } labels["shapes"] = { type = "related-to", parents = {"geometry"}, } labels["surfaces"] = { type = "related-to", description = "=geometric [[surface]]s", parents = {"shapes"}, } labels["topology"] = { type = "related-to", parents = {"mathematics"}, } labels["trigonometry"] = { type = "related-to", parents = {"mathematics"}, } labels["trigonometric functions"] = { type = "related-to", parents = {"functions", "trigonometry", "circle"}, } return labels 8gutluqo514djwtharuf3yg3wu6971p 88803 88802 2026-08-06T20:14:33Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Mathematics]] 88802 Scribunto text/plain local labels = {} labels["formal sciences"] = { type = "related-to", description = "=the [[formal science]]s, the study of non-physical systems and abstractions", parents = {"sciences"}, } labels["mathematics"] = { type = "related-to", description = "default no singularize", parents = {"formal sciences"}, } labels["actuarial notation"] = { type = "related-to", parents = {"mathematics"}, } labels["algebra"] = { type = "related-to", parents = {"mathematics"}, } labels["algebraic geometry"] = { type = "related-to", parents = {"geometry", "algebra"}, } labels["algebraic topology"] = { type = "related-to", parents = {"topology", "algebra"}, } labels["analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["applied mathematics"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["arithmetic"] = { type = "related-to", parents = {"mathematics", "applied sciences"}, } labels["calculus"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["category theory"] = { type = "related-to", parents = {"mathematics"}, } labels["cellular automata"] = { type = "related-to", parents = {"mathematics", "theory of computing"}, } labels["chaos theory"] = { type = "related-to", parents = {"systems theory", "calculus"}, } labels["circle"] = { type = "related-to", parents = {"curves"}, } labels["coding theory"] = { type = "related-to", parents = {"information theory"}, } labels["combinatorics"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["complex analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["curves"] = { type = "related-to", parents = {"shapes"}, } labels["differential geometry"] = { type = "related-to", parents = {"geometry", "mathematical analysis"}, } labels["functional analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["functions"] = { type = "related-to", parents = {"algebra", "calculus", "geometry", "mathematical analysis"}, } labels["fuzzy logic"] = { type = "related-to", parents = {"logic"}, } labels["game theory"] = { type = "related-to", parents = {"mathematics"}, } labels["geometry"] = { type = "related-to", parents = {"mathematics"}, } labels["graph theory"] = { type = "related-to", parents = {"mathematics", "visualization"}, } labels["group theory"] = { type = "related-to", parents = {"algebra"}, } labels["higher-dimensional geometry"] = { type = "related-to", parents = {"geometry"}, } labels["hyperbolic functions"] = { type = "related-to", parents = {"functions"}, } labels["information theory"] = { type = "related-to", parents = {"applied mathematics"}, } labels["linear algebra"] = { type = "related-to", parents = {"algebra"}, } labels["logic"] = { type = "related-to", parents = {"formal sciences", "philosophy"}, } labels["mathematical analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematics"}, } labels["measure theory"] = { type = "related-to", parents = {"mathematics"}, } labels["number theory"] = { type = "related-to", parents = {"mathematics"}, } labels["numerical analysis"] = { type = "related-to", description = "default no singularize", parents = {"mathematical analysis"}, } labels["order theory"] = { type = "related-to", parents = {"mathematics"}, } labels["polygons"] = { type = "related-to", parents = {"shapes"}, } labels["polyhedra"] = { type = "related-to", description = "=[[polyhedron|polyhedra]], i.e. solid figures with straight edges and flat faces", parents = {"shapes"}, } labels["probability theory"] = { type = "related-to", parents = {"mathematical analysis"}, } labels["ring theory"] = { type = "related-to", parents = {"algebra"}, } labels["set theory"] = { type = "related-to", parents = {"mathematics"}, } labels["shapes"] = { type = "related-to", parents = {"geometry"}, } labels["surfaces"] = { type = "related-to", description = "=geometric [[surface]]s", parents = {"shapes"}, } labels["topology"] = { type = "related-to", parents = {"mathematics"}, } labels["trigonometry"] = { type = "related-to", parents = {"mathematics"}, } labels["trigonometric functions"] = { type = "related-to", parents = {"functions", "trigonometry", "circle"}, } return labels 8gutluqo514djwtharuf3yg3wu6971p Mòideal:category tree/topic/Sex 828 17903 88804 2026-07-23T19:36:48Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88804 Scribunto text/plain local labels = {} labels["sex"] = { type = "related-to", description = "=[[sexual intercourse]] or [[sexuality]]", additional = "For terms related to sex and gender, see [[:Category:Gender]].", parents = {"all topics", "reproduction"}, } labels["ABDL"] = { type = "related-to", description = "=the [[ABDL]] ([[adult baby]]/[[diaper lover]]) community", parents = {"paraphilias", "diapers"}, } labels["BDSM"] = { type = "related-to", parents = {"sexuality"}, } labels["birth control"] = { type = "related-to", parents = {"sex", "pregnancy"}, } labels["incest"] = { type = "related-to", parents = {"sex"}, } labels["LGBTQ"] = { type = "related-to", description = "=[[LGBTQ]] ([[lesbian]], [[gay]], [[bisexual]], [[transgender]], [[queer]]/[[questioning]])", parents = {"sexuality"}, -- for the T 'gender' should perhaps be a parent, but then nesting gets circularish } labels["masturbation"] = { type = "related-to", parents = {"sex"}, } labels["pedophilia"] = { type = "related-to", parents = {"paraphilias"}, } labels["paraphilias"] = { type = "set", parents = {"sexuality", "sexology", "philias"}, } labels["polyamory"] = { type = "related-to", parents = {"love", "romantic orientations", "sexual orientations"}, } labels["pornography"] = { type = "related-to", parents = {"sex"}, } labels["Japanese pornography"] = { type = "related-to", parents = {"pornography", "Japanese fiction"}, } labels["prostitution"] = { type = "related-to", parents = {"sexuality"}, } labels["seduction community"] = { type = "related-to", description = "default with the wikify", parents = {"masculism", "sex"}, } labels["sex positions"] = { type = "set", parents = {"sex"}, } labels["sexuality"] = { type = "related-to", parents = {"sex", "human behaviour"}, } labels["sexual orientations"] = { type = "set", parents = {"sexuality", "LGBTQ", "love"}, } labels["romantic orientations"] = { type = "set", parents = {"sexuality", "LGBTQ", "love"}, } labels["vorarephilia"] = { type = "related-to", parents = {"paraphilias"}, } return labels byzge5ammo3til1g7mbg9g4dtmljaz4 88805 88804 2026-08-06T20:14:47Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Sex]] 88804 Scribunto text/plain local labels = {} labels["sex"] = { type = "related-to", description = "=[[sexual intercourse]] or [[sexuality]]", additional = "For terms related to sex and gender, see [[:Category:Gender]].", parents = {"all topics", "reproduction"}, } labels["ABDL"] = { type = "related-to", description = "=the [[ABDL]] ([[adult baby]]/[[diaper lover]]) community", parents = {"paraphilias", "diapers"}, } labels["BDSM"] = { type = "related-to", parents = {"sexuality"}, } labels["birth control"] = { type = "related-to", parents = {"sex", "pregnancy"}, } labels["incest"] = { type = "related-to", parents = {"sex"}, } labels["LGBTQ"] = { type = "related-to", description = "=[[LGBTQ]] ([[lesbian]], [[gay]], [[bisexual]], [[transgender]], [[queer]]/[[questioning]])", parents = {"sexuality"}, -- for the T 'gender' should perhaps be a parent, but then nesting gets circularish } labels["masturbation"] = { type = "related-to", parents = {"sex"}, } labels["pedophilia"] = { type = "related-to", parents = {"paraphilias"}, } labels["paraphilias"] = { type = "set", parents = {"sexuality", "sexology", "philias"}, } labels["polyamory"] = { type = "related-to", parents = {"love", "romantic orientations", "sexual orientations"}, } labels["pornography"] = { type = "related-to", parents = {"sex"}, } labels["Japanese pornography"] = { type = "related-to", parents = {"pornography", "Japanese fiction"}, } labels["prostitution"] = { type = "related-to", parents = {"sexuality"}, } labels["seduction community"] = { type = "related-to", description = "default with the wikify", parents = {"masculism", "sex"}, } labels["sex positions"] = { type = "set", parents = {"sex"}, } labels["sexuality"] = { type = "related-to", parents = {"sex", "human behaviour"}, } labels["sexual orientations"] = { type = "set", parents = {"sexuality", "LGBTQ", "love"}, } labels["romantic orientations"] = { type = "set", parents = {"sexuality", "LGBTQ", "love"}, } labels["vorarephilia"] = { type = "related-to", parents = {"paraphilias"}, } return labels byzge5ammo3til1g7mbg9g4dtmljaz4 Mòideal:category tree/topic/Society 828 17904 88806 2026-07-23T19:36:49Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88806 Scribunto text/plain local labels = {} local unpack = unpack or table.unpack -- Lua 5.2 compatibility labels["society"] = { type = "related-to", parents = {"all topics"}, } labels["academic degrees"] = { type = "name", parents = {"education"}, } labels["academic grades"] = { type = "set", parents = {"education"}, } labels["accounting"] = { type = "related-to", parents = {"finance"}, } labels["administrative divisions"] = { type = "set", parents = {"government"}, } labels["advertising"] = { type = "related-to", parents = {"business", "marketing"}, } labels["alt-right"] = { type = "related-to", description = "=the [[alt-right]], a loosely connected [[far-right]], [[white nationalist]] movement", parents = {"conservatism", "fascism", "ideologies", "white supremacist ideology"}, } labels["anarchism"] = { type = "related-to", parents = {"ideologies", "leftism"}, } labels["anti-Semitism"] = { type = "related-to", parents = {"forms of discrimination"}, } labels["awards"] = { type = "name,type", parents = {"society"}, } labels["banking"] = { type = "related-to", parents = {"finance", "industries"}, } labels["bars"] = { type = "type", parents = {"businesses", "drinking"}, } labels["Basque nationalism"] = { type = "related-to", parents = {"Basque Country, Spain", "nationalism"}, } labels["bedding"] = { type = "related-to", parents = {"home"}, } labels["blacksmithing"] = { type = "related-to", parents = {"metalworking"}, } labels["bond market"] = { type = "related-to", description = "default with the", parents = {"finance"}, } labels["bookbinding"] = { type = "related-to", parents = {"publishing"}, } labels["book sizes"] = { type = "name", parents = {"bookbinding"}, } labels["Brexit"] = { type = "related-to", description = "={{w|Brexit}}, i.e. the withdrawal of the {{w|United Kingdom}} from the {{w|European Union}}", parents = {"nationalism", "EU politics", "UK politics"}, } labels["burial"] = { type = "related-to", parents = {"society", "death"}, } labels["business"] = { type = "related-to", parents = {"economics", "society"}, } labels["businesses"] = { type = "type", description = "=[[business]]es (specific commercial enterprises or establishments)", parents = {"business"}, } labels["capitalism"] = { type = "related-to", parents = {"economics", "ideologies"}, } labels["chairs"] = { type = "related-to", parents = {"furniture", "sitting"}, } labels["child abuse"] = { type = "related-to", parents = {"crime", "children", "violence"}, } labels["Chinese restaurants"] = { type = "related-to", breadcrumb = "Chinese", parents = {"restaurants", "China"}, } labels["cleaning"] = { type = "related-to", parents = {"home"}, } labels["coins"] = { type = "set,related-to", parents = {"money"}, } labels["conservatism"] = { type = "related-to", description = "=[[conservatism]] or [[traditionalist]] beliefs", parents = {"ideologies"}, } labels["commerce"] = { type = "related-to", parents = {"business"}, } labels["commercial documents"] = { type = "set", parents = {"commerce"}, } labels["commercial law"] = { type = "related-to", breacrumb = "commercial", parents = {"law", "commerce"}, } labels["competition law"] = { type = "related-to", breacrumb = "competition", parents = {"law"}, } labels["antitrust law"] = { breacrumb = "antitrust", parents = {"competition law"}, } labels["law of unfair competition"] = { description = "default with the", breacrumb = "unfair", parents = {{name = "competition law", sort = "unfair"}}, } labels["communism"] = { type = "related-to", parents = {"ideologies", "socialism", "leftism"}, } labels["constitutional law"] = { type = "related-to", breadcrumb = "constitutional", parents = {"law"}, } labels["copyright"] = { type = "related-to", parents = {"intellectual property"}, } labels["copyright licenses"] = { type = "name", description = "=[[license]]s of [[copyright]]", breadcrumb_and_first_sort_key = "licenses", parents = {"copyright"}, } labels["corporate law"] = { type = "related-to", breadcrumb = "corporate", parents = {"law"}, } labels["corruption"] = { type = "related-to", parents = {"crime", "politics"}, } labels["crafts"] = { type = "type", parents = {"society"}, } labels["crime"] = { type = "related-to", parents = {"society", "criminal law"}, } labels["crime prevention"] = { type = "related-to", parents = {"public safety", "crime"}, } labels["criminal law"] = { type = "related-to", breadcrumb = "criminal", parents = {"law"}, } labels["crochet"] = { type = "related-to", parents = {"crafts"}, } labels["cryptocurrency"] = { type = "related-to", parents = {"currency", "cryptography", "technology"}, } labels["currencies"] = { type = "set", parents = {"money", "currency"}, } labels["currency"] = { type = "related-to", parents = {"money"}, } labels["dairy farming"] = { type = "related-to", parents = {"agriculture", "industries"}, } labels["democracy"] = { type = "related-to", parents = {"forms of government"}, } labels["diplomacy"] = { type = "related-to", parents = {"society"}, } labels["discrimination"] = { type = "related-to", parents = {"society"}, } labels["drug trafficking"] = { type = "related-to", parents = {"crime", "drugs"}, } labels["education"] = { type = "related-to", parents = {"society"}, } labels["emergency services"] = { type = "related-to", parents = {"public safety"}, } labels["employment"] = { type = "related-to", parents = {"business", "work"}, } labels["espionage"] = { type = "related-to", parents = {"security", "deception", "secrecy"}, } labels["evil"] = { type = "related-to", parents = {"ethics", "religion"}, } labels["fame"] = { type = "related-to", parents = {"society", "knowledge"}, } labels["family law"] = { type = "related-to", breadcrumb = "family", parents = {"law"}, } labels["fascism"] = { type = "related-to", parents = {"ideologies"}, } labels["farriery"] = { type = "related-to", parents = {"blacksmithing", "horses"}, } labels["feminism"] = { type = "related-to", parents = {"gender", "female", "ideologies", "society", "sociology"}, } labels["feudalism"] = { type = "related-to", parents = {"forms of government"}, } labels["finance"] = { type = "related-to", parents = {"business"}, } labels["firefighting"] = { type = "related-to", parents = {"emergency services", "fire"}, } labels["forms of discrimination"] = { type = "type", description = "{{{langname}}} terms for [[form]]s of [[discrimination]].", additional = "{{also|Category:{{{langcode}}}:Biases|Category:{{{langcode}}}:Conspiracy theories|Category:{{{langcode}}}:Ideologies}}", breadcrumb = "forms", parents = {"discrimination"}, } labels["forms of government"] = { type = "type", description = "{{{langname}}} terms for [[form]]s of [[government]].", breadcrumb = "forms", parents = {"government"}, } labels["freedom"] = { type = "related-to", parents = {"society"}, } labels["freedom of speech"] = { type = "related-to", breadcrumb = "speech", parents = {{name = "freedom", sort = "speech"}, "law"}, } labels["freemasonry"] = { type = "related-to", parents = {"organizations"}, } labels["funeral"] = { type = "related-to", parents = {"society", "death", "industries"}, } labels["furniture"] = { type = "related-to", parents = {"home"}, commonscat = true, wpcat = true, } labels["gender-critical feminism"] = { type = "related-to", breadcrumb = "gender-critical", parents = {"feminism", "gender", "transphobia"}, } labels["glassblowing"] = { type = "related-to", parents = {"crafts", "glass"}, } labels["good"] = { type = "related-to", parents = {"ethics", "religion"}, } labels["government"] = { type = "related-to", parents = {"society", "politics"}, } labels["hairdressing"] = { type = "related-to", parents = {"hair", "crafts"}, } labels["high society"] = { type = "related-to", description = "=royalty and nobility", parents = {"society"}, } labels["Hindutva"] = { type = "related-to", description = "=[[Hindutva]] or {{w|Hindu nationalism}}", parents = {"conservatism", "Hinduism", "ideologies", "Indian politics", "nationalism", "theocracy"}, } labels["historical currencies"] = { type = "set", breadcrumb = "historical", parents = {"currencies"}, } labels["home"] = { type = "related-to", description = "default with the", parents = {"society"}, } labels["homophobia"] = { type = "related-to", parents = {"queerphobia"}, } labels["hospitality"] = { type = "related-to", parents = {"business"}, } labels["host industry"] = { type = "related-to", parents = {"hospitality", "businesses"}, } labels["hotels"] = { type = "type", parents = {"businesses", "tourism", "hospitality"}, } labels["household"] = { type = "related-to", parents = {"home"}, } labels["housing"] = { type = "related-to", parents = {"home", "buildings"}, } labels["human resources"] = { type = "related-to", description = "default no singularize", parents = {"business", "sociology"}, } labels["ideologies"] = { type = "related-to", parents = {"society", "politics"}, } labels["imperialism"] = { type = "related-to", parents = {"ideologies"}, } labels["import/export"] = { type = "related-to", description = "=[[import]]s and [[export]]s", parents = {"trading", "transport"}, } labels["incel community"] = { type = "related-to", description = "=the [[incel]] community", parents = {"masculism", "sex"}, } labels["incoterms"] = { type = "related-to", description = "=[[Incoterm]]s", parents = {"business", "import/export"}, } labels["industries"] = { type = "related-to", parents = {"business"}, } labels["inheritance law"] = { type = "related-to", breadcrumb = "inheritance", parents = {"law"}, } labels["insurance"] = { type = "related-to", parents = {"finance", "industries"}, } labels["intellectual property"] = { type = "related-to", description = "=[[intellectual property]] [[law]]", parents = {"law"}, } labels["international law"] = { type = "related-to", breadcrumb = "international", parents = {"law"}, } labels["international relations"] = { type = "related-to", description = "default wikify", parents = {"politics", "Earth"}, } labels["Islamic finance"] = { type = "related-to", description = "default wikify", breadcrumb = "Islamic", parents = {"finance", "banking", "Islam"}, } labels["Islamic law"] = { type = "related-to", description = "default wikify", breadcrumb = "law", parents = {{name = "Islam", sort = "law"}, "law"}, } labels["Islamism"] = { type = "related-to", parents = {"ideologies", "conservatism", "Islam", "theocracy"}, } labels["Juche"] = { type = "related-to", parents = {"North Korea", "communism", "nationalism"}, } labels["justice"] = { type = "related-to", parents = {"society"}, } labels["Kentucky Fried Chicken"] = { type = "related-to", description = "=the {{w|Kentucky Fried Chicken}} [[chain]] of [[fast-food]] [[restaurant]]s", parents = {"restaurants"}, } labels["knitting"] = { type = "related-to", parents = {"crafts"}, } labels["Ku Klux Klan"] = { type = "related-to", description = "default with the", parents = {"organizations", "white supremacist ideology"}, } labels["kyabakura industry"] = { type = "related-to", parents = {"hospitality", "businesses"}, } labels["labour"] = { type = "related-to", description = "=[[labour]] or the {{w|labour movement}}", parents = {"work", "leftism"}, } labels["laundry"] = { type = "related-to", parents = {"cleaning"}, } labels["law"] = { type = "related-to", description = "=the [[science]] and [[practice]] of [[law]]", parents = {"justice"}, } labels["law enforcement"] = { type = "related-to", parents = {"crime prevention", "emergency services", "law"}, } labels["law of obligations"] = { type = "related-to", description = "default with the no singularize", breadcrumb = "obligations", parents = {{name = "law", sort = "obligations"}}, } labels["leatherworking"] = { type = "related-to", parents = {"crafts"}, } labels["leftism"] = { type = "related-to", parents = {"ideologies"}, } labels["liberalism"] = { type = "related-to", parents = {"ideologies"}, } labels["libertarianism"] = { type = "related-to", parents = {"ideologies"}, } labels["logistics"] = { type = "related-to", description = "default no singularize", parents = {"operations"}, } labels["management"] = { type = "related-to", parents = {"business"}, } labels["Maoism"] = { type = "related-to", parents = {"ideologies", "communism", "Marxism"}, } labels["marketing"] = { type = "related-to", parents = {"business"}, } labels["Marxism"] = { type = "related-to", parents = {"ideologies", "socialism"}, } labels["masculism"] = { type = "related-to", parents = {"ideologies", "male"}, } labels["metalworking"] = { type = "related-to", parents = {"crafts", "metallurgy"}, } labels["McDonald's"] = { type = "related-to", description = "=the {{w|McDonald's}} [[chain]] of [[fast-food]] [[restaurant]]s", parents = {"restaurants"}, } labels["micronationalism"] = { type = "related-to", parents = {"forms of government", "ideologies"}, } labels["military"] = { type = "related-to", description = "default with the", parents = {"society"}, } labels["military units"] = { type = "related-to", parents = {"military", "occupations"}, } labels["mining"] = { type = "related-to", parents = {"industries"}, } labels["monarchism"] = { type = "related-to", parents = {"ideologies", "monarchy"}, } labels["monarchy"] = { type = "related-to", parents = {"forms of government", "high society"}, } labels["money"] = { type = "related-to", parents = {"business"}, } labels["museums"] = { type = "related-to", parents = {"businesses", "tourism", "art"}, } labels["nationalism"] = { type = "related-to", parents = {"ideologies"}, } labels["Nazism"] = { type = "related-to", parents = {"fascism", "white supremacist ideology", "ideologies"}, } labels["neo-Nazism"] = { -- Adjacent to Nazism, but not quite the same thing. type = "related-to", parents = {"Nazism", "fascism", "white supremacist ideology", "ideologies"}, } labels["Nobel Prize"] = { type = "related-to", description = "default with the", parents = {"awards"}, } labels["Objectivism"] = { type = "related-to", description = "=the political philosophy of {{w|Objectivism}} developed by {{w|Ayn Rand}}", parents = {"ideologies", "libertarianism"}, } labels["offices"] = { type = "type", description = "=offices, in the sense \"position of responsibility of some authority within an organisation\"", parents = {"government"}, } labels["oil industry"] = { type = "related-to", description = "default with the", breadcrumb = "oil", parents = {"industries", "petroleum"}, } labels["operations"] = { type = "related-to", description = "{{{langname}}} terms covering all operational matters in [[production]], [[logistics]], or [[services]].", parents = {"management", "systems theory"}, } labels["organizations"] = { type = "name", parents = {"society"}, } labels["papermaking"] = { type = "related-to", parents = {"crafts", "industries"}, } labels["patent law"] = { type = "related-to", breadcrumb = "patent", parents = {"law"}, } labels["peace"] = { type = "related-to", parents = {"security"}, } labels["pensions"] = { type = "related-to", parents = {"finance"}, } labels["philanthropy"] = { type = "related-to", parents = {"society"}, } labels["Philmont Scout Ranch"] = { type = "related-to", description = "={{w|Philmont Scout Ranch}}, a Scouting ranch in the United States", parents = {"Scouting"}, } labels["piracy"] = { type = "related-to", parents = {"crime", "nautical"}, } labels["politics"] = { type = "related-to", description = "default no singularize", parents = {"society"}, } labels["poverty"] = { type = "related-to", parents = {"wealth"}, } for _, country_demonym in ipairs { {"Argentina", "Argentine"}, {"Australia", "Australian"}, {"Bangladesh", "Bangladeshi"}, {"Brazil", "Brazilian"}, {"Bulgaria", "Bulgarian"}, {"Canada", "Canadian"}, {"Chile", "Chilean"}, {"China", "Chinese"}, {"Europe", "European"}, {"European Union", "EU", "the European Union", "European politics"}, {"France", "French", nil, "European politics"}, {"Germany", "German", nil, "European politics"}, {"Hong Kong", "Hong Kong"}, {"Hungary", "Hungarian", nil, "European politics"}, {"India", "Indian"}, {"Indonesia", "Indonesian"}, {"Ireland", "Irish", nil, "European politics"}, {"Japan", "Japanese"}, {"Malaysia", "Malaysian"}, {"Mexico", "Mexican"}, {"New Zealand", "New Zealand"}, {"Nigeria", "Nigerian"}, {"Pakistan", "Pakistani"}, {"Palestine", "Palestinian"}, {"Peru", "Peruvian"}, {"Philippines", "Philippine", "the Philippines"}, {"Poland", "Polish", nil, "European politics"}, {"Portugal", "Portuguese", nil, "European politics"}, {"Russia", "Russian"}, {"Singapore", "Singaporean"}, {"South Africa", "South African"}, {"South Korea", "South Korean"}, {"Spain", "Spanish", nil, "European politics"}, {"Switzerland", "Swiss", nil, "European politics"}, {"Taiwan", "Taiwanese"}, {"Ukraine", "Ukrainian"}, {"United Kingdom", "UK", "the United Kingdom", "European politics"}, {"United States", "US", "the United States"}, {"Venezuela", "Venezuelan"}, {"Vietnam", "Vietnamese"}, } do local country, demonym, full_country, parent = unpack(country_demonym) labels[demonym .. " politics"] = { type = "related-to", description = ("=the {{w|politics of %s}}"):format(full_country or country), parents = {parent or "politics", country}, } end labels["printing"] = { type = "related-to", parents = {"industries"}, } labels["prison"] = { type = "related-to", parents = {"law enforcement", "buildings"}, } labels["procedural law"] = { type = "related-to", breadcrumb = "procedural", parents = {"law"}, } labels["property law"] = { type = "related-to", breadcrumb = "property", parents = {"law"}, } labels["public administration"] = { type = "related-to", description = "=the field of [[public]] [[administration]]", parents = {"government"}, } labels["public safety"] = { type = "related-to", description = "=the field of [[public]] [[safety]]", parents = {"public administration", "security"}, } labels["publishing"] = { type = "related-to", parents = {"industries", "mass media"}, } labels["QAnon"] = { type = "related-to", description = "=the [[QAnon]] movement", parents = {"alt-right", "conspiracy theories", "Donald Trump", "pedophilia"}, } labels["queerphobia"] = { type = "related-to", parents = {"forms of discrimination", "LGBTQ"}, } labels["racism"] = { type = "related-to", parents = {"forms of discrimination"}, } labels["rape"] = { type = "related-to", description = "=the field of [[sexual violence]]", parents = {"sex", "crime", "violence"}, } labels["real estate"] = { type = "related-to", parents = {"industries", "housing"}, } labels["restaurants"] = { type = "related-to", description = "=[[restaurant]]s (including [[pub]]s, [[café]]s etc.)", parents = {"businesses", "food and drink"}, } labels["royal residences"] = { type = "related-to", parents = {"housing", "monarchy"}, } labels["schools"] = { type = "related-to", parents = {"education", "buildings"}, } -- Note: this is the usual term, not "Scottish law". labels["Scots law"] = { type = "related-to", breadcrumb = "Scots", parents = {"law", "Scotland"}, } labels["Scouting"] = { type = "related-to", parents = {"society"}, } labels["security"] = { type = "related-to", parents = {"society"}, } labels["sexism"] = { type = "related-to", parents = {"forms of discrimination", "gender"}, } labels["sewing"] = { type = "related-to", description = "=[[sewing]], sewing tools, sewing [[technique]]s and so on", parents = {"crafts"}, } labels["shoemaking"] = { type = "related-to", parents = {"crafts"}, } labels["slavery"] = { type = "related-to", parents = {"society", "work"}, } labels["socialism"] = { type = "related-to", parents = {"economics", "ideologies", "leftism"}, } labels["social justice"] = { type = "related-to", parents = {"politics", "society", "sociology", "leftism"}, } labels["social security"] = { type = "related-to", parents = {"government", "law", "money"}, } labels["spinning"] = { type = "related-to", description = "=[[spinning]], the process of making [[yarn]] or [[string]] from raw [[fiber]]", parents = {"crafts"}, } labels["square dancing"] = { type = "related-to", parents = {"dance"}, } labels["standards of identity"] = { type = "related-to", parents = {"law", "food and drink"}, } labels["stock market"] = { type = "related-to", description = "default with the", parents = {"finance"}, } labels["stock symbols for companies"] = { type = "name", description = "=[[stock symbol]]s for [[company|companies]]", parents = {"trading"}, } labels["supply chain"] = { type = "related-to", description = "default no singularize", parents = {"operations"}, } labels["taxation"] = { type = "related-to", parents = {"government", "law", "money"}, } labels["theft"] = { type = "related-to", parents = {"crime"}, } labels["theocracy"] = { type = "related-to", parents = {"ideologies", "religion"}, } labels["timber industry"] = { type = "related-to", description = "default with the", breadcrumb = "timber", parents = {"industries"}, } labels["trademark"] = { type = "related-to", description = "=[[trademark]] [[law]]", parents = {"intellectual property"}, } labels["trading"] = { type = "related-to", parents = {"business"}, } labels["transphobia"] = { type = "related-to", parents = {"forms of discrimination", "transgender"}, } labels["trust"] = { type = "related-to", parents = {"security"}, } labels["types of settlements"] = { type = "type", topic = "settlements", description = "=[[settlement]]s", parents = {"government"}, } labels["United Nations"] = { type = "related-to", description = "=the [[United Nations Organization]]", parents = {"organizations"}, } labels["universities"] = { type = "related-to", parents = {"schools"}, } labels["voting systems"] = { type = "related-to", parents = {"democracy", "systems"}, } labels["wealth"] = { type = "related-to", parents = {"economics"}, } labels["weaving"] = { type = "related-to", parents = {"crafts"}, } labels["white supremacist ideology"] = { type = "related-to", parents = {"racism", "anti-Semitism", "ideologies"}, } labels["woodworking"] = { type = "related-to", parents = {"crafts"}, } labels["Zionism"] = { type = "related-to", parents = {"ideologies", "Judaism", "Israel", "nationalism"}, } return labels snpr4mk3ymmjcvcyb5ttksd00pkkk8r 88807 88806 2026-08-06T20:15:11Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Society]] 88806 Scribunto text/plain local labels = {} local unpack = unpack or table.unpack -- Lua 5.2 compatibility labels["society"] = { type = "related-to", parents = {"all topics"}, } labels["academic degrees"] = { type = "name", parents = {"education"}, } labels["academic grades"] = { type = "set", parents = {"education"}, } labels["accounting"] = { type = "related-to", parents = {"finance"}, } labels["administrative divisions"] = { type = "set", parents = {"government"}, } labels["advertising"] = { type = "related-to", parents = {"business", "marketing"}, } labels["alt-right"] = { type = "related-to", description = "=the [[alt-right]], a loosely connected [[far-right]], [[white nationalist]] movement", parents = {"conservatism", "fascism", "ideologies", "white supremacist ideology"}, } labels["anarchism"] = { type = "related-to", parents = {"ideologies", "leftism"}, } labels["anti-Semitism"] = { type = "related-to", parents = {"forms of discrimination"}, } labels["awards"] = { type = "name,type", parents = {"society"}, } labels["banking"] = { type = "related-to", parents = {"finance", "industries"}, } labels["bars"] = { type = "type", parents = {"businesses", "drinking"}, } labels["Basque nationalism"] = { type = "related-to", parents = {"Basque Country, Spain", "nationalism"}, } labels["bedding"] = { type = "related-to", parents = {"home"}, } labels["blacksmithing"] = { type = "related-to", parents = {"metalworking"}, } labels["bond market"] = { type = "related-to", description = "default with the", parents = {"finance"}, } labels["bookbinding"] = { type = "related-to", parents = {"publishing"}, } labels["book sizes"] = { type = "name", parents = {"bookbinding"}, } labels["Brexit"] = { type = "related-to", description = "={{w|Brexit}}, i.e. the withdrawal of the {{w|United Kingdom}} from the {{w|European Union}}", parents = {"nationalism", "EU politics", "UK politics"}, } labels["burial"] = { type = "related-to", parents = {"society", "death"}, } labels["business"] = { type = "related-to", parents = {"economics", "society"}, } labels["businesses"] = { type = "type", description = "=[[business]]es (specific commercial enterprises or establishments)", parents = {"business"}, } labels["capitalism"] = { type = "related-to", parents = {"economics", "ideologies"}, } labels["chairs"] = { type = "related-to", parents = {"furniture", "sitting"}, } labels["child abuse"] = { type = "related-to", parents = {"crime", "children", "violence"}, } labels["Chinese restaurants"] = { type = "related-to", breadcrumb = "Chinese", parents = {"restaurants", "China"}, } labels["cleaning"] = { type = "related-to", parents = {"home"}, } labels["coins"] = { type = "set,related-to", parents = {"money"}, } labels["conservatism"] = { type = "related-to", description = "=[[conservatism]] or [[traditionalist]] beliefs", parents = {"ideologies"}, } labels["commerce"] = { type = "related-to", parents = {"business"}, } labels["commercial documents"] = { type = "set", parents = {"commerce"}, } labels["commercial law"] = { type = "related-to", breacrumb = "commercial", parents = {"law", "commerce"}, } labels["competition law"] = { type = "related-to", breacrumb = "competition", parents = {"law"}, } labels["antitrust law"] = { breacrumb = "antitrust", parents = {"competition law"}, } labels["law of unfair competition"] = { description = "default with the", breacrumb = "unfair", parents = {{name = "competition law", sort = "unfair"}}, } labels["communism"] = { type = "related-to", parents = {"ideologies", "socialism", "leftism"}, } labels["constitutional law"] = { type = "related-to", breadcrumb = "constitutional", parents = {"law"}, } labels["copyright"] = { type = "related-to", parents = {"intellectual property"}, } labels["copyright licenses"] = { type = "name", description = "=[[license]]s of [[copyright]]", breadcrumb_and_first_sort_key = "licenses", parents = {"copyright"}, } labels["corporate law"] = { type = "related-to", breadcrumb = "corporate", parents = {"law"}, } labels["corruption"] = { type = "related-to", parents = {"crime", "politics"}, } labels["crafts"] = { type = "type", parents = {"society"}, } labels["crime"] = { type = "related-to", parents = {"society", "criminal law"}, } labels["crime prevention"] = { type = "related-to", parents = {"public safety", "crime"}, } labels["criminal law"] = { type = "related-to", breadcrumb = "criminal", parents = {"law"}, } labels["crochet"] = { type = "related-to", parents = {"crafts"}, } labels["cryptocurrency"] = { type = "related-to", parents = {"currency", "cryptography", "technology"}, } labels["currencies"] = { type = "set", parents = {"money", "currency"}, } labels["currency"] = { type = "related-to", parents = {"money"}, } labels["dairy farming"] = { type = "related-to", parents = {"agriculture", "industries"}, } labels["democracy"] = { type = "related-to", parents = {"forms of government"}, } labels["diplomacy"] = { type = "related-to", parents = {"society"}, } labels["discrimination"] = { type = "related-to", parents = {"society"}, } labels["drug trafficking"] = { type = "related-to", parents = {"crime", "drugs"}, } labels["education"] = { type = "related-to", parents = {"society"}, } labels["emergency services"] = { type = "related-to", parents = {"public safety"}, } labels["employment"] = { type = "related-to", parents = {"business", "work"}, } labels["espionage"] = { type = "related-to", parents = {"security", "deception", "secrecy"}, } labels["evil"] = { type = "related-to", parents = {"ethics", "religion"}, } labels["fame"] = { type = "related-to", parents = {"society", "knowledge"}, } labels["family law"] = { type = "related-to", breadcrumb = "family", parents = {"law"}, } labels["fascism"] = { type = "related-to", parents = {"ideologies"}, } labels["farriery"] = { type = "related-to", parents = {"blacksmithing", "horses"}, } labels["feminism"] = { type = "related-to", parents = {"gender", "female", "ideologies", "society", "sociology"}, } labels["feudalism"] = { type = "related-to", parents = {"forms of government"}, } labels["finance"] = { type = "related-to", parents = {"business"}, } labels["firefighting"] = { type = "related-to", parents = {"emergency services", "fire"}, } labels["forms of discrimination"] = { type = "type", description = "{{{langname}}} terms for [[form]]s of [[discrimination]].", additional = "{{also|Category:{{{langcode}}}:Biases|Category:{{{langcode}}}:Conspiracy theories|Category:{{{langcode}}}:Ideologies}}", breadcrumb = "forms", parents = {"discrimination"}, } labels["forms of government"] = { type = "type", description = "{{{langname}}} terms for [[form]]s of [[government]].", breadcrumb = "forms", parents = {"government"}, } labels["freedom"] = { type = "related-to", parents = {"society"}, } labels["freedom of speech"] = { type = "related-to", breadcrumb = "speech", parents = {{name = "freedom", sort = "speech"}, "law"}, } labels["freemasonry"] = { type = "related-to", parents = {"organizations"}, } labels["funeral"] = { type = "related-to", parents = {"society", "death", "industries"}, } labels["furniture"] = { type = "related-to", parents = {"home"}, commonscat = true, wpcat = true, } labels["gender-critical feminism"] = { type = "related-to", breadcrumb = "gender-critical", parents = {"feminism", "gender", "transphobia"}, } labels["glassblowing"] = { type = "related-to", parents = {"crafts", "glass"}, } labels["good"] = { type = "related-to", parents = {"ethics", "religion"}, } labels["government"] = { type = "related-to", parents = {"society", "politics"}, } labels["hairdressing"] = { type = "related-to", parents = {"hair", "crafts"}, } labels["high society"] = { type = "related-to", description = "=royalty and nobility", parents = {"society"}, } labels["Hindutva"] = { type = "related-to", description = "=[[Hindutva]] or {{w|Hindu nationalism}}", parents = {"conservatism", "Hinduism", "ideologies", "Indian politics", "nationalism", "theocracy"}, } labels["historical currencies"] = { type = "set", breadcrumb = "historical", parents = {"currencies"}, } labels["home"] = { type = "related-to", description = "default with the", parents = {"society"}, } labels["homophobia"] = { type = "related-to", parents = {"queerphobia"}, } labels["hospitality"] = { type = "related-to", parents = {"business"}, } labels["host industry"] = { type = "related-to", parents = {"hospitality", "businesses"}, } labels["hotels"] = { type = "type", parents = {"businesses", "tourism", "hospitality"}, } labels["household"] = { type = "related-to", parents = {"home"}, } labels["housing"] = { type = "related-to", parents = {"home", "buildings"}, } labels["human resources"] = { type = "related-to", description = "default no singularize", parents = {"business", "sociology"}, } labels["ideologies"] = { type = "related-to", parents = {"society", "politics"}, } labels["imperialism"] = { type = "related-to", parents = {"ideologies"}, } labels["import/export"] = { type = "related-to", description = "=[[import]]s and [[export]]s", parents = {"trading", "transport"}, } labels["incel community"] = { type = "related-to", description = "=the [[incel]] community", parents = {"masculism", "sex"}, } labels["incoterms"] = { type = "related-to", description = "=[[Incoterm]]s", parents = {"business", "import/export"}, } labels["industries"] = { type = "related-to", parents = {"business"}, } labels["inheritance law"] = { type = "related-to", breadcrumb = "inheritance", parents = {"law"}, } labels["insurance"] = { type = "related-to", parents = {"finance", "industries"}, } labels["intellectual property"] = { type = "related-to", description = "=[[intellectual property]] [[law]]", parents = {"law"}, } labels["international law"] = { type = "related-to", breadcrumb = "international", parents = {"law"}, } labels["international relations"] = { type = "related-to", description = "default wikify", parents = {"politics", "Earth"}, } labels["Islamic finance"] = { type = "related-to", description = "default wikify", breadcrumb = "Islamic", parents = {"finance", "banking", "Islam"}, } labels["Islamic law"] = { type = "related-to", description = "default wikify", breadcrumb = "law", parents = {{name = "Islam", sort = "law"}, "law"}, } labels["Islamism"] = { type = "related-to", parents = {"ideologies", "conservatism", "Islam", "theocracy"}, } labels["Juche"] = { type = "related-to", parents = {"North Korea", "communism", "nationalism"}, } labels["justice"] = { type = "related-to", parents = {"society"}, } labels["Kentucky Fried Chicken"] = { type = "related-to", description = "=the {{w|Kentucky Fried Chicken}} [[chain]] of [[fast-food]] [[restaurant]]s", parents = {"restaurants"}, } labels["knitting"] = { type = "related-to", parents = {"crafts"}, } labels["Ku Klux Klan"] = { type = "related-to", description = "default with the", parents = {"organizations", "white supremacist ideology"}, } labels["kyabakura industry"] = { type = "related-to", parents = {"hospitality", "businesses"}, } labels["labour"] = { type = "related-to", description = "=[[labour]] or the {{w|labour movement}}", parents = {"work", "leftism"}, } labels["laundry"] = { type = "related-to", parents = {"cleaning"}, } labels["law"] = { type = "related-to", description = "=the [[science]] and [[practice]] of [[law]]", parents = {"justice"}, } labels["law enforcement"] = { type = "related-to", parents = {"crime prevention", "emergency services", "law"}, } labels["law of obligations"] = { type = "related-to", description = "default with the no singularize", breadcrumb = "obligations", parents = {{name = "law", sort = "obligations"}}, } labels["leatherworking"] = { type = "related-to", parents = {"crafts"}, } labels["leftism"] = { type = "related-to", parents = {"ideologies"}, } labels["liberalism"] = { type = "related-to", parents = {"ideologies"}, } labels["libertarianism"] = { type = "related-to", parents = {"ideologies"}, } labels["logistics"] = { type = "related-to", description = "default no singularize", parents = {"operations"}, } labels["management"] = { type = "related-to", parents = {"business"}, } labels["Maoism"] = { type = "related-to", parents = {"ideologies", "communism", "Marxism"}, } labels["marketing"] = { type = "related-to", parents = {"business"}, } labels["Marxism"] = { type = "related-to", parents = {"ideologies", "socialism"}, } labels["masculism"] = { type = "related-to", parents = {"ideologies", "male"}, } labels["metalworking"] = { type = "related-to", parents = {"crafts", "metallurgy"}, } labels["McDonald's"] = { type = "related-to", description = "=the {{w|McDonald's}} [[chain]] of [[fast-food]] [[restaurant]]s", parents = {"restaurants"}, } labels["micronationalism"] = { type = "related-to", parents = {"forms of government", "ideologies"}, } labels["military"] = { type = "related-to", description = "default with the", parents = {"society"}, } labels["military units"] = { type = "related-to", parents = {"military", "occupations"}, } labels["mining"] = { type = "related-to", parents = {"industries"}, } labels["monarchism"] = { type = "related-to", parents = {"ideologies", "monarchy"}, } labels["monarchy"] = { type = "related-to", parents = {"forms of government", "high society"}, } labels["money"] = { type = "related-to", parents = {"business"}, } labels["museums"] = { type = "related-to", parents = {"businesses", "tourism", "art"}, } labels["nationalism"] = { type = "related-to", parents = {"ideologies"}, } labels["Nazism"] = { type = "related-to", parents = {"fascism", "white supremacist ideology", "ideologies"}, } labels["neo-Nazism"] = { -- Adjacent to Nazism, but not quite the same thing. type = "related-to", parents = {"Nazism", "fascism", "white supremacist ideology", "ideologies"}, } labels["Nobel Prize"] = { type = "related-to", description = "default with the", parents = {"awards"}, } labels["Objectivism"] = { type = "related-to", description = "=the political philosophy of {{w|Objectivism}} developed by {{w|Ayn Rand}}", parents = {"ideologies", "libertarianism"}, } labels["offices"] = { type = "type", description = "=offices, in the sense \"position of responsibility of some authority within an organisation\"", parents = {"government"}, } labels["oil industry"] = { type = "related-to", description = "default with the", breadcrumb = "oil", parents = {"industries", "petroleum"}, } labels["operations"] = { type = "related-to", description = "{{{langname}}} terms covering all operational matters in [[production]], [[logistics]], or [[services]].", parents = {"management", "systems theory"}, } labels["organizations"] = { type = "name", parents = {"society"}, } labels["papermaking"] = { type = "related-to", parents = {"crafts", "industries"}, } labels["patent law"] = { type = "related-to", breadcrumb = "patent", parents = {"law"}, } labels["peace"] = { type = "related-to", parents = {"security"}, } labels["pensions"] = { type = "related-to", parents = {"finance"}, } labels["philanthropy"] = { type = "related-to", parents = {"society"}, } labels["Philmont Scout Ranch"] = { type = "related-to", description = "={{w|Philmont Scout Ranch}}, a Scouting ranch in the United States", parents = {"Scouting"}, } labels["piracy"] = { type = "related-to", parents = {"crime", "nautical"}, } labels["politics"] = { type = "related-to", description = "default no singularize", parents = {"society"}, } labels["poverty"] = { type = "related-to", parents = {"wealth"}, } for _, country_demonym in ipairs { {"Argentina", "Argentine"}, {"Australia", "Australian"}, {"Bangladesh", "Bangladeshi"}, {"Brazil", "Brazilian"}, {"Bulgaria", "Bulgarian"}, {"Canada", "Canadian"}, {"Chile", "Chilean"}, {"China", "Chinese"}, {"Europe", "European"}, {"European Union", "EU", "the European Union", "European politics"}, {"France", "French", nil, "European politics"}, {"Germany", "German", nil, "European politics"}, {"Hong Kong", "Hong Kong"}, {"Hungary", "Hungarian", nil, "European politics"}, {"India", "Indian"}, {"Indonesia", "Indonesian"}, {"Ireland", "Irish", nil, "European politics"}, {"Japan", "Japanese"}, {"Malaysia", "Malaysian"}, {"Mexico", "Mexican"}, {"New Zealand", "New Zealand"}, {"Nigeria", "Nigerian"}, {"Pakistan", "Pakistani"}, {"Palestine", "Palestinian"}, {"Peru", "Peruvian"}, {"Philippines", "Philippine", "the Philippines"}, {"Poland", "Polish", nil, "European politics"}, {"Portugal", "Portuguese", nil, "European politics"}, {"Russia", "Russian"}, {"Singapore", "Singaporean"}, {"South Africa", "South African"}, {"South Korea", "South Korean"}, {"Spain", "Spanish", nil, "European politics"}, {"Switzerland", "Swiss", nil, "European politics"}, {"Taiwan", "Taiwanese"}, {"Ukraine", "Ukrainian"}, {"United Kingdom", "UK", "the United Kingdom", "European politics"}, {"United States", "US", "the United States"}, {"Venezuela", "Venezuelan"}, {"Vietnam", "Vietnamese"}, } do local country, demonym, full_country, parent = unpack(country_demonym) labels[demonym .. " politics"] = { type = "related-to", description = ("=the {{w|politics of %s}}"):format(full_country or country), parents = {parent or "politics", country}, } end labels["printing"] = { type = "related-to", parents = {"industries"}, } labels["prison"] = { type = "related-to", parents = {"law enforcement", "buildings"}, } labels["procedural law"] = { type = "related-to", breadcrumb = "procedural", parents = {"law"}, } labels["property law"] = { type = "related-to", breadcrumb = "property", parents = {"law"}, } labels["public administration"] = { type = "related-to", description = "=the field of [[public]] [[administration]]", parents = {"government"}, } labels["public safety"] = { type = "related-to", description = "=the field of [[public]] [[safety]]", parents = {"public administration", "security"}, } labels["publishing"] = { type = "related-to", parents = {"industries", "mass media"}, } labels["QAnon"] = { type = "related-to", description = "=the [[QAnon]] movement", parents = {"alt-right", "conspiracy theories", "Donald Trump", "pedophilia"}, } labels["queerphobia"] = { type = "related-to", parents = {"forms of discrimination", "LGBTQ"}, } labels["racism"] = { type = "related-to", parents = {"forms of discrimination"}, } labels["rape"] = { type = "related-to", description = "=the field of [[sexual violence]]", parents = {"sex", "crime", "violence"}, } labels["real estate"] = { type = "related-to", parents = {"industries", "housing"}, } labels["restaurants"] = { type = "related-to", description = "=[[restaurant]]s (including [[pub]]s, [[café]]s etc.)", parents = {"businesses", "food and drink"}, } labels["royal residences"] = { type = "related-to", parents = {"housing", "monarchy"}, } labels["schools"] = { type = "related-to", parents = {"education", "buildings"}, } -- Note: this is the usual term, not "Scottish law". labels["Scots law"] = { type = "related-to", breadcrumb = "Scots", parents = {"law", "Scotland"}, } labels["Scouting"] = { type = "related-to", parents = {"society"}, } labels["security"] = { type = "related-to", parents = {"society"}, } labels["sexism"] = { type = "related-to", parents = {"forms of discrimination", "gender"}, } labels["sewing"] = { type = "related-to", description = "=[[sewing]], sewing tools, sewing [[technique]]s and so on", parents = {"crafts"}, } labels["shoemaking"] = { type = "related-to", parents = {"crafts"}, } labels["slavery"] = { type = "related-to", parents = {"society", "work"}, } labels["socialism"] = { type = "related-to", parents = {"economics", "ideologies", "leftism"}, } labels["social justice"] = { type = "related-to", parents = {"politics", "society", "sociology", "leftism"}, } labels["social security"] = { type = "related-to", parents = {"government", "law", "money"}, } labels["spinning"] = { type = "related-to", description = "=[[spinning]], the process of making [[yarn]] or [[string]] from raw [[fiber]]", parents = {"crafts"}, } labels["square dancing"] = { type = "related-to", parents = {"dance"}, } labels["standards of identity"] = { type = "related-to", parents = {"law", "food and drink"}, } labels["stock market"] = { type = "related-to", description = "default with the", parents = {"finance"}, } labels["stock symbols for companies"] = { type = "name", description = "=[[stock symbol]]s for [[company|companies]]", parents = {"trading"}, } labels["supply chain"] = { type = "related-to", description = "default no singularize", parents = {"operations"}, } labels["taxation"] = { type = "related-to", parents = {"government", "law", "money"}, } labels["theft"] = { type = "related-to", parents = {"crime"}, } labels["theocracy"] = { type = "related-to", parents = {"ideologies", "religion"}, } labels["timber industry"] = { type = "related-to", description = "default with the", breadcrumb = "timber", parents = {"industries"}, } labels["trademark"] = { type = "related-to", description = "=[[trademark]] [[law]]", parents = {"intellectual property"}, } labels["trading"] = { type = "related-to", parents = {"business"}, } labels["transphobia"] = { type = "related-to", parents = {"forms of discrimination", "transgender"}, } labels["trust"] = { type = "related-to", parents = {"security"}, } labels["types of settlements"] = { type = "type", topic = "settlements", description = "=[[settlement]]s", parents = {"government"}, } labels["United Nations"] = { type = "related-to", description = "=the [[United Nations Organization]]", parents = {"organizations"}, } labels["universities"] = { type = "related-to", parents = {"schools"}, } labels["voting systems"] = { type = "related-to", parents = {"democracy", "systems"}, } labels["wealth"] = { type = "related-to", parents = {"economics"}, } labels["weaving"] = { type = "related-to", parents = {"crafts"}, } labels["white supremacist ideology"] = { type = "related-to", parents = {"racism", "anti-Semitism", "ideologies"}, } labels["woodworking"] = { type = "related-to", parents = {"crafts"}, } labels["Zionism"] = { type = "related-to", parents = {"ideologies", "Judaism", "Israel", "nationalism"}, } return labels snpr4mk3ymmjcvcyb5ttksd00pkkk8r Mòideal:category tree/topic/Sports 828 17905 88808 2026-07-23T19:36:50Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88808 Scribunto text/plain local labels = {} labels["sports"] = { type = "related-to", parents = {"human activity"}, } labels["archery"] = { type = "related-to", parents = {"sports", "weapons"}, } labels["athletics"] = { type = "related-to", description = "default no singularize", parents = {"sports"}, } labels["Australian rules football"] = { type = "related-to", description = "=[[Australian rules football]], often known as [[Aussie rules]]", parents = {"football"}, commonscat = true, wpcat = true, } labels["auto racing"] = { type = "related-to", parents = {"motor racing", "automotive"}, } labels["badminton"] = { type = "related-to", parents = {"racquet sports"}, } labels["ball games"] = { type = "related-to", parents = {"sports"}, } labels["baseball"] = { type = "related-to", parents = {"ball games"}, } labels["basketball"] = { type = "related-to", parents = {"ball games"}, commonscat = true, wpcat = true, } labels["Basque pelota"] = { type = "related-to", parents = {"ball games"}, } labels["board sports"] = { type = "related-to", parents = {"sports"}, } labels["bodybuilding"] = { type = "related-to", parents = {"sports"}, } labels["boxing"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["bullfighting"] = { type = "related-to", parents = {"sports"}, } labels["Canadian football"] = { type = "related-to", parents = {"football"}, } labels["capoeira"] = { type = "related-to", parents = {"martial arts"}, } labels["caving"] = { type = "related-to", parents = {"sports"}, } labels["climbing"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["cockfighting"] = { type = "related-to", parents = {"sports"}, } labels["college sports"] = { type = "related-to", parents = {"sports", "universities"}, } labels["cricket"] = { type = "related-to", parents = {"ball games"}, } labels["croquet"] = { type = "related-to", parents = {"ball games"}, } labels["curling"] = { type = "related-to", parents = {"winter sports"}, } labels["cycle racing"] = { type = "related-to", parents = {"sports", "cycling"}, } labels["disc golf"] = { type = "related-to", parents = {"sports"}, } labels["diving"] = { type = "related-to", description = "=[[diving]] (the [[sport#Noun|sport]] of [[jump#Verb|jumping]] or [[fall#Verb|falling]] into [[water#Noun|water]] from a [[platform]] or [[springboard#Noun|springboard]])", additional = "For terms related to [[underwater]] diving, see [[:Category:Underwater diving]] or one of its subcategories.", parents = {"water sports"}, commonscat = true, wpcat = true, } labels["dressage"] = { type = "related-to", parents = {"equestrianism"}, } labels["equestrianism"] = { type = "related-to", parents = {"animal riding", "sports"}, } labels["exercise"] = { type = "related-to", parents = {"sports"}, } labels["exercise equipment"] = { type = "set", description = "=devices designed for pursuing fitness goals by performing sporting activities on them", parents = {"exercise", "tools"}, } labels["falconry"] = { type = "related-to", parents = {"sports"}, } labels["fencing"] = { type = "related-to", parents = {"sports"}, } labels["field hockey"] = { type = "related-to", parents = {"hockey"}, } labels["figure skating"] = { type = "related-to", parents = {"winter sports"}, } labels["football"] = { type = "related-to", parents = {"ball games"}, } labels["football (American)"] = { type = "related-to", description = "=[[American football]]", parents = {"football"}, commonscat = "American football", wpcat = "American football", } labels["football (soccer)"] = { type = "related-to", description = "=[[soccer]]", parents = {"football"}, } labels["Gaelic football"] = { type = "related-to", parents = {"football"}, } labels["gladiatorial combat"] = { type = "related-to", parents = {"sports", "entertainment"}, } labels["golf"] = { type = "related-to", parents = {"ball games"}, } labels["gun sports"] = { type = "related-to", parents = {"sports", "firearms"}, } labels["gymnastics"] = { type = "related-to", description = "default no singularize", parents = {"sports"}, } labels["handball"] = { type = "related-to", parents = {"ball games"}, } labels["Highland games"] = { type = "related-to", parents = {"sports"}, commonscat = true, wpcat = true, } labels["hockey"] = { type = "related-to", parents = {"sports"}, } labels["horse racing"] = { type = "related-to", parents = {"equestrianism", "horses"}, commonscat = true, wpcat = true, } labels["hurling"] = { type = "related-to", parents = {"ball games"}, } labels["ice hockey"] = { type = "related-to", parents = {"hockey", "winter sports"}, commonscat = true, wpcat = true, } labels["judo"] = { type = "related-to", parents = {"martial arts"}, } labels["karate"] = { type = "related-to", parents = {"martial arts"}, } labels["kendo"] = { type = "related-to", parents = {"martial arts"}, } labels["lacrosse"] = { type = "related-to", parents = {"ball games", "racquet sports"}, } labels["martial arts"] = { type = "related-to", parents = {"sports"}, } labels["motor racing"] = { type = "related-to", parents = {"sports", "automotive"}, } labels["netball"] = { type = "related-to", parents = {"ball games"}, } labels["paintball"] = { type = "related-to", parents = {"sports"}, } labels["pesäpallo"] = { type = "related-to", parents = {"ball games", "Finland"}, wp = true, wpcat = true, commonscat = true, } labels["professional wrestling"] = { type = "related-to", parents = {"sports", "entertainment"}, } labels["racquet sports"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["rhythmic gymnastics"] = { type = "related-to", parents = {"gymnastics"}, wpcat = true, commonscat = true, } labels["roller derby"] = { type = "related-to", parents = {"sports"}, } labels["rowing"] = { type = "related-to", parents = {"water sports"}, wp = "Rowing (sport)", commonscat = true, wpcat = true, } labels["rugby"] = { type = "related-to", parents = {"ball games"}, } labels["rugby league"] = { type = "related-to", parents = {"rugby"}, } labels["rugby union"] = { type = "related-to", parents = {"rugby"}, } labels["skateboarding"] = { type = "related-to", parents = {"board sports"}, } labels["skiing"] = { type = "related-to", description = "=[[snow]] [[skiing]]", parents = {"winter sports"}, } labels["skydiving"] = { type = "related-to", parents = {"sports"}, } labels["snowboarding"] = { type = "related-to", parents = {"winter sports"}, } labels["softball"] = { type = "related-to", parents = {"ball games"}, } labels["sports areas"] = { type = "set", description = "=designated areas where [[sports]] are played", parents = {"sports"}, } labels["sports equipment"] = { type = "type", parents = {"sports", "exercise equipment", "tools"}, } labels["squash"] = { type = "related-to", description = "=the sport of [[squash]]", parents = {"ball games", "racquet sports"}, } labels["sumo"] = { type = "related-to", parents = {"sports"}, } labels["surfing"] = { type = "related-to", parents = {"water sports"}, } labels["swimming"] = { type = "related-to", parents = {"water sports"}, commonscat = true, wpcat = true, } labels["table tennis"] = { type = "related-to", description = "default no singularize", parents = {"ball games", "racquet sports"}, } labels["tennis"] = { type = "related-to", description = "default no singularize", parents = {"ball games", "racquet sports"}, } labels["ultimate"] = { type = "related-to", description = "=the sport of [[ultimate]]", parents = {"sports"}, } labels["underwater diving"] = { type = "related-to", description = "default wikify", parents = {"water sports"}, } labels["volleyball"] = { type = "related-to", parents = {"ball games"}, } labels["water sports"] = { type = "related-to", parents = {"sports"}, } labels["winter sports"] = { type = "related-to", parents = {"sports", "winter activities"}, } labels["wrestling"] = { type = "related-to", parents = {"sports"}, } return labels 1x34h1gyeik85xzppyguevby6zjw5q5 88809 88808 2026-08-06T20:15:59Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Sports]] 88808 Scribunto text/plain local labels = {} labels["sports"] = { type = "related-to", parents = {"human activity"}, } labels["archery"] = { type = "related-to", parents = {"sports", "weapons"}, } labels["athletics"] = { type = "related-to", description = "default no singularize", parents = {"sports"}, } labels["Australian rules football"] = { type = "related-to", description = "=[[Australian rules football]], often known as [[Aussie rules]]", parents = {"football"}, commonscat = true, wpcat = true, } labels["auto racing"] = { type = "related-to", parents = {"motor racing", "automotive"}, } labels["badminton"] = { type = "related-to", parents = {"racquet sports"}, } labels["ball games"] = { type = "related-to", parents = {"sports"}, } labels["baseball"] = { type = "related-to", parents = {"ball games"}, } labels["basketball"] = { type = "related-to", parents = {"ball games"}, commonscat = true, wpcat = true, } labels["Basque pelota"] = { type = "related-to", parents = {"ball games"}, } labels["board sports"] = { type = "related-to", parents = {"sports"}, } labels["bodybuilding"] = { type = "related-to", parents = {"sports"}, } labels["boxing"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["bullfighting"] = { type = "related-to", parents = {"sports"}, } labels["Canadian football"] = { type = "related-to", parents = {"football"}, } labels["capoeira"] = { type = "related-to", parents = {"martial arts"}, } labels["caving"] = { type = "related-to", parents = {"sports"}, } labels["climbing"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["cockfighting"] = { type = "related-to", parents = {"sports"}, } labels["college sports"] = { type = "related-to", parents = {"sports", "universities"}, } labels["cricket"] = { type = "related-to", parents = {"ball games"}, } labels["croquet"] = { type = "related-to", parents = {"ball games"}, } labels["curling"] = { type = "related-to", parents = {"winter sports"}, } labels["cycle racing"] = { type = "related-to", parents = {"sports", "cycling"}, } labels["disc golf"] = { type = "related-to", parents = {"sports"}, } labels["diving"] = { type = "related-to", description = "=[[diving]] (the [[sport#Noun|sport]] of [[jump#Verb|jumping]] or [[fall#Verb|falling]] into [[water#Noun|water]] from a [[platform]] or [[springboard#Noun|springboard]])", additional = "For terms related to [[underwater]] diving, see [[:Category:Underwater diving]] or one of its subcategories.", parents = {"water sports"}, commonscat = true, wpcat = true, } labels["dressage"] = { type = "related-to", parents = {"equestrianism"}, } labels["equestrianism"] = { type = "related-to", parents = {"animal riding", "sports"}, } labels["exercise"] = { type = "related-to", parents = {"sports"}, } labels["exercise equipment"] = { type = "set", description = "=devices designed for pursuing fitness goals by performing sporting activities on them", parents = {"exercise", "tools"}, } labels["falconry"] = { type = "related-to", parents = {"sports"}, } labels["fencing"] = { type = "related-to", parents = {"sports"}, } labels["field hockey"] = { type = "related-to", parents = {"hockey"}, } labels["figure skating"] = { type = "related-to", parents = {"winter sports"}, } labels["football"] = { type = "related-to", parents = {"ball games"}, } labels["football (American)"] = { type = "related-to", description = "=[[American football]]", parents = {"football"}, commonscat = "American football", wpcat = "American football", } labels["football (soccer)"] = { type = "related-to", description = "=[[soccer]]", parents = {"football"}, } labels["Gaelic football"] = { type = "related-to", parents = {"football"}, } labels["gladiatorial combat"] = { type = "related-to", parents = {"sports", "entertainment"}, } labels["golf"] = { type = "related-to", parents = {"ball games"}, } labels["gun sports"] = { type = "related-to", parents = {"sports", "firearms"}, } labels["gymnastics"] = { type = "related-to", description = "default no singularize", parents = {"sports"}, } labels["handball"] = { type = "related-to", parents = {"ball games"}, } labels["Highland games"] = { type = "related-to", parents = {"sports"}, commonscat = true, wpcat = true, } labels["hockey"] = { type = "related-to", parents = {"sports"}, } labels["horse racing"] = { type = "related-to", parents = {"equestrianism", "horses"}, commonscat = true, wpcat = true, } labels["hurling"] = { type = "related-to", parents = {"ball games"}, } labels["ice hockey"] = { type = "related-to", parents = {"hockey", "winter sports"}, commonscat = true, wpcat = true, } labels["judo"] = { type = "related-to", parents = {"martial arts"}, } labels["karate"] = { type = "related-to", parents = {"martial arts"}, } labels["kendo"] = { type = "related-to", parents = {"martial arts"}, } labels["lacrosse"] = { type = "related-to", parents = {"ball games", "racquet sports"}, } labels["martial arts"] = { type = "related-to", parents = {"sports"}, } labels["motor racing"] = { type = "related-to", parents = {"sports", "automotive"}, } labels["netball"] = { type = "related-to", parents = {"ball games"}, } labels["paintball"] = { type = "related-to", parents = {"sports"}, } labels["pesäpallo"] = { type = "related-to", parents = {"ball games", "Finland"}, wp = true, wpcat = true, commonscat = true, } labels["professional wrestling"] = { type = "related-to", parents = {"sports", "entertainment"}, } labels["racquet sports"] = { type = "related-to", parents = {"sports"}, wpcat = true, commonscat = true, } labels["rhythmic gymnastics"] = { type = "related-to", parents = {"gymnastics"}, wpcat = true, commonscat = true, } labels["roller derby"] = { type = "related-to", parents = {"sports"}, } labels["rowing"] = { type = "related-to", parents = {"water sports"}, wp = "Rowing (sport)", commonscat = true, wpcat = true, } labels["rugby"] = { type = "related-to", parents = {"ball games"}, } labels["rugby league"] = { type = "related-to", parents = {"rugby"}, } labels["rugby union"] = { type = "related-to", parents = {"rugby"}, } labels["skateboarding"] = { type = "related-to", parents = {"board sports"}, } labels["skiing"] = { type = "related-to", description = "=[[snow]] [[skiing]]", parents = {"winter sports"}, } labels["skydiving"] = { type = "related-to", parents = {"sports"}, } labels["snowboarding"] = { type = "related-to", parents = {"winter sports"}, } labels["softball"] = { type = "related-to", parents = {"ball games"}, } labels["sports areas"] = { type = "set", description = "=designated areas where [[sports]] are played", parents = {"sports"}, } labels["sports equipment"] = { type = "type", parents = {"sports", "exercise equipment", "tools"}, } labels["squash"] = { type = "related-to", description = "=the sport of [[squash]]", parents = {"ball games", "racquet sports"}, } labels["sumo"] = { type = "related-to", parents = {"sports"}, } labels["surfing"] = { type = "related-to", parents = {"water sports"}, } labels["swimming"] = { type = "related-to", parents = {"water sports"}, commonscat = true, wpcat = true, } labels["table tennis"] = { type = "related-to", description = "default no singularize", parents = {"ball games", "racquet sports"}, } labels["tennis"] = { type = "related-to", description = "default no singularize", parents = {"ball games", "racquet sports"}, } labels["ultimate"] = { type = "related-to", description = "=the sport of [[ultimate]]", parents = {"sports"}, } labels["underwater diving"] = { type = "related-to", description = "default wikify", parents = {"water sports"}, } labels["volleyball"] = { type = "related-to", parents = {"ball games"}, } labels["water sports"] = { type = "related-to", parents = {"sports"}, } labels["winter sports"] = { type = "related-to", parents = {"sports", "winter activities"}, } labels["wrestling"] = { type = "related-to", parents = {"sports"}, } return labels 1x34h1gyeik85xzppyguevby6zjw5q5 Mòideal:category tree/topic/Technology 828 17906 88810 2026-07-23T19:36:51Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88810 Scribunto text/plain local labels = {} labels["technology"] = { type = "related-to", parents = {"all topics"}, } labels["aircraft"] = { type = "related-to", parents = {"technology", "aviation"}, } labels["amusement rides"] = { type = "type", parents = {"machines"}, } labels["Apple Inc."] = { type = "related-to", description = "={{w|Apple Inc.}} or its products", parents = {"technology", "computing"}, } labels["armor"] = { type = "related-to", parents = {"technology"}, } labels["artillery"] = { type = "related-to", parents = {"weapons"}, } labels["automotive parts"] = { type = "type", description = "=[[automotive]] [[part]]s", breadcrumb = "Parts", parents = {"automotive", "automobiles"}, } labels["automobiles"] = { type = "related-to", parents = {"vehicles", "automotive"}, } labels["bags"] = { type = "type", parents = {"containers"}, } labels["bicycle parts"] = { type = "type", description = "=parts of a [[bicycle]]", parents = {"cycling"}, } labels["bicycle types"] = { type = "type", description = "=[[bicycle]]s", parents = {"cycling", "vehicles"}, } labels["biotechnology"] = { type = "related-to", parents = {"technology", "biology"}, } labels["buttons"] = { type = "name,type", description = "=[[button]]s of electronic [[device]]s", parents = {"mechanisms"}, } labels["C programming language"] = { type = "related-to", description = "=the [[w:C (programming language)|C programming language]] and related [[technology|technologies]]", parents = {"computer languages"}, } labels["canals"] = { type = "name,related-to", parents = {"technology", "transport"}, } labels["carpentry tools"] = { type = "type", parents = {"tools", "carpentry"}, } labels["carriages"] = { type = "type", parents = {"vehicles"}, } labels["clocks"] = { type = "type", parents = {"machines", "timekeeping"}, } labels["compilation"] = { type = "related-to", description = "=[[compilation]] of source code", parents = {"computing"}, } labels["computer graphics"] = { type = "related-to", description = "default no singularize", parents = {"computing"}, wpcat = true, commonscat = true, } labels["computer hardware"] = { type = "related-to", parents = {"electronics", "computing"}, } labels["computer languages"] = { type = "name", description = "[[computer language]]s and computer [[programming language]]s", parents = {"programming"}, } labels["computer security"] = { type = "related-to", parents = {"computing", "security"}, } labels["computing"] = { type = "related-to", parents = {"technology"}, } labels["consumer electronics"] = { type = "related-to", description = "default no singularize", parents = {"electronics"}, } labels["connectors"] = { type = "type", parents = {"electronics"}, } labels["construction vehicles"] = { type = "type", description = "=vehicles designed to be employed in building settlements", parents = {"vehicles", "construction"}, } labels["containers"] = { type = "type", parents = {"tools"}, } labels["food and drink containers"] = { type = "type", description = "=[[container]]s for holding [[food]] or [[liquid]]s", parents = {"containers", "food and drink"}, } labels["cookware and bakeware"] = { type = "type", description = "=[[kitchenware]] used to prepare [[food]]", parents = {"kitchenware"}, } labels["cutlery"] = { type = "type", parents = {"kitchenware"}, } labels["data modeling"] = { type = "related-to", parents = {"computing"}, } labels["databases"] = { type = "related-to", parents = {"computing"}, } labels["Dragon Ball"] = { type = "related-to", displaytitle = "''Dragon Ball''", description = "=the Japanese media franchise ''{{w|Dragon Ball}}''", parents = {"animation", "fantasy", "Japanese fiction"}, } labels["e-mail"] = { type = "related-to", parents = {"Internet", "communication"}, } labels["electron tubes"] = { type = "related-to", description = "=[[electron tube|electron tubes]] such as [[vacuum tube]]s/[[thermionic valve]]s", parents = {"electronics"}, } labels["electronics"] = { type = "related-to", description = "default no singularize", parents = {"technology"}, } labels["fans"] = { type = "type", additional = "{{also|Category:{{{langcode}}}:Fans (people)}}", parents = {"tools"}, } labels["fasteners"] = { type = "type", parents = {"tools"}, } labels["farming tools"] = { type = "type", parents = {"tools", "agriculture"}, } labels["file formats"] = { type = "name", parents = {"computing"}, } labels["firearms"] = { type = "related-to", parents = {"weapons"}, } labels["glasses"] = { type = "related-to", parents = {"eyewear"}, } labels["graphical user interface"] = { type = "related-to", parents = {"computing"}, } labels["Google"] = { type = "related-to", description = "={{w|Google}} or its products", parents = {"World Wide Web"}, } labels["gun mechanisms"] = { type = "type", description = "=[[firearm]] [[mechanism]]s or their parts", parents = {"firearms", "mechanisms"}, } labels["home appliances"] = { type = "type", parents = {"machines", "home"}, } labels["horse tack"] = { type = "type", parents = {"tools", "horses", "animal riding"}, } labels["HTML"] = { type = "related-to", description = "=[[HTML]], [[XHTML]], and related [[technology|technologies]]", parents = {"computer languages", "World Wide Web"}, } labels["Huawei"] = { type = "related-to", description = "={{w|Huawei}} or its products", parents = {"technology", "mobile phones"}, } labels["IBM"] = { type = "related-to", description = "=the [[American]] [[technology]] and [[consulting]] [[firm]] {{w|IBM}}", parents = {"technology", "computing"}, } labels["Internet"] = { type = "related-to", description = "default with the", parents = {"computing", "networking"}, } labels["Internet memes"] = { type = "related-to", parents = {"comedy", "Internet", "memetics"}, } labels["Java programming language"] = { type = "related-to", description = "=the [[w:Java (programming language)|Java programming language]] and related [[technology|technologies]]", parents = {"computer languages"}, } labels["JavaScript"] = { type = "related-to", description = "={{w|JavaScript}} and related [[technology|technologies]]", parents = {"computer languages", "World Wide Web"}, } labels["kitchenware"] = { type = "type", parents = {"tools", "cooking", "home appliances"}, } labels["knives"] = { type = "type", parents = {"tools", "weapons"}, } labels["knots"] = { type = "type", parents = {"fasteners"}, } labels["Linux"] = { type = "related-to", description = "=[[Linux]]", parents = {"Unix"}, } labels["locks"] = { type = "type", parents = {"mechanisms", "fasteners", "security"}, } labels["machines"] = { type = "type", parents = {"technology"}, } labels["malware"] = { type = "type", parents = {"software", "computer security"}, } labels["masonry tools"] = { type = "type", parents = {"tools", "masonry"}, } labels["measuring instruments"] = { type = "type", parents = {"tools"}, } labels["mechanisms"] = { type = "type", parents = {"machines"}, } labels["medical equipment"] = { type = "type", parents = {"tools", "medicine"}, } labels["metallurgy"] = { type = "related-to", parents = {"technology"}, } labels["metalworking tools"] = { type = "type", parents = {"tools", "metalworking"}, } labels["microelectronics"] = { type = "related-to", parents = {"electronics"}, } labels["Microsoft"] = { type = "related-to", description = "={{w|Microsoft Corporation}}", parents = {"computing"}, } labels["military vehicles"] = { type = "type", parents = {"vehicles", "military"}, } labels["milling"] = { type = "related-to", parents = {"agriculture"}, } labels["motorcycles"] = { type = "related-to", parents = {"vehicles"}, } labels["nanotechnology"] = { type = "related-to", parents = {"technology"}, } labels["networking"] = { type = "related-to", parents = {"computing"}, } labels["newsgroups"] = { type = "related-to", description = "=[[Usenet]] [[newsgroup]]s", parents = {"Usenet"}, } labels["Nintendo"] = { type = "related-to", description = "{{{langname}}} terms either deriving from or relating to {{w|Nintendo}} or its products", parents = {"video games"}, } labels["object-oriented programming"] = { type = "related-to", description = "default wikify", parents = {"programming"}, } labels["plumbing"] = { type = "related-to", parents = {"technology"}, } labels["polearms"] = { type = "type", parents = {"weapons"}, } labels["Pokémon"] = { type = "related-to", displaytitle = "''Pokémon''", description = "=''{{w|Pokémon}}''", parents = {"Nintendo", "Japanese fiction"}, } labels["programming"] = { type = "related-to", description = "=[[computer programming]]", parents = {"computing", "software engineering"}, } labels["pumps"] = { type = "type", parents = {"mechanisms"}, } labels["regular expressions"] = { type = "related-to", description = "{{{langname}}} terms used in [[regular expression]]s.", parents = {"computing", "programming"}, } labels["ropes and cords"] = { type = "type", parents = {"tools", "fasteners"}, } labels["saws"] = { type = "type", parents = {"tools"}, } labels["Sega"] = { type = "related-to", description = "{{{langname}}} terms either deriving from or relating to {{w|Sega}} or its products", parents = {"video games"}, } labels["semiconductors"] = { type = "related-to", parents = {"electronics"}, } labels["simple machines"] = { type = "type", parents = {"machines"}, } labels["software"] = { type = "related-to", parents = {"computing", "media"}, } labels["spacecraft"] = { type = "related-to", parents = {"vehicles", "space travel"}, } labels["spears"] = { type = "type", parents = {"weapons"}, } labels["stationery"] = { type = "related-to", parents = {"tools"}, } labels["swords"] = { type = "type", parents = {"weapons"}, } labels["tools"] = { type = "type", parents = {"technology"}, } labels["trapping"] = { type = "related-to", description = "=the business of [[trapper]]s", parents = {"hunting"}, } labels["typing keyboards"] = { type = "related-to", description = "=[[keyboards]] used as [[writing]] [[instrument]]s", parents = {"writing instruments"}, } labels["Unicode"] = { type = "related-to", parents = {"computing"}, } labels["Unix"] = { type = "related-to", parents = {"computing"}, } labels["Usenet"] = { type = "related-to", parents = {"Internet"}, } labels["vehicles"] = { type = "related-to", parents = {"machines", "transport"}, } labels["video compression"] = { type = "related-to", parents = {"computing"}, } labels["visualization"] = { type = "related-to", parents = {"computing", "interdisciplinary fields"}, } labels["warships"] = { type = "type", parents = {"watercraft", "military"}, } labels["watercraft"] = { type = "type", description = "=[[watercraft]]: [[ship]]s, [[boat]]s, or any other vehicle that moves on or through the water", parents = {"vehicles", "nautical"}, } labels["weapons"] = { type = "type", parents = {"tools", "hunting", "military"}, } labels["websites"] = { type = "name,type", parents = {"World Wide Web"}, } labels["wiki"] = { type = "related-to", description = "=[[wiki]]s", parents = {"World Wide Web"}, } labels["Wikimedia"] = { type = "related-to", description = "={{w|Wikimedia}}-specific [[wiki]]s such as {{w|Wikipedia}} and {{w|Wiktionary}}", parents = {"wiki"}, } labels["World Wide Web"] = { type = "related-to", description = "default with the", parents = {"Internet"}, } labels["writing instruments"] = { type = "type", parents = {"tools", "writing", "stationery"}, } labels["quantum computing"] = { type = "related-to", parents = {"computing", "quantum mechanics"}, } return labels 41ph3apfr48cfr5l7ktui8zymtvvt7a 88811 88810 2026-08-06T20:16:11Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Technology]] 88810 Scribunto text/plain local labels = {} labels["technology"] = { type = "related-to", parents = {"all topics"}, } labels["aircraft"] = { type = "related-to", parents = {"technology", "aviation"}, } labels["amusement rides"] = { type = "type", parents = {"machines"}, } labels["Apple Inc."] = { type = "related-to", description = "={{w|Apple Inc.}} or its products", parents = {"technology", "computing"}, } labels["armor"] = { type = "related-to", parents = {"technology"}, } labels["artillery"] = { type = "related-to", parents = {"weapons"}, } labels["automotive parts"] = { type = "type", description = "=[[automotive]] [[part]]s", breadcrumb = "Parts", parents = {"automotive", "automobiles"}, } labels["automobiles"] = { type = "related-to", parents = {"vehicles", "automotive"}, } labels["bags"] = { type = "type", parents = {"containers"}, } labels["bicycle parts"] = { type = "type", description = "=parts of a [[bicycle]]", parents = {"cycling"}, } labels["bicycle types"] = { type = "type", description = "=[[bicycle]]s", parents = {"cycling", "vehicles"}, } labels["biotechnology"] = { type = "related-to", parents = {"technology", "biology"}, } labels["buttons"] = { type = "name,type", description = "=[[button]]s of electronic [[device]]s", parents = {"mechanisms"}, } labels["C programming language"] = { type = "related-to", description = "=the [[w:C (programming language)|C programming language]] and related [[technology|technologies]]", parents = {"computer languages"}, } labels["canals"] = { type = "name,related-to", parents = {"technology", "transport"}, } labels["carpentry tools"] = { type = "type", parents = {"tools", "carpentry"}, } labels["carriages"] = { type = "type", parents = {"vehicles"}, } labels["clocks"] = { type = "type", parents = {"machines", "timekeeping"}, } labels["compilation"] = { type = "related-to", description = "=[[compilation]] of source code", parents = {"computing"}, } labels["computer graphics"] = { type = "related-to", description = "default no singularize", parents = {"computing"}, wpcat = true, commonscat = true, } labels["computer hardware"] = { type = "related-to", parents = {"electronics", "computing"}, } labels["computer languages"] = { type = "name", description = "[[computer language]]s and computer [[programming language]]s", parents = {"programming"}, } labels["computer security"] = { type = "related-to", parents = {"computing", "security"}, } labels["computing"] = { type = "related-to", parents = {"technology"}, } labels["consumer electronics"] = { type = "related-to", description = "default no singularize", parents = {"electronics"}, } labels["connectors"] = { type = "type", parents = {"electronics"}, } labels["construction vehicles"] = { type = "type", description = "=vehicles designed to be employed in building settlements", parents = {"vehicles", "construction"}, } labels["containers"] = { type = "type", parents = {"tools"}, } labels["food and drink containers"] = { type = "type", description = "=[[container]]s for holding [[food]] or [[liquid]]s", parents = {"containers", "food and drink"}, } labels["cookware and bakeware"] = { type = "type", description = "=[[kitchenware]] used to prepare [[food]]", parents = {"kitchenware"}, } labels["cutlery"] = { type = "type", parents = {"kitchenware"}, } labels["data modeling"] = { type = "related-to", parents = {"computing"}, } labels["databases"] = { type = "related-to", parents = {"computing"}, } labels["Dragon Ball"] = { type = "related-to", displaytitle = "''Dragon Ball''", description = "=the Japanese media franchise ''{{w|Dragon Ball}}''", parents = {"animation", "fantasy", "Japanese fiction"}, } labels["e-mail"] = { type = "related-to", parents = {"Internet", "communication"}, } labels["electron tubes"] = { type = "related-to", description = "=[[electron tube|electron tubes]] such as [[vacuum tube]]s/[[thermionic valve]]s", parents = {"electronics"}, } labels["electronics"] = { type = "related-to", description = "default no singularize", parents = {"technology"}, } labels["fans"] = { type = "type", additional = "{{also|Category:{{{langcode}}}:Fans (people)}}", parents = {"tools"}, } labels["fasteners"] = { type = "type", parents = {"tools"}, } labels["farming tools"] = { type = "type", parents = {"tools", "agriculture"}, } labels["file formats"] = { type = "name", parents = {"computing"}, } labels["firearms"] = { type = "related-to", parents = {"weapons"}, } labels["glasses"] = { type = "related-to", parents = {"eyewear"}, } labels["graphical user interface"] = { type = "related-to", parents = {"computing"}, } labels["Google"] = { type = "related-to", description = "={{w|Google}} or its products", parents = {"World Wide Web"}, } labels["gun mechanisms"] = { type = "type", description = "=[[firearm]] [[mechanism]]s or their parts", parents = {"firearms", "mechanisms"}, } labels["home appliances"] = { type = "type", parents = {"machines", "home"}, } labels["horse tack"] = { type = "type", parents = {"tools", "horses", "animal riding"}, } labels["HTML"] = { type = "related-to", description = "=[[HTML]], [[XHTML]], and related [[technology|technologies]]", parents = {"computer languages", "World Wide Web"}, } labels["Huawei"] = { type = "related-to", description = "={{w|Huawei}} or its products", parents = {"technology", "mobile phones"}, } labels["IBM"] = { type = "related-to", description = "=the [[American]] [[technology]] and [[consulting]] [[firm]] {{w|IBM}}", parents = {"technology", "computing"}, } labels["Internet"] = { type = "related-to", description = "default with the", parents = {"computing", "networking"}, } labels["Internet memes"] = { type = "related-to", parents = {"comedy", "Internet", "memetics"}, } labels["Java programming language"] = { type = "related-to", description = "=the [[w:Java (programming language)|Java programming language]] and related [[technology|technologies]]", parents = {"computer languages"}, } labels["JavaScript"] = { type = "related-to", description = "={{w|JavaScript}} and related [[technology|technologies]]", parents = {"computer languages", "World Wide Web"}, } labels["kitchenware"] = { type = "type", parents = {"tools", "cooking", "home appliances"}, } labels["knives"] = { type = "type", parents = {"tools", "weapons"}, } labels["knots"] = { type = "type", parents = {"fasteners"}, } labels["Linux"] = { type = "related-to", description = "=[[Linux]]", parents = {"Unix"}, } labels["locks"] = { type = "type", parents = {"mechanisms", "fasteners", "security"}, } labels["machines"] = { type = "type", parents = {"technology"}, } labels["malware"] = { type = "type", parents = {"software", "computer security"}, } labels["masonry tools"] = { type = "type", parents = {"tools", "masonry"}, } labels["measuring instruments"] = { type = "type", parents = {"tools"}, } labels["mechanisms"] = { type = "type", parents = {"machines"}, } labels["medical equipment"] = { type = "type", parents = {"tools", "medicine"}, } labels["metallurgy"] = { type = "related-to", parents = {"technology"}, } labels["metalworking tools"] = { type = "type", parents = {"tools", "metalworking"}, } labels["microelectronics"] = { type = "related-to", parents = {"electronics"}, } labels["Microsoft"] = { type = "related-to", description = "={{w|Microsoft Corporation}}", parents = {"computing"}, } labels["military vehicles"] = { type = "type", parents = {"vehicles", "military"}, } labels["milling"] = { type = "related-to", parents = {"agriculture"}, } labels["motorcycles"] = { type = "related-to", parents = {"vehicles"}, } labels["nanotechnology"] = { type = "related-to", parents = {"technology"}, } labels["networking"] = { type = "related-to", parents = {"computing"}, } labels["newsgroups"] = { type = "related-to", description = "=[[Usenet]] [[newsgroup]]s", parents = {"Usenet"}, } labels["Nintendo"] = { type = "related-to", description = "{{{langname}}} terms either deriving from or relating to {{w|Nintendo}} or its products", parents = {"video games"}, } labels["object-oriented programming"] = { type = "related-to", description = "default wikify", parents = {"programming"}, } labels["plumbing"] = { type = "related-to", parents = {"technology"}, } labels["polearms"] = { type = "type", parents = {"weapons"}, } labels["Pokémon"] = { type = "related-to", displaytitle = "''Pokémon''", description = "=''{{w|Pokémon}}''", parents = {"Nintendo", "Japanese fiction"}, } labels["programming"] = { type = "related-to", description = "=[[computer programming]]", parents = {"computing", "software engineering"}, } labels["pumps"] = { type = "type", parents = {"mechanisms"}, } labels["regular expressions"] = { type = "related-to", description = "{{{langname}}} terms used in [[regular expression]]s.", parents = {"computing", "programming"}, } labels["ropes and cords"] = { type = "type", parents = {"tools", "fasteners"}, } labels["saws"] = { type = "type", parents = {"tools"}, } labels["Sega"] = { type = "related-to", description = "{{{langname}}} terms either deriving from or relating to {{w|Sega}} or its products", parents = {"video games"}, } labels["semiconductors"] = { type = "related-to", parents = {"electronics"}, } labels["simple machines"] = { type = "type", parents = {"machines"}, } labels["software"] = { type = "related-to", parents = {"computing", "media"}, } labels["spacecraft"] = { type = "related-to", parents = {"vehicles", "space travel"}, } labels["spears"] = { type = "type", parents = {"weapons"}, } labels["stationery"] = { type = "related-to", parents = {"tools"}, } labels["swords"] = { type = "type", parents = {"weapons"}, } labels["tools"] = { type = "type", parents = {"technology"}, } labels["trapping"] = { type = "related-to", description = "=the business of [[trapper]]s", parents = {"hunting"}, } labels["typing keyboards"] = { type = "related-to", description = "=[[keyboards]] used as [[writing]] [[instrument]]s", parents = {"writing instruments"}, } labels["Unicode"] = { type = "related-to", parents = {"computing"}, } labels["Unix"] = { type = "related-to", parents = {"computing"}, } labels["Usenet"] = { type = "related-to", parents = {"Internet"}, } labels["vehicles"] = { type = "related-to", parents = {"machines", "transport"}, } labels["video compression"] = { type = "related-to", parents = {"computing"}, } labels["visualization"] = { type = "related-to", parents = {"computing", "interdisciplinary fields"}, } labels["warships"] = { type = "type", parents = {"watercraft", "military"}, } labels["watercraft"] = { type = "type", description = "=[[watercraft]]: [[ship]]s, [[boat]]s, or any other vehicle that moves on or through the water", parents = {"vehicles", "nautical"}, } labels["weapons"] = { type = "type", parents = {"tools", "hunting", "military"}, } labels["websites"] = { type = "name,type", parents = {"World Wide Web"}, } labels["wiki"] = { type = "related-to", description = "=[[wiki]]s", parents = {"World Wide Web"}, } labels["Wikimedia"] = { type = "related-to", description = "={{w|Wikimedia}}-specific [[wiki]]s such as {{w|Wikipedia}} and {{w|Wiktionary}}", parents = {"wiki"}, } labels["World Wide Web"] = { type = "related-to", description = "default with the", parents = {"Internet"}, } labels["writing instruments"] = { type = "type", parents = {"tools", "writing", "stationery"}, } labels["quantum computing"] = { type = "related-to", parents = {"computing", "quantum mechanics"}, } return labels 41ph3apfr48cfr5l7ktui8zymtvvt7a Mòideal:category tree/topic/Thesaurus 828 17907 88812 2026-07-23T19:36:52Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88812 Scribunto text/plain local labels = {} -- THESE CATEGORIES ARE ONLY INTENDED FOR USE IN THE THESAURUS! labels["thesaurus-only categories"] = { type = "grouping", description = "{{error|do not use this category}}", parents = {"all topics"}, } -- closest existing label: ???? labels["aggression"] = { type = "related-to", parents = {"human behaviour", "anger"}, thesaurusonly = true, } labels["concepts"] = { type = "grouping", description = "{{{langname}}} terms grouped into conceptual categories", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: None (handled by POS categories like "LANG offensive terms") labels["abusive language"] = { type = "related-to", parents = {"communication"}, thesaurusonly = true, } -- closest existing label: ????? labels["change"] = { type = "related-to", description = "=[[change]] and [[stasis]]", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["connection"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "metaphysics" or "ontology" - but this is broader in scope labels["existence"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["harmony and opposition"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ???? labels["intellectual faculties"] = { type = "related-to", parents = {"human"}, thesaurusonly = true, } -- closest existing label: None (handled by the POS category "LANG interjections") labels["interjections"] = { type = "related-to", parents = {"communication"}, thesaurusonly = true, } -- closest existing label: "drugs" - but this is broader in scope labels["intoxication and intoxicants"] = { type = "related-to", description = "=[[intoxication]] and [[intoxicants]]", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: "love" - but the thesaurus cat incorporates friendship etc labels["love and affection"] = { type = "related-to", parents = {"emotions"}, thesaurusonly = true, } -- closest existing label: ???? labels["morality"] = { type = "related-to", parents = {"personal qualities", "concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["order"] = { type = "related-to", description = "{{{langname}}} terms describing the order and disorder in which things occur or are found; terms to do with the sequential and chaotic nature of things", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "personality" - but we use that cat for personality traits, while "personal qualities" is for transient states one can be in (e.g. lucky, drunk) labels["personal qualities"] = { type = "related-to", description = "{{{langname}}} terms describing transient states a person can be in (e.g. lucky, drunk)", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: ????? labels["possession"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["power"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "quantity" - but we don't want this category to be under Mathematics, these are not mathematical concepts labels["quantities"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["relative qualities"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ???? labels["social acts"] = { type = "related-to", parents = {"human behaviour", "communication"}, thesaurusonly = true, } -- closest existing label: ????? labels["status"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "transport" - but this is much broader, containing verbs of motion and the like labels["travel and movement"] = { type = "related-to", parents = {"concepts", "human behaviour"}, thesaurusonly = true, } -- closest existing label: ????? labels["volition"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } return labels 8s0s2aee5axq3paz3lsbirgkpqsskmr 88813 88812 2026-08-06T20:16:28Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Thesaurus]] 88812 Scribunto text/plain local labels = {} -- THESE CATEGORIES ARE ONLY INTENDED FOR USE IN THE THESAURUS! labels["thesaurus-only categories"] = { type = "grouping", description = "{{error|do not use this category}}", parents = {"all topics"}, } -- closest existing label: ???? labels["aggression"] = { type = "related-to", parents = {"human behaviour", "anger"}, thesaurusonly = true, } labels["concepts"] = { type = "grouping", description = "{{{langname}}} terms grouped into conceptual categories", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: None (handled by POS categories like "LANG offensive terms") labels["abusive language"] = { type = "related-to", parents = {"communication"}, thesaurusonly = true, } -- closest existing label: ????? labels["change"] = { type = "related-to", description = "=[[change]] and [[stasis]]", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["connection"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "metaphysics" or "ontology" - but this is broader in scope labels["existence"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["harmony and opposition"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ???? labels["intellectual faculties"] = { type = "related-to", parents = {"human"}, thesaurusonly = true, } -- closest existing label: None (handled by the POS category "LANG interjections") labels["interjections"] = { type = "related-to", parents = {"communication"}, thesaurusonly = true, } -- closest existing label: "drugs" - but this is broader in scope labels["intoxication and intoxicants"] = { type = "related-to", description = "=[[intoxication]] and [[intoxicants]]", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: "love" - but the thesaurus cat incorporates friendship etc labels["love and affection"] = { type = "related-to", parents = {"emotions"}, thesaurusonly = true, } -- closest existing label: ???? labels["morality"] = { type = "related-to", parents = {"personal qualities", "concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["order"] = { type = "related-to", description = "{{{langname}}} terms describing the order and disorder in which things occur or are found; terms to do with the sequential and chaotic nature of things", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "personality" - but we use that cat for personality traits, while "personal qualities" is for transient states one can be in (e.g. lucky, drunk) labels["personal qualities"] = { type = "related-to", description = "{{{langname}}} terms describing transient states a person can be in (e.g. lucky, drunk)", parents = {"thesaurus-only categories"}, thesaurusonly = true, } -- closest existing label: ????? labels["possession"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["power"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "quantity" - but we don't want this category to be under Mathematics, these are not mathematical concepts labels["quantities"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ????? labels["relative qualities"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: ???? labels["social acts"] = { type = "related-to", parents = {"human behaviour", "communication"}, thesaurusonly = true, } -- closest existing label: ????? labels["status"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } -- closest existing label: "transport" - but this is much broader, containing verbs of motion and the like labels["travel and movement"] = { type = "related-to", parents = {"concepts", "human behaviour"}, thesaurusonly = true, } -- closest existing label: ????? labels["volition"] = { type = "related-to", parents = {"concepts"}, thesaurusonly = true, } return labels 8s0s2aee5axq3paz3lsbirgkpqsskmr Mòideal:category tree/topic/Time 828 17908 88814 2026-07-23T19:36:54Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88814 Scribunto text/plain local labels = {} labels["time"] = { type = "related-to", parents = {"all topics"}, } labels["Anglo-Saxon calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Anglo-Saxon calendar}}.", parents = {"months", "lunar months"}, } labels["Armenian calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Armenian calendar}}.", parents = {"months"}, } labels["calendar"] = { type = "related-to", description = "default with the", parents = {"timekeeping"}, } labels["centuries"] = { type = "name", parents = {"calendar"}, } labels["Bengali calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Bengali calendar}}.", parents = {"months"}, } labels["Burmese zodiac signs"] = { type = "name", description = "{{{langname}}} names for the signs of the {{w|Burmese zodiac}}.", parents = {"astrology", "calendar"}, } labels["Chinese earthly branches"] = { type = "name", description = "=[[Chinese]] [[earthly branch]]es", parents = {"Chinese sexagenary cycle terms"}, } labels["Chinese heavenly stems"] = { type = "name", description = "=[[Chinese]] [[heavenly stem]]s", parents = {"Chinese sexagenary cycle terms"}, } labels["Chinese months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Chinese calendar}}.", parents = {"months"}, } labels["Chinese sexagenary cycle terms"] = { type = "name", description = "=[[Chinese]] {{w|sexagenary cycle}} [[term]]s", parents = {"calendar"}, } labels["Chinese zodiac signs"] = { type = "name", description = "default wikify", parents = {"astrology", "calendar", "Chinese mythology"}, } labels["Christmas"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "Christianity"}, } labels["days of the Hindu calendar"] = { type = "name", description = "{{{langname}}} names for the [[day]]s of the {{w|Hindu calendar}}.", parents = {"periodic occurrences", "Hinduism"}, } labels["days of the week"] = { type = "name", description = "=the [[Appendix:Days of the week|days of the week]]", parents = {"periodic occurrences"}, } labels["decades"] = { type = "name", parents = {"calendar"}, } labels["Easter"] = { type = "related-to", parents = {"holidays", "Christianity"}, } labels["Egyptian calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the ancient {{w|Egyptian calendar}}.", parents = {"Ancient Egypt", "months"}, } labels["festivals"] = { type = "name,type", parents = {"observances"}, } labels["Gregorian calendar months"] = { type = "name", parents = {"months"}, } labels["Halloween"] = { type = "related-to", parents = {"holidays"}, } labels["Hanukkah"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "Judaism"}, } labels["Hebrew calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hebrew calendar}}.", parents = {"months"}, } labels["Hindu Jovian years"] = { type = "name", description = "{{{langname}}} names for years in the cycle of [[Jovian year]]s in traditional calendars of [[Hinduism]].", additional = "These are based on the movement of the planet Jupiter rather than that of the sun.", parents = {"calendar", "Hinduism"}, } labels["Hindu lunar calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hindu calendar|Hindu lunar calendar}}.", parents = {"months", "Hinduism"}, } labels["Hindu solar calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hindu calendar|Hindu solar calendar}}.", parents = {"months", "Hinduism"}, } labels["holidays"] = { type = "name,type", parents = {"observances"}, } labels["Icelandic calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Icelandic calendar}}.", parents = {"months"}, } labels["Islamic calendar months"] = { type = "name", parents = {"months", "Islam"}, } labels["Japanese calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Japanese calendar}}.", parents = {"months"}, } labels["Javanese calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Javanese calendar}}.", parents = {"months"}, } labels["Kojoda months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Yoruba calendar}}.", parents = {"months"}, } labels["lunar months"] = { type = "set", parents = {"months"}, } labels["Mesoamerican day signs"] = { type = "name", parents = {"symbols", "calendar"}, wp = "Aztec calendar", } labels["months"] = { type = "set", preceding = "{{also|Appendix:Months of the year}}", description = "{{{langname}}} names of the [[month]]s of the [[year]].", parents = {"periodic occurrences"}, wpcat = true, commonscat = true, } labels["Nanakshahi calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Nanakshahi calendar}}.", parents = {"months"}, } labels["Norse calendar months"] = { type = "name", parents = {"months"}, } labels["observances"] = { type = "set", parents = {"calendar"}, } labels["periodic occurrences"] = { type = "set", description = "=occurrences that repeat at certain intervals of time", parents = {"time"}, } labels["Persian months"] = { type = "name", parents = {"months"}, } labels["Ramadan"] = { type = "related-to", parents = {"observances", "Islam", "Islamic calendar months"}, } labels["seasons"] = { type = "set", parents = {"periodic occurrences", "nature"}, } labels["Sinterklaas"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "mythological figures"}, } labels["Chinese solar terms"] = { type = "set", parents = {"calendar", "Sun"}, } labels["New Year"] = { type = "related-to", description = "=the [[Gregorian]] [[New Year]]", parents = {"holidays"}, } labels["Syrian Christian months"] = { type = "name", parents = {"months"}, } labels["Tamil calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Tamil calendar}}.", parents = {"months"}, } labels["time zones"] = { type = "name", parents = {"timekeeping"}, } labels["Thanksgiving"] = { type = "related-to", parents = {"holidays"}, } labels["timekeeping"] = { type = "related-to", parents = {"time"}, } labels["times of day"] = { type = "set", description = "=[[time]]s of the [[day]]", parents = {"periodic occurrences", "timekeeping"}, } labels["day"] = { type = "related-to", description = "=the [[day]] ([[etymologically]] or [[semantically]])", additional = "'''NOTE''': Do not include days of the week within this category. These should be in [[:Category:{{{langcode}}}:Days of the week]].", parents = {"time"}, } labels["night"] = { type = "related-to", description = "=the [[night]] ([[etymologically]] or [[semantically]])", parents = {"time", "darkness"}, } labels["years"] = { type = "type", parents = {"periodic occurrences"}, } labels["past"] = { type = "related-to", description = "{{{langname}}} terms for the [[past]], or for events in the [[past]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["present"] = { type = "related-to", description = "{{{langname}}} terms for the [[present]], or for events in the [[present]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["future"] = { type = "related-to", description = "{{{langname}}} terms for the [[future]], or for events in the [[future]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["time travel"] = { type = "related-to", parents = {"time", "science fiction", "travel", "relativity"}, } return labels qf1mz3v3w3ifoh4tpwmr1hvq5z5ftlc 88815 88814 2026-08-06T20:16:37Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Time]] 88814 Scribunto text/plain local labels = {} labels["time"] = { type = "related-to", parents = {"all topics"}, } labels["Anglo-Saxon calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Anglo-Saxon calendar}}.", parents = {"months", "lunar months"}, } labels["Armenian calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Armenian calendar}}.", parents = {"months"}, } labels["calendar"] = { type = "related-to", description = "default with the", parents = {"timekeeping"}, } labels["centuries"] = { type = "name", parents = {"calendar"}, } labels["Bengali calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Bengali calendar}}.", parents = {"months"}, } labels["Burmese zodiac signs"] = { type = "name", description = "{{{langname}}} names for the signs of the {{w|Burmese zodiac}}.", parents = {"astrology", "calendar"}, } labels["Chinese earthly branches"] = { type = "name", description = "=[[Chinese]] [[earthly branch]]es", parents = {"Chinese sexagenary cycle terms"}, } labels["Chinese heavenly stems"] = { type = "name", description = "=[[Chinese]] [[heavenly stem]]s", parents = {"Chinese sexagenary cycle terms"}, } labels["Chinese months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Chinese calendar}}.", parents = {"months"}, } labels["Chinese sexagenary cycle terms"] = { type = "name", description = "=[[Chinese]] {{w|sexagenary cycle}} [[term]]s", parents = {"calendar"}, } labels["Chinese zodiac signs"] = { type = "name", description = "default wikify", parents = {"astrology", "calendar", "Chinese mythology"}, } labels["Christmas"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "Christianity"}, } labels["days of the Hindu calendar"] = { type = "name", description = "{{{langname}}} names for the [[day]]s of the {{w|Hindu calendar}}.", parents = {"periodic occurrences", "Hinduism"}, } labels["days of the week"] = { type = "name", description = "=the [[Appendix:Days of the week|days of the week]]", parents = {"periodic occurrences"}, } labels["decades"] = { type = "name", parents = {"calendar"}, } labels["Easter"] = { type = "related-to", parents = {"holidays", "Christianity"}, } labels["Egyptian calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the ancient {{w|Egyptian calendar}}.", parents = {"Ancient Egypt", "months"}, } labels["festivals"] = { type = "name,type", parents = {"observances"}, } labels["Gregorian calendar months"] = { type = "name", parents = {"months"}, } labels["Halloween"] = { type = "related-to", parents = {"holidays"}, } labels["Hanukkah"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "Judaism"}, } labels["Hebrew calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hebrew calendar}}.", parents = {"months"}, } labels["Hindu Jovian years"] = { type = "name", description = "{{{langname}}} names for years in the cycle of [[Jovian year]]s in traditional calendars of [[Hinduism]].", additional = "These are based on the movement of the planet Jupiter rather than that of the sun.", parents = {"calendar", "Hinduism"}, } labels["Hindu lunar calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hindu calendar|Hindu lunar calendar}}.", parents = {"months", "Hinduism"}, } labels["Hindu solar calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Hindu calendar|Hindu solar calendar}}.", parents = {"months", "Hinduism"}, } labels["holidays"] = { type = "name,type", parents = {"observances"}, } labels["Icelandic calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Icelandic calendar}}.", parents = {"months"}, } labels["Islamic calendar months"] = { type = "name", parents = {"months", "Islam"}, } labels["Japanese calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Japanese calendar}}.", parents = {"months"}, } labels["Javanese calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Javanese calendar}}.", parents = {"months"}, } labels["Kojoda months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Yoruba calendar}}.", parents = {"months"}, } labels["lunar months"] = { type = "set", parents = {"months"}, } labels["Mesoamerican day signs"] = { type = "name", parents = {"symbols", "calendar"}, wp = "Aztec calendar", } labels["months"] = { type = "set", preceding = "{{also|Appendix:Months of the year}}", description = "{{{langname}}} names of the [[month]]s of the [[year]].", parents = {"periodic occurrences"}, wpcat = true, commonscat = true, } labels["Nanakshahi calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Nanakshahi calendar}}.", parents = {"months"}, } labels["Norse calendar months"] = { type = "name", parents = {"months"}, } labels["observances"] = { type = "set", parents = {"calendar"}, } labels["periodic occurrences"] = { type = "set", description = "=occurrences that repeat at certain intervals of time", parents = {"time"}, } labels["Persian months"] = { type = "name", parents = {"months"}, } labels["Ramadan"] = { type = "related-to", parents = {"observances", "Islam", "Islamic calendar months"}, } labels["seasons"] = { type = "set", parents = {"periodic occurrences", "nature"}, } labels["Sinterklaas"] = { type = "related-to", description = "default no singularize", parents = {"holidays", "mythological figures"}, } labels["Chinese solar terms"] = { type = "set", parents = {"calendar", "Sun"}, } labels["New Year"] = { type = "related-to", description = "=the [[Gregorian]] [[New Year]]", parents = {"holidays"}, } labels["Syrian Christian months"] = { type = "name", parents = {"months"}, } labels["Tamil calendar months"] = { type = "name", description = "{{{langname}}} names for the months of the {{w|Tamil calendar}}.", parents = {"months"}, } labels["time zones"] = { type = "name", parents = {"timekeeping"}, } labels["Thanksgiving"] = { type = "related-to", parents = {"holidays"}, } labels["timekeeping"] = { type = "related-to", parents = {"time"}, } labels["times of day"] = { type = "set", description = "=[[time]]s of the [[day]]", parents = {"periodic occurrences", "timekeeping"}, } labels["day"] = { type = "related-to", description = "=the [[day]] ([[etymologically]] or [[semantically]])", additional = "'''NOTE''': Do not include days of the week within this category. These should be in [[:Category:{{{langcode}}}:Days of the week]].", parents = {"time"}, } labels["night"] = { type = "related-to", description = "=the [[night]] ([[etymologically]] or [[semantically]])", parents = {"time", "darkness"}, } labels["years"] = { type = "type", parents = {"periodic occurrences"}, } labels["past"] = { type = "related-to", description = "{{{langname}}} terms for the [[past]], or for events in the [[past]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["present"] = { type = "related-to", description = "{{{langname}}} terms for the [[present]], or for events in the [[present]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["future"] = { type = "related-to", description = "{{{langname}}} terms for the [[future]], or for events in the [[future]].", additional = "NOTE: Do NOT include words that are exclusively verbs, or words related to the field of history or historiography, within this category.", parents = {"time"}, } labels["time travel"] = { type = "related-to", parents = {"time", "science fiction", "travel", "relativity"}, } return labels qf1mz3v3w3ifoh4tpwmr1hvq5z5ftlc Mòideal:category tree/topic/Transport 828 17909 88816 2026-07-23T19:36:55Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88816 Scribunto text/plain local labels = {} labels["transport"] = { type = "related-to", parents = {"all topics"}, } labels["animal riding"] = { type = "related-to", description = "=riding [[animal]]s", parents = {"transport", "horses"}, } labels["automotive"] = { type = "related-to", parents = {"transport"}, } labels["cycling"] = { type = "related-to", parents = {"transport"}, } labels["nautical"] = { type = "related-to", parents = {"transport"}, } labels["navigation"] = { type = "related-to", parents = {"transport"}, } labels["rail transportation"] = { type = "related-to", parents = {"transport"}, } labels["road transport"] = { type = "related-to", parents = {"transport"}, } labels["roads"] = { type = "related-to", parents = {"road transport"}, } labels["sailing"] = { type = "related-to", parents = {"nautical"}, } labels["ship parts"] = { type = "type", parents = {"nautical"}, } labels["ship prefixes"] = { type = "name", parents = {"nautical"}, } labels["shipping"] = { type = "related-to", description = "=the transportation of goods by ship", additional = "For the [[fandom]] sense of {{l|en|ship|shipping|id=fandomverb}}, see [[:Category:Shipping (fandom)]].", parents = {"transport", "nautical"}, } labels["space travel"] = { type = "related-to", parents = {"transport", "astronautics"}, } labels["walking"] = { type = "related-to", parents = {"transport"}, } return labels 0x4n5ofohmfmwnlquqmv56vl094lg7z 88817 88816 2026-08-06T20:16:47Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Transport]] 88816 Scribunto text/plain local labels = {} labels["transport"] = { type = "related-to", parents = {"all topics"}, } labels["animal riding"] = { type = "related-to", description = "=riding [[animal]]s", parents = {"transport", "horses"}, } labels["automotive"] = { type = "related-to", parents = {"transport"}, } labels["cycling"] = { type = "related-to", parents = {"transport"}, } labels["nautical"] = { type = "related-to", parents = {"transport"}, } labels["navigation"] = { type = "related-to", parents = {"transport"}, } labels["rail transportation"] = { type = "related-to", parents = {"transport"}, } labels["road transport"] = { type = "related-to", parents = {"transport"}, } labels["roads"] = { type = "related-to", parents = {"road transport"}, } labels["sailing"] = { type = "related-to", parents = {"nautical"}, } labels["ship parts"] = { type = "type", parents = {"nautical"}, } labels["ship prefixes"] = { type = "name", parents = {"nautical"}, } labels["shipping"] = { type = "related-to", description = "=the transportation of goods by ship", additional = "For the [[fandom]] sense of {{l|en|ship|shipping|id=fandomverb}}, see [[:Category:Shipping (fandom)]].", parents = {"transport", "nautical"}, } labels["space travel"] = { type = "related-to", parents = {"transport", "astronautics"}, } labels["walking"] = { type = "related-to", parents = {"transport"}, } return labels 0x4n5ofohmfmwnlquqmv56vl094lg7z Mòideal:category tree/topic/Physical actions 828 17910 88818 2026-07-23T19:36:42Z en>WingerBot 0 explicit 'description = "default"' unnecessary; remove it (manually assisted) 88818 Scribunto text/plain local labels = {} labels["physical actions"] = { type = "set", parents = {"all topics"}, } labels["physical impact"] = { type = "set", description = "{{{langname}}} terms for [[physical]] [[impact]] on something", parents = {"physical actions"}, } labels["hit"] = { type = "set", description = "{{{langname}}} terms for [[hitting]] something", parents = {"physical impact"}, } labels["rub"] = { type = "set", description = "{{{langname}}} terms for [[rubbing]] something, moving something smooth against something else, in order to make it smooth or clean", parents = {"physical impact"}, } return labels 7muuojzvu8rrqziv9eazpgengxy5qjm 88819 88818 2026-08-06T20:16:57Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/topic/Physical_actions]] 88818 Scribunto text/plain local labels = {} labels["physical actions"] = { type = "set", parents = {"all topics"}, } labels["physical impact"] = { type = "set", description = "{{{langname}}} terms for [[physical]] [[impact]] on something", parents = {"physical actions"}, } labels["hit"] = { type = "set", description = "{{{langname}}} terms for [[hitting]] something", parents = {"physical impact"}, } labels["rub"] = { type = "set", description = "{{{langname}}} terms for [[rubbing]] something, moving something smooth against something else, in order to make it smooth or clean", parents = {"physical impact"}, } return labels 7muuojzvu8rrqziv9eazpgengxy5qjm Mòideal:category tree/fam/alg 828 17911 88820 2026-07-26T06:02:54Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/alg]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88820 Scribunto text/plain local labels = {} labels["transitive animate verbs"] = { description = "{{{langname}}} transitive verbs with an animate object, commonly abbreviated VTA.", breadcrumb = "transitive animate", parents = {"verbs by inflection type", {name = "transitive verbs", sort = "animate"}}, } labels["transitive inanimate verbs"] = { description = "{{{langname}}} transitive verbs with an inanimate object, commonly abbreviated VTI.", breadcrumb = "transitive inanimate", parents = {"verbs by inflection type", {name = "transitive verbs", sort = "inanimate"}}, } labels["animate intransitive verbs"] = { description = "{{{langname}}} intransitive verbs with an animate subject, commonly abbreviated VAI.", breadcrumb = "animate intransitive", parents = {"verbs by inflection type", {name = "intransitive verbs", sort = "animate"}}, } labels["inanimate intransitive verbs"] = { description = "{{{langname}}} intransitive verbs with an inanimate subject, commonly abbreviated VII.", breadcrumb = "inanimate intransitive", parents = {"verbs by inflection type", {name = "intransitive verbs", sort = "inanimate"}}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 85qdgi9z8fm0fttnf1ltxgr2wyrtvw0 88821 88820 2026-08-06T20:17:32Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/alg]] 88820 Scribunto text/plain local labels = {} labels["transitive animate verbs"] = { description = "{{{langname}}} transitive verbs with an animate object, commonly abbreviated VTA.", breadcrumb = "transitive animate", parents = {"verbs by inflection type", {name = "transitive verbs", sort = "animate"}}, } labels["transitive inanimate verbs"] = { description = "{{{langname}}} transitive verbs with an inanimate object, commonly abbreviated VTI.", breadcrumb = "transitive inanimate", parents = {"verbs by inflection type", {name = "transitive verbs", sort = "inanimate"}}, } labels["animate intransitive verbs"] = { description = "{{{langname}}} intransitive verbs with an animate subject, commonly abbreviated VAI.", breadcrumb = "animate intransitive", parents = {"verbs by inflection type", {name = "intransitive verbs", sort = "animate"}}, } labels["inanimate intransitive verbs"] = { description = "{{{langname}}} intransitive verbs with an inanimate subject, commonly abbreviated VII.", breadcrumb = "inanimate intransitive", parents = {"verbs by inflection type", {name = "intransitive verbs", sort = "inanimate"}}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 85qdgi9z8fm0fttnf1ltxgr2wyrtvw0 Mòideal:category tree/fam/gem 828 17912 88822 2026-07-26T06:03:10Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/gem]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88822 Scribunto text/plain local labels = {} ------- GERMANIC VERB CLASSES ------- labels["strong verbs"] = { description = "{{{langname}}} verbs that do not use a dental suffix to mark the past tense and past participle, instead using vowel change ([[ablaut]]) and often a suffix ''-(e)n'' in the past participle.", breadcrumb = "strong", parents = {"verbs by inflection type"}, } labels["weak verbs"] = { description = "{{{langname}}} verbs that display dental suffixes in their past tense conjugated forms.", breadcrumb = "weak", parents = {"verbs by inflection type"}, } labels["preterite-present verbs"] = { description = "{{{langname}}} verbs that inflect in the present tense like the past tense of strong verbs.", breadcrumb = "preterite-present", parents = {"verbs by inflection type"}, } labels["class 1 strong verbs"] = { description = "{{{langname}}} class 1 strong verbs, where the [[ablaut]] vowel was followed by ''-y-'' in Proto-Indo-European.", breadcrumb = "class 1", parents = {{name = "strong verbs", sort = "1"}}, } labels["class 1 weak verbs"] = { description = "{{{langname}}} class 1 weak verbs, where the stem was followed by {{ic|/i/~/j/}} in Proto-Germanic (or {{ic|/ij/}} after a heavy stem, due to {{w|Sievers' Law}}).", additional = "This triggered [[umlaut]] in most daughter languages, as well as gemination of the final consonant in light stems in West Germanic.", breadcrumb = "class 1", parents = {{name = "weak verbs", sort = "1"}}, } labels["class 1 weak j-present verbs"] = { description = "{{{langname}}} class 1 weak verbs with {{ic|/i/~/j/~/ij/}} in Proto-Germanic only in the present tense, but not elsewhere.", additional = "Most class 1 weak verbs had {{ic|/i/}} in the past tense and past participle, leading to " .. "[[umlaut]] throughout the verb in daughter languages with umlaut. A few archaic verbs, however, lacked " .. "this [[interfix]], with the [[dental]] consonant of the ending attached directly to the stem. Original " .. "instances of this are the reflexes of English [[seek]], [[think]], [[buy]] and [[work]], with apparently " .. "irregular pasts ''sought'', ''thought'', ''bought'' and archaic ''wrought'', and it was often extended " .. "to other verbs in various daughter languages (e.g. the [[Old English]] reflexes of [[sell]], [[tell]], " .. "[[teach]] and formerly [[reach]], with apparently irregular pasts ''sold'', ''told'', ''taught'' and " .. "now-obsolete ''raught''). The apparent reversal of umlaut in the past tense is sometimes called " .. "{{m|de|Rückumlaut|lit=backwards umlaut}} in Germanic studies.", breadcrumb = "''j''-present", parents = {{name = "class 1 weak verbs", sort = "j-present"}}, } labels["class 1 weak heavy-stem verbs"] = { description = "{{{langname}}} class 1 weak verbs with a heavy stem in Proto-Germanic, i.e. a stem containing a long vowel or ending in two consonants.", additional = "Such verbs had the {{w|Sievers' Law}} variant interfix {{ic|/ij/}} between the stem and endings " .. "in the present tense, which evolved differently from light-stem verbs in most daughter languages, which " .. "had an interfix {{ic|/i/~/j/}} in the present tense. Note that some verbs with multisyllabic stems were " .. "treated as heavy-stem and some as light-stem, depending on the analysis of the metrical feet of the stem.", breadcrumb_and_first_sort_key = "heavy-stem", parents = "class 1 weak verbs", } labels["class 1 weak light-stem verbs"] = { description = "{{{langname}}} class 1 weak verbs with a light stem in Proto-Germanic, i.e. a stem containing a short vowel and ending in only one consonant.", additional = "Such verbs had the {{w|Sievers' Law}} variant interfix {{ic|/i/~/j/}} between the stem and " .. "endings in the present tense, which evolved differently from heavy-stem verbs in most daughter languages, " .. "which had an interfix {{ic|/ij/}} in the present tense. Note that some verbs with multisyllabic stems were " .. "treated as heavy-stem and some as light-stem, depending on the analysis of the metrical feet of the stem.", breadcrumb_and_first_sort_key = "light-stem", parents = "class 1 weak verbs", } labels["class 2 strong verbs"] = { description = "{{{langname}}} class 2 strong verbs, where the [[ablaut]] vowel was followed by ''-w-'' in Proto-Indo-European.", breadcrumb = "class 2", parents = {{name = "strong verbs", sort = "2"}}, } labels["class 2a strong verbs"] = { description = "{{{langname}}} class 2 strong verbs where the [[ablaut]] vowel was ''*eu'' in Proto-Germanic.", breadcrumb = "class 2a", parents = {{name = "class 2 strong verbs", sort = "1"}}, } labels["class 2b strong verbs"] = { description = "{{{langname}}} class 2 strong verbs where the [[ablaut]] vowel was ''*ū'' in Proto-Germanic.", breadcrumb = "class 2b", parents = {{name = "class 2 strong verbs", sort = "2"}}, } labels["class 2 weak verbs"] = { description = "{{{langname}}} class 2 weak verbs, where the stem was followed by ''*ō'' in Proto-Germanic.", breadcrumb = "class 2", parents = {{name = "weak verbs", sort = "2"}}, } labels["class 3 weak verbs"] = { description = "{{{langname}}} class 3 weak verbs, where the stem was followed by ''*ai''~''*ā'' in Proto-Germanic, which was generalized to ''*ē'' in West Germanic.", breadcrumb = "class 3", parents = {{name = "weak verbs", sort = "3"}}, } labels["class 3 strong verbs"] = { description = "{{{langname}}} class 3 strong verbs, where the [[ablaut]] vowel was followed by a [[consonant cluster]] in Proto-Indo-European.", breadcrumb = "class 3", parents = {{name = "strong verbs", sort = "3"}}, } labels["class 3a strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a nasal consonant.", breadcrumb = "class 3a", parents = {{name = "class 3 strong verbs", sort = "1"}}, } labels["class 3b strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a lateral consonant or velar fricative.", breadcrumb = "class 3b", parents = {{name = "class 3 strong verbs", sort = "2"}}, } labels["class 3c strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a rhotic consonant.", breadcrumb = "class 3c", parents = {{name = "class 3 strong verbs", sort = "3"}}, } labels["class 4 strong verbs"] = { description = "{{{langname}}} class 4 strong verbs, where the [[ablaut]] vowel was followed by a [[sonorant]] (''m'', ''n'', ''l'', ''r'') but no other consonant in Proto-Indo-European.", breadcrumb = "class 4", parents = {{name = "strong verbs", sort = "4"}}, } labels["class 4 weak verbs"] = { description = "{{{langname}}} class 4 weak verbs, where the stem was followed by ''*n'' in Proto-Germanic.", breadcrumb = "class 4", parents = {{name = "weak verbs", sort = "4"}}, } labels["class 5 strong verbs"] = { description = "{{{langname}}} class 5 strong verbs, where the [[ablaut]] vowel was followed by [[consonant]] other than a [[sonorant]] in Proto-Indo-European.", breadcrumb = "class 5", parents = {{name = "strong verbs", sort = "5"}}, } labels["class 5 strong j-present verbs"] = { description = "{{{langname}}} class 5 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This [[umlaut]]ed the root vowel to {{ic|/i/}}, and caused gemination of the stem-final consonant in the West Germanic languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 5 strong verbs", sort = "j-present"}}, } labels["class 6 strong verbs"] = { description = "{{{langname}}} class 6 strong verbs, with the stem vowel ''-a-'' (and usually a single stem-final consonant), except those where it is followed by a sonorant and another consonant (this combination was considered a diphthong in PIE and therefore belonged to class 7).", additional = "The Proto-Indo-European origin of this class is not securely known.", breadcrumb = "class 6", parents = {{name = "strong verbs", sort = "6"}}, } labels["class 6 strong j-present verbs"] = { description = "{{{langname}}} class 6 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This caused gemination of the stem-final consonant in the West Germanic languages, and [[umlaut]] of the root vowel in most languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 6 strong verbs", sort = "j-present"}}, } labels["class 7 strong verbs"] = { description = "{{{langname}}} class 7 strong verbs, which retained their reduplication in the past tense in Proto-Germanic.", breadcrumb = "class 7", parents = {{name = "strong verbs", sort = "7"}}, } labels["class 7a strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ai'' in Proto-Germanic, analogous to class 1.", breadcrumb = "class 7a", parents = {{name = "class 7 strong verbs", sort = "a"}}, } labels["class 7b strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*au'' in Proto-Germanic, analogous to class 2.", breadcrumb = "class 7b", parents = {{name = "class 7 strong verbs", sort = "b"}}, } labels["class 7c strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*a'' followed by a [[consonant cluster]] in Proto-Germanic, analogous to class 3.", breadcrumb = "class 7c", parents = {{name = "class 7 strong verbs", sort = "c"}}, } labels["class 7d strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ē'' in Proto-Germanic.", breadcrumb = "class 7d", parents = {{name = "class 7 strong verbs", sort = "d"}}, } labels["class 7e strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ō'' in Proto-Germanic.", breadcrumb = "class 7e", parents = {{name = "class 7 strong verbs", sort = "e"}}, } labels["class 7 strong j-present verbs"] = { description = "{{{langname}}} class 7 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This caused [[umlaut]] of the root vowel in most languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 7 strong verbs", sort = "j-present"}}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 88k7sky1bf589e9xdsynl8pwglofaen 88823 88822 2026-08-06T20:17:35Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/gem]] 88822 Scribunto text/plain local labels = {} ------- GERMANIC VERB CLASSES ------- labels["strong verbs"] = { description = "{{{langname}}} verbs that do not use a dental suffix to mark the past tense and past participle, instead using vowel change ([[ablaut]]) and often a suffix ''-(e)n'' in the past participle.", breadcrumb = "strong", parents = {"verbs by inflection type"}, } labels["weak verbs"] = { description = "{{{langname}}} verbs that display dental suffixes in their past tense conjugated forms.", breadcrumb = "weak", parents = {"verbs by inflection type"}, } labels["preterite-present verbs"] = { description = "{{{langname}}} verbs that inflect in the present tense like the past tense of strong verbs.", breadcrumb = "preterite-present", parents = {"verbs by inflection type"}, } labels["class 1 strong verbs"] = { description = "{{{langname}}} class 1 strong verbs, where the [[ablaut]] vowel was followed by ''-y-'' in Proto-Indo-European.", breadcrumb = "class 1", parents = {{name = "strong verbs", sort = "1"}}, } labels["class 1 weak verbs"] = { description = "{{{langname}}} class 1 weak verbs, where the stem was followed by {{ic|/i/~/j/}} in Proto-Germanic (or {{ic|/ij/}} after a heavy stem, due to {{w|Sievers' Law}}).", additional = "This triggered [[umlaut]] in most daughter languages, as well as gemination of the final consonant in light stems in West Germanic.", breadcrumb = "class 1", parents = {{name = "weak verbs", sort = "1"}}, } labels["class 1 weak j-present verbs"] = { description = "{{{langname}}} class 1 weak verbs with {{ic|/i/~/j/~/ij/}} in Proto-Germanic only in the present tense, but not elsewhere.", additional = "Most class 1 weak verbs had {{ic|/i/}} in the past tense and past participle, leading to " .. "[[umlaut]] throughout the verb in daughter languages with umlaut. A few archaic verbs, however, lacked " .. "this [[interfix]], with the [[dental]] consonant of the ending attached directly to the stem. Original " .. "instances of this are the reflexes of English [[seek]], [[think]], [[buy]] and [[work]], with apparently " .. "irregular pasts ''sought'', ''thought'', ''bought'' and archaic ''wrought'', and it was often extended " .. "to other verbs in various daughter languages (e.g. the [[Old English]] reflexes of [[sell]], [[tell]], " .. "[[teach]] and formerly [[reach]], with apparently irregular pasts ''sold'', ''told'', ''taught'' and " .. "now-obsolete ''raught''). The apparent reversal of umlaut in the past tense is sometimes called " .. "{{m|de|Rückumlaut|lit=backwards umlaut}} in Germanic studies.", breadcrumb = "''j''-present", parents = {{name = "class 1 weak verbs", sort = "j-present"}}, } labels["class 1 weak heavy-stem verbs"] = { description = "{{{langname}}} class 1 weak verbs with a heavy stem in Proto-Germanic, i.e. a stem containing a long vowel or ending in two consonants.", additional = "Such verbs had the {{w|Sievers' Law}} variant interfix {{ic|/ij/}} between the stem and endings " .. "in the present tense, which evolved differently from light-stem verbs in most daughter languages, which " .. "had an interfix {{ic|/i/~/j/}} in the present tense. Note that some verbs with multisyllabic stems were " .. "treated as heavy-stem and some as light-stem, depending on the analysis of the metrical feet of the stem.", breadcrumb_and_first_sort_key = "heavy-stem", parents = "class 1 weak verbs", } labels["class 1 weak light-stem verbs"] = { description = "{{{langname}}} class 1 weak verbs with a light stem in Proto-Germanic, i.e. a stem containing a short vowel and ending in only one consonant.", additional = "Such verbs had the {{w|Sievers' Law}} variant interfix {{ic|/i/~/j/}} between the stem and " .. "endings in the present tense, which evolved differently from heavy-stem verbs in most daughter languages, " .. "which had an interfix {{ic|/ij/}} in the present tense. Note that some verbs with multisyllabic stems were " .. "treated as heavy-stem and some as light-stem, depending on the analysis of the metrical feet of the stem.", breadcrumb_and_first_sort_key = "light-stem", parents = "class 1 weak verbs", } labels["class 2 strong verbs"] = { description = "{{{langname}}} class 2 strong verbs, where the [[ablaut]] vowel was followed by ''-w-'' in Proto-Indo-European.", breadcrumb = "class 2", parents = {{name = "strong verbs", sort = "2"}}, } labels["class 2a strong verbs"] = { description = "{{{langname}}} class 2 strong verbs where the [[ablaut]] vowel was ''*eu'' in Proto-Germanic.", breadcrumb = "class 2a", parents = {{name = "class 2 strong verbs", sort = "1"}}, } labels["class 2b strong verbs"] = { description = "{{{langname}}} class 2 strong verbs where the [[ablaut]] vowel was ''*ū'' in Proto-Germanic.", breadcrumb = "class 2b", parents = {{name = "class 2 strong verbs", sort = "2"}}, } labels["class 2 weak verbs"] = { description = "{{{langname}}} class 2 weak verbs, where the stem was followed by ''*ō'' in Proto-Germanic.", breadcrumb = "class 2", parents = {{name = "weak verbs", sort = "2"}}, } labels["class 3 weak verbs"] = { description = "{{{langname}}} class 3 weak verbs, where the stem was followed by ''*ai''~''*ā'' in Proto-Germanic, which was generalized to ''*ē'' in West Germanic.", breadcrumb = "class 3", parents = {{name = "weak verbs", sort = "3"}}, } labels["class 3 strong verbs"] = { description = "{{{langname}}} class 3 strong verbs, where the [[ablaut]] vowel was followed by a [[consonant cluster]] in Proto-Indo-European.", breadcrumb = "class 3", parents = {{name = "strong verbs", sort = "3"}}, } labels["class 3a strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a nasal consonant.", breadcrumb = "class 3a", parents = {{name = "class 3 strong verbs", sort = "1"}}, } labels["class 3b strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a lateral consonant or velar fricative.", breadcrumb = "class 3b", parents = {{name = "class 3 strong verbs", sort = "2"}}, } labels["class 3c strong verbs"] = { description = "{{{langname}}} class 3 strong verbs where the [[consonant cluster]] following the [[ablaut]] vowel begins with a rhotic consonant.", breadcrumb = "class 3c", parents = {{name = "class 3 strong verbs", sort = "3"}}, } labels["class 4 strong verbs"] = { description = "{{{langname}}} class 4 strong verbs, where the [[ablaut]] vowel was followed by a [[sonorant]] (''m'', ''n'', ''l'', ''r'') but no other consonant in Proto-Indo-European.", breadcrumb = "class 4", parents = {{name = "strong verbs", sort = "4"}}, } labels["class 4 weak verbs"] = { description = "{{{langname}}} class 4 weak verbs, where the stem was followed by ''*n'' in Proto-Germanic.", breadcrumb = "class 4", parents = {{name = "weak verbs", sort = "4"}}, } labels["class 5 strong verbs"] = { description = "{{{langname}}} class 5 strong verbs, where the [[ablaut]] vowel was followed by [[consonant]] other than a [[sonorant]] in Proto-Indo-European.", breadcrumb = "class 5", parents = {{name = "strong verbs", sort = "5"}}, } labels["class 5 strong j-present verbs"] = { description = "{{{langname}}} class 5 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This [[umlaut]]ed the root vowel to {{ic|/i/}}, and caused gemination of the stem-final consonant in the West Germanic languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 5 strong verbs", sort = "j-present"}}, } labels["class 6 strong verbs"] = { description = "{{{langname}}} class 6 strong verbs, with the stem vowel ''-a-'' (and usually a single stem-final consonant), except those where it is followed by a sonorant and another consonant (this combination was considered a diphthong in PIE and therefore belonged to class 7).", additional = "The Proto-Indo-European origin of this class is not securely known.", breadcrumb = "class 6", parents = {{name = "strong verbs", sort = "6"}}, } labels["class 6 strong j-present verbs"] = { description = "{{{langname}}} class 6 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This caused gemination of the stem-final consonant in the West Germanic languages, and [[umlaut]] of the root vowel in most languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 6 strong verbs", sort = "j-present"}}, } labels["class 7 strong verbs"] = { description = "{{{langname}}} class 7 strong verbs, which retained their reduplication in the past tense in Proto-Germanic.", breadcrumb = "class 7", parents = {{name = "strong verbs", sort = "7"}}, } labels["class 7a strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ai'' in Proto-Germanic, analogous to class 1.", breadcrumb = "class 7a", parents = {{name = "class 7 strong verbs", sort = "a"}}, } labels["class 7b strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*au'' in Proto-Germanic, analogous to class 2.", breadcrumb = "class 7b", parents = {{name = "class 7 strong verbs", sort = "b"}}, } labels["class 7c strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*a'' followed by a [[consonant cluster]] in Proto-Germanic, analogous to class 3.", breadcrumb = "class 7c", parents = {{name = "class 7 strong verbs", sort = "c"}}, } labels["class 7d strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ē'' in Proto-Germanic.", breadcrumb = "class 7d", parents = {{name = "class 7 strong verbs", sort = "d"}}, } labels["class 7e strong verbs"] = { description = "{{{langname}}} class 7 strong verbs where the root vowel was ''*ō'' in Proto-Germanic.", breadcrumb = "class 7e", parents = {{name = "class 7 strong verbs", sort = "e"}}, } labels["class 7 strong j-present verbs"] = { description = "{{{langname}}} class 7 strong verbs with a {{IPAchar|/j/}} suffix in the present tense in Proto-Germanic.", additional = "This caused [[umlaut]] of the root vowel in most languages. The {{ic|/j/}} was maintained in Gothic, Old Norse (and modern Icelandic) and Old Saxon, but otherwise dropped.", breadcrumb = "''j''-present", parents = {{name = "class 7 strong verbs", sort = "j-present"}}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 88k7sky1bf589e9xdsynl8pwglofaen Mòideal:category tree/fam/jpx 828 17913 88824 2026-07-26T06:03:25Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/jpx]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88824 Scribunto text/plain local labels = {} local handlers = {} local m_str_utils = require("Module:string utilities") local concat = table.concat local full_link = require("Module:links").full_link local insert = table.insert local Hani_sort = require("Module:Hani-sortkey").makeSortKey local match = m_str_utils.match local sort = table.sort local tag_text = require("Module:script_utilities").tag_text local ucfirst = m_str_utils.ucfirst local Hira = require("Module:scripts").getByCode("Hira") local Jpan = require("Module:scripts").getByCode("Jpan") local kana_to_romaji = require("Module:Hrkt-translit").tr local m_numeric = require("Module:ConvertNumeric") local kana_capture = "([-" .. require("Module:ja/data/range").kana .. "・]+)" local yomi_data = require("Module:kanjitab/data") labels["adnominals"] = { description = "{{{langname}}} adnominals, or {{ja-r|連%体%詞|れん%たい%し}}, which modify nouns, and do not conjugate or [[predicate#Verb|predicate]].", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["hiragana"] = { description = "{{{langname}}} terms with hiragana {{mdash}} {{ja-r|平%仮%名|ひら%が%な}} {{mdash}} forms, sorted by conventional hiragana sequence. The hiragana form is a [[phonetic]] representation of that word. " .. "Wiktionary represents {{{langname}}}-language segments in three ways: in normal form (with [[kanji]], if appropriate), in [[hiragana]] " .. "form (this differs from kanji form only when the segment contains kanji), and in [[romaji]] form.", additional = "''See also'' [[:Category:{{{langname}}} katakana]]", toc_template = "Hira-categoryTOC", toc_template_full = "Hira-categoryTOC/full", parents = { {name = "{{{langcat}}}", raw = true}, "Category:Hiragana script characters", } } labels["historical hiragana"] = { description = "{{{langname}}} historical [[hiragana]].", additional = "''See also'' [[:Category:{{{langname}}} historical katakana]].", toc_template = "Hira-categoryTOC", toc_template_full = "Hira-categoryTOC/full", parents = { "hiragana", {name = "{{{langcat}}}", raw = true}, "Category:Hiragana script characters", } } labels["katakana"] = { description = "{{{langname}}} terms with katakana {{mdash}} {{ja-r|片%仮%名|かた%か%な}} {{mdash}} forms, sorted by conventional katakana sequence. Katakana is used primarily for transliterations of foreign words, including old Chinese hanzi not used in [[shinjitai]].", additional = "''See also'' [[:Category:{{{langname}}} hiragana]]", toc_template = "Kana-categoryTOC", toc_template_full = "Kana-categoryTOC/full", parents = { {name = "{{{langcat}}}", raw = true}, "Category:Katakana script characters", } } labels["historical katakana"] = { description = "{{{langname}}} historical [[katakana]].", additional = "''See also'' [[:Category:{{{langname}}} historical hiragana]].", toc_template = "Kana-categoryTOC", toc_template_full = "Kana-categoryTOC/full", parents = { "katakana", {name = "{{{langcat}}}", raw = true}, "Category:Katakana script characters", } } labels["terms spelled with mixed kana"] = { description = "{{{langname}}} terms which combine [[hiragana]] and [[katakana]] characters, potentially with [[kanji]] too.", parents = { {name = "{{{langcat}}}", raw = true}, "hiragana", "katakana", }, } labels["kanji"] = { topright = "{{wp|Kanji}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", toc_template = "Hani-categoryTOC", umbrella = "Han characters", parents = "logograms", } labels["kanji by reading"] = { description = "{{{langname}}} kanji categorized by reading.", parents = {{name = "kanji", sort = "reading"}}, } labels["makurakotoba"] = { topright = "{{wp|Makurakotoba}}", description = "{{{langname}}} idioms used in poetry to introduce specific words.", parents = {"idioms"}, } labels["terms by kanji readings"] = { description = "{{{langname}}} categories grouped with regard to the readings of the kanji with which they are spelled.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms by reading pattern"] = { description = "{{{langname}}} categories with terms grouped by their reading patterns.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms by number of kanji"] = { description = "{{{langname}}} terms categorized by number of kanji.", parents = {"terms by orthographic property"}, } local function handle_onyomi_list(category, category_type, cat_yomi_type) local onyomi, seen = {}, {} for _, yomi in pairs(yomi_data) do if not seen[yomi] and yomi.onyomi then local yomi_catname = yomi[category_type] if yomi_catname ~= false then local yomi_type = yomi.type if yomi_type ~= "on'yomi" and yomi_type ~= cat_yomi_type then insert(onyomi, "[[:Category:{{{langname}}} " .. category:gsub("{{{yomi_catname}}}", yomi_catname) .. "]]") end end end seen[yomi] = true end sort(onyomi) return onyomi end local function add_yomi_category(category, category_type, parent, description) for _, yomi in pairs(yomi_data) do local yomi_catname = yomi[category_type] if yomi_catname ~= false then local yomi_type = yomi.type local yomi_desc = yomi.link or yomi_catname if yomi.description then yomi_desc = yomi_desc .. "; " .. yomi.description end local label = { description = description .. " " .. yomi_desc .. ".", breadcrumb = yomi_type, parents = {{name = parent, sort = yomi_catname}}, } if yomi.onyomi then local onyomi = handle_onyomi_list(category, category_type, yomi_type) label.additional = "Categories of terms with " .. (yomi_type == "on'yomi" and "more" or "other") .. " specific types of on'yomi readings can be found in the following categories:\n* " .. concat(onyomi, "\n* ") if yomi_type ~= "on'yomi" then insert(label.parents, 1, { name = (category:gsub("{{{yomi_catname}}}", yomi_data.on[category_type])), sort = yomi_catname }) end end labels[category:gsub("{{{yomi_catname}}}", yomi_catname)] = label end end end add_yomi_category( "terms read with {{{yomi_catname}}}", "reading_category", "terms by reading pattern", "{{{langname}}} terms read with" ) add_yomi_category( "terms spelled with kanji with {{{yomi_catname}}} readings", "kanji_category", "terms by kanji reading type", "{{{langname}}} categories with terms that are spelled with one or more kanji read with" ) labels["terms with missing yomi"] = { description = "{{{langname}}} terms where at least one [[Appendix:Japanese glossary#yomi|yomi]] is missing from {{tl|{{{langcode}}}-kanjitab}}.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["terms with IPA pronunciation with pitch accent"] = { description = "{{{langname}}} terms with pronunciations that have {{w|Japanese pitch accent|pitch accent}} specified.", additional = "Pitch accent can be specified in {{tl|{{{langcode}}}-pron}} with the {{code|=acc=}} parameter.", can_be_empty = true, parents = {"entry maintenance", "pitch accent"}, } labels["terms with IPA pronunciation missing pitch accent"] = { description = "{{{langname}}} terms with pronunciations that do not have a {{w|Japanese pitch accent|pitch accent}} specified.", additional = "Pitch accent can be specified in {{tl|{{{langcode}}}-pron}} with the {{code|=acc=}} parameter.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["pitch accent"] = { description = "{{{langname}}} terms regarding {{w|Japanese pitch accent|pitch accent}} pronunciation.", can_be_empty = true, parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms with Heiban pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[平板型|Heiban]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Atamadaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[頭高型|Atamadaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Nakadaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[中高型|Nakadaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Odaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[尾高型|Odaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with complex pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) complex {{w|Japanese pitch accent|pitch accent}}, as in having more than one {{m|ja|アクセント句}}.", can_be_empty = true, parents = {"pitch accent"} } labels["pitch accent deaccenting before の"] = { description = "{{{langname}}} terms with {{w|Japanese pitch accent|pitch accent}} pronunciations that have exceptional deaccenting or lack thereof before の ({{ja-deaccenting-before-no}}).", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Odaka pitch accent not deaccented before の (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[尾高型|Odaka]] {{w|Japanese pitch accent|pitch accent}} and do not become deaccented before の ({{ja-deaccenting-before-no}}).\n\nTerms are placed in this category using {{tl|ja-odaka-deaccent-exception}}.", can_be_empty = true, parents = {"pitch accent deaccenting before の"} } labels["terms with Nakadaka pitch accent deaccented before の (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[中高型|Nakadaka]] {{w|Japanese pitch accent|pitch accent}} and become deaccented before の ({{ja-deaccenting-before-no}}).\n\nTerms are placed in this category using {{tl|ja-nakadaka-deaccent}}.", can_be_empty = true, parents = {"pitch accent deaccenting before の"} } labels["terms by kanji reading type"] = { description = "{{{langname}}} categories with terms grouped with regard to the types of readings of the kanji with which " .. "they are spelled; broadly, those of Chinese origin, {{ja-r|音|おん}} readings, and those of non-Chinese origin, {{ja-r|訓|くん}} readings.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms spelled with ateji"] = { topright = "{{wp|Ateji}}", description = "{{{langname}}} terms containing one or more [[Appendix:Japanese glossary#ateji|ateji]] {{mdash}} {{ja-r|当て字|あてじ}} {{mdash}} which are [[kanji]] used to represent sounds rather than meanings (though meaning may have some influence on which kanji are chosen).", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms spelled with daiyōji"] = { description = "Japanese terms spelled using [[Appendix:Japanese glossary#daiyouji|daiyōji]], categorized using {{temp|ja-daiyouji}}.", parents = {"terms by etymology"}, } labels["terms spelled with jukujikun"] = { description = "{{{langname}}} terms containing one or more [[Appendix:Japanese glossary#jukujikun|jukujikun]] {{mdash}} {{ja-r|熟%字%訓|じゅく%じ%くん}} {{mdash}} which are [[kanji]] used to represent meanings rather than sounds.", parents = {{name = "{{{langcat}}}", raw = true}}, } local function add_grade_categories(grade, desc, wp, only_one, parent, sort) local grade_kanji = grade .. " kanji" local topright = wp and ("{{wp|%s}}"):format(ucfirst(grade_kanji)) or nil labels[grade_kanji] = { topright = topright, description = "{{{langname}}} kanji " .. desc, toc_template = "Hani-categoryTOC", parents = {{ name = parent and (parent .. " kanji") or "kanji", sort = sort or grade }}, } labels["terms spelled with " .. grade_kanji] = { topright = topright, description = "{{{langname}}} terms spelled with " .. (only_one and "at least one " or "") .. "kanji " .. desc, parents = {{ name = parent and ("terms spelled with " .. parent .. " kanji") or "terms by orthographic property", sort = sort or grade }}, } end for i = 1, 6 do local ord = m_numeric.ones_position_ord[i] add_grade_categories( ord .. " grade", "taught in the " .. ord .. " grade of elementary school, as designated by the the official list of {{ja-r|教%育 漢%字|きょう%いく かん%じ|education kanji}}.", false, false, "kyōiku", i ) end add_grade_categories( "kyōiku", "on the official list of {{ja-r|教%育 漢%字|きょう%いく かん%じ|education kanji}}.", true, false, "jōyō" ) add_grade_categories( "secondary school", "on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}} that are generally taught in secondary school.", false, false, "jōyō" ) add_grade_categories( "jōyō", "on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}}.", true, false ) add_grade_categories( "tōyō", "on the official list of {{ja-r|当%用 漢%字|とう%よう かん%じ|general-use characters}}, which was used from 1946{{ndash}}1981 until the publication of the list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}}.", true, false ) add_grade_categories( "jinmeiyō", "on the official list of {{ja-r|人%名%用 漢%字|じん%めい%-よう かん%じ|kanji for use in personal names}}.", true, true ) add_grade_categories( "hyōgai", "not included on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}} or {{ja-r|人%名%用 漢%字|じん%めい%-よう かん%じ|kanji for use in personal names}}, known as {{ja-r|表%外 漢%字|ひょう%がい かん%じ}} or {{ja-r|表%外%字|ひょう%がい%じ|unlisted characters}}.", true, true ) labels["terms with multiple readings"] = { description = "{{{langname}}} terms with multiple pronunciations (hence multiple [[kana]] spellings).", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["kanji readings by number of morae"] = { description = "{{{langname}}} categories grouped with regard to the number of morae in their kanji readings.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["single-kanji terms"] = { description = "{{{langname}}} terms written as a single kanji.", parents = { "terms by orthographic property", {name = "terms with 1 kanji", sort = " "}, }, } labels["kanji with kun readings missing okurigana designation"] = { breadcrumb = "Kanji missing okurigana designation", description = "{{{langname}}} kanji entries in which one or more kun readings entered into {{tl|{{{langcode}}}-readings}} is missing a hyphen denoting okurigana.", toc_template = "Hani-categoryTOC", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["terms by the individual characters in their historical spellings"] = { breadcrumb = "Historical", description = "{{{langname}}} terms categorized by whether their spellings in the {{w|historical kana orthography}} included certain individual characters.", parents = {{name = "terms by their individual characters", sort = " "}}, } labels["verbs without transitivity"] = { description = "{{{langname}}} verbs missing the {{code|=tr=}} parameter from their headword templates.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["yojijukugo"] = { topright = "{{wp|Yojijukugo}}", description = "{{{langname}}} four-[[kanji]] compound terms, {{ja-r|四%字 熟%語|よ%じ じゅく%ご}}, with idiomatic meanings; typically derived from Classical Chinese, Buddhist scripture or traditional Japanese proverbs.", additional = "Compare Chinese {{w|chengyu}} and Korean {{w|sajaseong-eo}}.", umbrella = "four-character idioms", parents = {"idioms"}, } -- FIXME: Only works for 0 through 19. local word_to_number = {} for k, v in pairs(m_numeric.ones_position) do word_to_number[v] = k end local periods = { historical = true, ancient = true, } local function get_period_text_and_reading_type_link(period, reading_type) if period and not periods[period] then return nil end local period_text = period and period .. " " or nil -- Allow periods (historical or ancient) by themselves; they will parse as reading types. if not period and periods[reading_type] then return nil, reading_type end local reading_type_link = "[[Appendix:Japanese glossary#" .. reading_type .. "|" .. reading_type .. "]]" return period_text, reading_type_link end local function get_sc(str) return match(str:gsub("[%s%p]+", ""), "[^" .. Hira:getCharacters() .. "]") and Jpan or Hira end local function get_tagged_reading(reading, lang) return tag_text(reading, lang, get_sc(reading)) end local function get_reading_link(reading, lang, period, link) local hist = periods[period] reading = reading:gsub("[%.%-%s]+", "") return full_link({ lang = lang, sc = get_sc(reading), term = link or reading:gsub("・", ""), -- If we have okurigana, demarcate furigana. alt = reading:gsub("^(.-)・", "<span style=\"border-top:1px solid;position:relative;padding:1px;\">%1<span style=\"position:absolute;top:0;bottom:67%%;right:0%%;border-right:1px solid;\"></span></span>"), tr = kana_to_romaji((reading:gsub("・", ".")), lang:getCode(), nil, {keep_dot = true, hist = hist}) :gsub("^(.-)%.", "<u>%1</u>"), pos = reading:find("・", 1, true) and get_tagged_reading((reading:gsub("^.-・", "~")), lang) or nil }, "term") end local function is_on_subtype(reading_type) return reading_type:find(".on$") end insert(handlers, function(data) local n =data.label:match("^terms with ([1-9]%d*) kanji$") if not n then return end local sortkey = require("Module:category tree").numeral_sortkey(n, 2097152) return { breadcrumb = n, description = ("{{{langname}}} terms containing exactly %d kanji."):format(n), -- TODO: implement this using the same mechanism used to implement parents (i.e. avoiding the need for raw categories). -- umbrella = { -- breadcrumb = ("%d kanji"):format(n), -- parents = {{name = "terms by number of kanji subcategories by language", sort = sortkey}}, -- }, parents = {{name = ("terms by number of kanji"), sort = sortkey}} } end) insert(handlers, function(data) local label_pref, kana = data.label:match("^(terms historically spelled with )" .. kana_capture .. "$") if not kana then return end local lang = data.lang return { description = "{{{langname}}} terms spelled with " .. get_reading_link(kana, lang, "historical") .. " in the {{w|historical kana orthography}}.", displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(kana, lang), breadcrumb = "historical", parents = { {name = "terms spelled with " .. kana, sort = " "}, {name = "terms by the individual characters in their historical spellings", sort = lang:makeSortKey(kana)} }, umbrella = false, } end) insert(handlers, function(data) local count, plural = data.label:match("^kanji readings with (.+) mora(e?)$") -- Make sure 'one' goes with singular and other numbers with plural. if not count or (count == "one") ~= (plural == "") then return end local num = word_to_number[count] if not num then return nil end return { description = "{{{langname}}} kanji readings containing " .. count .. " mora" .. plural .. ".", breadcrumb = num, parents = {{name = "kanji readings by number of morae", sort = num}}, umbrella = false, } end) insert(handlers, function(data) local label_pref, period, reading_type, reading = match(data.label, "^(kanji with ([a-z]-) ?([%a']+) reading )" .. kana_capture .. "$") if not period then return end period = period ~= "" and period or nil local period_text, reading_type_link = get_period_text_and_reading_type_link(period, reading_type) if not reading_type_link then return end local lang = data.lang -- Compute parents. local parents, breadcrumb = {} if reading:find("・", 1, true) then local okurigana = reading:match("・(.*)") insert(parents, { name = "kanji with " .. (period_text or "") .. reading_type .. " reading " .. reading:match("(.-)・"), -- Sort by okurigana, since all coordinate categories will have the same furigana. sort = (lang:makeSortKey(okurigana)) }) breadcrumb = "~" .. okurigana else insert(parents, { name = "kanji by " .. (period_text or "") .. reading_type .. " reading", sort = (lang:makeSortKey(reading)) }) breadcrumb = reading end if is_on_subtype(reading_type) then insert(parents, {name = "kanji with " .. (period_text or "") .. "on reading " .. reading, sort = reading_type}) elseif period_text then insert(parents, {name = "kanji with " .. period_text .. "reading " .. reading, sort = reading_type}) end if not period_text then insert(parents, {name = "kanji read as " .. reading, sort = reading_type}) end return { description = "{{{langname}}} [[kanji]] with the " .. (period_text or "") .. reading_type_link .. " reading " .. get_reading_link(reading, lang, period or reading_type) .. ".", displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(reading, lang), breadcrumb = get_tagged_reading(breadcrumb, lang), parents = parents, umbrella = false, } end) insert(handlers, function(data) local period, reading_type = match(data.label, "^kanji by ([a-z]-) ?([%a']+) reading$") if not period then return end period = period ~= "" and period or nil local period_text, reading_type_link = get_period_text_and_reading_type_link(period, reading_type) if not reading_type_link then return nil end -- Compute parents. local parents = { is_on_subtype(reading_type) and {name = "kanji by " .. (period_text or "") .. "on reading", sort = reading_type} or period_text and {name = "kanji by " .. reading_type .. " reading", sort = period} or {name = "kanji by reading", sort = reading_type} } if period_text then insert(parents, {name = "kanji by " .. period_text .. "reading", sort = reading_type}) end -- Compute description. local description = "{{{langname}}} [[kanji]] categorized by " .. (period_text or "") .. reading_type_link .. " reading." return { description = description, breadcrumb = (period_text or "") .. reading_type, parents = parents, umbrella = false, } end) insert(handlers, function(data) local label_pref, reading = match(data.label, "^(kanji read as )" .. kana_capture .. "$") if not reading then return end local args = require("Module:parameters").process(data.args, { ["histconsol"] = true, }) local lang = data.lang local parents, breadcrumb = {} if reading:find("・", 1, true) then local okurigana = reading:match("・(.*)") insert(parents, { name = "kanji read as " .. reading:match("(.-)・"), -- Sort by okurigana, since all coordinate categories will have the same furigana. sort = (lang:makeSortKey(okurigana)) }) breadcrumb = "~" .. okurigana else insert(parents, { name = "kanji by reading", sort = (lang:makeSortKey(reading)) }) breadcrumb = reading end local addl local period_text if args.histconsol then period_text = "historical" addl = ("This is a [[Wikipedia:Historical kana orthography|historical]] [[Wikipedia:Kanazukai|reading]], now " .. "consolidated with the [[Wikipedia:Modern kana usage|modern reading]] of " .. get_reading_link(args.histconsol, lang, nil, ("Category:Japanese kanji read as %s"):format(args.histconsol)) .. ".") end return { description = "{{{langname}}} [[kanji]] read as " .. get_reading_link(reading, lang, period_text) .. ".", additional = addl, displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(reading, lang), breadcrumb = get_tagged_reading(breadcrumb, lang), parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local label_pref, reading = match(data.label, "^(terms spelled with kanji read as )" .. kana_capture .. "$") if not reading then return end -- Compute parents. local lang = data.lang local sort_key = (lang:makeSortKey(reading)) local mora_count = require("Module:ja").count_morae(reading) local mora_count_words = m_numeric.spell_number(tostring(mora_count)) local parents = { {name = "terms by kanji readings", sort = sort_key}, {name = "kanji readings with " .. mora_count_words .. " mora" .. (mora_count > 1 and "e" or ""), sort = sort_key}, {name = "kanji read as " .. reading, sort = " "}, } local tagged_reading = get_tagged_reading(reading, lang) return { description = "{{{langname}}} terms that contain kanji that exhibit a reading of " .. get_reading_link(reading, lang) .. " in those terms prior to any sound changes.", displaytitle = "{{{langname}}} " .. label_pref .. tagged_reading, breadcrumb = tagged_reading, parents = parents, umbrella = false, } end) insert(handlers, function(data) local kanji, reading = match(data.label, "^terms spelled with (.) read as " .. kana_capture .. "$") if not kanji then return nil end local args = require("Module:parameters").process(data.args, { [1] = {list = true}, }) local lang = data.lang if #args[1] == 0 then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms spelled with KANJI read as READING\", at least one reading type (e.g. <code>kun</code> or <code>on</code>) must be specified using <code>1=</code>, <code>2=</code>, <code>3=</code>, etc.") end local yomi_types, parents = {}, {} for _, yomi, category in ipairs(args[1]) do local yomi_data = yomi_data[yomi] if not yomi_data then error("The yomi type \"" .. yomi .. "\" is not recognized.") end category = yomi_data.kanji_category if not category then error("The yomi type \"" .. yomi .. "\" is not valid for this type of category.") end insert(yomi_types, yomi_data.link) insert(parents, { name = "terms spelled with kanji with " .. category .. " readings", sort = (lang:makeSortKey(reading)) }) end insert(parents, 1, {name = "terms spelled with " .. kanji, sort = (lang:makeSortKey(reading))}) insert(parents, 2, {name = "terms spelled with kanji read as " .. reading, sort = Hani_sort(kanji)}) yomi_types = (#yomi_types > 1 and "one of " or "") .. "its " .. require("Module:table").serialCommaJoin(yomi_types, {conj = "or"}) .. " reading" .. (#yomi_types > 1 and "s" or "") local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_reading = get_tagged_reading(reading, lang) return { description = "{{{langname}}} terms spelled with {{l|{{{langcode}}}|" .. kanji .. "}} with " .. yomi_types .. " of " .. get_reading_link(reading, lang) .. ".", displaytitle = "{{{langname}}} terms spelled with " .. tagged_kanji .. " read as " .. tagged_reading, breadcrumb = "read as " .. tagged_reading, parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local affix, kanji, reading = data.label:match("^terms ([a-z]+fix)ed with (.+) read as " .. kana_capture .. "$") if not affix or not kanji or not reading then return nil end local args = require("Module:parameters").process(data.args, { [1] = {list = true}, }) local lang = data.lang if #args[1] == 0 then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms AFFIXed with KANJI read as READING\", at least one reading type (e.g. <code>kun</code> or <code>on</code>) must be specified using <code>1=</code>, <code>2=</code>, <code>3=</code>, etc.") end local yomi_types = {} for _, yomi, category in ipairs(args[1]) do local yomi_data = yomi_data[yomi] if not yomi_data then error("The yomi type \"" .. yomi .. "\" is not recognized.") end category = yomi_data.kanji_category if not category then error("The yomi type \"" .. yomi .. "\" is not valid for this type of category.") end insert(yomi_types, yomi_data.link) end yomi_types = (#yomi_types > 1 and "one of " or "") .. "its " .. require("Module:table").serialCommaJoin(yomi_types, {conj = "or"}) .. " reading" .. (#yomi_types > 1 and "s" or "") local description = "{{{langname}}} terms " .. affix .. "ed with {{l|{{{langcode}}}|" .. kanji .. "}} with " .. yomi_types .. " of " .. get_reading_link(reading, lang) .. "." local what_categorizes_msg = require("Module:category tree/fam/jpx/what-categorizes-msg") .get_what_categorizes_msg(kanji, reading, affix) if what_categorizes_msg then description = description .. "\n\n" .. what_categorizes_msg end local parents = {} table.insert(parents, {name = "terms " .. affix .. "ed with " .. kanji, sort = (lang:makeSortKey(reading))}) if mw.title.new("Category:" .. lang:getCanonicalName() .. " terms spelled with " .. kanji .. " read as " .. reading).exists then table.insert(parents, {name = "terms spelled with " .. kanji .. " read as " .. reading, sort = (lang:makeSortKey(reading)), args=data.args}) end local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_reading = get_tagged_reading(reading, lang) return { description = description, displaytitle = "{{{langname}}} terms " .. affix .. "ed with " .. tagged_kanji .. " read as " .. tagged_reading, breadcrumb = "read as " .. reading, parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local kanji, daiyoji = match(data.label, "^terms with (.) replaced by daiyōji (.)$") if not kanji then return nil end local args = require("Module:parameters").process(data.args, { ["sort"] = true, }) local lang = data.lang if not args.sort then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms with KANJI replaced by daiyōji DAIYOJI\", the sort key must be specified using sort=") end local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_daiyoji = get_tagged_reading(daiyoji, lang) return { description = "{{{langname}}} terms with {{l|{{{langcode}}}|" .. kanji .. "}} replaced by [[Appendix:Japanese glossary#daiyouji|daiyōji]] {{l|{{{langcode}}}|" .. daiyoji .. "}}.", displaytitle = "{{{langname}}} terms with " .. tagged_kanji .. " replaced by daiyōji " .. tagged_daiyoji, breadcrumb = tagged_kanji .. " replaced by daiyōji " .. tagged_daiyoji, parents = {{name = "terms spelled with daiyōji", sort = args.sort}}, umbrella = false, }, true end) return {LABELS = labels, HANDLERS = handlers} ea2zmcmhguqw3ivdjan9pb199sxgqx3 88825 88824 2026-08-06T20:17:39Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/jpx]] 88824 Scribunto text/plain local labels = {} local handlers = {} local m_str_utils = require("Module:string utilities") local concat = table.concat local full_link = require("Module:links").full_link local insert = table.insert local Hani_sort = require("Module:Hani-sortkey").makeSortKey local match = m_str_utils.match local sort = table.sort local tag_text = require("Module:script_utilities").tag_text local ucfirst = m_str_utils.ucfirst local Hira = require("Module:scripts").getByCode("Hira") local Jpan = require("Module:scripts").getByCode("Jpan") local kana_to_romaji = require("Module:Hrkt-translit").tr local m_numeric = require("Module:ConvertNumeric") local kana_capture = "([-" .. require("Module:ja/data/range").kana .. "・]+)" local yomi_data = require("Module:kanjitab/data") labels["adnominals"] = { description = "{{{langname}}} adnominals, or {{ja-r|連%体%詞|れん%たい%し}}, which modify nouns, and do not conjugate or [[predicate#Verb|predicate]].", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["hiragana"] = { description = "{{{langname}}} terms with hiragana {{mdash}} {{ja-r|平%仮%名|ひら%が%な}} {{mdash}} forms, sorted by conventional hiragana sequence. The hiragana form is a [[phonetic]] representation of that word. " .. "Wiktionary represents {{{langname}}}-language segments in three ways: in normal form (with [[kanji]], if appropriate), in [[hiragana]] " .. "form (this differs from kanji form only when the segment contains kanji), and in [[romaji]] form.", additional = "''See also'' [[:Category:{{{langname}}} katakana]]", toc_template = "Hira-categoryTOC", toc_template_full = "Hira-categoryTOC/full", parents = { {name = "{{{langcat}}}", raw = true}, "Category:Hiragana script characters", } } labels["historical hiragana"] = { description = "{{{langname}}} historical [[hiragana]].", additional = "''See also'' [[:Category:{{{langname}}} historical katakana]].", toc_template = "Hira-categoryTOC", toc_template_full = "Hira-categoryTOC/full", parents = { "hiragana", {name = "{{{langcat}}}", raw = true}, "Category:Hiragana script characters", } } labels["katakana"] = { description = "{{{langname}}} terms with katakana {{mdash}} {{ja-r|片%仮%名|かた%か%な}} {{mdash}} forms, sorted by conventional katakana sequence. Katakana is used primarily for transliterations of foreign words, including old Chinese hanzi not used in [[shinjitai]].", additional = "''See also'' [[:Category:{{{langname}}} hiragana]]", toc_template = "Kana-categoryTOC", toc_template_full = "Kana-categoryTOC/full", parents = { {name = "{{{langcat}}}", raw = true}, "Category:Katakana script characters", } } labels["historical katakana"] = { description = "{{{langname}}} historical [[katakana]].", additional = "''See also'' [[:Category:{{{langname}}} historical hiragana]].", toc_template = "Kana-categoryTOC", toc_template_full = "Kana-categoryTOC/full", parents = { "katakana", {name = "{{{langcat}}}", raw = true}, "Category:Katakana script characters", } } labels["terms spelled with mixed kana"] = { description = "{{{langname}}} terms which combine [[hiragana]] and [[katakana]] characters, potentially with [[kanji]] too.", parents = { {name = "{{{langcat}}}", raw = true}, "hiragana", "katakana", }, } labels["kanji"] = { topright = "{{wp|Kanji}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", toc_template = "Hani-categoryTOC", umbrella = "Han characters", parents = "logograms", } labels["kanji by reading"] = { description = "{{{langname}}} kanji categorized by reading.", parents = {{name = "kanji", sort = "reading"}}, } labels["makurakotoba"] = { topright = "{{wp|Makurakotoba}}", description = "{{{langname}}} idioms used in poetry to introduce specific words.", parents = {"idioms"}, } labels["terms by kanji readings"] = { description = "{{{langname}}} categories grouped with regard to the readings of the kanji with which they are spelled.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms by reading pattern"] = { description = "{{{langname}}} categories with terms grouped by their reading patterns.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms by number of kanji"] = { description = "{{{langname}}} terms categorized by number of kanji.", parents = {"terms by orthographic property"}, } local function handle_onyomi_list(category, category_type, cat_yomi_type) local onyomi, seen = {}, {} for _, yomi in pairs(yomi_data) do if not seen[yomi] and yomi.onyomi then local yomi_catname = yomi[category_type] if yomi_catname ~= false then local yomi_type = yomi.type if yomi_type ~= "on'yomi" and yomi_type ~= cat_yomi_type then insert(onyomi, "[[:Category:{{{langname}}} " .. category:gsub("{{{yomi_catname}}}", yomi_catname) .. "]]") end end end seen[yomi] = true end sort(onyomi) return onyomi end local function add_yomi_category(category, category_type, parent, description) for _, yomi in pairs(yomi_data) do local yomi_catname = yomi[category_type] if yomi_catname ~= false then local yomi_type = yomi.type local yomi_desc = yomi.link or yomi_catname if yomi.description then yomi_desc = yomi_desc .. "; " .. yomi.description end local label = { description = description .. " " .. yomi_desc .. ".", breadcrumb = yomi_type, parents = {{name = parent, sort = yomi_catname}}, } if yomi.onyomi then local onyomi = handle_onyomi_list(category, category_type, yomi_type) label.additional = "Categories of terms with " .. (yomi_type == "on'yomi" and "more" or "other") .. " specific types of on'yomi readings can be found in the following categories:\n* " .. concat(onyomi, "\n* ") if yomi_type ~= "on'yomi" then insert(label.parents, 1, { name = (category:gsub("{{{yomi_catname}}}", yomi_data.on[category_type])), sort = yomi_catname }) end end labels[category:gsub("{{{yomi_catname}}}", yomi_catname)] = label end end end add_yomi_category( "terms read with {{{yomi_catname}}}", "reading_category", "terms by reading pattern", "{{{langname}}} terms read with" ) add_yomi_category( "terms spelled with kanji with {{{yomi_catname}}} readings", "kanji_category", "terms by kanji reading type", "{{{langname}}} categories with terms that are spelled with one or more kanji read with" ) labels["terms with missing yomi"] = { description = "{{{langname}}} terms where at least one [[Appendix:Japanese glossary#yomi|yomi]] is missing from {{tl|{{{langcode}}}-kanjitab}}.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["terms with IPA pronunciation with pitch accent"] = { description = "{{{langname}}} terms with pronunciations that have {{w|Japanese pitch accent|pitch accent}} specified.", additional = "Pitch accent can be specified in {{tl|{{{langcode}}}-pron}} with the {{code|=acc=}} parameter.", can_be_empty = true, parents = {"entry maintenance", "pitch accent"}, } labels["terms with IPA pronunciation missing pitch accent"] = { description = "{{{langname}}} terms with pronunciations that do not have a {{w|Japanese pitch accent|pitch accent}} specified.", additional = "Pitch accent can be specified in {{tl|{{{langcode}}}-pron}} with the {{code|=acc=}} parameter.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["pitch accent"] = { description = "{{{langname}}} terms regarding {{w|Japanese pitch accent|pitch accent}} pronunciation.", can_be_empty = true, parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms with Heiban pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[平板型|Heiban]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Atamadaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[頭高型|Atamadaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Nakadaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[中高型|Nakadaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Odaka pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[尾高型|Odaka]] {{w|Japanese pitch accent|pitch accent}}.", can_be_empty = true, parents = {"pitch accent"} } labels["terms with complex pitch accent (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) complex {{w|Japanese pitch accent|pitch accent}}, as in having more than one {{m|ja|アクセント句}}.", can_be_empty = true, parents = {"pitch accent"} } labels["pitch accent deaccenting before の"] = { description = "{{{langname}}} terms with {{w|Japanese pitch accent|pitch accent}} pronunciations that have exceptional deaccenting or lack thereof before の ({{ja-deaccenting-before-no}}).", can_be_empty = true, parents = {"pitch accent"} } labels["terms with Odaka pitch accent not deaccented before の (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[尾高型|Odaka]] {{w|Japanese pitch accent|pitch accent}} and do not become deaccented before の ({{ja-deaccenting-before-no}}).\n\nTerms are placed in this category using {{tl|ja-odaka-deaccent-exception}}.", can_be_empty = true, parents = {"pitch accent deaccenting before の"} } labels["terms with Nakadaka pitch accent deaccented before の (Tōkyō)"] = { description = "{{{langname}}} terms with pronunciations that are (Tōkyō) [[中高型|Nakadaka]] {{w|Japanese pitch accent|pitch accent}} and become deaccented before の ({{ja-deaccenting-before-no}}).\n\nTerms are placed in this category using {{tl|ja-nakadaka-deaccent}}.", can_be_empty = true, parents = {"pitch accent deaccenting before の"} } labels["terms by kanji reading type"] = { description = "{{{langname}}} categories with terms grouped with regard to the types of readings of the kanji with which " .. "they are spelled; broadly, those of Chinese origin, {{ja-r|音|おん}} readings, and those of non-Chinese origin, {{ja-r|訓|くん}} readings.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms spelled with ateji"] = { topright = "{{wp|Ateji}}", description = "{{{langname}}} terms containing one or more [[Appendix:Japanese glossary#ateji|ateji]] {{mdash}} {{ja-r|当て字|あてじ}} {{mdash}} which are [[kanji]] used to represent sounds rather than meanings (though meaning may have some influence on which kanji are chosen).", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["terms spelled with daiyōji"] = { description = "Japanese terms spelled using [[Appendix:Japanese glossary#daiyouji|daiyōji]], categorized using {{temp|ja-daiyouji}}.", parents = {"terms by etymology"}, } labels["terms spelled with jukujikun"] = { description = "{{{langname}}} terms containing one or more [[Appendix:Japanese glossary#jukujikun|jukujikun]] {{mdash}} {{ja-r|熟%字%訓|じゅく%じ%くん}} {{mdash}} which are [[kanji]] used to represent meanings rather than sounds.", parents = {{name = "{{{langcat}}}", raw = true}}, } local function add_grade_categories(grade, desc, wp, only_one, parent, sort) local grade_kanji = grade .. " kanji" local topright = wp and ("{{wp|%s}}"):format(ucfirst(grade_kanji)) or nil labels[grade_kanji] = { topright = topright, description = "{{{langname}}} kanji " .. desc, toc_template = "Hani-categoryTOC", parents = {{ name = parent and (parent .. " kanji") or "kanji", sort = sort or grade }}, } labels["terms spelled with " .. grade_kanji] = { topright = topright, description = "{{{langname}}} terms spelled with " .. (only_one and "at least one " or "") .. "kanji " .. desc, parents = {{ name = parent and ("terms spelled with " .. parent .. " kanji") or "terms by orthographic property", sort = sort or grade }}, } end for i = 1, 6 do local ord = m_numeric.ones_position_ord[i] add_grade_categories( ord .. " grade", "taught in the " .. ord .. " grade of elementary school, as designated by the the official list of {{ja-r|教%育 漢%字|きょう%いく かん%じ|education kanji}}.", false, false, "kyōiku", i ) end add_grade_categories( "kyōiku", "on the official list of {{ja-r|教%育 漢%字|きょう%いく かん%じ|education kanji}}.", true, false, "jōyō" ) add_grade_categories( "secondary school", "on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}} that are generally taught in secondary school.", false, false, "jōyō" ) add_grade_categories( "jōyō", "on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}}.", true, false ) add_grade_categories( "tōyō", "on the official list of {{ja-r|当%用 漢%字|とう%よう かん%じ|general-use characters}}, which was used from 1946{{ndash}}1981 until the publication of the list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}}.", true, false ) add_grade_categories( "jinmeiyō", "on the official list of {{ja-r|人%名%用 漢%字|じん%めい%-よう かん%じ|kanji for use in personal names}}.", true, true ) add_grade_categories( "hyōgai", "not included on the official list of {{ja-r|常%用 漢%字|じょう%よう かん%じ|regular-use characters}} or {{ja-r|人%名%用 漢%字|じん%めい%-よう かん%じ|kanji for use in personal names}}, known as {{ja-r|表%外 漢%字|ひょう%がい かん%じ}} or {{ja-r|表%外%字|ひょう%がい%じ|unlisted characters}}.", true, true ) labels["terms with multiple readings"] = { description = "{{{langname}}} terms with multiple pronunciations (hence multiple [[kana]] spellings).", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["kanji readings by number of morae"] = { description = "{{{langname}}} categories grouped with regard to the number of morae in their kanji readings.", parents = {{name = "{{{langcat}}}", raw = true}}, } labels["single-kanji terms"] = { description = "{{{langname}}} terms written as a single kanji.", parents = { "terms by orthographic property", {name = "terms with 1 kanji", sort = " "}, }, } labels["kanji with kun readings missing okurigana designation"] = { breadcrumb = "Kanji missing okurigana designation", description = "{{{langname}}} kanji entries in which one or more kun readings entered into {{tl|{{{langcode}}}-readings}} is missing a hyphen denoting okurigana.", toc_template = "Hani-categoryTOC", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["terms by the individual characters in their historical spellings"] = { breadcrumb = "Historical", description = "{{{langname}}} terms categorized by whether their spellings in the {{w|historical kana orthography}} included certain individual characters.", parents = {{name = "terms by their individual characters", sort = " "}}, } labels["verbs without transitivity"] = { description = "{{{langname}}} verbs missing the {{code|=tr=}} parameter from their headword templates.", hidden = true, can_be_empty = true, parents = {"entry maintenance"}, } labels["yojijukugo"] = { topright = "{{wp|Yojijukugo}}", description = "{{{langname}}} four-[[kanji]] compound terms, {{ja-r|四%字 熟%語|よ%じ じゅく%ご}}, with idiomatic meanings; typically derived from Classical Chinese, Buddhist scripture or traditional Japanese proverbs.", additional = "Compare Chinese {{w|chengyu}} and Korean {{w|sajaseong-eo}}.", umbrella = "four-character idioms", parents = {"idioms"}, } -- FIXME: Only works for 0 through 19. local word_to_number = {} for k, v in pairs(m_numeric.ones_position) do word_to_number[v] = k end local periods = { historical = true, ancient = true, } local function get_period_text_and_reading_type_link(period, reading_type) if period and not periods[period] then return nil end local period_text = period and period .. " " or nil -- Allow periods (historical or ancient) by themselves; they will parse as reading types. if not period and periods[reading_type] then return nil, reading_type end local reading_type_link = "[[Appendix:Japanese glossary#" .. reading_type .. "|" .. reading_type .. "]]" return period_text, reading_type_link end local function get_sc(str) return match(str:gsub("[%s%p]+", ""), "[^" .. Hira:getCharacters() .. "]") and Jpan or Hira end local function get_tagged_reading(reading, lang) return tag_text(reading, lang, get_sc(reading)) end local function get_reading_link(reading, lang, period, link) local hist = periods[period] reading = reading:gsub("[%.%-%s]+", "") return full_link({ lang = lang, sc = get_sc(reading), term = link or reading:gsub("・", ""), -- If we have okurigana, demarcate furigana. alt = reading:gsub("^(.-)・", "<span style=\"border-top:1px solid;position:relative;padding:1px;\">%1<span style=\"position:absolute;top:0;bottom:67%%;right:0%%;border-right:1px solid;\"></span></span>"), tr = kana_to_romaji((reading:gsub("・", ".")), lang:getCode(), nil, {keep_dot = true, hist = hist}) :gsub("^(.-)%.", "<u>%1</u>"), pos = reading:find("・", 1, true) and get_tagged_reading((reading:gsub("^.-・", "~")), lang) or nil }, "term") end local function is_on_subtype(reading_type) return reading_type:find(".on$") end insert(handlers, function(data) local n =data.label:match("^terms with ([1-9]%d*) kanji$") if not n then return end local sortkey = require("Module:category tree").numeral_sortkey(n, 2097152) return { breadcrumb = n, description = ("{{{langname}}} terms containing exactly %d kanji."):format(n), -- TODO: implement this using the same mechanism used to implement parents (i.e. avoiding the need for raw categories). -- umbrella = { -- breadcrumb = ("%d kanji"):format(n), -- parents = {{name = "terms by number of kanji subcategories by language", sort = sortkey}}, -- }, parents = {{name = ("terms by number of kanji"), sort = sortkey}} } end) insert(handlers, function(data) local label_pref, kana = data.label:match("^(terms historically spelled with )" .. kana_capture .. "$") if not kana then return end local lang = data.lang return { description = "{{{langname}}} terms spelled with " .. get_reading_link(kana, lang, "historical") .. " in the {{w|historical kana orthography}}.", displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(kana, lang), breadcrumb = "historical", parents = { {name = "terms spelled with " .. kana, sort = " "}, {name = "terms by the individual characters in their historical spellings", sort = lang:makeSortKey(kana)} }, umbrella = false, } end) insert(handlers, function(data) local count, plural = data.label:match("^kanji readings with (.+) mora(e?)$") -- Make sure 'one' goes with singular and other numbers with plural. if not count or (count == "one") ~= (plural == "") then return end local num = word_to_number[count] if not num then return nil end return { description = "{{{langname}}} kanji readings containing " .. count .. " mora" .. plural .. ".", breadcrumb = num, parents = {{name = "kanji readings by number of morae", sort = num}}, umbrella = false, } end) insert(handlers, function(data) local label_pref, period, reading_type, reading = match(data.label, "^(kanji with ([a-z]-) ?([%a']+) reading )" .. kana_capture .. "$") if not period then return end period = period ~= "" and period or nil local period_text, reading_type_link = get_period_text_and_reading_type_link(period, reading_type) if not reading_type_link then return end local lang = data.lang -- Compute parents. local parents, breadcrumb = {} if reading:find("・", 1, true) then local okurigana = reading:match("・(.*)") insert(parents, { name = "kanji with " .. (period_text or "") .. reading_type .. " reading " .. reading:match("(.-)・"), -- Sort by okurigana, since all coordinate categories will have the same furigana. sort = (lang:makeSortKey(okurigana)) }) breadcrumb = "~" .. okurigana else insert(parents, { name = "kanji by " .. (period_text or "") .. reading_type .. " reading", sort = (lang:makeSortKey(reading)) }) breadcrumb = reading end if is_on_subtype(reading_type) then insert(parents, {name = "kanji with " .. (period_text or "") .. "on reading " .. reading, sort = reading_type}) elseif period_text then insert(parents, {name = "kanji with " .. period_text .. "reading " .. reading, sort = reading_type}) end if not period_text then insert(parents, {name = "kanji read as " .. reading, sort = reading_type}) end return { description = "{{{langname}}} [[kanji]] with the " .. (period_text or "") .. reading_type_link .. " reading " .. get_reading_link(reading, lang, period or reading_type) .. ".", displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(reading, lang), breadcrumb = get_tagged_reading(breadcrumb, lang), parents = parents, umbrella = false, } end) insert(handlers, function(data) local period, reading_type = match(data.label, "^kanji by ([a-z]-) ?([%a']+) reading$") if not period then return end period = period ~= "" and period or nil local period_text, reading_type_link = get_period_text_and_reading_type_link(period, reading_type) if not reading_type_link then return nil end -- Compute parents. local parents = { is_on_subtype(reading_type) and {name = "kanji by " .. (period_text or "") .. "on reading", sort = reading_type} or period_text and {name = "kanji by " .. reading_type .. " reading", sort = period} or {name = "kanji by reading", sort = reading_type} } if period_text then insert(parents, {name = "kanji by " .. period_text .. "reading", sort = reading_type}) end -- Compute description. local description = "{{{langname}}} [[kanji]] categorized by " .. (period_text or "") .. reading_type_link .. " reading." return { description = description, breadcrumb = (period_text or "") .. reading_type, parents = parents, umbrella = false, } end) insert(handlers, function(data) local label_pref, reading = match(data.label, "^(kanji read as )" .. kana_capture .. "$") if not reading then return end local args = require("Module:parameters").process(data.args, { ["histconsol"] = true, }) local lang = data.lang local parents, breadcrumb = {} if reading:find("・", 1, true) then local okurigana = reading:match("・(.*)") insert(parents, { name = "kanji read as " .. reading:match("(.-)・"), -- Sort by okurigana, since all coordinate categories will have the same furigana. sort = (lang:makeSortKey(okurigana)) }) breadcrumb = "~" .. okurigana else insert(parents, { name = "kanji by reading", sort = (lang:makeSortKey(reading)) }) breadcrumb = reading end local addl local period_text if args.histconsol then period_text = "historical" addl = ("This is a [[Wikipedia:Historical kana orthography|historical]] [[Wikipedia:Kanazukai|reading]], now " .. "consolidated with the [[Wikipedia:Modern kana usage|modern reading]] of " .. get_reading_link(args.histconsol, lang, nil, ("Category:Japanese kanji read as %s"):format(args.histconsol)) .. ".") end return { description = "{{{langname}}} [[kanji]] read as " .. get_reading_link(reading, lang, period_text) .. ".", additional = addl, displaytitle = "{{{langname}}} " .. label_pref .. get_tagged_reading(reading, lang), breadcrumb = get_tagged_reading(breadcrumb, lang), parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local label_pref, reading = match(data.label, "^(terms spelled with kanji read as )" .. kana_capture .. "$") if not reading then return end -- Compute parents. local lang = data.lang local sort_key = (lang:makeSortKey(reading)) local mora_count = require("Module:ja").count_morae(reading) local mora_count_words = m_numeric.spell_number(tostring(mora_count)) local parents = { {name = "terms by kanji readings", sort = sort_key}, {name = "kanji readings with " .. mora_count_words .. " mora" .. (mora_count > 1 and "e" or ""), sort = sort_key}, {name = "kanji read as " .. reading, sort = " "}, } local tagged_reading = get_tagged_reading(reading, lang) return { description = "{{{langname}}} terms that contain kanji that exhibit a reading of " .. get_reading_link(reading, lang) .. " in those terms prior to any sound changes.", displaytitle = "{{{langname}}} " .. label_pref .. tagged_reading, breadcrumb = tagged_reading, parents = parents, umbrella = false, } end) insert(handlers, function(data) local kanji, reading = match(data.label, "^terms spelled with (.) read as " .. kana_capture .. "$") if not kanji then return nil end local args = require("Module:parameters").process(data.args, { [1] = {list = true}, }) local lang = data.lang if #args[1] == 0 then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms spelled with KANJI read as READING\", at least one reading type (e.g. <code>kun</code> or <code>on</code>) must be specified using <code>1=</code>, <code>2=</code>, <code>3=</code>, etc.") end local yomi_types, parents = {}, {} for _, yomi, category in ipairs(args[1]) do local yomi_data = yomi_data[yomi] if not yomi_data then error("The yomi type \"" .. yomi .. "\" is not recognized.") end category = yomi_data.kanji_category if not category then error("The yomi type \"" .. yomi .. "\" is not valid for this type of category.") end insert(yomi_types, yomi_data.link) insert(parents, { name = "terms spelled with kanji with " .. category .. " readings", sort = (lang:makeSortKey(reading)) }) end insert(parents, 1, {name = "terms spelled with " .. kanji, sort = (lang:makeSortKey(reading))}) insert(parents, 2, {name = "terms spelled with kanji read as " .. reading, sort = Hani_sort(kanji)}) yomi_types = (#yomi_types > 1 and "one of " or "") .. "its " .. require("Module:table").serialCommaJoin(yomi_types, {conj = "or"}) .. " reading" .. (#yomi_types > 1 and "s" or "") local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_reading = get_tagged_reading(reading, lang) return { description = "{{{langname}}} terms spelled with {{l|{{{langcode}}}|" .. kanji .. "}} with " .. yomi_types .. " of " .. get_reading_link(reading, lang) .. ".", displaytitle = "{{{langname}}} terms spelled with " .. tagged_kanji .. " read as " .. tagged_reading, breadcrumb = "read as " .. tagged_reading, parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local affix, kanji, reading = data.label:match("^terms ([a-z]+fix)ed with (.+) read as " .. kana_capture .. "$") if not affix or not kanji or not reading then return nil end local args = require("Module:parameters").process(data.args, { [1] = {list = true}, }) local lang = data.lang if #args[1] == 0 then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms AFFIXed with KANJI read as READING\", at least one reading type (e.g. <code>kun</code> or <code>on</code>) must be specified using <code>1=</code>, <code>2=</code>, <code>3=</code>, etc.") end local yomi_types = {} for _, yomi, category in ipairs(args[1]) do local yomi_data = yomi_data[yomi] if not yomi_data then error("The yomi type \"" .. yomi .. "\" is not recognized.") end category = yomi_data.kanji_category if not category then error("The yomi type \"" .. yomi .. "\" is not valid for this type of category.") end insert(yomi_types, yomi_data.link) end yomi_types = (#yomi_types > 1 and "one of " or "") .. "its " .. require("Module:table").serialCommaJoin(yomi_types, {conj = "or"}) .. " reading" .. (#yomi_types > 1 and "s" or "") local description = "{{{langname}}} terms " .. affix .. "ed with {{l|{{{langcode}}}|" .. kanji .. "}} with " .. yomi_types .. " of " .. get_reading_link(reading, lang) .. "." local what_categorizes_msg = require("Module:category tree/fam/jpx/what-categorizes-msg") .get_what_categorizes_msg(kanji, reading, affix) if what_categorizes_msg then description = description .. "\n\n" .. what_categorizes_msg end local parents = {} table.insert(parents, {name = "terms " .. affix .. "ed with " .. kanji, sort = (lang:makeSortKey(reading))}) if mw.title.new("Category:" .. lang:getCanonicalName() .. " terms spelled with " .. kanji .. " read as " .. reading).exists then table.insert(parents, {name = "terms spelled with " .. kanji .. " read as " .. reading, sort = (lang:makeSortKey(reading)), args=data.args}) end local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_reading = get_tagged_reading(reading, lang) return { description = description, displaytitle = "{{{langname}}} terms " .. affix .. "ed with " .. tagged_kanji .. " read as " .. tagged_reading, breadcrumb = "read as " .. reading, parents = parents, umbrella = false, }, true end) insert(handlers, function(data) local kanji, daiyoji = match(data.label, "^terms with (.) replaced by daiyōji (.)$") if not kanji then return nil end local args = require("Module:parameters").process(data.args, { ["sort"] = true, }) local lang = data.lang if not args.sort then error("For categories of the form \"" .. lang:getCanonicalName() .. " terms with KANJI replaced by daiyōji DAIYOJI\", the sort key must be specified using sort=") end local tagged_kanji = get_tagged_reading(kanji, lang) local tagged_daiyoji = get_tagged_reading(daiyoji, lang) return { description = "{{{langname}}} terms with {{l|{{{langcode}}}|" .. kanji .. "}} replaced by [[Appendix:Japanese glossary#daiyouji|daiyōji]] {{l|{{{langcode}}}|" .. daiyoji .. "}}.", displaytitle = "{{{langname}}} terms with " .. tagged_kanji .. " replaced by daiyōji " .. tagged_daiyoji, breadcrumb = tagged_kanji .. " replaced by daiyōji " .. tagged_daiyoji, parents = {{name = "terms spelled with daiyōji", sort = args.sort}}, umbrella = false, }, true end) return {LABELS = labels, HANDLERS = handlers} ea2zmcmhguqw3ivdjan9pb199sxgqx3 Mòideal:category tree/fam/jpx/what-categorizes-msg 828 17914 88826 2026-07-26T06:04:37Z en>Benwing 0 Protected "[[Module:category tree/fam/jpx/what-categorizes-msg]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88826 Scribunto text/plain local export = {} local m_str_utils = require("Module:string utilities") local d_range = mw.loadData("Module:ja/data/range") -- Handles the "Terms are placed in this category..." text in Japanese affix categories -- Used in -- [[Module:category tree/affixes and compounds]] -- [[Module:category tree/fam/jpx]] function export.get_what_categorizes_msg(affix, affix_reading, affix_type) if not affix_reading then if m_str_utils.find(affix, "[" .. d_range.kanji .. "々〻]") then --Category has kanji but no reading "read as" return nil end affix_reading = affix end local tl if affix_type == "suffix" then tl = "{{tl|ja-compound|<var>|...|</var>|" .. affix .. "|-" .. affix_reading .. "}}" elseif affix_type == "prefix" then tl = "{{tl|ja-compound|" .. affix .. "|" .. affix_reading .. "-|<var>|...|</var>}}" elseif affix_type == "infix" then tl = "{{tl|ja-compound|<var>|...|</var>|" .. affix .. "|-" .. affix_reading .. "-|<var>|...|</var>}}" end if tl then tl = "Terms are placed in this category using " .. tl .. "." end return tl end return export aseik7d8zcfi37ce42nxrihk8lz825b 88827 88826 2026-08-06T20:17:49Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/jpx/what-categorizes-msg]] 88826 Scribunto text/plain local export = {} local m_str_utils = require("Module:string utilities") local d_range = mw.loadData("Module:ja/data/range") -- Handles the "Terms are placed in this category..." text in Japanese affix categories -- Used in -- [[Module:category tree/affixes and compounds]] -- [[Module:category tree/fam/jpx]] function export.get_what_categorizes_msg(affix, affix_reading, affix_type) if not affix_reading then if m_str_utils.find(affix, "[" .. d_range.kanji .. "々〻]") then --Category has kanji but no reading "read as" return nil end affix_reading = affix end local tl if affix_type == "suffix" then tl = "{{tl|ja-compound|<var>|...|</var>|" .. affix .. "|-" .. affix_reading .. "}}" elseif affix_type == "prefix" then tl = "{{tl|ja-compound|" .. affix .. "|" .. affix_reading .. "-|<var>|...|</var>}}" elseif affix_type == "infix" then tl = "{{tl|ja-compound|<var>|...|</var>|" .. affix .. "|-" .. affix_reading .. "-|<var>|...|</var>}}" end if tl then tl = "Terms are placed in this category using " .. tl .. "." end return tl end return export aseik7d8zcfi37ce42nxrihk8lz825b Mòideal:category tree/fam/qfa-kor 828 17915 88828 2026-07-26T06:05:01Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/qfa-kor]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88828 Scribunto text/plain local labels = {} local handlers = {} labels["hanja"] = { topright = "{{wp|Hanja}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", toc_template = "Hani-categoryTOC", umbrella = "Han characters", parents = "logograms", } labels["hanja forms"] = { topright = "{{wp|Hanja}}", description = "{{{langname}}} terms written in [[hanja]].", parents = "terms by script", } labels["idu forms"] = { topright = "{{wp|Idu script}}", description = "{{{langname}}} terms written in [[idu]].", parents = "terms by script", } labels["four-character idioms"] = { topright = "{{wp|Sajaseong-eo}}", description = "{{{langname}}} traditional idiomatic expressions, also called sajaseong-eo, usually consisting of four syllables and traditionally given in [[hanja]]; typically derived from [[Classical Chinese]].", additional = "Compare Chinese {{w|chengyu}} and Japanese {{w|yojijukugo}}.", umbrella = "four-character idioms", parents = "idioms", } labels["terms written in Hanja-Hangul mixed script"] = { topright = "{{wp|Korean mixed script}}", description = "{{{langname}}} mixed script is a form of writing that uses both [[hangeul]] (hangul) (an alphabetical script) and [[hanja]] (logo-syllabic characters).", parents = "terms written in multiple scripts", } return {LABELS = labels, HANDLERS = handlers} sg8wfygn9ns7dv1gh1uvf8z468u1th2 88829 88828 2026-08-06T20:17:59Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/qfa-kor]] 88828 Scribunto text/plain local labels = {} local handlers = {} labels["hanja"] = { topright = "{{wp|Hanja}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", toc_template = "Hani-categoryTOC", umbrella = "Han characters", parents = "logograms", } labels["hanja forms"] = { topright = "{{wp|Hanja}}", description = "{{{langname}}} terms written in [[hanja]].", parents = "terms by script", } labels["idu forms"] = { topright = "{{wp|Idu script}}", description = "{{{langname}}} terms written in [[idu]].", parents = "terms by script", } labels["four-character idioms"] = { topright = "{{wp|Sajaseong-eo}}", description = "{{{langname}}} traditional idiomatic expressions, also called sajaseong-eo, usually consisting of four syllables and traditionally given in [[hanja]]; typically derived from [[Classical Chinese]].", additional = "Compare Chinese {{w|chengyu}} and Japanese {{w|yojijukugo}}.", umbrella = "four-character idioms", parents = "idioms", } labels["terms written in Hanja-Hangul mixed script"] = { topright = "{{wp|Korean mixed script}}", description = "{{{langname}}} mixed script is a form of writing that uses both [[hangeul]] (hangul) (an alphabetical script) and [[hanja]] (logo-syllabic characters).", parents = "terms written in multiple scripts", } return {LABELS = labels, HANDLERS = handlers} sg8wfygn9ns7dv1gh1uvf8z468u1th2 Mòideal:category tree/fam/roa-ibe 828 17916 88830 2026-07-26T06:05:21Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/roa-ibe]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88830 Scribunto text/plain local labels = {} local conjugations = { ["ar"] = "{{{langname}}} first conjugation verbs, derived from Latin [[:Category:Latin first conjugation verbs|first conjugation (-āre) verbs]].", ["er"] = "{{{langname}}} second conjugation verbs, derived from Latin [[:Category:Latin second conjugation verbs|second conjugation (-ēre)]] or [[:Category:Latin third conjugation verbs|third conjugation (-ere)]] verbs.", ["ir"] = "{{{langname}}} third conjugation verbs, derived from Latin [[:Category:Latin third conjugation verbs|third conjugation (-ere)]] or [[:Category:Latin fourth conjugation verbs|fourth conjugation (-īre)]] verbs.", } labels["verbs by conjugation"] = { description = "{{{langname}}} verbs categorized by conjugation.", parents = {"verbs by inflection type"}, } for conj, conjdesc in pairs(conjugations) do labels["verbs ending in -" .. conj] = { description = conjdesc, displaytitle = "{{{langname}}} verbs ending in {{m|{{{langcode}}}||-" .. conj .. "}}", parents = { {name = "verbs by conjugation", sort = conj}, }, breadcrumb = "{{m|{{{langcode}}}||-" .. conj .. "}}", } end labels["verbs by vowel alternation"] = { description = "{{{langname}}} verbs categorized by type of vowel alternation.", parents = {"verbs by inflection type"}, } labels["verbs by consonant alternation"] = { description = "{{{langname}}} verbs categorized by type of consonant alternation.", parents = {"verbs by inflection type"}, } labels["third-person-only verbs"] = { description = "{{{langname}}} verbs with forms that exist only in the third person, and have no imperatives.", parents = {{name = "defective verbs"}}, breadcrumb = "third-person-only", } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 4hqzujtavdjpjcevxpm30i0mf4rf6vg 88831 88830 2026-08-06T20:18:05Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/roa-ibe]] 88830 Scribunto text/plain local labels = {} local conjugations = { ["ar"] = "{{{langname}}} first conjugation verbs, derived from Latin [[:Category:Latin first conjugation verbs|first conjugation (-āre) verbs]].", ["er"] = "{{{langname}}} second conjugation verbs, derived from Latin [[:Category:Latin second conjugation verbs|second conjugation (-ēre)]] or [[:Category:Latin third conjugation verbs|third conjugation (-ere)]] verbs.", ["ir"] = "{{{langname}}} third conjugation verbs, derived from Latin [[:Category:Latin third conjugation verbs|third conjugation (-ere)]] or [[:Category:Latin fourth conjugation verbs|fourth conjugation (-īre)]] verbs.", } labels["verbs by conjugation"] = { description = "{{{langname}}} verbs categorized by conjugation.", parents = {"verbs by inflection type"}, } for conj, conjdesc in pairs(conjugations) do labels["verbs ending in -" .. conj] = { description = conjdesc, displaytitle = "{{{langname}}} verbs ending in {{m|{{{langcode}}}||-" .. conj .. "}}", parents = { {name = "verbs by conjugation", sort = conj}, }, breadcrumb = "{{m|{{{langcode}}}||-" .. conj .. "}}", } end labels["verbs by vowel alternation"] = { description = "{{{langname}}} verbs categorized by type of vowel alternation.", parents = {"verbs by inflection type"}, } labels["verbs by consonant alternation"] = { description = "{{{langname}}} verbs categorized by type of consonant alternation.", parents = {"verbs by inflection type"}, } labels["third-person-only verbs"] = { description = "{{{langname}}} verbs with forms that exist only in the third person, and have no imperatives.", parents = {{name = "defective verbs"}}, breadcrumb = "third-person-only", } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 4hqzujtavdjpjcevxpm30i0mf4rf6vg Mòideal:category tree/fam/sem-ara 828 17917 88832 2026-07-26T06:05:40Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/sem-ara]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88832 Scribunto text/plain local labels = {} --[=[ This module handles language-specific categories for all Aramaic varieties. ]=] ----------------------------------------------------------------------------- -- -- -- NOUNS -- -- -- ----------------------------------------------------------------------------- ---------------------------------- Noun labels --------------------------------- local function add_noun_labels(labels) -- Currently there is no [[Appendix:Aramaic nominals]]. Formerly the code conditionalized on the language -- but only referenced [[Appendix:Assyrian Neo-Aramaic nominals]] (which also doesn't exist) for lang code 'aii', -- and was broken for all other languages. If we want to conditionalize on the language now, we have to make the -- description a function (in which case it will be passed an object whose `.lang` field is the language), or use -- a handler. local nominal_appendix = "Appendix:Aramaic nominals" local appendix_exists = mw.title.new(nominal_appendix).exists local function make_appendix_link(text, anchor) if appendix_exists then anchor = anchor or mw.getContentLanguage():ucfirst(text) return ("[[%s#%s|%s]]"):format(nominal_appendix, anchor, text) else return text end end labels["nouns by derivation type"] = { description = "{{{langname}}} nouns categorized by type of derivation.", breadcrumb = "by derivation type", parents = {{name = "nouns", sort = "derivation type"}}, } labels["agents"] = { description = "{{{langname}}} " .. make_appendix_link("agents") .. ", i.e. nouns and adjectives having the meaning \"one who does X\" for some verb.", breadcrumb_and_first_sort_key = "agents", parents = {"nouns by derivation type"}, } labels["instance nouns"] = { description = "{{{langname}}} " .. make_appendix_link("instance nouns") .. ", i.e. nouns having the meaning \"an instance of doing X\" for some verb.", breadcrumb_and_first_sort_key = "instance nouns", parents = {"nouns by derivation type"}, } labels["nouns of place"] = { description = "{{{langname}}} " .. make_appendix_link("nouns of place") .. ", i.e. nouns having the approximate meaning \"the place for doing X\" for some verb.", breadcrumb_and_first_sort_key = "nouns of place", parents = {"nouns by derivation type"}, } labels["occupational nouns"] = { description = "{{{langname}}} " .. make_appendix_link("occupational nouns") .. ", i.e. nouns referring to people employed in doing something.", breadcrumb_and_first_sort_key = "occupational nouns", parents = {"nouns by derivation type"}, } labels["tool nouns"] = { description = "{{{langname}}} " .. make_appendix_link("tool nouns") .. ", i.e. nouns having the approximate meaning \"tool for doing X\" for some verb.", breadcrumb_and_first_sort_key = "tool nouns", parents = {"nouns by derivation type"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Lemmas subcategories by language" end end end ----------------------------------------------------------------------------- -- -- -- WRAPPERS -- -- -- ----------------------------------------------------------------------------- add_noun_labels(labels) return {LABELS = labels} 2wnbtxzybpb1981cnjrrsfk1xh5g10d 88833 88832 2026-08-06T20:18:10Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/sem-ara]] 88832 Scribunto text/plain local labels = {} --[=[ This module handles language-specific categories for all Aramaic varieties. ]=] ----------------------------------------------------------------------------- -- -- -- NOUNS -- -- -- ----------------------------------------------------------------------------- ---------------------------------- Noun labels --------------------------------- local function add_noun_labels(labels) -- Currently there is no [[Appendix:Aramaic nominals]]. Formerly the code conditionalized on the language -- but only referenced [[Appendix:Assyrian Neo-Aramaic nominals]] (which also doesn't exist) for lang code 'aii', -- and was broken for all other languages. If we want to conditionalize on the language now, we have to make the -- description a function (in which case it will be passed an object whose `.lang` field is the language), or use -- a handler. local nominal_appendix = "Appendix:Aramaic nominals" local appendix_exists = mw.title.new(nominal_appendix).exists local function make_appendix_link(text, anchor) if appendix_exists then anchor = anchor or mw.getContentLanguage():ucfirst(text) return ("[[%s#%s|%s]]"):format(nominal_appendix, anchor, text) else return text end end labels["nouns by derivation type"] = { description = "{{{langname}}} nouns categorized by type of derivation.", breadcrumb = "by derivation type", parents = {{name = "nouns", sort = "derivation type"}}, } labels["agents"] = { description = "{{{langname}}} " .. make_appendix_link("agents") .. ", i.e. nouns and adjectives having the meaning \"one who does X\" for some verb.", breadcrumb_and_first_sort_key = "agents", parents = {"nouns by derivation type"}, } labels["instance nouns"] = { description = "{{{langname}}} " .. make_appendix_link("instance nouns") .. ", i.e. nouns having the meaning \"an instance of doing X\" for some verb.", breadcrumb_and_first_sort_key = "instance nouns", parents = {"nouns by derivation type"}, } labels["nouns of place"] = { description = "{{{langname}}} " .. make_appendix_link("nouns of place") .. ", i.e. nouns having the approximate meaning \"the place for doing X\" for some verb.", breadcrumb_and_first_sort_key = "nouns of place", parents = {"nouns by derivation type"}, } labels["occupational nouns"] = { description = "{{{langname}}} " .. make_appendix_link("occupational nouns") .. ", i.e. nouns referring to people employed in doing something.", breadcrumb_and_first_sort_key = "occupational nouns", parents = {"nouns by derivation type"}, } labels["tool nouns"] = { description = "{{{langname}}} " .. make_appendix_link("tool nouns") .. ", i.e. nouns having the approximate meaning \"tool for doing X\" for some verb.", breadcrumb_and_first_sort_key = "tool nouns", parents = {"nouns by derivation type"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Lemmas subcategories by language" end end end ----------------------------------------------------------------------------- -- -- -- WRAPPERS -- -- -- ----------------------------------------------------------------------------- add_noun_labels(labels) return {LABELS = labels} 2wnbtxzybpb1981cnjrrsfk1xh5g10d Mòideal:category tree/fam/sla 828 17918 88834 2026-07-26T06:05:52Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/sla]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only template editors and administrators] (indefinite) [Move=Allow only template editors and administrators] (indefinite)) 88834 Scribunto text/plain local labels = {} labels["multidirectional verbs"] = { description = "{{{langname}}} verbs of motion whose motion is multidirectional (as opposed to unidirectional) or indirect, or whose action is repeated or in a series, instead of being a single, completed action.", additional = "Multidirectional verbs are always imperfective in aspect, even with prefixes that are normally associated with the perfective aspect. See also {{lg|unidirectional verb}}.", parents = {"verbs"}, umbrella_parents = "Lemmas subcategories by language", } labels["unidirectional verbs"] = { description = "{{{langname}}} verbs of motion whose motion is unidirectional (as opposed to multidirectional), a definitely directed motion, or a single, completed action (instead of a repeated action or series of actions).", additional = "Unidirectional verbs may be either imperfective or perfective. See also {{lg|multidirectional verb}}.", parents = {"verbs"}, umbrella_parents = "Lemmas subcategories by language", } ------- Slavic terms with prothetic consonants ------- for _, back_sound in ipairs {"v-", "w-", "в-"} do labels["terms with prothetic " .. back_sound] = { description = "{{{langname}}} terms with a prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}, which was not present etymologically in {{w|Proto-Slavic}}.", displaytitle = "{{{langname}}} terms with prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}", additional = "This sound was originally added before terms beginning with a back vowel (''o'' or ''u'') to prevent {{lg|hiatus}} when the preceding word ended in a vowel, and in time was incorporated into the word itself.", breadcrumb = "with prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}", parents = {{name = "terms by lexical property", sort = "prothetic"}}, umbrella = { description = "Categories with terms with a prothetic {{m|und||" .. back_sound .. "}}, which was not present etymologically in {{w|Proto-Slavic}}.", breadcrumb = "Terms with prothetic {{m|und||" .. back_sound .. "}}", parents = {"Terms by lexical property subcategories by language"}, } } end labels["terms with prothetic h-"] = { description = "{{{langname}}} terms with a prothetic {{m|{{{langcode}}}||h}}, which was not present etymologically in {{w|Proto-Slavic}}.", displaytitle = "{{{langname}}} terms with prothetic {{m|{{{langcode}}}||h}}", additional = "This sound was originally added before terms beginning with a vowel to prevent {{lg|hiatus}} when the preceding word ended in a vowel, and in time was incorporated into the word itself.", breadcrumb = "with prothetic {{m|{{{langcode}}}||h}}", parents = {{name = "terms by lexical property", sort = "prothetic"}}, umbrella = { description = "Categories with terms with a prothetic {{m|und||h}}, which was not present etymologically in {{w|Proto-Slavic}}.", breadcrumb = "Terms with prothetic {{m|und||h}}", parents = {"Terms by lexical property subcategories by language"}, } } return {LABELS = labels} s4khv5hpn2b3ncc7mqr1hlxeaftnq8z 88835 88834 2026-08-06T20:18:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/sla]] 88834 Scribunto text/plain local labels = {} labels["multidirectional verbs"] = { description = "{{{langname}}} verbs of motion whose motion is multidirectional (as opposed to unidirectional) or indirect, or whose action is repeated or in a series, instead of being a single, completed action.", additional = "Multidirectional verbs are always imperfective in aspect, even with prefixes that are normally associated with the perfective aspect. See also {{lg|unidirectional verb}}.", parents = {"verbs"}, umbrella_parents = "Lemmas subcategories by language", } labels["unidirectional verbs"] = { description = "{{{langname}}} verbs of motion whose motion is unidirectional (as opposed to multidirectional), a definitely directed motion, or a single, completed action (instead of a repeated action or series of actions).", additional = "Unidirectional verbs may be either imperfective or perfective. See also {{lg|multidirectional verb}}.", parents = {"verbs"}, umbrella_parents = "Lemmas subcategories by language", } ------- Slavic terms with prothetic consonants ------- for _, back_sound in ipairs {"v-", "w-", "в-"} do labels["terms with prothetic " .. back_sound] = { description = "{{{langname}}} terms with a prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}, which was not present etymologically in {{w|Proto-Slavic}}.", displaytitle = "{{{langname}}} terms with prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}", additional = "This sound was originally added before terms beginning with a back vowel (''o'' or ''u'') to prevent {{lg|hiatus}} when the preceding word ended in a vowel, and in time was incorporated into the word itself.", breadcrumb = "with prothetic {{m|{{{langcode}}}||" .. back_sound .. "}}", parents = {{name = "terms by lexical property", sort = "prothetic"}}, umbrella = { description = "Categories with terms with a prothetic {{m|und||" .. back_sound .. "}}, which was not present etymologically in {{w|Proto-Slavic}}.", breadcrumb = "Terms with prothetic {{m|und||" .. back_sound .. "}}", parents = {"Terms by lexical property subcategories by language"}, } } end labels["terms with prothetic h-"] = { description = "{{{langname}}} terms with a prothetic {{m|{{{langcode}}}||h}}, which was not present etymologically in {{w|Proto-Slavic}}.", displaytitle = "{{{langname}}} terms with prothetic {{m|{{{langcode}}}||h}}", additional = "This sound was originally added before terms beginning with a vowel to prevent {{lg|hiatus}} when the preceding word ended in a vowel, and in time was incorporated into the word itself.", breadcrumb = "with prothetic {{m|{{{langcode}}}||h}}", parents = {{name = "terms by lexical property", sort = "prothetic"}}, umbrella = { description = "Categories with terms with a prothetic {{m|und||h}}, which was not present etymologically in {{w|Proto-Slavic}}.", breadcrumb = "Terms with prothetic {{m|und||h}}", parents = {"Terms by lexical property subcategories by language"}, } } return {LABELS = labels} s4khv5hpn2b3ncc7mqr1hlxeaftnq8z Mòideal:category tree/fam/trk 828 17919 88836 2026-07-26T06:02:25Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/trk]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88836 Scribunto text/plain local labels = {} ------- Turkic izafet I/II/III compounds ------- -- FIXME: Possibly should be limited to a subfamily of Turkic. labels["izafet I compounds"] = { description = "{{{langname}}} izafet I compounds, i.e. nominal compounds consisting of two nouns both lacking 3rd-person possessive marking.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet I", parents = {"compound terms"}, } labels["izafet II compounds"] = { description = "{{{langname}}} izafet II compounds, i.e. nominal compounds with the first noun having zero-marking, and the second noun receiving a possessive suffix.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet II", parents = {"compound terms"}, } labels["izafet III compounds"] = { description = "{{{langname}}} izafet III compounds, i.e. nominal compounds with the first noun in the genitive case and the second noun receiving a possessive suffix.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet III", parents = {"compound terms"}, } labels["Persian-style izafet compounds"] = { description = "{{{langname}}} Persian-style izafet compounds, i.e. left-headed nominal compounds with the first noun receiving a Persian-style {{lg|ezafe}} suffix and the second noun having zero-marking.", additional = "These compounds are left-headed (the first noun is modified by second), unlike native Turkic izafet compounds, which are always right-headed.", breadcrumb_and_first_sort_key = "Persian-style", parents = {"izafet II compounds"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Types of compound terms by language" end end return {LABELS = labels} ps5lfysh0wgnpjatzdh4pzsy8y1w7y6 88837 88836 2026-08-06T20:18:37Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/trk]] 88836 Scribunto text/plain local labels = {} ------- Turkic izafet I/II/III compounds ------- -- FIXME: Possibly should be limited to a subfamily of Turkic. labels["izafet I compounds"] = { description = "{{{langname}}} izafet I compounds, i.e. nominal compounds consisting of two nouns both lacking 3rd-person possessive marking.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet I", parents = {"compound terms"}, } labels["izafet II compounds"] = { description = "{{{langname}}} izafet II compounds, i.e. nominal compounds with the first noun having zero-marking, and the second noun receiving a possessive suffix.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet II", parents = {"compound terms"}, } labels["izafet III compounds"] = { description = "{{{langname}}} izafet III compounds, i.e. nominal compounds with the first noun in the genitive case and the second noun receiving a possessive suffix.", additional = "These compounds are right-headed (the second noun is modified by the first), unlike Persian {{lg|ezafe}} compounds, which are typically left-headed.", breadcrumb_and_first_sort_key = "izafet III", parents = {"compound terms"}, } labels["Persian-style izafet compounds"] = { description = "{{{langname}}} Persian-style izafet compounds, i.e. left-headed nominal compounds with the first noun receiving a Persian-style {{lg|ezafe}} suffix and the second noun having zero-marking.", additional = "These compounds are left-headed (the first noun is modified by second), unlike native Turkic izafet compounds, which are always right-headed.", breadcrumb_and_first_sort_key = "Persian-style", parents = {"izafet II compounds"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Types of compound terms by language" end end return {LABELS = labels} ps5lfysh0wgnpjatzdh4pzsy8y1w7y6 Mòideal:category tree/fam/tup 828 17920 88838 2026-07-26T06:06:16Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/tup]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88838 Scribunto text/plain local labels = {} ------- TUPIAN LEMMA CLASSES ------- labels["pluriform adjectives"] = { description = "{{{langname}}} adjectives that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"adjectives by inflection type"}, } labels["pluriform nouns"] = { description = "{{{langname}}} nouns that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"nouns by inflection type"}, } labels["pluriform postpositions"] = { description = "{{{langname}}} postpositions that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"postpositions by inflection type"}, } labels["pluriform verbs"] = { description = "{{{langname}}} verbs that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"verbs by inflection type"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 9d7dzb67cu3aowe6olrn7k161dlypdp 88839 88838 2026-08-06T20:18:40Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/tup]] 88838 Scribunto text/plain local labels = {} ------- TUPIAN LEMMA CLASSES ------- labels["pluriform adjectives"] = { description = "{{{langname}}} adjectives that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"adjectives by inflection type"}, } labels["pluriform nouns"] = { description = "{{{langname}}} nouns that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"nouns by inflection type"}, } labels["pluriform postpositions"] = { description = "{{{langname}}} postpositions that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"postpositions by inflection type"}, } labels["pluriform verbs"] = { description = "{{{langname}}} verbs that have a relational prefix added to their stem.", breadcrumb = "pluriform", parents = {"verbs by inflection type"}, } -- Add 'umbrella_parents' key if not already present. for key, data in pairs(labels) do if not data.umbrella_parents then data.umbrella_parents = "Terms by grammatical category subcategories by language" end end return {LABELS = labels} 9d7dzb67cu3aowe6olrn7k161dlypdp Mòideal:category tree/fam/zhx 828 17921 88840 2026-07-26T06:06:29Z en>Benwing 0 Changed protection settings for "[[Module:category tree/fam/zhx]]": per existence of [[WT:CLTR]]; changes to these modules should go through a vetting process ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88840 Scribunto text/plain local labels = {} local handlers = {} labels["hanzi"] = { topright = "{{wp|Chinese characters}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", umbrella = "Han characters", parents = "logograms", } labels["chengyu"] = { topright = "{{wp|Chengyu}}", description = "{{{langname}}} traditional idiomatic expressions, usually consisting of four [[hanzi]]; typically derived from [[Classical Chinese]].", additional = "Compare Japanese {{w|yojijukugo}} and Korean {{w|sajaseong-eo}}.", parents = "idioms", } labels["terms with uncreated forms"] = { description = "{{{langname}}} terms that use a hanzi box template (such as {{temp|zh-forms}}) with a form not having a page of its own, or a {{temp|zh-see}} template linking to a page without a Chinese section or a nonexistent page", additional = "If the redlink in the hanzi box is a variant or simplified form, the page may be created with {{temp|subst:zh-new}}.", parents = {"redlinks", "entry maintenance"}, } for _, source in ipairs { "Mencius", "the Analects", "the Book of Documents", "the Book of Rites", "the Classic of Poetry", "the Han Feizi", "the I Ching", "the Zhuangzi", "the Zuo Zhuan", } do local book = source:match("^the (.*)$") local sort_key = book or source local italicized = book and "the ''" .. book .. "''" or source labels["terms derived from " .. source] = { displaytitle = book and "{{{langname}}} terms derived from " .. italicized or nil, parents = {{name = "terms attributed to a specific source", sort = sort_key}}, description = "{{{langname}}} terms derived from " .. italicized .. ".", breadcrumb = italicized, } labels["chengyu derived from " .. source] = { displaytitle = book and "{{{langname}}} chengyu derived from " .. italicized or nil, parents = {{name = "chengyu", sort = sort_key}, "terms derived from " .. source}, description = "{{{langname}}} [[chengyu]] derived from " .. italicized .. ".", breadcrumb = "derived from " .. italicized, } end return {LABELS = labels, HANDLERS = handlers} rm746jovo6y2tar6jekijha49gudmt4 88841 88840 2026-08-06T20:18:44Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Module:category_tree/fam/zhx]] 88840 Scribunto text/plain local labels = {} local handlers = {} labels["hanzi"] = { topright = "{{wp|Chinese characters}}", description = "{{{langname}}} symbols of the Han logographic script, which can represent sounds or convey meanings directly.", umbrella = "Han characters", parents = "logograms", } labels["chengyu"] = { topright = "{{wp|Chengyu}}", description = "{{{langname}}} traditional idiomatic expressions, usually consisting of four [[hanzi]]; typically derived from [[Classical Chinese]].", additional = "Compare Japanese {{w|yojijukugo}} and Korean {{w|sajaseong-eo}}.", parents = "idioms", } labels["terms with uncreated forms"] = { description = "{{{langname}}} terms that use a hanzi box template (such as {{temp|zh-forms}}) with a form not having a page of its own, or a {{temp|zh-see}} template linking to a page without a Chinese section or a nonexistent page", additional = "If the redlink in the hanzi box is a variant or simplified form, the page may be created with {{temp|subst:zh-new}}.", parents = {"redlinks", "entry maintenance"}, } for _, source in ipairs { "Mencius", "the Analects", "the Book of Documents", "the Book of Rites", "the Classic of Poetry", "the Han Feizi", "the I Ching", "the Zhuangzi", "the Zuo Zhuan", } do local book = source:match("^the (.*)$") local sort_key = book or source local italicized = book and "the ''" .. book .. "''" or source labels["terms derived from " .. source] = { displaytitle = book and "{{{langname}}} terms derived from " .. italicized or nil, parents = {{name = "terms attributed to a specific source", sort = sort_key}}, description = "{{{langname}}} terms derived from " .. italicized .. ".", breadcrumb = italicized, } labels["chengyu derived from " .. source] = { displaytitle = book and "{{{langname}}} chengyu derived from " .. italicized or nil, parents = {{name = "chengyu", sort = sort_key}, "terms derived from " .. source}, description = "{{{langname}}} [[chengyu]] derived from " .. italicized .. ".", breadcrumb = "derived from " .. italicized, } end return {LABELS = labels, HANDLERS = handlers} rm746jovo6y2tar6jekijha49gudmt4 Teamplaid:R:DIL 10 17922 88844 2025-12-24T04:54:04Z en>WingerBot 0 rename {{safe page name}} to {{pagename}} 88844 wikitext text/x-wiki {{#invoke:quote|call_template |template=cite-book |entry={{{head|{{{2|{{pagename}}}}}}}} |editors=Gregory Toner; Sharon Arbuthnot; Máire Ní Mhaonaigh; Marie-Luise Theuerkauf; Dagmar Wodtko |title=[[w:Dictionary of the Irish Language|eDIL: Electronic Dictionary of the Irish Language]] |entryurl=http://dil.ie/{{#ifeq:{{{1}}}|0|search?q={{urlencode:{{{head|{{{2}}}}}}}}&search_in=headword|{{urlencode:{{{1}}}}}}} |year=2019 |propagateparams = accessdate |allowparams = head,2,1 }}<noinclude>{{documentation}}</noinclude> t42llq40w47jbweac37c7f6drftmtz2 88845 88844 2026-08-06T21:54:37Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:R:DIL]] 88844 wikitext text/x-wiki {{#invoke:quote|call_template |template=cite-book |entry={{{head|{{{2|{{pagename}}}}}}}} |editors=Gregory Toner; Sharon Arbuthnot; Máire Ní Mhaonaigh; Marie-Luise Theuerkauf; Dagmar Wodtko |title=[[w:Dictionary of the Irish Language|eDIL: Electronic Dictionary of the Irish Language]] |entryurl=http://dil.ie/{{#ifeq:{{{1}}}|0|search?q={{urlencode:{{{head|{{{2}}}}}}}}&search_in=headword|{{urlencode:{{{1}}}}}}} |year=2019 |propagateparams = accessdate |allowparams = head,2,1 }}<noinclude>{{documentation}}</noinclude> t42llq40w47jbweac37c7f6drftmtz2 Teamplaid:refcat 10 17923 88848 2026-04-15T19:36:27Z en>Surjection 0 Changed protection settings for "[[Template:refcat]]" ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88848 wikitext text/x-wiki #redirect [[Template:reference template cat]] q8uahfu56samwe29nej3feicj9ugg5q 88849 88848 2026-08-06T22:17:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:refcat]] 88848 wikitext text/x-wiki #redirect [[Template:reference template cat]] q8uahfu56samwe29nej3feicj9ugg5q Teamplaid:reference template cat 10 17924 88850 2026-04-15T19:36:27Z en>Surjection 0 Changed protection settings for "[[Template:reference template cat]]" ([Edit=Allow only autopatrollers] (indefinite) [Move=Allow only autopatrollers] (indefinite)) 88850 wikitext text/x-wiki <includeonly>{{#invoke:reference template cat|main}}</includeonly><noinclude>{{documentation}}</noinclude> luksmm5vfifoqus9yfyen1rylkztzgo 88851 88850 2026-08-06T22:17:40Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:reference_template_cat]] 88850 wikitext text/x-wiki <includeonly>{{#invoke:reference template cat|main}}</includeonly><noinclude>{{documentation}}</noinclude> luksmm5vfifoqus9yfyen1rylkztzgo MediaWiki:Gadget-defaultVisibilityToggles.js 8 17925 88852 2026-05-15T18:04:24Z en>Surjection 0 support data-toggle-show-default 88852 javascript text/javascript /* jshint undef: true */ /* globals $, jQuery, mw, window, getComputedStyle */ (function defaultVisibilityTogglesIIFE() { "use strict"; if (window.noDefaultVisibilityToggles) return; /* == NavBars == */ var NavigationBarHide = "hide ▲"; var NavigationBarShow = "show ▼"; var nbsp = "\u00a0"; // Check if an element has been activated with a toggle. // For convenience, this has the side effect of marking the element as having // a toggle, if it is not already marked. // Allows the functions to avoid toggleifying elements more than once, which // can lead to multiple "show" buttons, for instance. // The argument must be an Element, not a jQuery object. function checkAndSetToggleified(element) { if (element.isToggleified) { return true; } element.isToggleified = true; } function getToggleCategory(element, defaultCategory) { if ($(element).find("table").first().is(".translations")) return "translations"; var heading = element; while ((heading = heading.previousElementSibling)) { // tagName is always uppercase: // https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName var num = heading.tagName.match(/H(\d)/); if (num) num = Number(num[1]); else continue; if (4 <= num && num <= 6) { if (heading.getElementsByTagName("span")[1]) heading = heading.getElementsByTagName("span")[0]; var text = jQuery(heading).text() .toLowerCase() // jQuery's .text() is inconsistent about whitespace: .replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ") // remove numbers added by the "Auto-number headings" pref: .replace(/^[1-9][0-9.]+ ?/, ""); // Toggle category must be convertible to a valid CSS identifier so // that it can be used in an id selector in jQuery in // ToggleCategory.prototype.newSidebarToggle // in [[MediaWiki:Gadget-VisibilityToggles.js]]. // Spaces must later be converted to hyphens or underscores. // Reference: https://drafts.csswg.org/selectors-4/#id-selectors if (/^[a-zA-Z0-9\s_-]+$/.test(text)) return text; else break; } else if (num) break; } return defaultCategory; } function createNavToggle(navFrame) { if (checkAndSetToggleified(navFrame) || navFrame.classList.contains('no-collapse')) { return; } var navHead, navContent; for (var i = 0, children = navFrame.childNodes; i < children.length; ++i) { var child = children[i]; if (child.nodeName === "DIV") { var classList = child.classList; if (classList.contains("NavHead")) navHead = child; if (classList.contains("NavContent")) navContent = child; } } if (!(navHead && navContent)) return; // Step 1, don't react when a subitem is clicked. $(navHead).find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Step 2, toggle visibility when bar is clicked. // NOTE This function was chosen due to some funny behaviour in Safari. var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "") .append($navToggle) .prependTo(navHead); navHead.style.cursor = "pointer"; var toggleCategory = $(navFrame).data("toggle-category") || getToggleCategory(navFrame, "other boxes"); navHead.onclick = window.VisibilityToggles.register(toggleCategory, function show() { $navToggle.text(NavigationBarHide); if (navContent) navContent.style.display = "block"; }, function hide() { $navToggle.text(NavigationBarShow); if (navContent) navContent.style.display = "none"; }, $(navFrame).is("[data-toggle-show-default]")); } function createNavToggleForInflectionTable(it) { if (checkAndSetToggleified(it)) { return; } // The table caption is the clickable element var itCaption = $(it).find("caption").get(0); // Step 1, don't react when a subitem is clicked. $(itCaption).find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Step 2, toggle visibility when bar is clicked. // NOTE This function was chosen due to some funny behaviour in Safari. var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "") .append($navToggle) .prependTo(itCaption); itCaption.style.cursor = "pointer"; var toggleCategory = $(it).data("toggle-category") || getToggleCategory(it, "other boxes"); itCaption.onclick = window.VisibilityToggles.register(toggleCategory, function show() { $navToggle.text(NavigationBarHide); if (it) { it.classList.remove("inflection-table-collapsed"); } }, function hide() { $navToggle.text(NavigationBarShow); if (it) { it.classList.add("inflection-table-collapsed"); } }, $(it).is("[data-toggle-show-default]")); // Check to see if we are on a browser that is known to support // visibility: collapse, which permits inflection table headings to wrap. // WebKit needs to be special-cased, as technically it does support // visibility: collapse, but it just implements it as a synonym for // visibility: hidden, which is useless. (as of November 2024) // Yes, I know User-Agent sniffing is so 2004... but WebKit is the new IE if ( CSS && CSS.supports && CSS.supports("visibility:collapse") && // exclude WebKit/Safari, excepting Blink engines which have a frozen WebKit version number (navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1) ) { it.classList.remove("no-vc"); } else { // Strange behaviour occurs when you set the table caption to nowrap // The [show/hide] toggle crashes into the caption text // This spacer element prevents that $("<span>").addClass("no-vc-spacer").appendTo(itCaption); } } /* ==Hidden Quotes== */ function setupHiddenQuotes(li) { if (checkAndSetToggleified(li)) return; let HQToggleButton, liComp, dl; function show() { HQToggleButton.text("quotations ▲"); $(li).children("ul").show(); } function hide() { HQToggleButton.text("quotations ▼"); $(li).children("ul").hide(); } for (const liComp of li.childNodes) { // Look at each component of the definition. if (liComp.tagName === "DL" && !dl) dl = liComp; // If we find a ul or dl, we have quotes or example sentences, and thus need a button. if (liComp.tagName === "UL") { $(li).children("ul").addClass("wikt-quote-container"); HQToggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); $(dl || liComp).before($("<span>").addClass("HQToggle").attr("data-nosnippet", "").append(HQToggleButton).css("margin-left", "5px")); HQToggleButton.on("click", window.VisibilityToggles.register("quotations", show, hide)); break; } } } /* == View Switching == */ function viewSwitching(rootElement) { if (checkAndSetToggleified(rootElement)) { return; } var $rootElement = $(rootElement); var showButtonText = $rootElement.data("vs-showtext") || "more ▼"; var hideButtonText = $rootElement.data("vs-hidetext") || "less ▲"; var toSkip = $rootElement.find(".vsSwitcher").find("*"); var elemsToHide = $rootElement.find(".vsHide").not(toSkip); var elemsToShow = $rootElement.find(".vsShow").not(toSkip); // Find the element to place the toggle button in. var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first(); // The toggleElement becomes clickable in its entirety, but // we need to prevent this if a contained link is clicked instead. toggleElement.find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Add the toggle button. var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement); // Determine the visibility toggle category (for the links in the bar on the left). var toggleCategory = $rootElement.data("toggle-category"); if (!toggleCategory) { var classNames = $rootElement.attr("class").split(/\s+/); for (var i = 0; i < classNames.length; ++i) { var className = classNames[i].split("-"); if (className[0] == "vsToggleCategory") { toggleCategory = className[1]; } } } if (!toggleCategory) toggleCategory = "others"; // Register the visibility toggle. toggleElement.css("cursor", "pointer"); toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { toggleButton.text(hideButtonText); elemsToShow.hide(); elemsToHide.show(); }, function hide() { toggleButton.text(showButtonText); elemsToShow.show(); elemsToHide.hide(); }, $rootElement.is("[data-toggle-show-default]"))); } /* ==List switching== */ function enableListSwitchGeneric(rootElement) { if (checkAndSetToggleified(rootElement)) { return; } var $rootElement = $(rootElement); // Create a toggle button. var $toggleElement = $("<div>").addClass("list-switcher-element"); var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", ""); var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); // Add the toggle button to the DOM tree. $navToggle.append($toggleButton).prependTo($toggleElement); $toggleElement.insertAfter($rootElement); $toggleElement.show(); // Determine the visibility toggle category (for the links in the bar on the // left). It will either be the value of the "data-toggle-category" // attribute or will be based on the text of the closest preceding // fourth-to-sixth-level header. var toggleCategory = $rootElement.data("toggle-category") || getToggleCategory($rootElement[0], "other lists"); // Determine the text for the $toggleButton. var showButtonText = "show more ▼"; var hideButtonText = "show less ▲"; var numItems; // special handling for [[Module:collapsible category tree]] var $categoryTreeTag = $rootElement.children(".CategoryTreeTag"); if ($categoryTreeTag) { if ($categoryTreeTag.attr("data-pages-left-over") !== "0") { // some category members are omitted from the list (MediaWiki limitation) // just use basic "show more/less" in this case for now, this is a big change //showButtonText = "show first 200 of " + $categoryTreeTag.attr("data-pages-in-cat") + " ▼"; //hideButtonText = "show fewer ▲"; } else { // all category members are included in the list numItems = $categoryTreeTag.attr("data-pages-in-cat"); } } else { // standard list-switcher using <li> elements numItems = $rootElement.find("li").length; } if (numItems) { showButtonText = "show all " + numItems + " ▼"; hideButtonText = "show fewer ▲"; } // Register the visibility toggle. $toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { $toggleButton.text(hideButtonText); if (rootElement) { rootElement.classList.remove("list-switcher-collapsed"); } }, function hide() { $toggleButton.text(showButtonText); if (rootElement) { rootElement.classList.add("list-switcher-collapsed"); } }, $rootElement.is("[data-toggle-show-default]"))); // Register a resize observer to see if we need to keep the // show/hide toggle visible var termList = rootElement.querySelector(':scope > .term-list'); if (termList && window.ResizeObserver) { var resizeObserver = new ResizeObserver(function(entries) { if (entries[0] && entries[0].contentBoxSize[0]) { // Work out what the max-height would be, in pixels // As a hack, this value is stored in the CSS `bottom` // property, as `max-height` is only in place when // the list is collapsed, but we need to do this check // even when the list is not collapsed var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom); // If box height is less than its max height + 20 px, suppress // collapsibility. The 20 px buffer prevents the situation where // clicking "show more" expands the box by just a few pixels if (entries[0].contentBoxSize[0].blockSize <= maxHeightPx + 20) { $toggleElement.hide(); if (rootElement.classList.contains("list-switcher-collapsed")) { rootElement.classList.remove("list-switcher-collapsed"); rootElement.classList.add("list-switcher-collapsibility-suppressed"); } } else { $toggleElement.show(); if (rootElement.classList.contains("list-switcher-collapsibility-suppressed")) { rootElement.classList.remove("list-switcher-collapsibility-suppressed"); rootElement.classList.add("list-switcher-collapsed"); } } } }); resizeObserver.observe(termList); } } // based on [[User:Erutuon/scripts/semhide.js]], [[User:Jberkel/semhide.js]], // [[User:Ungoliant_MMDCCLXIV/synshide.js]] function setupNyms(index, dlTag) { // [[Wiktionary:Semantic relations]] var relationClasses = [ "synonym", "antonym", "hypernym", "hyponym", "meronym", "holonym", "troponym", "comeronym", "coordinate-term", "near-synonym", "imperfective", "perfective", "alternative-form" ]; var relations = $(dlTag).find("dd > .nyms").get().filter( function(element) { return Array.prototype.some.call(element.classList, function (className) { if (relationClasses.indexOf(className) !== -1) { element.dataset.relationClass = className; return true; } }); }); function setupToggle(elements, category, visibleByDefault) { if (elements.length === 0) return null; var toggler = $("<a>").attr("role", "button").attr("tabindex", "0"); var text = elements.map(function (e) { var linkCount = e.querySelectorAll("span[lang]").length; return e.dataset.relationClass.replace("-", " ") + (linkCount > 1 ? "s" : ""); }).join(", "); function show() { toggler.text(text + nbsp + "▲"); $(dlTag).show(); $(elements).show(); } function hide() { toggler.text(text + nbsp + "▼"); if ($(dlTag).children().length === elements.length) { $(dlTag).hide(); } else { $(elements).hide(); } } $(dlTag).before($("<span>") .addClass("nyms-toggle") .attr("data-nosnippet", "") .append(toggler) .css("margin-left", "5px")); toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault)); } var synonyms = relations.filter(function (e) { return ["synonym", "antonym", "near-synonym", "coordinate-term", "alternative-form"].indexOf(e.dataset.relationClass) !== -1; }); var other = relations.filter(function (e) { return synonyms.indexOf(e) === -1; }); setupToggle(synonyms, "synonyms", true /* show by default */); setupToggle(other, "semantic relations"); } function setupUsageExampleCollapses(index, dlTag) { var usexTags = $(dlTag).find("dd > .h-usage-example").get(); function setupToggle(elements, category, visibleByDefault) { if (elements.length === 0) return null; var toggler = $("<a>").attr("role", "button").attr("tabindex", "0"); function show() { toggler.text(category + nbsp + "▲"); $(dlTag).show(); $(elements).show(); } function hide() { toggler.text(category + nbsp + "▼"); if ($(dlTag).children().length === elements.length) { $(dlTag).hide(); } else { $(elements).hide(); } } $(dlTag).before($("<span>") .addClass("nyms-toggle") .append(toggler) .css("margin-left", "5px")); toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault)); } var collocations = usexTags.filter(function (e) { return $(e).hasClass("collocation"); }); var usexes = usexTags.filter(function (e) { return collocations.indexOf(e) === -1; }); setupToggle(usexes, "usage examples", true /* show by default */); setupToggle(collocations, "collocations", true /* show by default */); } window.createNavToggle = createNavToggle; window.setupHiddenQuotes = setupHiddenQuotes; window.viewSwitching = viewSwitching; window.getToggleCategory = getToggleCategory; /* == Apply four functions defined above == */ mw.hook("wikipage.content").add(function($content) { // NavToggles $(".NavFrame", $content).each(function(){ createNavToggle(this); }); $(".inflection-table-collapsible", $content).each(function(){ createNavToggleForInflectionTable(this); }); // order nyms -> usexes -> quotes, to match the conventional order in entries // synonyms and such under definitions // if (mw.config.get("wgNamespaceNumber") === 0) { $("dl:has(dd > .nyms)", $content).each(setupNyms); // } // usage examples and collocations var namespaceNumber = mw.config.get("wgNamespaceNumber"); if (window.defaultVisibilityTogglesForUsageExamples) { if (namespaceNumber === 0) { $("ol > li dl:has(dd > .h-usage-example)", $content).each(setupUsageExampleCollapses); } } // quotes if (namespaceNumber === 0 || namespaceNumber === 100 || namespaceNumber === 118) { // First, find all the ordered lists, i.e. all the series of definitions. $("ol > li", $content).each(function(){ setupHiddenQuotes(this); }); } //view switching $(".vsSwitcher", $content).each(function(){ viewSwitching(this); }); // list switching $(".list-switcher", $content).each(function () { enableListSwitchGeneric(this); }); }); jQuery(mw).on("LivePreviewDone", function (ev, sels) { var ols = jQuery(sels.join(",")).find("ol"); for (var i = 0; i < ols.length; i++) { for (var j = 0; j < ols[i].childNodes.length; j++) { var li = ols[i].childNodes[j]; if (li.nodeName.toUpperCase() == "LI") { setupHiddenQuotes(li); } } } }); })(); 0cwdst3iiscohi6qwxwwbpuhjxc4vxb 88853 88852 2026-08-06T22:32:00Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-defaultVisibilityToggles.js]] 88852 javascript text/javascript /* jshint undef: true */ /* globals $, jQuery, mw, window, getComputedStyle */ (function defaultVisibilityTogglesIIFE() { "use strict"; if (window.noDefaultVisibilityToggles) return; /* == NavBars == */ var NavigationBarHide = "hide ▲"; var NavigationBarShow = "show ▼"; var nbsp = "\u00a0"; // Check if an element has been activated with a toggle. // For convenience, this has the side effect of marking the element as having // a toggle, if it is not already marked. // Allows the functions to avoid toggleifying elements more than once, which // can lead to multiple "show" buttons, for instance. // The argument must be an Element, not a jQuery object. function checkAndSetToggleified(element) { if (element.isToggleified) { return true; } element.isToggleified = true; } function getToggleCategory(element, defaultCategory) { if ($(element).find("table").first().is(".translations")) return "translations"; var heading = element; while ((heading = heading.previousElementSibling)) { // tagName is always uppercase: // https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName var num = heading.tagName.match(/H(\d)/); if (num) num = Number(num[1]); else continue; if (4 <= num && num <= 6) { if (heading.getElementsByTagName("span")[1]) heading = heading.getElementsByTagName("span")[0]; var text = jQuery(heading).text() .toLowerCase() // jQuery's .text() is inconsistent about whitespace: .replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ") // remove numbers added by the "Auto-number headings" pref: .replace(/^[1-9][0-9.]+ ?/, ""); // Toggle category must be convertible to a valid CSS identifier so // that it can be used in an id selector in jQuery in // ToggleCategory.prototype.newSidebarToggle // in [[MediaWiki:Gadget-VisibilityToggles.js]]. // Spaces must later be converted to hyphens or underscores. // Reference: https://drafts.csswg.org/selectors-4/#id-selectors if (/^[a-zA-Z0-9\s_-]+$/.test(text)) return text; else break; } else if (num) break; } return defaultCategory; } function createNavToggle(navFrame) { if (checkAndSetToggleified(navFrame) || navFrame.classList.contains('no-collapse')) { return; } var navHead, navContent; for (var i = 0, children = navFrame.childNodes; i < children.length; ++i) { var child = children[i]; if (child.nodeName === "DIV") { var classList = child.classList; if (classList.contains("NavHead")) navHead = child; if (classList.contains("NavContent")) navContent = child; } } if (!(navHead && navContent)) return; // Step 1, don't react when a subitem is clicked. $(navHead).find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Step 2, toggle visibility when bar is clicked. // NOTE This function was chosen due to some funny behaviour in Safari. var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "") .append($navToggle) .prependTo(navHead); navHead.style.cursor = "pointer"; var toggleCategory = $(navFrame).data("toggle-category") || getToggleCategory(navFrame, "other boxes"); navHead.onclick = window.VisibilityToggles.register(toggleCategory, function show() { $navToggle.text(NavigationBarHide); if (navContent) navContent.style.display = "block"; }, function hide() { $navToggle.text(NavigationBarShow); if (navContent) navContent.style.display = "none"; }, $(navFrame).is("[data-toggle-show-default]")); } function createNavToggleForInflectionTable(it) { if (checkAndSetToggleified(it)) { return; } // The table caption is the clickable element var itCaption = $(it).find("caption").get(0); // Step 1, don't react when a subitem is clicked. $(itCaption).find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Step 2, toggle visibility when bar is clicked. // NOTE This function was chosen due to some funny behaviour in Safari. var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "") .append($navToggle) .prependTo(itCaption); itCaption.style.cursor = "pointer"; var toggleCategory = $(it).data("toggle-category") || getToggleCategory(it, "other boxes"); itCaption.onclick = window.VisibilityToggles.register(toggleCategory, function show() { $navToggle.text(NavigationBarHide); if (it) { it.classList.remove("inflection-table-collapsed"); } }, function hide() { $navToggle.text(NavigationBarShow); if (it) { it.classList.add("inflection-table-collapsed"); } }, $(it).is("[data-toggle-show-default]")); // Check to see if we are on a browser that is known to support // visibility: collapse, which permits inflection table headings to wrap. // WebKit needs to be special-cased, as technically it does support // visibility: collapse, but it just implements it as a synonym for // visibility: hidden, which is useless. (as of November 2024) // Yes, I know User-Agent sniffing is so 2004... but WebKit is the new IE if ( CSS && CSS.supports && CSS.supports("visibility:collapse") && // exclude WebKit/Safari, excepting Blink engines which have a frozen WebKit version number (navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1) ) { it.classList.remove("no-vc"); } else { // Strange behaviour occurs when you set the table caption to nowrap // The [show/hide] toggle crashes into the caption text // This spacer element prevents that $("<span>").addClass("no-vc-spacer").appendTo(itCaption); } } /* ==Hidden Quotes== */ function setupHiddenQuotes(li) { if (checkAndSetToggleified(li)) return; let HQToggleButton, liComp, dl; function show() { HQToggleButton.text("quotations ▲"); $(li).children("ul").show(); } function hide() { HQToggleButton.text("quotations ▼"); $(li).children("ul").hide(); } for (const liComp of li.childNodes) { // Look at each component of the definition. if (liComp.tagName === "DL" && !dl) dl = liComp; // If we find a ul or dl, we have quotes or example sentences, and thus need a button. if (liComp.tagName === "UL") { $(li).children("ul").addClass("wikt-quote-container"); HQToggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); $(dl || liComp).before($("<span>").addClass("HQToggle").attr("data-nosnippet", "").append(HQToggleButton).css("margin-left", "5px")); HQToggleButton.on("click", window.VisibilityToggles.register("quotations", show, hide)); break; } } } /* == View Switching == */ function viewSwitching(rootElement) { if (checkAndSetToggleified(rootElement)) { return; } var $rootElement = $(rootElement); var showButtonText = $rootElement.data("vs-showtext") || "more ▼"; var hideButtonText = $rootElement.data("vs-hidetext") || "less ▲"; var toSkip = $rootElement.find(".vsSwitcher").find("*"); var elemsToHide = $rootElement.find(".vsHide").not(toSkip); var elemsToShow = $rootElement.find(".vsShow").not(toSkip); // Find the element to place the toggle button in. var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first(); // The toggleElement becomes clickable in its entirety, but // we need to prevent this if a contained link is clicked instead. toggleElement.find("a").on("click", function (e) { e.stopPropagation(); e.stopImmediatePropagation(); }); // Add the toggle button. var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); $("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement); // Determine the visibility toggle category (for the links in the bar on the left). var toggleCategory = $rootElement.data("toggle-category"); if (!toggleCategory) { var classNames = $rootElement.attr("class").split(/\s+/); for (var i = 0; i < classNames.length; ++i) { var className = classNames[i].split("-"); if (className[0] == "vsToggleCategory") { toggleCategory = className[1]; } } } if (!toggleCategory) toggleCategory = "others"; // Register the visibility toggle. toggleElement.css("cursor", "pointer"); toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { toggleButton.text(hideButtonText); elemsToShow.hide(); elemsToHide.show(); }, function hide() { toggleButton.text(showButtonText); elemsToShow.show(); elemsToHide.hide(); }, $rootElement.is("[data-toggle-show-default]"))); } /* ==List switching== */ function enableListSwitchGeneric(rootElement) { if (checkAndSetToggleified(rootElement)) { return; } var $rootElement = $(rootElement); // Create a toggle button. var $toggleElement = $("<div>").addClass("list-switcher-element"); var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", ""); var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); // Add the toggle button to the DOM tree. $navToggle.append($toggleButton).prependTo($toggleElement); $toggleElement.insertAfter($rootElement); $toggleElement.show(); // Determine the visibility toggle category (for the links in the bar on the // left). It will either be the value of the "data-toggle-category" // attribute or will be based on the text of the closest preceding // fourth-to-sixth-level header. var toggleCategory = $rootElement.data("toggle-category") || getToggleCategory($rootElement[0], "other lists"); // Determine the text for the $toggleButton. var showButtonText = "show more ▼"; var hideButtonText = "show less ▲"; var numItems; // special handling for [[Module:collapsible category tree]] var $categoryTreeTag = $rootElement.children(".CategoryTreeTag"); if ($categoryTreeTag) { if ($categoryTreeTag.attr("data-pages-left-over") !== "0") { // some category members are omitted from the list (MediaWiki limitation) // just use basic "show more/less" in this case for now, this is a big change //showButtonText = "show first 200 of " + $categoryTreeTag.attr("data-pages-in-cat") + " ▼"; //hideButtonText = "show fewer ▲"; } else { // all category members are included in the list numItems = $categoryTreeTag.attr("data-pages-in-cat"); } } else { // standard list-switcher using <li> elements numItems = $rootElement.find("li").length; } if (numItems) { showButtonText = "show all " + numItems + " ▼"; hideButtonText = "show fewer ▲"; } // Register the visibility toggle. $toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { $toggleButton.text(hideButtonText); if (rootElement) { rootElement.classList.remove("list-switcher-collapsed"); } }, function hide() { $toggleButton.text(showButtonText); if (rootElement) { rootElement.classList.add("list-switcher-collapsed"); } }, $rootElement.is("[data-toggle-show-default]"))); // Register a resize observer to see if we need to keep the // show/hide toggle visible var termList = rootElement.querySelector(':scope > .term-list'); if (termList && window.ResizeObserver) { var resizeObserver = new ResizeObserver(function(entries) { if (entries[0] && entries[0].contentBoxSize[0]) { // Work out what the max-height would be, in pixels // As a hack, this value is stored in the CSS `bottom` // property, as `max-height` is only in place when // the list is collapsed, but we need to do this check // even when the list is not collapsed var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom); // If box height is less than its max height + 20 px, suppress // collapsibility. The 20 px buffer prevents the situation where // clicking "show more" expands the box by just a few pixels if (entries[0].contentBoxSize[0].blockSize <= maxHeightPx + 20) { $toggleElement.hide(); if (rootElement.classList.contains("list-switcher-collapsed")) { rootElement.classList.remove("list-switcher-collapsed"); rootElement.classList.add("list-switcher-collapsibility-suppressed"); } } else { $toggleElement.show(); if (rootElement.classList.contains("list-switcher-collapsibility-suppressed")) { rootElement.classList.remove("list-switcher-collapsibility-suppressed"); rootElement.classList.add("list-switcher-collapsed"); } } } }); resizeObserver.observe(termList); } } // based on [[User:Erutuon/scripts/semhide.js]], [[User:Jberkel/semhide.js]], // [[User:Ungoliant_MMDCCLXIV/synshide.js]] function setupNyms(index, dlTag) { // [[Wiktionary:Semantic relations]] var relationClasses = [ "synonym", "antonym", "hypernym", "hyponym", "meronym", "holonym", "troponym", "comeronym", "coordinate-term", "near-synonym", "imperfective", "perfective", "alternative-form" ]; var relations = $(dlTag).find("dd > .nyms").get().filter( function(element) { return Array.prototype.some.call(element.classList, function (className) { if (relationClasses.indexOf(className) !== -1) { element.dataset.relationClass = className; return true; } }); }); function setupToggle(elements, category, visibleByDefault) { if (elements.length === 0) return null; var toggler = $("<a>").attr("role", "button").attr("tabindex", "0"); var text = elements.map(function (e) { var linkCount = e.querySelectorAll("span[lang]").length; return e.dataset.relationClass.replace("-", " ") + (linkCount > 1 ? "s" : ""); }).join(", "); function show() { toggler.text(text + nbsp + "▲"); $(dlTag).show(); $(elements).show(); } function hide() { toggler.text(text + nbsp + "▼"); if ($(dlTag).children().length === elements.length) { $(dlTag).hide(); } else { $(elements).hide(); } } $(dlTag).before($("<span>") .addClass("nyms-toggle") .attr("data-nosnippet", "") .append(toggler) .css("margin-left", "5px")); toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault)); } var synonyms = relations.filter(function (e) { return ["synonym", "antonym", "near-synonym", "coordinate-term", "alternative-form"].indexOf(e.dataset.relationClass) !== -1; }); var other = relations.filter(function (e) { return synonyms.indexOf(e) === -1; }); setupToggle(synonyms, "synonyms", true /* show by default */); setupToggle(other, "semantic relations"); } function setupUsageExampleCollapses(index, dlTag) { var usexTags = $(dlTag).find("dd > .h-usage-example").get(); function setupToggle(elements, category, visibleByDefault) { if (elements.length === 0) return null; var toggler = $("<a>").attr("role", "button").attr("tabindex", "0"); function show() { toggler.text(category + nbsp + "▲"); $(dlTag).show(); $(elements).show(); } function hide() { toggler.text(category + nbsp + "▼"); if ($(dlTag).children().length === elements.length) { $(dlTag).hide(); } else { $(elements).hide(); } } $(dlTag).before($("<span>") .addClass("nyms-toggle") .append(toggler) .css("margin-left", "5px")); toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault)); } var collocations = usexTags.filter(function (e) { return $(e).hasClass("collocation"); }); var usexes = usexTags.filter(function (e) { return collocations.indexOf(e) === -1; }); setupToggle(usexes, "usage examples", true /* show by default */); setupToggle(collocations, "collocations", true /* show by default */); } window.createNavToggle = createNavToggle; window.setupHiddenQuotes = setupHiddenQuotes; window.viewSwitching = viewSwitching; window.getToggleCategory = getToggleCategory; /* == Apply four functions defined above == */ mw.hook("wikipage.content").add(function($content) { // NavToggles $(".NavFrame", $content).each(function(){ createNavToggle(this); }); $(".inflection-table-collapsible", $content).each(function(){ createNavToggleForInflectionTable(this); }); // order nyms -> usexes -> quotes, to match the conventional order in entries // synonyms and such under definitions // if (mw.config.get("wgNamespaceNumber") === 0) { $("dl:has(dd > .nyms)", $content).each(setupNyms); // } // usage examples and collocations var namespaceNumber = mw.config.get("wgNamespaceNumber"); if (window.defaultVisibilityTogglesForUsageExamples) { if (namespaceNumber === 0) { $("ol > li dl:has(dd > .h-usage-example)", $content).each(setupUsageExampleCollapses); } } // quotes if (namespaceNumber === 0 || namespaceNumber === 100 || namespaceNumber === 118) { // First, find all the ordered lists, i.e. all the series of definitions. $("ol > li", $content).each(function(){ setupHiddenQuotes(this); }); } //view switching $(".vsSwitcher", $content).each(function(){ viewSwitching(this); }); // list switching $(".list-switcher", $content).each(function () { enableListSwitchGeneric(this); }); }); jQuery(mw).on("LivePreviewDone", function (ev, sels) { var ols = jQuery(sels.join(",")).find("ol"); for (var i = 0; i < ols.length; i++) { for (var j = 0; j < ols[i].childNodes.length; j++) { var li = ols[i].childNodes[j]; if (li.nodeName.toUpperCase() == "LI") { setupHiddenQuotes(li); } } } }); })(); 0cwdst3iiscohi6qwxwwbpuhjxc4vxb MediaWiki:Gadget-VisibilityToggles.js 8 17926 88854 2025-09-23T17:18:09Z en>Surjection 0 88854 javascript text/javascript /* eslint-env es5, browser, jquery */ /* eslint semi: "error" */ /* jshint esversion: 5, eqeqeq: true */ /* globals $, mw */ /* requires mw.cookie, mw.storage */ (function VisibilityTogglesIIFE () { "use strict"; // Toggle object that is constructed so that `toggle.status = !toggle.status` // automatically calls either `toggle.show()` or `toggle.hide()` as appropriate. // Creating toggle also automatically calls either the show or the hide function. function Toggle (showFunction, hideFunction) { this.show = showFunction, this.hide = hideFunction; } Toggle.prototype = { get status () { return this._status; }, set status (newStatus) { if (typeof newStatus !== "boolean") throw new TypeError("Value of 'status' must be a boolean."); if (newStatus === this._status) return; this._status = newStatus; if (this._status !== this.toggleCategory.status) this.toggleCategory.updateToggle(this._status); if (this._status) this.show(); else this.hide(); }, }; /* * Handles storing a boolean value associated with a `name` stored in * localStorage under `key`. * * The `get` method returns `true`, `false`, or `undefined` (if the storage * hasn't been tampered with). * The `set` method only allows setting `true` or `false`. */ function BooleanStorage(key, name) { if (typeof key !== "string") throw new TypeError("Expected string"); if (!(typeof name === "string" && name !== "")) { throw new TypeError("Expected non-empty string"); } this.key = key; // key for localStorage this.name = name; // name of toggle category function convertOldCookie(cookie) { return cookie.split(';') .filter(function(e) { return e !== ''; }) .reduce(function(memo, currentValue) { var match = /(.+?)=(\d)/.exec(currentValue); // only to test for temporary =[01] format if (match) { memo[match[1]] = Boolean(Number(match[2])); } else { memo[currentValue] = true; } return memo; }, {}); } // Look for cookie in old format. var cookie = mw.cookie.get(key); if (cookie !== null) { this.obj = $.extend(this.obj, convertOldCookie(cookie)); mw.cookie.set(key, null); // Remove cookie. } } BooleanStorage.prototype = { get: function () { return this.obj[this.name]; }, set: function (value) { if (typeof value !== "boolean") throw new TypeError("Expected boolean"); var obj = this.obj; if (obj[this.name] !== value) { obj[this.name] = value; this.obj = obj; } }, // obj allows getting and setting the object version of the stored value. get obj() { if (typeof this.rawValue !== "string") return {}; try { return JSON.parse(this.rawValue); } catch (e) { if (e instanceof SyntaxError) { return {}; } else { throw e; } } }, set obj(value) { // throws TypeError ("cyclic object value") this.rawValue = JSON.stringify(value); }, // rawValue allows simple getting and setting of the stringified object. get rawValue () { return mw.storage.get(this.key); }, set rawValue (value) { return mw.storage.set(this.key, value); }, }; // This is a version of the actual CSS identifier syntax (described here: // https://stackoverflow.com/a/2812097), with only ASCII and that must begin // with an alphabetic character. var asciiCssIdentifierRegex = /^[a-zA-Z][a-zA-Z0-9_-]+$/; function ToggleCategory (name, defaultStatus) { this.name = name; this.sidebarToggle = this.newSidebarToggle(); this.storage = new BooleanStorage("Visibility", name); this.status = this.getInitialStatus(defaultStatus); } // Have toggle category inherit array methods. ToggleCategory.prototype = []; ToggleCategory.prototype.addToggle = function (showFunction, hideFunction) { var toggle = new Toggle(showFunction, hideFunction); toggle.toggleCategory = this; this.push(toggle); toggle.status = this.status; return toggle; }; // Generate an identifier consisting of a lowercase ASCII letter and a random integer. function randomAsciiCssIdentifier() { var digits = 9; var lowCodepoint = "a".codePointAt(0), highCodepoint = "z".codePointAt(0); return String.fromCodePoint( lowCodepoint + Math.floor(Math.random() * (highCodepoint - lowCodepoint))) + String(Math.floor(Math.random() * Math.pow(10, digits))); } function getCssIdentifier(name) { name = name.replace(/\s+/g, "-"); // Generate a valid ASCII CSS identifier. if (!asciiCssIdentifierRegex.test(name)) { // Remove characters that are invalid in an ASCII CSS identifier. name = name.replace(/^[^a-zA-Z]+/, "").replace(/[^a-zA-Z_-]+/g, ""); if (!asciiCssIdentifierRegex.test(name)) name = randomAsciiCssIdentifier(); } return name; } // Add a new global toggle to the sidebar. ToggleCategory.prototype.newSidebarToggle = function () { var name = getCssIdentifier(this.name); var id = "p-visibility-" + name; var sidebarToggle = $("#" + id); if (sidebarToggle.length > 0) return sidebarToggle; var listEntry = $("<li>"); if (mw.config.get("skin") === "vector-2022") listEntry.addClass("mw-list-item"); sidebarToggle = $("<a>", { id: id, href: "#visibility-" + this.name, }) .click((function () { this.status = !this.status; this.storage.set(this.status); return false; }).bind(this)); listEntry.append(sidebarToggle).appendTo(this.buttons); return sidebarToggle; }; // Update the status of the sidebar toggle for the category when all of its // toggles on the page are toggled one way. ToggleCategory.prototype.updateToggle = function (status) { if (this.length > 0 && this.every(function (toggle) { return toggle.status === status; })) this.status = status; }; // getInitialStatus is only called when a category is first created. ToggleCategory.prototype.getInitialStatus = function (defaultStatus) { function isFragmentSet(name) { return location.hash.toLowerCase().split("_")[0] === "#" + name.toLowerCase(); } function isHideCatsSet(name) { var match = /^.+?\?(?:.*?&)*?hidecats=(.+?)(?:&.*)?$/.exec(location.href); if (match !== null) { var hidecats = match[1].split(","); for (var i = 0; i < hidecats.length; ++i) { switch (hidecats[i]) { case name: case "all": return false; case "!" + name: case "none": return true; } } } return false; } function isWiktionaryPreferencesCookieSet() { return mw.cookie.get("WiktionaryPreferencesShowNav") === "true"; } // TODO check category-specific cookies return isFragmentSet(this.name) || isHideCatsSet(this.name) || isWiktionaryPreferencesCookieSet() || (function(storedValue) { return storedValue !== undefined ? storedValue : Boolean(defaultStatus); }(this.storage.get())); }; Object.defineProperties(ToggleCategory.prototype, { status: { get: function () { return this._status; }, set: function (status) { if (typeof status !== "boolean") throw new TypeError("Value of 'status' must be a boolean."); if (status === this._status) return; this._status = status; // Change the state of all Toggles in the ToggleCategory. for (var i = 0; i < this.length; i++) this[i].status = status; this.sidebarToggle.text((status ? "Hide " : "Show ") + this.name); }, }, buttons: { get: function () { var buttons = $("#p-visibility ul"); if (buttons.length > 0) return buttons; buttons = $("<ul>"); // unused var collapsed = mw.cookie.get("vector-nav-p-visibility") === "false"; if (mw.config.get("skin") === "vector-2022") { /* add to right-hand side ('tools') bar */ var toolbox = $("<div>", { "class": "vector-menu mw-portlet mw-portlet-visibility", "id": "p-visibility" }) .append($('<div id="p-visibility-label" aria-label="" class="vector-menu-heading">Visibility</div>')) .append($("<div>", { class: "vector-menu-content" }).append(buttons.addClass("vector-menu-content-list"))); $('#vector-page-tools').append(toolbox); } else { var toolbox = $("<div>", { "class": "vector-menu vector-menu-portal portal portlet", "id": "p-visibility" }) .append($('<label id="p-visibility-label" aria-label="" class="vector-menu-heading"><span class="vector-menu-heading-label">Visibility</span></label>')) .append($("<div>", { class: "pBody body vector-menu-content" }).append(buttons)); var insert = document.getElementById("p-lang") || document.getElementById("p-feedback"); if (insert) { $(insert).before(toolbox); } else { var sidebar = document.getElementById("mw-panel") || document.getElementById("column-one"); $(sidebar).append(toolbox); } } return buttons; } } }); function VisibilityToggles () { // table containing ToggleCategories this.togglesByCategory = {}; } // Add a new toggle, adds a Show/Hide category button in the toolbar. // Returns a function that when called, calls showFunction and hideFunction // alternately and updates the sidebar toggle for the category if necessary. VisibilityToggles.prototype.register = function (category, showFunction, hideFunction, defaultStatus) { if (!(typeof category === "string" && category !== "")) return; var toggle = this.addToggleCategory(category, defaultStatus) .addToggle(showFunction, hideFunction); return function () { toggle.status = !toggle.status; }; }; VisibilityToggles.prototype.addToggleCategory = function (name, defaultStatus) { return (this.togglesByCategory[name] = this.togglesByCategory[name] || new ToggleCategory(name, defaultStatus)); }; window.alternativeVisibilityToggles = new VisibilityToggles(); window.VisibilityToggles = window.alternativeVisibilityToggles; })(); 8qjkkje953u8o41wk9sjre7nivtbk7y 88855 88854 2026-08-06T22:32:26Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-VisibilityToggles.js]] 88854 javascript text/javascript /* eslint-env es5, browser, jquery */ /* eslint semi: "error" */ /* jshint esversion: 5, eqeqeq: true */ /* globals $, mw */ /* requires mw.cookie, mw.storage */ (function VisibilityTogglesIIFE () { "use strict"; // Toggle object that is constructed so that `toggle.status = !toggle.status` // automatically calls either `toggle.show()` or `toggle.hide()` as appropriate. // Creating toggle also automatically calls either the show or the hide function. function Toggle (showFunction, hideFunction) { this.show = showFunction, this.hide = hideFunction; } Toggle.prototype = { get status () { return this._status; }, set status (newStatus) { if (typeof newStatus !== "boolean") throw new TypeError("Value of 'status' must be a boolean."); if (newStatus === this._status) return; this._status = newStatus; if (this._status !== this.toggleCategory.status) this.toggleCategory.updateToggle(this._status); if (this._status) this.show(); else this.hide(); }, }; /* * Handles storing a boolean value associated with a `name` stored in * localStorage under `key`. * * The `get` method returns `true`, `false`, or `undefined` (if the storage * hasn't been tampered with). * The `set` method only allows setting `true` or `false`. */ function BooleanStorage(key, name) { if (typeof key !== "string") throw new TypeError("Expected string"); if (!(typeof name === "string" && name !== "")) { throw new TypeError("Expected non-empty string"); } this.key = key; // key for localStorage this.name = name; // name of toggle category function convertOldCookie(cookie) { return cookie.split(';') .filter(function(e) { return e !== ''; }) .reduce(function(memo, currentValue) { var match = /(.+?)=(\d)/.exec(currentValue); // only to test for temporary =[01] format if (match) { memo[match[1]] = Boolean(Number(match[2])); } else { memo[currentValue] = true; } return memo; }, {}); } // Look for cookie in old format. var cookie = mw.cookie.get(key); if (cookie !== null) { this.obj = $.extend(this.obj, convertOldCookie(cookie)); mw.cookie.set(key, null); // Remove cookie. } } BooleanStorage.prototype = { get: function () { return this.obj[this.name]; }, set: function (value) { if (typeof value !== "boolean") throw new TypeError("Expected boolean"); var obj = this.obj; if (obj[this.name] !== value) { obj[this.name] = value; this.obj = obj; } }, // obj allows getting and setting the object version of the stored value. get obj() { if (typeof this.rawValue !== "string") return {}; try { return JSON.parse(this.rawValue); } catch (e) { if (e instanceof SyntaxError) { return {}; } else { throw e; } } }, set obj(value) { // throws TypeError ("cyclic object value") this.rawValue = JSON.stringify(value); }, // rawValue allows simple getting and setting of the stringified object. get rawValue () { return mw.storage.get(this.key); }, set rawValue (value) { return mw.storage.set(this.key, value); }, }; // This is a version of the actual CSS identifier syntax (described here: // https://stackoverflow.com/a/2812097), with only ASCII and that must begin // with an alphabetic character. var asciiCssIdentifierRegex = /^[a-zA-Z][a-zA-Z0-9_-]+$/; function ToggleCategory (name, defaultStatus) { this.name = name; this.sidebarToggle = this.newSidebarToggle(); this.storage = new BooleanStorage("Visibility", name); this.status = this.getInitialStatus(defaultStatus); } // Have toggle category inherit array methods. ToggleCategory.prototype = []; ToggleCategory.prototype.addToggle = function (showFunction, hideFunction) { var toggle = new Toggle(showFunction, hideFunction); toggle.toggleCategory = this; this.push(toggle); toggle.status = this.status; return toggle; }; // Generate an identifier consisting of a lowercase ASCII letter and a random integer. function randomAsciiCssIdentifier() { var digits = 9; var lowCodepoint = "a".codePointAt(0), highCodepoint = "z".codePointAt(0); return String.fromCodePoint( lowCodepoint + Math.floor(Math.random() * (highCodepoint - lowCodepoint))) + String(Math.floor(Math.random() * Math.pow(10, digits))); } function getCssIdentifier(name) { name = name.replace(/\s+/g, "-"); // Generate a valid ASCII CSS identifier. if (!asciiCssIdentifierRegex.test(name)) { // Remove characters that are invalid in an ASCII CSS identifier. name = name.replace(/^[^a-zA-Z]+/, "").replace(/[^a-zA-Z_-]+/g, ""); if (!asciiCssIdentifierRegex.test(name)) name = randomAsciiCssIdentifier(); } return name; } // Add a new global toggle to the sidebar. ToggleCategory.prototype.newSidebarToggle = function () { var name = getCssIdentifier(this.name); var id = "p-visibility-" + name; var sidebarToggle = $("#" + id); if (sidebarToggle.length > 0) return sidebarToggle; var listEntry = $("<li>"); if (mw.config.get("skin") === "vector-2022") listEntry.addClass("mw-list-item"); sidebarToggle = $("<a>", { id: id, href: "#visibility-" + this.name, }) .click((function () { this.status = !this.status; this.storage.set(this.status); return false; }).bind(this)); listEntry.append(sidebarToggle).appendTo(this.buttons); return sidebarToggle; }; // Update the status of the sidebar toggle for the category when all of its // toggles on the page are toggled one way. ToggleCategory.prototype.updateToggle = function (status) { if (this.length > 0 && this.every(function (toggle) { return toggle.status === status; })) this.status = status; }; // getInitialStatus is only called when a category is first created. ToggleCategory.prototype.getInitialStatus = function (defaultStatus) { function isFragmentSet(name) { return location.hash.toLowerCase().split("_")[0] === "#" + name.toLowerCase(); } function isHideCatsSet(name) { var match = /^.+?\?(?:.*?&)*?hidecats=(.+?)(?:&.*)?$/.exec(location.href); if (match !== null) { var hidecats = match[1].split(","); for (var i = 0; i < hidecats.length; ++i) { switch (hidecats[i]) { case name: case "all": return false; case "!" + name: case "none": return true; } } } return false; } function isWiktionaryPreferencesCookieSet() { return mw.cookie.get("WiktionaryPreferencesShowNav") === "true"; } // TODO check category-specific cookies return isFragmentSet(this.name) || isHideCatsSet(this.name) || isWiktionaryPreferencesCookieSet() || (function(storedValue) { return storedValue !== undefined ? storedValue : Boolean(defaultStatus); }(this.storage.get())); }; Object.defineProperties(ToggleCategory.prototype, { status: { get: function () { return this._status; }, set: function (status) { if (typeof status !== "boolean") throw new TypeError("Value of 'status' must be a boolean."); if (status === this._status) return; this._status = status; // Change the state of all Toggles in the ToggleCategory. for (var i = 0; i < this.length; i++) this[i].status = status; this.sidebarToggle.text((status ? "Hide " : "Show ") + this.name); }, }, buttons: { get: function () { var buttons = $("#p-visibility ul"); if (buttons.length > 0) return buttons; buttons = $("<ul>"); // unused var collapsed = mw.cookie.get("vector-nav-p-visibility") === "false"; if (mw.config.get("skin") === "vector-2022") { /* add to right-hand side ('tools') bar */ var toolbox = $("<div>", { "class": "vector-menu mw-portlet mw-portlet-visibility", "id": "p-visibility" }) .append($('<div id="p-visibility-label" aria-label="" class="vector-menu-heading">Visibility</div>')) .append($("<div>", { class: "vector-menu-content" }).append(buttons.addClass("vector-menu-content-list"))); $('#vector-page-tools').append(toolbox); } else { var toolbox = $("<div>", { "class": "vector-menu vector-menu-portal portal portlet", "id": "p-visibility" }) .append($('<label id="p-visibility-label" aria-label="" class="vector-menu-heading"><span class="vector-menu-heading-label">Visibility</span></label>')) .append($("<div>", { class: "pBody body vector-menu-content" }).append(buttons)); var insert = document.getElementById("p-lang") || document.getElementById("p-feedback"); if (insert) { $(insert).before(toolbox); } else { var sidebar = document.getElementById("mw-panel") || document.getElementById("column-one"); $(sidebar).append(toolbox); } } return buttons; } } }); function VisibilityToggles () { // table containing ToggleCategories this.togglesByCategory = {}; } // Add a new toggle, adds a Show/Hide category button in the toolbar. // Returns a function that when called, calls showFunction and hideFunction // alternately and updates the sidebar toggle for the category if necessary. VisibilityToggles.prototype.register = function (category, showFunction, hideFunction, defaultStatus) { if (!(typeof category === "string" && category !== "")) return; var toggle = this.addToggleCategory(category, defaultStatus) .addToggle(showFunction, hideFunction); return function () { toggle.status = !toggle.status; }; }; VisibilityToggles.prototype.addToggleCategory = function (name, defaultStatus) { return (this.togglesByCategory[name] = this.togglesByCategory[name] || new ToggleCategory(name, defaultStatus)); }; window.alternativeVisibilityToggles = new VisibilityToggles(); window.VisibilityToggles = window.alternativeVisibilityToggles; })(); 8qjkkje953u8o41wk9sjre7nivtbk7y MediaWiki:Gadgets-definition 8 17927 88856 2026-08-01T13:57:56Z en>Fenakhay 0 88856 wikitext text/x-wiki {{shortcut|WT:GD}} See [[Special:Gadgets]] for documentation of these gadgets, and [[Wiktionary:Gadgets]] for general information about gadgets on Wiktionary. See also [[WT:PREFS]] for other preferences. {{gadgets pages}} == appearance == * MonobookSmallerHeadings[ResourceLoader|default|skins=monobook]|MonobookSmallerHeadings.css * LanguagesAndScripts[ResourceLoader|default]|LanguagesAndScripts.css * VectorClassic[ResourceLoader|type=styles|skins=vector]|VectorClassic.css * CatchMyAttention[ResourceLoader|type=styles]|CatchMyAttention.css * HideLogo[ResourceLoader|type=styles]|HideLogo.css * vectorTabs[ResourceLoader|skins=vector|type=styles]|vectorTabs.js|vectorTabs.css * WiktCountryFlags[ResourceLoader|type=styles|namespaces=0]|WiktCountryFlags.css * WiktPreviewRightTOCs[ResourceLoader|namespaces=0]|WiktPreviewRightTOCs.css * LogoTiles[ResourceLoader|type=styles]|LogoTiles.css * RoundBullets4Lists[ResourceLoader|type=styles]|RoundBullets4Lists.css * BC-AD[ResourceLoader]|BC-AD.js * AutoContrastFixer[ResourceLoader|skins=vector-2022,minerva|dependencies=ext.gadget.WiktGadgetPrefs]|AutoContrastFixer.js * ShowIDs[ResourceLoader|dependencies=mediawiki.util|peers=ShowIDs-pagestyles]|ShowIDs.js * TreeDescs[ResourceLoader|peers=TreeDescs-pagestyles]|TreeDescs.js * NoMiniToc[ResourceLoader|type=general]|NoMiniToc.js|NoMiniToc.css * NsfwOverride[ResourceLoader|dependencies=mediawiki.util]|NsfwOverride.js|NsfwOverride.css * MobileCollapseCategories[ResourceLoader|skins=minerva|dependencies=mediawiki.util,ext.gadget.VisibilityToggles]|MobileCollapseCategories.js == interface-gadgets == * TargetedTranslations[ResourceLoader|default|dependencies=site,mediawiki.storage,mediawiki.cookie,ext.gadget.StorageUtils|categories=Entries with translation boxes]|TargetedTranslations.js|TargetedTranslations.css * BlockInfo[ResourceLoader|default|dependencies=site,mediawiki.api,mediawiki.language.months,mediawiki.util|namespaces=-1,2,3]|BlockInfo.js * RevdelInfo[ResourceLoader|dependencies=site,mediawiki.api,mediawiki.language.months,mediawiki.util]|RevdelInfo.js * CodeLinks[ResourceLoader|dependencies=site,mediawiki.util]|CodeLinks.js * purgetab[ResourceLoader|dependencies=mediawiki.api,mediawiki.util]|purgetab.js * Navigation_popups[ResourceLoader]|popups.js * PagePreviews[ResourceLoader|default|dependencies=site,mediawiki.api,mediawiki.util,mediawiki.Title|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|PagePreviews.js * CommentsInLocalTime[ResourceLoader]|CommentsInLocalTime.js * UTCLiveClock[ResourceLoader|type=general|dependencies=mediawiki.util,mediawiki.api|peers=UTCLiveClock-pagestyles]|UTCLiveClock.js|UTCLiveClock.css * WiktSidebarTranslation[ResourceLoader|dependencies=ext.uls.interlanguage]|WiktSidebarTranslation.js * searchFocus[ResourceLoader]|searchFocus.js * TabbedLanguages[ResourceLoader|dependencies=mediawiki.cookie,mediawiki.util|type=general|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|TabbedLanguages.js|TabbedLanguages.css * FastRollback[ResourceLoader|rights=rollback|dependencies=mediawiki.api]|FastRollback.js * AudioBotBlacklist[ResourceLoader|default|dependencies=mediawiki.api,oojs-ui-core,oojs-ui-widgets,oojs-ui-windows,ext.gadget.WiktGadgetPrefs|rights=autoconfirmed]| AudioBotBlacklist.js * OrangeLinks[ResourceLoader|dependencies=mediawiki.api,mediawiki.Title,mediawiki.util]|OrangeLinks.js * U2693[ResourceLoader|dependencies=mediawiki.Title,mediawiki.util|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|U2693.js * AggregateInterprojectLinks[ResourceLoader|dependencies=mediawiki.cookie]|AggregateInterprojectLinks.js * MoreMenu-local[ResourceLoader|dependencies=mediawiki.api,mediawiki.util,user.options]|MoreMenu-local.js * nearby[ResourceLoader|dependencies=mediawiki.util,mediawiki.api,ext.gadget.UnsupportedTitles|namespaces=0,100,118]|nearby.js * linkLanguageHeaders[ResourceLoader|dependencies=mediawiki.api|namespaces=0,118]|linkLanguageHeaders.js * ReferenceTooltips[ResourceLoader|default|type=general|dependencies=mediawiki.cookie,jquery.client,site]|ReferenceTooltips.js * categoryTreeLanguageNames[ResourceLoader|dependencies=mediawiki.api,mediawiki.util|namespaces=0,14,100,118]|categoryTreeLanguageNames.js * Streamline[ResourceLoader|dependencies=mediawiki.api,mediawiki.util,ext.gadget.WiktGadgetPrefs,ext.gadget.defaultVisibilityToggles|namespaces=0,4,118]|Streamline.js * minitoc[ResourceLoader|default|dependencies=site|categories=Pages calling Template:minitoc,Mammoth pages]|minitoc.js * EtytreeZoom[ResourceLoader|default|dependencies=site,mediawiki.util|categories=Pages with etymology trees]|EtytreeZoom.js * CategoryJumpTo[ResourceLoader|dependencies=mediawiki.api,mediawiki.notification,mediawiki.util,oojs-ui-core|namespaces=14]|CategoryJumpTo.js * Anchor[ResourceLoader|dependencies=mediawiki.notification,mediawiki.util,ext.gadget.WiktGadgetPrefs]|Anchor.js * JumpToError[ResourceLoader|dependencies=mediawiki.notification]|JumpToError.js * VetVoters[ResourceLoader|dependencies=mediawiki.util,mediawiki.api|namespaces=4,5]|VetVoters.js * VisibilityToggles[ResourceLoader|dependencies=user,mediawiki.cookie]|VisibilityToggles.js * defaultVisibilityToggles[ResourceLoader|default|dependencies=ext.gadget.VisibilityToggles]|defaultVisibilityToggles.js == editing-gadgets == * TranslationAdder[ResourceLoader|default|dependencies=site,ext.gadget.Editor,mediawiki.cookie,ext.gadget.LanguageUtils,mediawiki.util,ext.gadget.TranslationAdder-Data|categories=Entries with translation boxes]|TranslationAdder.js * RhymesAdder[ResourceLoader|default|dependencies=site,ext.gadget.Editor,mediawiki.util,ext.gadget.LanguageUtils|namespaces=106]|RhymesAdder.js * PatrollingEnhancements[ResourceLoader|default|dependencies=site|rights=patrol]|PatrollingEnhancements.js * RegexMenuFramework[ResourceLoader]|RegexMenuFramework.js * AcceleratedFormCreation[ResourceLoader|dependencies=mediawiki.util]|AcceleratedFormCreation.css|AcceleratedFormCreation.js * HotCat[ResourceLoader]|HotCat.js * FastRevert[ResourceLoader|dependencies=mediawiki.util]|FastRevert.js * ChangesByLanguage[ResourceLoader]|ChangesByLanguage.js * DefSideBoxes[ResourceLoader|dependencies=mediawiki.cookie,mediawiki.util,ext.gadget.DefinitionsAdder|type=general]|DefSideBoxes.js|DefSideBoxes.css * DotsSyntaxHighlighter[ResourceLoader]|DotsSyntaxHighlighter.js * DeveloperEditorTweaks[ResourceLoader|dependencies=ext.wikiEditor,mediawiki.util]|DeveloperEditorTweaks.js * AjaxEdit[ResourceLoader|dependencies=mediawiki.util,mediawiki.user,mediawiki.api|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|AjaxEdit.js * EditHere[ResourceLoader]|EditHere.js * FlagMovedPageForDeletion[ResourceLoader|default|dependencies=site,mediawiki.api|namespaces=-1]|FlagMovedPageForDeletion.js == misc-gadgets == * zhDialMap[ResourceLoader|default|dependencies=site,oojs-ui-core|categories=Chinese dialectal equivalent maps]|zhDialMap.js|zhDialMap.css * DialectMap[ResourceLoader|default|dependencies=site]|DialectMap.js|DialectMap.css * NoAutoCaseRedirect[ResourceLoader]|NoAutoCaseRedirect.js * aWa[ResourceLoader|rights=autopatrol|dependencies=mediawiki.util,mediawiki.api,mediawiki.user,user.options,mediawiki.Title|type=general]|aWa.js|aWa.css * QQ[ResourceLoader|dependencies=jquery.ui,mediawiki.util|type=general]|QQ.js|QQ.css * AutoGlossary[ResourceLoader|default|dependencies=site,mediawiki.api|categories=Pages using auto-glossary]|AutoGlossary.js == Hidden gadgets and utils == * AGprefs[ResourceLoader|hidden|dependencies=mediawiki.util,oojs-ui-core]|AGprefs.js * DocTabs[ResourceLoader|hidden|default|dependencies=mediawiki.api,mediawiki.util|namespaces=0,1,10,11,114,828,829]|DocTabs.js|DocTabs.css * Editor[ResourceLoader|hidden|dependencies=mediawiki.util,mediawiki.api]|Editor.js * StorageUtils[ResourceLoader|hidden|dependencies=mediawiki.cookie,mediawiki.storage]|StorageUtils.js * LanguageUtils[ResourceLoader|hidden|dependencies=mediawiki.api,ext.gadget.StorageUtils]|LanguageUtils.js * DefinitionsAdder[ResourceLoader|hidden|dependencies=mediawiki.api,mediawiki.util,ext.gadget.Editor]|DefinitionsAdder.js * TranslationAdder-Data[ResourceLoader|hidden|dependencies=mediawiki.api,ext.gadget.LanguageUtils|categories=Entries with translation boxes]|TranslationAdder-Data.js * catfixRegrouper[ResourceLoader|hidden|default|dependencies=site,mediawiki.Title,ext.gadget.catfixRegrouper-Data|namespaces=14]|catfixRegrouper.js * catfixRegrouper-Data[ResourceLoader|hidden|default|dependencies=site|namespaces=14]|catfixRegrouper-Data.js * catfix[ResourceLoader|hidden|default|dependencies=site,mediawiki.Title|categories=Pages using catfix]|catfix.js * Edittools[ResourceLoader|hidden|default|dependencies=mediawiki.cookie,jquery.textSelection]|Edittools.js|Edittools.css * UnsupportedTitles[ResourceLoader|hidden|default|package]|UnsupportedTitles.js|UnsupportedTitles.json * CssTest[ResourceLoader|hidden|type=styles]|CssTest.css * Palette[ResourceLoader|hidden|default]|Palette.css * UTCLiveClock-pagestyles[hidden|skins=vector,monobook]|UTCLiveClock-pagestyles.css * Site[ResourceLoader|hidden|default]|Site.css * SiteJS[ResourceLoader|hidden|default]|Site.js * InflectionTable[ResourceLoader|hidden|default]|InflectionTable.css * WiktGadgetPrefs[ResourceLoader|hidden|default|dependencies=mediawiki.user,user.options]|WiktGadgetPrefs.js * ShowIDs-pagestyles[hidden|type=styles]|ShowIDs-pagestyles.css * TreeDescs-pagestyles[hidden|type=styles]|TreeDescs-pagestyles.css cq6u60f8n5buu87gslulknl40c84pjs 88857 88856 2026-08-06T22:32:57Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadgets-definition]] 88856 wikitext text/x-wiki {{shortcut|WT:GD}} See [[Special:Gadgets]] for documentation of these gadgets, and [[Wiktionary:Gadgets]] for general information about gadgets on Wiktionary. See also [[WT:PREFS]] for other preferences. {{gadgets pages}} == appearance == * MonobookSmallerHeadings[ResourceLoader|default|skins=monobook]|MonobookSmallerHeadings.css * LanguagesAndScripts[ResourceLoader|default]|LanguagesAndScripts.css * VectorClassic[ResourceLoader|type=styles|skins=vector]|VectorClassic.css * CatchMyAttention[ResourceLoader|type=styles]|CatchMyAttention.css * HideLogo[ResourceLoader|type=styles]|HideLogo.css * vectorTabs[ResourceLoader|skins=vector|type=styles]|vectorTabs.js|vectorTabs.css * WiktCountryFlags[ResourceLoader|type=styles|namespaces=0]|WiktCountryFlags.css * WiktPreviewRightTOCs[ResourceLoader|namespaces=0]|WiktPreviewRightTOCs.css * LogoTiles[ResourceLoader|type=styles]|LogoTiles.css * RoundBullets4Lists[ResourceLoader|type=styles]|RoundBullets4Lists.css * BC-AD[ResourceLoader]|BC-AD.js * AutoContrastFixer[ResourceLoader|skins=vector-2022,minerva|dependencies=ext.gadget.WiktGadgetPrefs]|AutoContrastFixer.js * ShowIDs[ResourceLoader|dependencies=mediawiki.util|peers=ShowIDs-pagestyles]|ShowIDs.js * TreeDescs[ResourceLoader|peers=TreeDescs-pagestyles]|TreeDescs.js * NoMiniToc[ResourceLoader|type=general]|NoMiniToc.js|NoMiniToc.css * NsfwOverride[ResourceLoader|dependencies=mediawiki.util]|NsfwOverride.js|NsfwOverride.css * MobileCollapseCategories[ResourceLoader|skins=minerva|dependencies=mediawiki.util,ext.gadget.VisibilityToggles]|MobileCollapseCategories.js == interface-gadgets == * TargetedTranslations[ResourceLoader|default|dependencies=site,mediawiki.storage,mediawiki.cookie,ext.gadget.StorageUtils|categories=Entries with translation boxes]|TargetedTranslations.js|TargetedTranslations.css * BlockInfo[ResourceLoader|default|dependencies=site,mediawiki.api,mediawiki.language.months,mediawiki.util|namespaces=-1,2,3]|BlockInfo.js * RevdelInfo[ResourceLoader|dependencies=site,mediawiki.api,mediawiki.language.months,mediawiki.util]|RevdelInfo.js * CodeLinks[ResourceLoader|dependencies=site,mediawiki.util]|CodeLinks.js * purgetab[ResourceLoader|dependencies=mediawiki.api,mediawiki.util]|purgetab.js * Navigation_popups[ResourceLoader]|popups.js * PagePreviews[ResourceLoader|default|dependencies=site,mediawiki.api,mediawiki.util,mediawiki.Title|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|PagePreviews.js * CommentsInLocalTime[ResourceLoader]|CommentsInLocalTime.js * UTCLiveClock[ResourceLoader|type=general|dependencies=mediawiki.util,mediawiki.api|peers=UTCLiveClock-pagestyles]|UTCLiveClock.js|UTCLiveClock.css * WiktSidebarTranslation[ResourceLoader|dependencies=ext.uls.interlanguage]|WiktSidebarTranslation.js * searchFocus[ResourceLoader]|searchFocus.js * TabbedLanguages[ResourceLoader|dependencies=mediawiki.cookie,mediawiki.util|type=general|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|TabbedLanguages.js|TabbedLanguages.css * FastRollback[ResourceLoader|rights=rollback|dependencies=mediawiki.api]|FastRollback.js * AudioBotBlacklist[ResourceLoader|default|dependencies=mediawiki.api,oojs-ui-core,oojs-ui-widgets,oojs-ui-windows,ext.gadget.WiktGadgetPrefs|rights=autoconfirmed]| AudioBotBlacklist.js * OrangeLinks[ResourceLoader|dependencies=mediawiki.api,mediawiki.Title,mediawiki.util]|OrangeLinks.js * U2693[ResourceLoader|dependencies=mediawiki.Title,mediawiki.util|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|U2693.js * AggregateInterprojectLinks[ResourceLoader|dependencies=mediawiki.cookie]|AggregateInterprojectLinks.js * MoreMenu-local[ResourceLoader|dependencies=mediawiki.api,mediawiki.util,user.options]|MoreMenu-local.js * nearby[ResourceLoader|dependencies=mediawiki.util,mediawiki.api,ext.gadget.UnsupportedTitles|namespaces=0,100,118]|nearby.js * linkLanguageHeaders[ResourceLoader|dependencies=mediawiki.api|namespaces=0,118]|linkLanguageHeaders.js * ReferenceTooltips[ResourceLoader|default|type=general|dependencies=mediawiki.cookie,jquery.client,site]|ReferenceTooltips.js * categoryTreeLanguageNames[ResourceLoader|dependencies=mediawiki.api,mediawiki.util|namespaces=0,14,100,118]|categoryTreeLanguageNames.js * Streamline[ResourceLoader|dependencies=mediawiki.api,mediawiki.util,ext.gadget.WiktGadgetPrefs,ext.gadget.defaultVisibilityToggles|namespaces=0,4,118]|Streamline.js * minitoc[ResourceLoader|default|dependencies=site|categories=Pages calling Template:minitoc,Mammoth pages]|minitoc.js * EtytreeZoom[ResourceLoader|default|dependencies=site,mediawiki.util|categories=Pages with etymology trees]|EtytreeZoom.js * CategoryJumpTo[ResourceLoader|dependencies=mediawiki.api,mediawiki.notification,mediawiki.util,oojs-ui-core|namespaces=14]|CategoryJumpTo.js * Anchor[ResourceLoader|dependencies=mediawiki.notification,mediawiki.util,ext.gadget.WiktGadgetPrefs]|Anchor.js * JumpToError[ResourceLoader|dependencies=mediawiki.notification]|JumpToError.js * VetVoters[ResourceLoader|dependencies=mediawiki.util,mediawiki.api|namespaces=4,5]|VetVoters.js * VisibilityToggles[ResourceLoader|dependencies=user,mediawiki.cookie]|VisibilityToggles.js * defaultVisibilityToggles[ResourceLoader|default|dependencies=ext.gadget.VisibilityToggles]|defaultVisibilityToggles.js == editing-gadgets == * TranslationAdder[ResourceLoader|default|dependencies=site,ext.gadget.Editor,mediawiki.cookie,ext.gadget.LanguageUtils,mediawiki.util,ext.gadget.TranslationAdder-Data|categories=Entries with translation boxes]|TranslationAdder.js * RhymesAdder[ResourceLoader|default|dependencies=site,ext.gadget.Editor,mediawiki.util,ext.gadget.LanguageUtils|namespaces=106]|RhymesAdder.js * PatrollingEnhancements[ResourceLoader|default|dependencies=site|rights=patrol]|PatrollingEnhancements.js * RegexMenuFramework[ResourceLoader]|RegexMenuFramework.js * AcceleratedFormCreation[ResourceLoader|dependencies=mediawiki.util]|AcceleratedFormCreation.css|AcceleratedFormCreation.js * HotCat[ResourceLoader]|HotCat.js * FastRevert[ResourceLoader|dependencies=mediawiki.util]|FastRevert.js * ChangesByLanguage[ResourceLoader]|ChangesByLanguage.js * DefSideBoxes[ResourceLoader|dependencies=mediawiki.cookie,mediawiki.util,ext.gadget.DefinitionsAdder|type=general]|DefSideBoxes.js|DefSideBoxes.css * DotsSyntaxHighlighter[ResourceLoader]|DotsSyntaxHighlighter.js * DeveloperEditorTweaks[ResourceLoader|dependencies=ext.wikiEditor,mediawiki.util]|DeveloperEditorTweaks.js * AjaxEdit[ResourceLoader|dependencies=mediawiki.util,mediawiki.user,mediawiki.api|skins=vector,vector-2022,monobook,timeless,modern,cologneblue]|AjaxEdit.js * EditHere[ResourceLoader]|EditHere.js * FlagMovedPageForDeletion[ResourceLoader|default|dependencies=site,mediawiki.api|namespaces=-1]|FlagMovedPageForDeletion.js == misc-gadgets == * zhDialMap[ResourceLoader|default|dependencies=site,oojs-ui-core|categories=Chinese dialectal equivalent maps]|zhDialMap.js|zhDialMap.css * DialectMap[ResourceLoader|default|dependencies=site]|DialectMap.js|DialectMap.css * NoAutoCaseRedirect[ResourceLoader]|NoAutoCaseRedirect.js * aWa[ResourceLoader|rights=autopatrol|dependencies=mediawiki.util,mediawiki.api,mediawiki.user,user.options,mediawiki.Title|type=general]|aWa.js|aWa.css * QQ[ResourceLoader|dependencies=jquery.ui,mediawiki.util|type=general]|QQ.js|QQ.css * AutoGlossary[ResourceLoader|default|dependencies=site,mediawiki.api|categories=Pages using auto-glossary]|AutoGlossary.js == Hidden gadgets and utils == * AGprefs[ResourceLoader|hidden|dependencies=mediawiki.util,oojs-ui-core]|AGprefs.js * DocTabs[ResourceLoader|hidden|default|dependencies=mediawiki.api,mediawiki.util|namespaces=0,1,10,11,114,828,829]|DocTabs.js|DocTabs.css * Editor[ResourceLoader|hidden|dependencies=mediawiki.util,mediawiki.api]|Editor.js * StorageUtils[ResourceLoader|hidden|dependencies=mediawiki.cookie,mediawiki.storage]|StorageUtils.js * LanguageUtils[ResourceLoader|hidden|dependencies=mediawiki.api,ext.gadget.StorageUtils]|LanguageUtils.js * DefinitionsAdder[ResourceLoader|hidden|dependencies=mediawiki.api,mediawiki.util,ext.gadget.Editor]|DefinitionsAdder.js * TranslationAdder-Data[ResourceLoader|hidden|dependencies=mediawiki.api,ext.gadget.LanguageUtils|categories=Entries with translation boxes]|TranslationAdder-Data.js * catfixRegrouper[ResourceLoader|hidden|default|dependencies=site,mediawiki.Title,ext.gadget.catfixRegrouper-Data|namespaces=14]|catfixRegrouper.js * catfixRegrouper-Data[ResourceLoader|hidden|default|dependencies=site|namespaces=14]|catfixRegrouper-Data.js * catfix[ResourceLoader|hidden|default|dependencies=site,mediawiki.Title|categories=Pages using catfix]|catfix.js * Edittools[ResourceLoader|hidden|default|dependencies=mediawiki.cookie,jquery.textSelection]|Edittools.js|Edittools.css * UnsupportedTitles[ResourceLoader|hidden|default|package]|UnsupportedTitles.js|UnsupportedTitles.json * CssTest[ResourceLoader|hidden|type=styles]|CssTest.css * Palette[ResourceLoader|hidden|default]|Palette.css * UTCLiveClock-pagestyles[hidden|skins=vector,monobook]|UTCLiveClock-pagestyles.css * Site[ResourceLoader|hidden|default]|Site.css * SiteJS[ResourceLoader|hidden|default]|Site.js * InflectionTable[ResourceLoader|hidden|default]|InflectionTable.css * WiktGadgetPrefs[ResourceLoader|hidden|default|dependencies=mediawiki.user,user.options]|WiktGadgetPrefs.js * ShowIDs-pagestyles[hidden|type=styles]|ShowIDs-pagestyles.css * TreeDescs-pagestyles[hidden|type=styles]|TreeDescs-pagestyles.css cq6u60f8n5buu87gslulknl40c84pjs MediaWiki:Gadget-ReferenceTooltips.js 8 17928 88858 2024-08-15T02:37:51Z en>Ioaxxere 0 try this 88858 javascript text/javascript if (document.querySelector(".reference") && mw.config.values.skin !== "minerva") { mw.loader.load('https://en.wikipedia.org/w/load.php?modules=ext.gadget.ReferenceTooltips&only=scripts'); mw.loader.load('https://en.wikipedia.org/w/load.php?modules=ext.gadget.ReferenceTooltips&only=styles', 'text/css'); } 338nz65nbt8zoj2jtwrzzy2sx41v3kz 88859 88858 2026-08-06T22:33:34Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-ReferenceTooltips.js]] 88858 javascript text/javascript if (document.querySelector(".reference") && mw.config.values.skin !== "minerva") { mw.loader.load('https://en.wikipedia.org/w/load.php?modules=ext.gadget.ReferenceTooltips&only=scripts'); mw.loader.load('https://en.wikipedia.org/w/load.php?modules=ext.gadget.ReferenceTooltips&only=styles', 'text/css'); } 338nz65nbt8zoj2jtwrzzy2sx41v3kz MediaWiki:Gadget-Site.css 8 17929 88860 2026-01-22T08:36:32Z en>This, that and the other 0 suppress collapsing of NavFrames with class no-collapse 88860 css text/css /* ---------- <nowiki> CSS Style * Indent with tab characters * One line space between each declaration * One selector per line * Opening brace on the same line as the last selector * Don't omit optional semicolons * Closing brace on its own line * Closing brace indented to match the preceding style declarations * Alternatively, very short style rules may be all on one line ---------- */ /* csslint adjoining-classes:false */ /* See also [[MediaWiki:Minerva.css]], [[MediaWiki:Vector.css]] */ sup, sub { /* prevent odd line-height for raised and lowered characters */ line-height: 1em; } /* and keep links at normal font size/weight, else they inherit the header attributes */ .editsection { font-size: 100%; font-weight: normal; } pre code, code code { border: none; padding: 0; } pre var, code var { color: var(--wikt-palette-grey-9,#777); } /* This fixes a bug where certain Tibetan terms are cut off at the bottom... */ #firstHeading { overflow: visible; } .ns-0 .timed-text { display: none; } .client-js .audiometa { display: none; } .client-nojs .audiofile { display: none; } .nowrap { white-space: nowrap; } /* wikitable is part of core. prettytable is deprecated but still used in some places, until fully replaced: */ table.prettytable { margin: 1em 1em 1em 0; background: var(--wikt-palette-paleblue, #f8f9fa); border: 1px var(--border-color-base, #aaaaaa) solid; border-collapse: collapse; } table.prettytable th, table.prettytable td { border: 1px var(--border-color-base, #aaaaaa) solid; padding: 0.2em; } table.prettytable th { background: var(--wikt-palette-lightergrey, #eeeeee); text-align: center; } table.prettytable caption { margin-left: inherit; margin-right: inherit; } /* default setting for {{qualifier}} and {{sense}}. (Related classes that can be overridden: .qualifier-comma, .qualifier-content, .ib-brac, .qualifier-brac, .sense-qualifier-colon.) */ .ib-comma { font-style: normal; } .ib-content { font-style: italic; } .ib-content i, .ib-content em { font-style: normal; } .context-qualifier-colon { display: none; } /* default style for indented "see also" */ .disambig-see-also { text-indent: 2em; } .mention-tr { font-style: italic; } /* add left-to-right mark */ .mention-gloss-paren::before, .mention-tr-paren::before { content: "‎"; } /* non-italic and non-bold gloss */ .mention-gloss, .mention-gloss-double-quote, .mention-gloss-paren, .mention-tr-gloss-separator-comma, .mention-tr-paren, .mention-tr-gloss-separator-comma { font-style: normal; font-weight: inherit; } /* default style for "form of" definitions */ .use-with-mention, .form-of-definition { font-style: italic; } .use-with-mention i, .form-of-definition-link { font-style: normal; } .use-with-mention .mention, .form-of-definition-link .mention { font-style: normal; font-weight: bold; } /* display normalization in {{ux}}/{{usex}}, {{quote}}, {{quote-*}} in italics */ .e-normalization { font-style: italic; } /* Inflection tables ----------------------------- */ /* To colour links in inflection tables (currently done with {{notred}}) black without using #ifexist and allowing for user override */ .inflection-table a.new { color: inherit; } /* fill a parent NavContent collapsing box */ .NavContent table.inflection, .NavContent table.inflection-table { margin-top: 0; width: 100%; display: table; border: 0; } /* basic inflection table styles */ table.inflection { border-collapse: collapse; border: 1px solid; background: #ffffff; /* TODO consider palettizing */ } table.inflection caption { caption-side: bottom; padding: 0.33em 1em; text-align: left; font-size: smaller; } /* subtle grey for alternate row backgrounds */ table.inflection tr:nth-child(odd) { background: #fcfcfc; /* TODO consider palettizing */ } /* and for row headers */ table.inflection tr:nth-child(odd):not(.rowgroup) th { background: #f6f6f6; /* TODO consider palettizing */ } /* dark mode background colors for table.inflection */ @media screen { html.skin-theme-clientpref-night table.inflection { background-color: #242424; } html.skin-theme-clientpref-night table.inflection tr:nth-child(odd) { background-color: #2E2E2E; } html.skin-theme-clientpref-night table.inflection tr:nth-child(odd):not(.rowgroup) th { background-color: #303030; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os table.inflection { background-color: #242424; } html.skin-theme-clientpref-os table.inflection tr:nth-child(odd) { background-color: #2E2E2E; } html.skin-theme-clientpref-os table.inflection tr:nth-child(odd):not(.rowgroup) th { background-color: #303030; } } table.inflection td, table.inflection th { padding: 0.33em 1em; vertical-align: baseline; } /* but vertically center multi-row cells */ table.inflection td[rowspan] { vertical-align: middle; } table.inflection td { text-align: center; } /* regular row headers, in the left column */ table.inflection th { background: var(--wikt-palette-paleblue, #f8f9fa); text-align: left; } /* rowgroup header rows */ table.inflection tr.rowgroup th { background: var(--wikt-palette-lightergrey, #eeeeee); text-align: center; } /* first-of-several rowgroup header cells is aligned left */ table.inflection tr.rowgroup th:first-child { text-align: left; } table.inflection tr.rowgroup th:first-child:only-child { text-align: center; } /* rows with dividers above */ table.inflection tr.divider th { border-top: 3px solid var(--wikt-palette-grey-7,#999999); } /* transliterations */ table.inflection .translit { color: var(--wikt-palette-grey-8,#888); } /* header links aren’t coloured until hover/active */ table.inflection th a:link, table.inflection th a:visited { color: inherit; text-decoration: inherit; } table.inflection th a:hover { color: var(--wikt-palette-blue-9,#0645ad); text-decoration: underline; } table.inflection th a:active { color: var(--wikt-palette-gold,#faa700); text-decoration: underline; } /* ---- end of Inflection tables */ /* Hide interproject links used by [[MediaWiki:Gadget-AggregateInterprojectLinks.js]] */ .interProject { display: none; clear: both; border-top: 2px dotted var(--border-color-base,#AAAAAA); margin-top: 2em; } /* Translation styling */ .checktrans, .rfc-trans, .trreq, .ttbc { background: var(--wikt-palette-palegreen, #f0fff0); } /* t+ t t- templates: TODO are these still wanted? */ .tneg, .tpos, .tunk { vertical-align: 20%; font-size: 80%; } .tneg a { color: var(--wikt-palette-red,#cc2200) !important; } /* monobook redlink colour, standard #ba0000 */ .tneg a:visited { color: var(--wikt-palette-grey-red-9,#a55858) !important; } /* standard visited redlink colour */ .tpos a { color: var(--wikt-palette-deepblue); } /* standard bluelink colour */ .tpos a:visited { color: var(--wikt-palette-blue); } /* standard bluelink colour */ .tunk a { color: var(--wikt-palette-blue-9,#3366BB) !important; } /* standard external interwiki colour */ .tunk a:active { color: var(--wikt-palette-blue-9,#3366BB) !important; } /* redundant */ /* for parentheses, we use .tlc and .tlcp, the latter has no definition here (display:inline) */ .tlc { display: none; } /* Main page fixes */ #interwiki-completelist { font-weight: bold; } /* Try to make search results more obviously links */ .mw-special-Search #bodyContent li a { font-weight: bold; } .mw-special-Search .searchmatch { font-weight: normal; color: var(--wikt-palette-black, #000000); background-color: var(--wikt-palette-brightyellow, #FFEE77); } /* [[WT:FEED]] */ #p-feedback a { cursor: pointer; } /* Old revisions */ #mw-revision-info { font-size: 110%; margin: 5px 0; } #mw-editingold { font-size: 120%; } /* maintenance line */ .maintenance-line { color: #777777; /* TODO consider palettizing */ } /* dark mode text color for maintenance line */ @media screen { html.skin-theme-clientpref-night .maintenance-line { color: #adb7bf; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .maintenance-line { color: #adb7bf; } } /* Night mode logo appearance, see [[Wiktionary:Grease pit/2025/January#Top left Wiktionary logo in dark mode]] */ @media screen { html.skin-theme-clientpref-night img.mw-logo-icon { color-scheme: light; filter: invert(1) brightness(55%) contrast(250%) hue-rotate(180deg); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os img.mw-logo-icon { color-scheme: light; filter: invert(1) brightness(55%) contrast(250%) hue-rotate(180deg); } } /* Make Recent changes look nice again */ span.newpage, span.minor, span.searchmatch, span.bot, span.unpatrolled { font-family: sans-serif !important; } /* Styling for the different kinds of collapsible boxes and lists */ /* NavFrames */ div.NavFrame, details.NavFrame { border: 1px solid var(--wikt-palette-grey, #9e9e9e); text-align: center; border-collapse: collapse; font-size: 95%; overflow: auto; width: auto; } div.NavFrame>ul, div.NavFrame>ol { text-align: left; } div.NavFrame div.NavHead, details.NavFrame summary.NavHead { margin: 2px; min-height: 1.6em; font-weight: bold; font-size: 100%; text-align: left; padding: 1px 5px 1px 10px; background-color: var(--wikt-palette-dullcyan, #eaecf0); } div.NavFrame p { font-size: 100%; } div.NavFrame div.NavContent, details.NavFrame div.NavContent { font-size: 100%; border-top: 1px solid var(--wikt-palette-grey, #9e9e9e); } div.NavFrame div.NavContent p, details.NavFrame div.NavContent p { font-size: 100%; } /* Used by box-top/box-bottom */ .NavContent.boxcontent { padding: 0.25em 0.5em; } .NavContent.boxcontent>p:last-child { margin-bottom: 0.5em; /* from 1em to avoid some extra asymmetric space */ } /* Override default added margins which mess up the background */ .NavContent.derivedterms>p, .NavContent.columns-bg>p { margin: 0; } .NavContent.derivedterms>p, .NavContent.derivedterms>ul, .NavContent.columns-bg>p, .NavContent.columns-bg>ul { padding: 0.5em; } /* Collapsible term lists */ .list-switcher { /* This is a hack so we can use getComputedStyle to find the maximum permissible height value of a list-switcher. It must be kept in sync with .list-switcher-collapsed `max-height` */ bottom: calc(3.2 * 1.6em); /* for browsers that don't support `lh` units */ bottom: 3.2lh; } .list-switcher-wrapper, :not(.list-switcher-wrapper)>.list-switcher { contain: layout; /* stop floating elements from messing with layout */ margin-top: 0.3em; /* replaces margin lost on <ul> in following ruleset */ } .list-switcher-wrapper+.list-switcher-wrapper { margin-top: 0.6em; } .list-switcher>div>ul, .list-switcher-wrapper>div>ul { margin-top: 0; /* needed to avoid jumps when collapsing/uncollapsing */ } .list-switcher ul ul { margin-top: 0.1em; /* make margin above nested lists equal to margin at bottom of <li>s */ } .list-switcher-collapsed { /* If changing this value, change .list-switcher `bottom` above */ max-height: calc(3.2 * 1.6em); /* for browsers that don't support `lh` units */ max-height: 3.2lh; overflow-y: hidden; transform: translateZ(0); /* Fix for iOS Safari overflow clipping */ } .list-switcher-header { background: var(--wikt-palette-grey-indigo-2); font-weight: bold; font-size: 95%; padding: 0.2em 0.4em 0.1em 0.6em; } .list-switcher-header+.list-switcher .term-list, .list-switcher-header+.term-list { padding-top: 0.1em; } .list-switcher-edit { margin-left: 1.5em; font-size: 87.75%; /* exactly match font size of [show more] button (in Chromium-based browsers at least) */ font-weight: normal; } .list-switcher-edit::before { content: "["; } .list-switcher-edit::after { content: "]"; } .list-switcher-large-text { /* Keep in sync with next ruleset */ bottom: calc(4 * 1.6em); /* for browsers that don't support `lh` units */ bottom: 4lh; } .list-switcher-large-text.list-switcher-collapsed { /* Keep in sync with previous ruleset */ max-height: calc(4 * 1.6em); /* for browsers that don't support `lh` units */ max-height: 4lh; } .list-switcher-element { text-align: center; cursor: pointer; background: var(--wikt-palette-grey-indigo-2); border-bottom-left-radius: 0.3lh; border-bottom-right-radius: 0.3lh; } .list-switcher-element .NavToggle { float: none; } /* this is a legacy rule that only applies to {{rootsee}} and {{script appendix}} - these need a fairly wide width */ .columns-bg:not(.term-list)>div>div>.CategoryTreeChildren, .columns-bg:not(.term-list)>div>.CategoryTreeChildren { -moz-column-width: 25em; column-width: 25em; } /* Hidden quotes */ .client-js .ns-0 ol>li>ul { display: none; } /* Hidden Quotes and *nyms toggle */ .HQToggle, .nyms-toggle, .usex-toggle { font-size: smaller; position: relative; bottom: 1px; left: 5px; } .NavToggle { float: right; font-weight: normal; font-size: smaller; margin-top: 1px; margin-left: 0.5em; } /* wrap toggle links with [ and ] */ .HQToggle:before, .NavToggle:before, .nyms-toggle:before, .usex-toggle:before { content: '['; } .HQToggle:after, .NavToggle:after, .nyms-toggle:after, .usex-toggle:after { content: ']'; } .HQToggle a, .NavToggle a, .nyms-toggle a, .usex-toggle a { -webkit-user-select: none; -moz-user-select: none; user-select: none; color: var(--wikt-palette-black); } .HQToggle a:focus:not(:hover), .NavToggle a:focus:not(:hover), .nyms-toggle a:focus:not(:hover), .usex-toggle a:focus:not(:hover) { text-decoration: none; } .client-js .NavFrame:not(.no-collapse) .NavContent { display: none; } /* View switcher */ .vsShow { display: none; } /* End styling for collapsible lists */ /* Quote clarifications, e.g. {{quote-gloss}}, {{quote-qualifier}} */ .quote-note { color: var(--wikt-palette-grey-9,#999); } /* Use same formatting for <mark> as used for bolding with certain scripts. */ mark { background-color: var(--wikt-palette-pink, #ffe0f0); color: var(--wikt-palette-black, #202122); } /* stuff visible when previewing an edit only */ .previewonly { display: none; } #wikiPreview .previewonly { display: inline; } /* Highlight the relevant sense when the user follows a link to a {{senseid}}. The class="senseid" should ideally be on the enclosing <li> tag. We attempt to make the highlight work when the class="senseid" is on a <span> inside the <li>, but the :has selector was not supported by all browsers as of late 2023. This feature was nonetheless requested by Benwing at [[Wiktionary:Grease_pit/2023/November#Why_does_Template%3Asenseid_use_HTML_li_tag%3F]]. THe version with :has is provided as a separate declaration to ensure maximum compatibility. */ .senseid:target { background: var(--wikt-palette-lightblue, #DEF); } li:has(> span.senseid:target) { background: var(--wikt-palette-lightblue, #DEF); } /* highlight the next paragraph for an etymid */ .etymid:target+p, .etymonid:target+p { background: var(--wikt-palette-lightblue, #DEF); } /* Highlight selected source in a bibliography */ .bibliography-id:target { background: var(--wikt-palette-lightblue, #DEF); } /* Skin CSS highlights table rows targeted by the current browser location (tr:target). This rule highlight table rows containing target cells so that there can be multiple IDs in a table row in [[Wiktionary:List of languages]] and [[Wiktionary:List of languages/special#Etymology-only languages]]. */ tr:has(> :target), tr:has(> td > code:target) { background: var(--wikt-palette-lightblue, #DEF); } /* show the "serial and" in the disambiguation see also */ .serial-and { display: inline; } /* hide the serial commas */ .serial-comma { display: none; } /* Gender and number templates */ .gender, .number, .noun-class { font-style: italic; } abbr { border-bottom-width: 0; } /* hide "did you mean" on Noarticletext self-links */ .did-you-mean strong { display: none; } /* make script/module errors smaller */ .scribunto-error { font-size: 75%; } /* allow inline hieroglyphs */ .mw-hiero-outer { display: inline-table !important; /* override skin styling on mobile */ vertical-align: middle; font-size: 10px; } /* allow mirrored custom hieroglyph (and other) images */ .mw-mirrored img { transform: scaleX(-1); } /* softer highlighting of 'updated since last visit' */ span.updatedmarker { background-color: var(--wikt-palette-mint, #c0e4c0); } /* {{TOC limit}} */ /* Allow limiting of which header levels are shown in a TOC; <div class="toclimit-3">, for instance, will limit to showing ==headings== and ===headings=== but no further (as long as there are no =headings= on the page, which there shouldn't be according to the MoS). */ .toclimit-2 .toclevel-1 ul, .toclimit-3 .toclevel-2 ul, .toclimit-4 .toclevel-3 ul, .toclimit-5 .toclevel-4 ul, .toclimit-6 .toclevel-5 ul, .toclimit-7 .toclevel-6 ul { display: none; } /* * Script and language-related styles are in [[MediaWiki:Gadget-LanguagesAndScripts.css]] */ /* A kludge that lets the members of [[:Category:Redirected combining characters]] be displayed. */ body.page-Category_Combining_characters div#mw-pages li, body.page-Category_Redirected_combining_characters div#mw-pages li, body.page-Category_IPA_combining_characters div#mw-pages li { letter-spacing: 0.3em; } /* Grease Pit edit button fix */ .page-Wiktionary_Grease_pit.skin-vector #ca-edit, .page-Wiktionary_Etymology_scriptorium.skin-vector #ca-edit, .page-Wiktionary_Information_desk.skin-vector #ca-edit, .page-Wiktionary_Beer_parlour.skin-vector #ca-edit, .page-Wiktionary_Tea_room.skin-vector #ca-edit { display: none; } /* unit tests filter */ table.unit-tests.unit-tests-hide-passing tr.unit-test-pass { display: none; } table.unit-tests th.unit-tests-img-corner { background: var(--wikt-palette-lightblue, #d9ebff); min-width: 1em; } table.unit-tests.unit-tests-hide-passing th.unit-tests-img-corner { background: red; } /* multi-column lists */ li, .group-in-column { -moz-column-break-inside: avoid; break-inside: avoid; } /* {{shortcut}} */ .shortcut-box, .category-edit-box { border: 1px solid var(--border-color-base, #aaaaaa); color: var(--color-base, black); background: var(--wikt-palette-paleblue, #f9f9f9); margin: 0 0 .5em 1em; text-align: center; padding: 5px; float: right; clear: both; font-weight: bold; font-size: smaller; } /* Display tabs with 4 spaces, see [[phab:T59824]] and [[phab:T59825]] */ textarea#wpTextbox1+div:last-child, /* workaround for [[mw:User:Remember the dot/Syntax highlighter]] */ textarea, pre, code, .mw-highlight { -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } /* stop double-bolding of self-links like in [[acquit]], [[fishbone]] */ /* old code: b .selflink, strong .selflink { font-weight: inherit; } */ b, strong { font-weight: bold; } tr:target { background: var(--wikt-palette-lightblue, #DEF); } #firstHeading var, .headword var { color: var(--wikt-palette-grey-9, #888); } /* Display a {{tlb}} / {{term-label}} template on its own line if it comes right after a headword template. It is too easy to miss after headwords (especially long ones). */ p .headword-line~.usage-label-term::before { content: "\a"; /* newline */ white-space: pre; } /* Temporary kludge to be used because categoryTree is generating a newline. This CSS line should be removed after the developers fix it. */ .CategoryTreeTag+p br:first-child { display: none; } /* Used by column templates (see [[Module:columns]]). */ .ul-column-count>ul, .ul-column-count>ol, .ul-column-count>dl { -moz-column-gap: 20px; column-gap: 20px; } .ul-column-count[data-column-count="2"]>ul, .ul-column-count[data-column-count="2"]>ol, .ul-column-count[data-column-count="2"]>dl { -moz-column-count: 2; column-count: 2; } .ul-column-count[data-column-count="3"]>ul, .ul-column-count[data-column-count="3"]>ol, .ul-column-count[data-column-count="3"]>dl { -moz-column-count: 3; column-count: 3; } .ul-column-count[data-column-count="4"]>ul, .ul-column-count[data-column-count="4"]>ol, .ul-column-count[data-column-count="4"]>dl { -moz-column-count: 4; column-count: 4; } .ul-column-count[data-column-count="5"]>ul, .ul-column-count[data-column-count="5"]>ol, .ul-column-count[data-column-count="5"]>dl { -moz-column-count: 5; column-count: 5; } .ul-column-count[data-column-count="6"]>ul, .ul-column-count[data-column-count="6"]>ol, .ul-column-count[data-column-count="6"]>dl { -moz-column-count: 6; column-count: 6; } .columns-bg { /* Default background color for multi-column lists. */ background: var(--wikt-palette-lavender, #f8f8ff); /* prevent text crashing into edge of box */ padding-right: 0.3em; } /* Default style for hypothetical inflections -- currently italic. */ .hypothetical { font-style: italic; } /* Style for entries using deprecated templates */ .deprecated { color: olivedrab; } .deprecated a { color: darkgreen; } /* Style for entries using deprecated labels */ .deprecated-label { color: olivedrab; text-decoration: line-through; } .deprecated-label a { color: darkgreen; text-decoration: line-through; } /* Style for notes added using the bad= param in {{audio}} */ .bad-audio-note { color: var(--wikt-palette-red, #FF2200); font-weight: bold; } /* WikiHiero kludge */ /* disable for now, apparently not necessary and breaks wrapping .wikt-hierokludge { display: inline-block; } */ /* Support lists that automatically split into limited-width columns (for translations tables and the like): */ .multicolumn-list>ul { -moz-column-width: 25em; column-width: 25em; -moz-column-gap: 20px; column-gap: 20px; } .multicolumn-list-wide>ul { -moz-column-width: 55em; column-width: 55em; -moz-column-gap: 20px; column-gap: 20px; } .multicolumn-list-narrow>ul { -moz-column-width: 22em; column-width: 22em; -moz-column-gap: 20px; column-gap: 20px; } /* Horizontal rules */ body.ns-0 .mw-parser-output> :not(.collapsible-block:not(.open-block))+h2:not(:first-of-type), body.ns-0 .mw-parser-output> .mw-heading2 ~ :not(.collapsible-block:not(.open-block))+.mw-heading2 { border-top: 1px solid var(--border-color-base, #a2a9b1); padding-top: 1em; margin-top: 0.2em; } /* [[phab:T156351]]: Support for Parsoid's Cite implementation */ a[ rel="mw:referencedBy"]::before { content: " ^"; } /* [[phab:T316670]]: fix header issues */ .mw-heading * { word-break: normal; } /* From [[Module:shortcut box/styles.css]] */ a .redlink { color: var(--color-destructive, #d73333); } a:visited .redlink { color: var(--color-destructive--visited, #a55858); } a:visited:hover .redlink { color: var(--color-destructive--visited, #a55858); } a:hover .redlink { color: var(--color-destructive--hover, #ff4242); text-decoration: underline; } a:active .redlink { color: var(--color-destructive--active, #b32424); text-decoration: underline; } a:focus .redlink { outline-color: var(--outline-color-progressive--focus, #36c); } /* Change the external link icon to a PDF icon for all PDF files */ .mw-parser-output a[href$=".pdf"].external, .mw-parser-output a[href*=".pdf?"].external, .mw-parser-output a[href*=".pdf#"].external, .mw-parser-output a[href$=".PDF"].external, .mw-parser-output a[href*=".PDF?"].external, .mw-parser-output a[href*=".PDF#"].external { background: url("//upload.wikimedia.org/wikipedia/commons/4/4d/Icon_pdf_file.png") no-repeat right; /* @noflip */ padding: 8px 18px 8px 0; } /* Add YouTube icon after links to YouTube. */ .mw-parser-output a[href*="youtube.com"].external, .mw-parser-output a[href*="youtu.be"].external { background: url("//upload.wikimedia.org/wikipedia/commons/f/fd/YouTube_full-color_icon_(2024).svg") no-repeat right; background-size: auto; padding: 8px 18px 8px 0; background-size: 16px; } /* approximate replacement for .toccolours, which is not defined in the Vector 2022 skin */ .standard-box { background-color: var(--wikt-palette-paleblue, #f8f9fa); border: 1px solid var(--wikt-palette-grey, #9e9e9e); /* was #aabbdd but no real equivalent in our palette */ padding: 5px; } /* fix for long titles e.g. [[Cnile]] */ .cited-source { overflow-wrap: break-word; } /* </nowiki> */ cwtiynx3ccovf6knw72g4ojp9cyxz0c 88861 88860 2026-08-06T22:47:37Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Site.css]] 88860 css text/css /* ---------- <nowiki> CSS Style * Indent with tab characters * One line space between each declaration * One selector per line * Opening brace on the same line as the last selector * Don't omit optional semicolons * Closing brace on its own line * Closing brace indented to match the preceding style declarations * Alternatively, very short style rules may be all on one line ---------- */ /* csslint adjoining-classes:false */ /* See also [[MediaWiki:Minerva.css]], [[MediaWiki:Vector.css]] */ sup, sub { /* prevent odd line-height for raised and lowered characters */ line-height: 1em; } /* and keep links at normal font size/weight, else they inherit the header attributes */ .editsection { font-size: 100%; font-weight: normal; } pre code, code code { border: none; padding: 0; } pre var, code var { color: var(--wikt-palette-grey-9,#777); } /* This fixes a bug where certain Tibetan terms are cut off at the bottom... */ #firstHeading { overflow: visible; } .ns-0 .timed-text { display: none; } .client-js .audiometa { display: none; } .client-nojs .audiofile { display: none; } .nowrap { white-space: nowrap; } /* wikitable is part of core. prettytable is deprecated but still used in some places, until fully replaced: */ table.prettytable { margin: 1em 1em 1em 0; background: var(--wikt-palette-paleblue, #f8f9fa); border: 1px var(--border-color-base, #aaaaaa) solid; border-collapse: collapse; } table.prettytable th, table.prettytable td { border: 1px var(--border-color-base, #aaaaaa) solid; padding: 0.2em; } table.prettytable th { background: var(--wikt-palette-lightergrey, #eeeeee); text-align: center; } table.prettytable caption { margin-left: inherit; margin-right: inherit; } /* default setting for {{qualifier}} and {{sense}}. (Related classes that can be overridden: .qualifier-comma, .qualifier-content, .ib-brac, .qualifier-brac, .sense-qualifier-colon.) */ .ib-comma { font-style: normal; } .ib-content { font-style: italic; } .ib-content i, .ib-content em { font-style: normal; } .context-qualifier-colon { display: none; } /* default style for indented "see also" */ .disambig-see-also { text-indent: 2em; } .mention-tr { font-style: italic; } /* add left-to-right mark */ .mention-gloss-paren::before, .mention-tr-paren::before { content: "‎"; } /* non-italic and non-bold gloss */ .mention-gloss, .mention-gloss-double-quote, .mention-gloss-paren, .mention-tr-gloss-separator-comma, .mention-tr-paren, .mention-tr-gloss-separator-comma { font-style: normal; font-weight: inherit; } /* default style for "form of" definitions */ .use-with-mention, .form-of-definition { font-style: italic; } .use-with-mention i, .form-of-definition-link { font-style: normal; } .use-with-mention .mention, .form-of-definition-link .mention { font-style: normal; font-weight: bold; } /* display normalization in {{ux}}/{{usex}}, {{quote}}, {{quote-*}} in italics */ .e-normalization { font-style: italic; } /* Inflection tables ----------------------------- */ /* To colour links in inflection tables (currently done with {{notred}}) black without using #ifexist and allowing for user override */ .inflection-table a.new { color: inherit; } /* fill a parent NavContent collapsing box */ .NavContent table.inflection, .NavContent table.inflection-table { margin-top: 0; width: 100%; display: table; border: 0; } /* basic inflection table styles */ table.inflection { border-collapse: collapse; border: 1px solid; background: #ffffff; /* TODO consider palettizing */ } table.inflection caption { caption-side: bottom; padding: 0.33em 1em; text-align: left; font-size: smaller; } /* subtle grey for alternate row backgrounds */ table.inflection tr:nth-child(odd) { background: #fcfcfc; /* TODO consider palettizing */ } /* and for row headers */ table.inflection tr:nth-child(odd):not(.rowgroup) th { background: #f6f6f6; /* TODO consider palettizing */ } /* dark mode background colors for table.inflection */ @media screen { html.skin-theme-clientpref-night table.inflection { background-color: #242424; } html.skin-theme-clientpref-night table.inflection tr:nth-child(odd) { background-color: #2E2E2E; } html.skin-theme-clientpref-night table.inflection tr:nth-child(odd):not(.rowgroup) th { background-color: #303030; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os table.inflection { background-color: #242424; } html.skin-theme-clientpref-os table.inflection tr:nth-child(odd) { background-color: #2E2E2E; } html.skin-theme-clientpref-os table.inflection tr:nth-child(odd):not(.rowgroup) th { background-color: #303030; } } table.inflection td, table.inflection th { padding: 0.33em 1em; vertical-align: baseline; } /* but vertically center multi-row cells */ table.inflection td[rowspan] { vertical-align: middle; } table.inflection td { text-align: center; } /* regular row headers, in the left column */ table.inflection th { background: var(--wikt-palette-paleblue, #f8f9fa); text-align: left; } /* rowgroup header rows */ table.inflection tr.rowgroup th { background: var(--wikt-palette-lightergrey, #eeeeee); text-align: center; } /* first-of-several rowgroup header cells is aligned left */ table.inflection tr.rowgroup th:first-child { text-align: left; } table.inflection tr.rowgroup th:first-child:only-child { text-align: center; } /* rows with dividers above */ table.inflection tr.divider th { border-top: 3px solid var(--wikt-palette-grey-7,#999999); } /* transliterations */ table.inflection .translit { color: var(--wikt-palette-grey-8,#888); } /* header links aren’t coloured until hover/active */ table.inflection th a:link, table.inflection th a:visited { color: inherit; text-decoration: inherit; } table.inflection th a:hover { color: var(--wikt-palette-blue-9,#0645ad); text-decoration: underline; } table.inflection th a:active { color: var(--wikt-palette-gold,#faa700); text-decoration: underline; } /* ---- end of Inflection tables */ /* Hide interproject links used by [[MediaWiki:Gadget-AggregateInterprojectLinks.js]] */ .interProject { display: none; clear: both; border-top: 2px dotted var(--border-color-base,#AAAAAA); margin-top: 2em; } /* Translation styling */ .checktrans, .rfc-trans, .trreq, .ttbc { background: var(--wikt-palette-palegreen, #f0fff0); } /* t+ t t- templates: TODO are these still wanted? */ .tneg, .tpos, .tunk { vertical-align: 20%; font-size: 80%; } .tneg a { color: var(--wikt-palette-red,#cc2200) !important; } /* monobook redlink colour, standard #ba0000 */ .tneg a:visited { color: var(--wikt-palette-grey-red-9,#a55858) !important; } /* standard visited redlink colour */ .tpos a { color: var(--wikt-palette-deepblue); } /* standard bluelink colour */ .tpos a:visited { color: var(--wikt-palette-blue); } /* standard bluelink colour */ .tunk a { color: var(--wikt-palette-blue-9,#3366BB) !important; } /* standard external interwiki colour */ .tunk a:active { color: var(--wikt-palette-blue-9,#3366BB) !important; } /* redundant */ /* for parentheses, we use .tlc and .tlcp, the latter has no definition here (display:inline) */ .tlc { display: none; } /* Main page fixes */ #interwiki-completelist { font-weight: bold; } /* Try to make search results more obviously links */ .mw-special-Search #bodyContent li a { font-weight: bold; } .mw-special-Search .searchmatch { font-weight: normal; color: var(--wikt-palette-black, #000000); background-color: var(--wikt-palette-brightyellow, #FFEE77); } /* [[WT:FEED]] */ #p-feedback a { cursor: pointer; } /* Old revisions */ #mw-revision-info { font-size: 110%; margin: 5px 0; } #mw-editingold { font-size: 120%; } /* maintenance line */ .maintenance-line { color: #777777; /* TODO consider palettizing */ } /* dark mode text color for maintenance line */ @media screen { html.skin-theme-clientpref-night .maintenance-line { color: #adb7bf; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .maintenance-line { color: #adb7bf; } } /* Night mode logo appearance, see [[Wiktionary:Grease pit/2025/January#Top left Wiktionary logo in dark mode]] */ @media screen { html.skin-theme-clientpref-night img.mw-logo-icon { color-scheme: light; filter: invert(1) brightness(55%) contrast(250%) hue-rotate(180deg); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os img.mw-logo-icon { color-scheme: light; filter: invert(1) brightness(55%) contrast(250%) hue-rotate(180deg); } } /* Make Recent changes look nice again */ span.newpage, span.minor, span.searchmatch, span.bot, span.unpatrolled { font-family: sans-serif !important; } /* Styling for the different kinds of collapsible boxes and lists */ /* NavFrames */ div.NavFrame, details.NavFrame { border: 1px solid var(--wikt-palette-grey, #9e9e9e); text-align: center; border-collapse: collapse; font-size: 95%; overflow: auto; width: auto; } div.NavFrame>ul, div.NavFrame>ol { text-align: left; } div.NavFrame div.NavHead, details.NavFrame summary.NavHead { margin: 2px; min-height: 1.6em; font-weight: bold; font-size: 100%; text-align: left; padding: 1px 5px 1px 10px; background-color: var(--wikt-palette-dullcyan, #eaecf0); } div.NavFrame p { font-size: 100%; } div.NavFrame div.NavContent, details.NavFrame div.NavContent { font-size: 100%; border-top: 1px solid var(--wikt-palette-grey, #9e9e9e); } div.NavFrame div.NavContent p, details.NavFrame div.NavContent p { font-size: 100%; } /* Used by box-top/box-bottom */ .NavContent.boxcontent { padding: 0.25em 0.5em; } .NavContent.boxcontent>p:last-child { margin-bottom: 0.5em; /* from 1em to avoid some extra asymmetric space */ } /* Override default added margins which mess up the background */ .NavContent.derivedterms>p, .NavContent.columns-bg>p { margin: 0; } .NavContent.derivedterms>p, .NavContent.derivedterms>ul, .NavContent.columns-bg>p, .NavContent.columns-bg>ul { padding: 0.5em; } /* Collapsible term lists */ .list-switcher { /* This is a hack so we can use getComputedStyle to find the maximum permissible height value of a list-switcher. It must be kept in sync with .list-switcher-collapsed `max-height` */ bottom: calc(3.2 * 1.6em); /* for browsers that don't support `lh` units */ bottom: 3.2lh; } .list-switcher-wrapper, :not(.list-switcher-wrapper)>.list-switcher { contain: layout; /* stop floating elements from messing with layout */ margin-top: 0.3em; /* replaces margin lost on <ul> in following ruleset */ } .list-switcher-wrapper+.list-switcher-wrapper { margin-top: 0.6em; } .list-switcher>div>ul, .list-switcher-wrapper>div>ul { margin-top: 0; /* needed to avoid jumps when collapsing/uncollapsing */ } .list-switcher ul ul { margin-top: 0.1em; /* make margin above nested lists equal to margin at bottom of <li>s */ } .list-switcher-collapsed { /* If changing this value, change .list-switcher `bottom` above */ max-height: calc(3.2 * 1.6em); /* for browsers that don't support `lh` units */ max-height: 3.2lh; overflow-y: hidden; transform: translateZ(0); /* Fix for iOS Safari overflow clipping */ } .list-switcher-header { background: var(--wikt-palette-grey-indigo-2); font-weight: bold; font-size: 95%; padding: 0.2em 0.4em 0.1em 0.6em; } .list-switcher-header+.list-switcher .term-list, .list-switcher-header+.term-list { padding-top: 0.1em; } .list-switcher-edit { margin-left: 1.5em; font-size: 87.75%; /* exactly match font size of [show more] button (in Chromium-based browsers at least) */ font-weight: normal; } .list-switcher-edit::before { content: "["; } .list-switcher-edit::after { content: "]"; } .list-switcher-large-text { /* Keep in sync with next ruleset */ bottom: calc(4 * 1.6em); /* for browsers that don't support `lh` units */ bottom: 4lh; } .list-switcher-large-text.list-switcher-collapsed { /* Keep in sync with previous ruleset */ max-height: calc(4 * 1.6em); /* for browsers that don't support `lh` units */ max-height: 4lh; } .list-switcher-element { text-align: center; cursor: pointer; background: var(--wikt-palette-grey-indigo-2); border-bottom-left-radius: 0.3lh; border-bottom-right-radius: 0.3lh; } .list-switcher-element .NavToggle { float: none; } /* this is a legacy rule that only applies to {{rootsee}} and {{script appendix}} - these need a fairly wide width */ .columns-bg:not(.term-list)>div>div>.CategoryTreeChildren, .columns-bg:not(.term-list)>div>.CategoryTreeChildren { -moz-column-width: 25em; column-width: 25em; } /* Hidden quotes */ .client-js .ns-0 ol>li>ul { display: none; } /* Hidden Quotes and *nyms toggle */ .HQToggle, .nyms-toggle, .usex-toggle { font-size: smaller; position: relative; bottom: 1px; left: 5px; } .NavToggle { float: right; font-weight: normal; font-size: smaller; margin-top: 1px; margin-left: 0.5em; } /* wrap toggle links with [ and ] */ .HQToggle:before, .NavToggle:before, .nyms-toggle:before, .usex-toggle:before { content: '['; } .HQToggle:after, .NavToggle:after, .nyms-toggle:after, .usex-toggle:after { content: ']'; } .HQToggle a, .NavToggle a, .nyms-toggle a, .usex-toggle a { -webkit-user-select: none; -moz-user-select: none; user-select: none; color: var(--wikt-palette-black); } .HQToggle a:focus:not(:hover), .NavToggle a:focus:not(:hover), .nyms-toggle a:focus:not(:hover), .usex-toggle a:focus:not(:hover) { text-decoration: none; } .client-js .NavFrame:not(.no-collapse) .NavContent { display: none; } /* View switcher */ .vsShow { display: none; } /* End styling for collapsible lists */ /* Quote clarifications, e.g. {{quote-gloss}}, {{quote-qualifier}} */ .quote-note { color: var(--wikt-palette-grey-9,#999); } /* Use same formatting for <mark> as used for bolding with certain scripts. */ mark { background-color: var(--wikt-palette-pink, #ffe0f0); color: var(--wikt-palette-black, #202122); } /* stuff visible when previewing an edit only */ .previewonly { display: none; } #wikiPreview .previewonly { display: inline; } /* Highlight the relevant sense when the user follows a link to a {{senseid}}. The class="senseid" should ideally be on the enclosing <li> tag. We attempt to make the highlight work when the class="senseid" is on a <span> inside the <li>, but the :has selector was not supported by all browsers as of late 2023. This feature was nonetheless requested by Benwing at [[Wiktionary:Grease_pit/2023/November#Why_does_Template%3Asenseid_use_HTML_li_tag%3F]]. THe version with :has is provided as a separate declaration to ensure maximum compatibility. */ .senseid:target { background: var(--wikt-palette-lightblue, #DEF); } li:has(> span.senseid:target) { background: var(--wikt-palette-lightblue, #DEF); } /* highlight the next paragraph for an etymid */ .etymid:target+p, .etymonid:target+p { background: var(--wikt-palette-lightblue, #DEF); } /* Highlight selected source in a bibliography */ .bibliography-id:target { background: var(--wikt-palette-lightblue, #DEF); } /* Skin CSS highlights table rows targeted by the current browser location (tr:target). This rule highlight table rows containing target cells so that there can be multiple IDs in a table row in [[Wiktionary:List of languages]] and [[Wiktionary:List of languages/special#Etymology-only languages]]. */ tr:has(> :target), tr:has(> td > code:target) { background: var(--wikt-palette-lightblue, #DEF); } /* show the "serial and" in the disambiguation see also */ .serial-and { display: inline; } /* hide the serial commas */ .serial-comma { display: none; } /* Gender and number templates */ .gender, .number, .noun-class { font-style: italic; } abbr { border-bottom-width: 0; } /* hide "did you mean" on Noarticletext self-links */ .did-you-mean strong { display: none; } /* make script/module errors smaller */ .scribunto-error { font-size: 75%; } /* allow inline hieroglyphs */ .mw-hiero-outer { display: inline-table !important; /* override skin styling on mobile */ vertical-align: middle; font-size: 10px; } /* allow mirrored custom hieroglyph (and other) images */ .mw-mirrored img { transform: scaleX(-1); } /* softer highlighting of 'updated since last visit' */ span.updatedmarker { background-color: var(--wikt-palette-mint, #c0e4c0); } /* {{TOC limit}} */ /* Allow limiting of which header levels are shown in a TOC; <div class="toclimit-3">, for instance, will limit to showing ==headings== and ===headings=== but no further (as long as there are no =headings= on the page, which there shouldn't be according to the MoS). */ .toclimit-2 .toclevel-1 ul, .toclimit-3 .toclevel-2 ul, .toclimit-4 .toclevel-3 ul, .toclimit-5 .toclevel-4 ul, .toclimit-6 .toclevel-5 ul, .toclimit-7 .toclevel-6 ul { display: none; } /* * Script and language-related styles are in [[MediaWiki:Gadget-LanguagesAndScripts.css]] */ /* A kludge that lets the members of [[:Category:Redirected combining characters]] be displayed. */ body.page-Category_Combining_characters div#mw-pages li, body.page-Category_Redirected_combining_characters div#mw-pages li, body.page-Category_IPA_combining_characters div#mw-pages li { letter-spacing: 0.3em; } /* Grease Pit edit button fix */ .page-Wiktionary_Grease_pit.skin-vector #ca-edit, .page-Wiktionary_Etymology_scriptorium.skin-vector #ca-edit, .page-Wiktionary_Information_desk.skin-vector #ca-edit, .page-Wiktionary_Beer_parlour.skin-vector #ca-edit, .page-Wiktionary_Tea_room.skin-vector #ca-edit { display: none; } /* unit tests filter */ table.unit-tests.unit-tests-hide-passing tr.unit-test-pass { display: none; } table.unit-tests th.unit-tests-img-corner { background: var(--wikt-palette-lightblue, #d9ebff); min-width: 1em; } table.unit-tests.unit-tests-hide-passing th.unit-tests-img-corner { background: red; } /* multi-column lists */ li, .group-in-column { -moz-column-break-inside: avoid; break-inside: avoid; } /* {{shortcut}} */ .shortcut-box, .category-edit-box { border: 1px solid var(--border-color-base, #aaaaaa); color: var(--color-base, black); background: var(--wikt-palette-paleblue, #f9f9f9); margin: 0 0 .5em 1em; text-align: center; padding: 5px; float: right; clear: both; font-weight: bold; font-size: smaller; } /* Display tabs with 4 spaces, see [[phab:T59824]] and [[phab:T59825]] */ textarea#wpTextbox1+div:last-child, /* workaround for [[mw:User:Remember the dot/Syntax highlighter]] */ textarea, pre, code, .mw-highlight { -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } /* stop double-bolding of self-links like in [[acquit]], [[fishbone]] */ /* old code: b .selflink, strong .selflink { font-weight: inherit; } */ b, strong { font-weight: bold; } tr:target { background: var(--wikt-palette-lightblue, #DEF); } #firstHeading var, .headword var { color: var(--wikt-palette-grey-9, #888); } /* Display a {{tlb}} / {{term-label}} template on its own line if it comes right after a headword template. It is too easy to miss after headwords (especially long ones). */ p .headword-line~.usage-label-term::before { content: "\a"; /* newline */ white-space: pre; } /* Temporary kludge to be used because categoryTree is generating a newline. This CSS line should be removed after the developers fix it. */ .CategoryTreeTag+p br:first-child { display: none; } /* Used by column templates (see [[Module:columns]]). */ .ul-column-count>ul, .ul-column-count>ol, .ul-column-count>dl { -moz-column-gap: 20px; column-gap: 20px; } .ul-column-count[data-column-count="2"]>ul, .ul-column-count[data-column-count="2"]>ol, .ul-column-count[data-column-count="2"]>dl { -moz-column-count: 2; column-count: 2; } .ul-column-count[data-column-count="3"]>ul, .ul-column-count[data-column-count="3"]>ol, .ul-column-count[data-column-count="3"]>dl { -moz-column-count: 3; column-count: 3; } .ul-column-count[data-column-count="4"]>ul, .ul-column-count[data-column-count="4"]>ol, .ul-column-count[data-column-count="4"]>dl { -moz-column-count: 4; column-count: 4; } .ul-column-count[data-column-count="5"]>ul, .ul-column-count[data-column-count="5"]>ol, .ul-column-count[data-column-count="5"]>dl { -moz-column-count: 5; column-count: 5; } .ul-column-count[data-column-count="6"]>ul, .ul-column-count[data-column-count="6"]>ol, .ul-column-count[data-column-count="6"]>dl { -moz-column-count: 6; column-count: 6; } .columns-bg { /* Default background color for multi-column lists. */ background: var(--wikt-palette-lavender, #f8f8ff); /* prevent text crashing into edge of box */ padding-right: 0.3em; } /* Default style for hypothetical inflections -- currently italic. */ .hypothetical { font-style: italic; } /* Style for entries using deprecated templates */ .deprecated { color: olivedrab; } .deprecated a { color: darkgreen; } /* Style for entries using deprecated labels */ .deprecated-label { color: olivedrab; text-decoration: line-through; } .deprecated-label a { color: darkgreen; text-decoration: line-through; } /* Style for notes added using the bad= param in {{audio}} */ .bad-audio-note { color: var(--wikt-palette-red, #FF2200); font-weight: bold; } /* WikiHiero kludge */ /* disable for now, apparently not necessary and breaks wrapping .wikt-hierokludge { display: inline-block; } */ /* Support lists that automatically split into limited-width columns (for translations tables and the like): */ .multicolumn-list>ul { -moz-column-width: 25em; column-width: 25em; -moz-column-gap: 20px; column-gap: 20px; } .multicolumn-list-wide>ul { -moz-column-width: 55em; column-width: 55em; -moz-column-gap: 20px; column-gap: 20px; } .multicolumn-list-narrow>ul { -moz-column-width: 22em; column-width: 22em; -moz-column-gap: 20px; column-gap: 20px; } /* Horizontal rules */ body.ns-0 .mw-parser-output> :not(.collapsible-block:not(.open-block))+h2:not(:first-of-type), body.ns-0 .mw-parser-output> .mw-heading2 ~ :not(.collapsible-block:not(.open-block))+.mw-heading2 { border-top: 1px solid var(--border-color-base, #a2a9b1); padding-top: 1em; margin-top: 0.2em; } /* [[phab:T156351]]: Support for Parsoid's Cite implementation */ a[ rel="mw:referencedBy"]::before { content: " ^"; } /* [[phab:T316670]]: fix header issues */ .mw-heading * { word-break: normal; } /* From [[Module:shortcut box/styles.css]] */ a .redlink { color: var(--color-destructive, #d73333); } a:visited .redlink { color: var(--color-destructive--visited, #a55858); } a:visited:hover .redlink { color: var(--color-destructive--visited, #a55858); } a:hover .redlink { color: var(--color-destructive--hover, #ff4242); text-decoration: underline; } a:active .redlink { color: var(--color-destructive--active, #b32424); text-decoration: underline; } a:focus .redlink { outline-color: var(--outline-color-progressive--focus, #36c); } /* Change the external link icon to a PDF icon for all PDF files */ .mw-parser-output a[href$=".pdf"].external, .mw-parser-output a[href*=".pdf?"].external, .mw-parser-output a[href*=".pdf#"].external, .mw-parser-output a[href$=".PDF"].external, .mw-parser-output a[href*=".PDF?"].external, .mw-parser-output a[href*=".PDF#"].external { background: url("//upload.wikimedia.org/wikipedia/commons/4/4d/Icon_pdf_file.png") no-repeat right; /* @noflip */ padding: 8px 18px 8px 0; } /* Add YouTube icon after links to YouTube. */ .mw-parser-output a[href*="youtube.com"].external, .mw-parser-output a[href*="youtu.be"].external { background: url("//upload.wikimedia.org/wikipedia/commons/f/fd/YouTube_full-color_icon_(2024).svg") no-repeat right; background-size: auto; padding: 8px 18px 8px 0; background-size: 16px; } /* approximate replacement for .toccolours, which is not defined in the Vector 2022 skin */ .standard-box { background-color: var(--wikt-palette-paleblue, #f8f9fa); border: 1px solid var(--wikt-palette-grey, #9e9e9e); /* was #aabbdd but no real equivalent in our palette */ padding: 5px; } /* fix for long titles e.g. [[Cnile]] */ .cited-source { overflow-wrap: break-word; } /* </nowiki> */ cwtiynx3ccovf6knw72g4ojp9cyxz0c Teamplaid:shortcut 10 17930 88862 2024-09-15T09:46:13Z en>Theknightwho 0 88862 wikitext text/x-wiki <includeonly>{{#invoke:shortcut box|shortcut_t}}</includeonly><noinclude>{{documentation}}</noinclude> exsyrlhl8x8eep173m56lwf7p5s2adf 88863 88862 2026-08-06T22:50:17Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:shortcut]] 88862 wikitext text/x-wiki <includeonly>{{#invoke:shortcut box|shortcut_t}}</includeonly><noinclude>{{documentation}}</noinclude> exsyrlhl8x8eep173m56lwf7p5s2adf Teamplaid:gadgets pages 10 17931 88864 2026-03-14T03:36:05Z en>ExcarnateSojourner 0 transclude documentation 88864 wikitext text/x-wiki {| style="width: 100%; text-align: center" class="wikitable" |- ! colspan="2" | All about [[Wiktionary:Gadgets|gadgets]] |- ! | For users | [[Special:Gadgets]] · [[Special:Preferences]] · [[Wiktionary:Gadget preferences]] · [[Wiktionary:Preferences for users without an account]] |- ! | For developers | [[Special:GadgetUsage]] · [[MediaWiki:Gadgets-definition]] · [[mw:Extension:Gadgets]] · [[:Category:User JavaScript coder]] |}<noinclude>{{documentation}}</noinclude> s3t1569tehyk3ndg0tsc2kedrd7gwrn 88865 88864 2026-08-06T22:50:28Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:gadgets_pages]] 88864 wikitext text/x-wiki {| style="width: 100%; text-align: center" class="wikitable" |- ! colspan="2" | All about [[Wiktionary:Gadgets|gadgets]] |- ! | For users | [[Special:Gadgets]] · [[Special:Preferences]] · [[Wiktionary:Gadget preferences]] · [[Wiktionary:Preferences for users without an account]] |- ! | For developers | [[Special:GadgetUsage]] · [[MediaWiki:Gadgets-definition]] · [[mw:Extension:Gadgets]] · [[:Category:User JavaScript coder]] |}<noinclude>{{documentation}}</noinclude> s3t1569tehyk3ndg0tsc2kedrd7gwrn MediaWiki:Gadget-MonobookSmallerHeadings.css 8 17932 88866 2014-07-26T10:37:52Z en>Kephir 0 moved from [[MediaWiki:Monobook.css]] 88866 css text/css /* headings a bit more balanced in size */ h1 { font-size:160%; font-weight:bold; } h2 { font-size:140%; font-weight:bold; } h3 { font-size:130%; } h4 { font-size:120%; } h5 { font-size:110%; } h6 { font-size:100%; } sc9io20biiqcj7j28lpmq4tf913rv08 88867 88866 2026-08-06T23:07:52Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-MonobookSmallerHeadings.css]] 88866 css text/css /* headings a bit more balanced in size */ h1 { font-size:160%; font-weight:bold; } h2 { font-size:140%; font-weight:bold; } h3 { font-size:130%; } h4 { font-size:120%; } h5 { font-size:110%; } h6 { font-size:100%; } sc9io20biiqcj7j28lpmq4tf913rv08 MediaWiki:Gadget-LanguagesAndScripts.css 8 17933 88868 2026-08-05T12:55:12Z en>Catonif 0 remove Code2000 from .pjt-Latn, .Cyrl, .Cyrs, .Polyt and .enPR 88868 css text/css /* Support for scripts. See [[Wiktionary:Scripts]]. */ /* Default style for mentions outside of "form of" definitions. See [[Wiktionary:Votes/2007-10/style for mentioned terms]] */ .mention { font-style: italic; } .mention i, i .mention { font-style: normal; } /* The following scripts do not support italic text, but do support bold text. Note: we repeat the first class selector twice to increase CSS 'specificity'. */ .Aghb.Aghb, .Aghb *, .Ahom.Ahom, .Ahom *, .Armi.Armi, .Armi *, .Armn.Armn, .Armn *, .Avst.Avst, .Avst *, .Bali.Bali, .Bali *, .Bamu.Bamu, .Bamu *, .Batk.Batk, .Batk *, .Beng.Beng, .Beng *, .as-Beng.as-Beng, .as-Beng *, .Bopo.Bopo, .Bopo *, .Brai.Brai, .Brai *, .Bugi.Bugi, .Bugi *, .Buhd.Buhd, .Buhd *, .Cakm.Cakm, .Cakm *, .Cans.Cans, .Cans *, .Cari.Cari, .Cari *, .Cham.Cham, .Cham *, .Cher.Cher, .Cher *, .Copt.Copt, .Copt *, .Cprt.Cprt, .Cprt *, .Cyrl.Cyrl, /* .Cyrl *, */ .Cyrs.Cyrs, .Cyrs *, .Deva.Deva, .Deva *, .Dsrt.Dsrt, .Dsrt *, .Egyp.Egyp, .Egyp *, .Ethi.Ethi, .Ethi *, .Geok.Geok, .Geok *, .Geor.Geor, .Geor *, .Glag.Glag, .Glag *, .Goth.Goth, .Goth *, .Grek.Grek, /* .Grek *, */ .Gujr.Gujr, .Gujr *, .Guru.Guru, .Guru *, .Hang.Hang, .Hang *, .Hani.Hani, .Hani *, .Hano.Hano, .Hano *, .Hans.Hans, .Hans *, .Hant.Hant, .Hant *, .Hira.Hira, .Hira *, .Hluw.Hluw, .Hluw *, .IPA.IPA, .IPA *, .Ipach.Ipach, .Ipach *, .IPAchar.IPAchar, .IPAchar *, .Ital.Ital, .Ital *, .Java.Java, .Java *, .Jpan.Jpan, .Jpan *, .Kali.Kali, .Kali *, .Kana.Kana, .Kana *, .Khar.Khar, .Khar *, .Khmr.Khmr, .Khmr *, .Knda.Knda, .Knda *, .Kore.Kore, .Kore *, .Kthi.Kthi, .Kthi *, .Lana.Lana, .Lana *, .Laoo.Laoo, .Laoo *, .Lepc.Lepc, .Lepc *, .Limb.Limb, .Limb *, .Lisu.Lisu, .Lisu *, .Lyci.Lyci, .Lyci *, .Lydi.Lydi, .Lydi *, .Mand.Mand, .Mand *, .Merc.Merc, .Merc *, .Mero.Mero, .Mero *, .Mlym.Mlym, .Mlym *, .Modi.Modi, .Modi *, .Mtei.Mtei, .Mtei *, .Music.Music, .Music *, .musical.musical, .musical *, .Narb.Narb, .Narb *, .Nkoo.Nkoo, .Nkoo *, .Olck.Olck, .Olck *, .Orya.Orya, .Orya *, .Osma.Osma, .Osma *, .Phag.Phag, .Phag *, .Phli.Phli, .Phli *, .Phlv.Phlv, .Phlv *, .Phnx.Phnx, .Phnx *, .Plrd.Plrd, .Plrd *, .Polyt.Polyt, .Polyt *, .polytonic.polytonic, .polytonic *, .Prti.Prti, .Prti *, .Rjng.Rjng, .Rjng *, .Samr.Samr, .Samr *, .Sarb.Sarb, .Sarb *, .Saur.Saur, .Saur *, .Sgnw.Sgnw, .Sgnw *, .Shaw.Shaw, .Shaw *, .Shrd.Shrd, .Shrd *, .Sinh.Sinh, .Sinh *, .Sora.Sora, .Sora *, .Sund.Sund, .Sund *, .Sylo.Sylo, .Sylo *, .Tagb.Tagb, .Tagb *, .Tale.Tale, .Tale *, .Talu.Talu, .Talu *, .Taml.Taml, .Taml *, .Tavt.Tavt, .Tavt *, .Tayo.Tayo, .Tayo *, .Telu.Telu, .Telu *, .Tfng.Tfng, .Tfng *, .Tglg.Tglg, .Tglg *, .Thaa.Thaa, .Thaa *, .Thai.Thai, .Thai *, .Tibt.Tibt, .Tibt *, .Ugar.Ugar, .Ugar *, .Vaii.Vaii, .Vaii *, .Xpeo.Xpeo, .Xpeo *, .Yiii.Yiii, .Yiii *, .Zmth.Zmth, .Zmth *, .Zname.Zname, .Zname *, .Zsym.Zsym, .Zsym * { font-style: normal; } /* The following scripts do not support neither bold nor italic text. Note: we repeat the first class selector twice to increase CSS 'specificity'. */ .Arab.Arab, .Arab *, .fa-Arab.fa-Arab, .fa-Arab *, .glk-Arab.glk-Arab, .glk-Arab *, .kk-Arab.kk-Arab, .kk-Arab *, .ks-Arab.ks-Arab, .ks-Arab *, .ku-Arab.ku-Arab, .ku-Arab *, .mzn-Arab.mzn-Arab, .mzn-Arab *, .ota-Arab.ota-Arab, .ota-Arab *, .pa-Arab.pa-Arab, .pa-Arab *, .ps-Arab.ps-Arab, .ps-Arab *, .sd-Arab.sd-Arab, .sd-Arab *, .tt-Arab.tt-Arab, .tt-Arab *, .ug-Arab.ug-Arab, .ug-Arab *, .ur-Arab.ur-Arab, .ur-Arab *, .ms-Arab.ms-Arab, .ms-Arab *, .Brah.Brah, .Brah *, .Elba.Elba, .Elba *, .Hebr.Hebr, .Hebr *, .Lina.Lina, .Lina *, .Linb.Linb, .Linb *, .Mani.Mani, .Mani *, .Mymr.Mymr, .Mymr *, .Mong.Mong, .Mong *, .mnc-Mong.mnc-Mong, .mnc-Mong *, .sjo-Mong.sjo-Mong, .sjo-Mong *, .xwo-Mong.xwo-Mong, .xwo-Mong *, .Ogam.Ogam, .Ogam *, .Orkh.Orkh, .Orkh *, .Ougr.Ougr, .Ougr *, .Runr.Runr, .Runr *, .Sogd.Sogd, .Sogd *, .Syrc.Syrc, .Syrc *, .Tang.Tang, .Tang *, .Vith.Vith, .Vith *, .Xsux.Xsux, .Xsux * { font-style: normal; font-weight: normal; } /* For scripts where bolding is not used or can be hard to see, the quoted word is highlighted in pink. */ .Arab.e-example b, .Arab.e-quotation b, .Arab.e-normalization b, .Brah.e-example b, .Brah.e-quotation b, .Brah.e-normalization b, .Deva.e-example b, .Deva.e-quotation b, .Deva.e-normalization b, .Elba.e-example b, .Elba.e-quotation b, .Elba.e-normalization b, .Hebr.e-example b, .Hebr.e-quotation b, .Hebr.e-normalization b, .Lina.e-example b, .Lina.e-quotation b, .Lina.e-normalization b, .Linb.e-example b, .Linb.e-quotation b, .Linb.e-normalization b, .Mani.e-example b, .Mani.e-quotation b, .Mani.e-normalization b, .Mong.e-example b, .Mong.e-quotation b, .Mong.e-normalization b, .Ogam.e-example b, .Ogam.e-quotation b, .Ogam.e-normalization b, .Orkh.e-example b, .Orkh.e-quotation b, .Orkh.e-normalization b, .Ougr.e-example b, .Ougr.e-quotation b, .Ougr.e-normalization b, .Runr.e-example b, .Runr.e-quotation b, .Runr.e-normalization b, .Sogd.e-example b, .Sogd.e-quotation b, .Sogd.e-normalization b, .Syrc.e-example b, .Syrc.e-quotation b, .Syrc.e-normalization b, .Ugar.e-example b, .Ugar.e-quotation b, .Ugar.e-normalization b, .Vith.e-example b, .Vith.e-quotation b, .Vith.e-normalization b, .Xpeo.e-example b, .Xpeo.e-quotation b, .Xpeo.e-normalization b, .Xsux.e-example b, .Xsux.e-quotation b, .Xsux.e-normalization b { background-color: var(--wikt-palette-pink, #ffe0f0); font-size: inherit; } /* Latin (.Latn) This is the default script, so it has no definitions. */ /* This is needed to overcome the "smartness" of certain web browsers */ .Latn:lang(ja), .Latn:lang(ko), .Latn:lang(zh) { font-family: inherit; } /* Latin Fraktur */ .Latf { font-family: UnifrakturMaguntia, UnifrakturCook, Unifraktur, sans-serif; font-size: 125%; } /* Navajo */ .nv-Latn { font-family: Calibri, 'Aboriginal Sans', 'DejaVu Sans', 'Arial Unicode MS', sans-serif !important; } /* Pitjantjatjara (ḻ ṉ ṟ ṯ and capitals) */ .pjt-Latn { font-family: Arial, 'Microsoft Sans Serif', Tahoma, sans-serif; } /* Latin extended */ /* no styles for .Latnx, .Latinx, .unicode, .Unicode */ /* Adlam */ .Adlm { font-family: 'Noto Sans Adlam', sans-serif; } /* Aghwan */ .Aghb { font-family: OptimaModoki, 'Noto Sans Caucasian Albanian', sans-serif; } /* Ahom */ .Ahom { font-family: AhomUnicode, 'Noto Serif Ahom', 'Unifont Upper', sans-serif; } /* Arabic */ .Arab, .fa-Arab, .glk-Arab, .kk-Arab, .ks-Arab, .ku-Arab, .mzn-Arab, .ota-Arab, .pa-Arab, .ps-Arab, .sd-Arab, .tt-Arab, .ug-Arab, .ur-Arab, .ms-Arab { font-family: 'Noto Naskh Arabic', 'Iranian Sans', Tahoma, 'Microsoft Sans Serif', 'Arial Unicode MS', sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Persian */ .fa-Arab { font-family: 'Iranian Sans', 'Geeza Pro', Tahoma, sans-serif; } /* Kashmiri */ .ks-Arab { font-family: 'Noto Naskh Arabic', Amiri, Mirza, 'Scheherazade New', Scheherazade, 'Geeza Pro', Tahoma, sans-serif; } /* Kurdish */ .ku-Arab { font-family: 'Noto Naskh Arabic', Tahoma, 'Arial Unicode MS', 'UT Cairo', 'UT Naskh', sans-serif; } /* Punjabi Shahmukhi, Urdu */ .pa-Arab, .ur-Arab { font-family: 'Noto Nastaliq Urdu', Tahoma, 'Arial Unicode MS', 'UT Cairo', 'UT Naskh', sans-serif; } /* Pashto */ .ps-Arab { font-family: Pokhto, 'Pashto Kror Asiatype', 'Scheherazade New', Scheherazade, sans-serif; } /* Sindhi */ .sd-Arab { font-family: 'MB Sindhi', Tahoma, 'MBSarang Sattar', 'MB Bhitai Sattar', 'MB Lateefi', 'Ayaz Gul', sans-serif; } /* Uyghur */ .ug-Arab { font-family: 'UKIJ Tuz', 'Microsoft Uighur', 'Scheherazade New', Scheherazade, sans-serif; } /* Imperial Aramaic */ .Armi { font-family: 'Segoe UI Historic', 'Aramaic Imperial Yeb', 'Noto Sans Imperial Aramaic', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Armenian */ .Armn { font-family: Mshtakan, Arial, 'Segoe UI', Tahoma, 'Arian AMU', 'DejaVu Sans', sans-serif; } /* Avestan */ .Avst { font-family: Avestan, Ahuramzda, 'Noto Sans Avestan', sans-serif; font-size: 125%; direction: rtl; unicode-bidi: isolate; font-variant-ligatures: none; /* Avestan language */ } .Avst:lang(pal) { /* Pazend (Middle Persian in Avestan script) */ font-variant-ligatures: normal; } /* Balinese */ .Bali { font-family: 'Noto Sans Balinese', sans-serif; } /* Bamum */ .Bamu { font-family: 'Noto Sans Bamum', sans-serif; } /* Bassa */ .Bass { font-family: 'Noto Sans Bassa Vah', sans-serif; } /* Batak */ .Batk { font-family: Batak-Unicode, 'Noto Sans Batak', sans-serif; } /* Bengali, Assamese */ .Beng, .as-Beng { font-family: 'Bangla Sangam MN', UniBangla, 'Code2000', Likhan, 'UT Bengali Dhaka', Vrinda, 'Noto Sans Bengali', sans-serif; font-size: 130%; } /* Bhaiksuki */ .Bhks { font-family: 'Noto Sans Bhaiksuki', sans-serif; } /* Zhuyin (Bopomofo) */ .Bopo { font-family: MOESongUN, DFKai-SB, 'Microsoft Yahei', 'Microsoft Jhenghei', 'Source Han Sans TC', 'Source Han Sans TW', 'Noto Sans CJK TC', sans-serif; } /* Brahmi */ .Brah { font-family: 'Segoe UI Historic', 'Noto Sans Brahmi', sans-serif; } /* Braille */ .Brai { font-size: 150%; } /* Buginese */ .Bugi { font-family: Saweri, 'Noto Sans Buginese', sans-serif; } /* Buhid [[Wiktionary:Grease pit/2025/February#Buhid]] */ .Buhd { font-family: 'Noto Sans Buhid', Quivira, sans-serif; font-size: 110%; } /* Chakma */ .Cakm { font-family: RibengUni, 'Noto Sans Chakma', sans-serif; } /* Unified Canadian Aboriginal Syllabics */ .Cans { font-family: 'Euphemia UCAS', Euphemia, 'Aboriginal Sans', OskiBlackfoot, 'Code2000', 'Everson Mono Unicode', 'Noto Sans Canadian Aboriginal', sans-serif; font-size: 110%; } /* Carian */ .Cari { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Carian', sans-serif; font-size: 125%; } /* Cham */ .Cham { font-family: 'Code2000', 'JG ChamCambodia', 'Noto Sans Cham', sans-serif; font-size: 110%; } /* Cherokee */ .Cher { font-family: Digohweli, 'Aboriginal Sans', 'Code2000', Marin, 'Rotinonhsonni Sans', 'Everson Mono Unicode', 'Noto Sans Cherokee', sans-serif; font-size: 110%; } /* Khwarezmian */ .Chrs { font-family: 'Noto Sans Chorasmian', sans-serif; } /* Coptic */ .Copt { font-family: Quivira, Antinoou, 'New Athena Unicode', Analecta, FreeSerifAvvaShenouda, 'Arial Coptic', 'Sophia Nubian', 'Code2000', 'Noto Sans Coptic', sans-serif; font-size: 130%; } /* Cypro-Minoan */ .Cpmn { font-family: 'Noto Sans Cypro Minoan', sans-serif; } /* Cypriot */ .Cprt { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Cypriot', sans-serif; font-size: 115%; direction: rtl; unicode-bidi: isolate; } /* Cyrillic */ .Cyrl { font-family: Helvetica, Geneva, 'Arial Unicode MS', 'Lucida Sans Unicode', sans-serif; } /* Old Cyrillic (Old Church Slavonic, Old East Slavic) */ .Cyrs { font-family: Monomakh, 'Monomakh Unicode', 'Monomakh Unicode TT', Menaion, 'Menaion Unicode', 'Menaion Unicode TT', Ponomar, 'Ponomar Unicode', 'Ponomar Unicode TT', Fedorovsk, 'Fedorovsk Unicode', 'Fedorovsk Unicode TT', Pochaevsk, 'Pochaevsk Unicode', 'Pochaevsk Unicode TT', Triodion, 'Triodion Unicode', 'Triodion Unicode TT', 'Acathist', 'Shafarik', Vilnius, BukyVede, 'Kliment Std', 'RomanCyrillic Std', 'Monomachus', 'Old Standard', 'Old Standard TT', Dilyana, 'Hirmos Ponomar', 'Hirmos Ponomar TT', 'Menaion Medieval', Lazov, 'DejaVu Sans', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', sans-serif; font-size: 125%; } /* Devanagari */ .Deva { font-family: 'Tiro Devanagari Sanskrit', 'Sanskrit Text', 'Adobe Devanagari', 'Noto Serif Devanagari', Utsaah, 'Devanagari MT', Raghu, Gargi, JanaSanskrit, JanaHindi, Siddhanta, 'Noto Sans Devanagari', sans-serif; font-size: 120%; } /* Dhives Akuru */ .Diak { font-family: 'Noto Serif Dives Akuru', serif; } /* Dogra */ .Dogr { font-family: 'Noto Serif Dogra', sans-serif; } /* Deseret */ .Dsrt { font-family: 'Segoe UI Symbol', 'Code2001', 'MPH 2B Damase', 'Everson Mono', sans-serif; } /* Duployan */ .Dupl { font-family: 'Noto Sans Duployan', sans-serif; } /* Demotic (Egyptian) */ .Egyd, .Egyd * { font-style: normal; direction: rtl; } /* Egyptian hieroglyphs */ .Egyp { font-family: 'NewGardiner', 'Noto Sans Egyptian Hieroglyphs', Abydos, Aegyptus, 'Segoe UI Historic', sans-serif; font-size: 150%; } /* Elbasan */ .Elba { font-family: 'Noto Sans Elbasan', sans-serif; } /* Elymaic */ .Elym { font-family: 'Noto Sans Elymaic', sans-serif; } /* Ethiopic (Ge'ez) */ .Ethi { font-family: 'Abyssinica SIL', Nyala, 'Code2000', 'Ethiopia Jiret', 'GF Zemen Unicode', 'TITUS Cyberbit Basic', 'Visual Geez Unicode', 'Visual Geez Unicode Agazian', 'Visual Geez Unicode Title', 'Noto Sans Ethiopic', sans-serif; font-size: 120%; } /* Georgian */ .Geor { font-family: 'DejaVu Sans', 'Arial Unicode MS', Sylfaen, sans-serif; } /* Glagolitic */ .Glag { font-family: Shafarik, Menaion, 'Menaion Unicode', 'Menaion Unicode TT', 'Segoe UI Historic', BukyVede, Dilyana, 'Noto Sans Glagolitic', sans-serif; font-size: 150%; } /* Gunjala Gondi */ .Gong { font-family: 'Noto Sans Gunjala Gondi', sans-serif; } /* Masaram Gondi */ .Gonm { font-family: 'Noto Sans Masaram Gondi', sans-serif; } /* Gothic */ .Goth { font-family: 'Segoe UI Historic', 'Code2001', Skeirs, 'MPH 2B Damase', 'Noto Sans Gothic', sans-serif; } b.Goth, strong.Goth { font-size: larger; } /* Grantha */ .Gran { font-family: 'Noto Sans Grantha', sans-serif; } /* Greek (.Grek) removed - [[Wiktionary:Grease pit/2025/February#Sans-serif Greek font]] */ /* Albanian, Pontic and Tsakonian in Greek script */ .Grek:lang(sq), .Grek:lang(pnt), .Grek:lang(tsd) { font-family: 'Gentium Plus', 'Gentium', 'Lucida Sans Unicode', sans-serif; } /* Polytonic Greek */ .polytonic, .Polyt { font-family: 'SBL Greek', 'SBL BibLit', 'New Athena Unicode', 'DejaVu Sans', Athena, 'Gentium Plus', Gentium, 'Palatino Linotype', Menaion, Times, 'Arial Unicode MS', 'Lucida Sans Unicode', 'Lucida Grande', sans-serif; } /* Messapic */ .Polyt:lang(cms) { font-family: 'Noto Serif', 'Lucida Sans Unicode', 'Gentium Plus', 'Gentium', 'Noto Sans', sans-serif; } /* Gujarati */ .Gujr { font-family: 'Noto Sans Gujarati', 'Gujarati Sangam MN', 'Gujarati MT', Shruti, 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'Code2000', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', sans-serif; font-size: 125%; } /* Gurmukhi */ .Guru { font-family: 'Gurmukhi MN', 'Gurmukhi MT', 'UT Punjabi Amritsar', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'Code2000', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', 'Noto Sans Gurmukhi', sans-serif; font-size: 125%; } /* Chinese (Han) .Hani = generic .Hans = simplified .Hant = traditional */ .Hans { font-family: 'PingFang SC', DengXian, 'Source Han Sans SC', 'Source Han Sans CN', 'Noto Sans CJK SC', 'Microsoft Yahei', SimHei, SimSun, NSimSun, SimSun-ExtB, Song, 'Heiti SC', HanaMinA, HanaMinB, sans-serif; } .Hani, .Hant { font-family: 'PingFang TC', 'Source Han Sans TC', 'Source Han Sans TW', 'Noto Sans CJK TC', 'Microsoft Jhenghei', MOESongUN, PMingLiU, PMingLiU-ExtB, MingLiU, MingLiU-ExtB, Ming, 'Heiti TC', HanaMinA, HanaMinB, sans-serif; } .Hani, .Hans, .Hant { font-size: 120%; line-height: 1; } .Hani:lang(vi), .Hani:lang(tyz) { font-family: 'Nom Na Tong', 'HAN NOM A', 'HAN NOM B', Sun-ExtA, Sun-ExtB, Ming-Lt-HKSCS-UNI-H, Ming-Lt-HKSCS-ExtB, HanaMinA, HanaMinB, HanaMin, 'PingFang TC', MingLiU, MingLiU-ExtB, 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', SimSun, SimSun-ExtB, 'Arial Unicode MS', 'TITUS Cyberbit Basic', sans-serif; /* CJK Unified Ideographs Extension C and Extension D (U+2A700..U+2B734, U+2B740..U+2B81F) font-family: Sun-ExtB, 'MingLiU_HKSCS-ExtB', Ming-Lt-HKSCS-ExtB, HanaMinB, sans-serif; **/ } /* Hanunoo */ .Hano { font-family: 'Noto Sans Hanunoo', Quivira, 'MPH 2B Damase', sans-serif; font-size: 110%; } /* Hatran */ .Hatr { font-family: 'Noto Sans Hatran', sans-serif; direction: rtl; } /* Hebrew */ .Hebr { font-family: 'SBL Hebrew', 'SBL BibLit', 'Taamey David CLM', 'Taamey Frank CLM', Alef, 'Noto Sans Hebrew', Narkisim, Miriam, Kinryu, 'Arial Hebrew', Arial, 'Adobe Hebrew', serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Hiragana: see .Jpan */ /* Anatolian Hieroglyphs */ .Hluw { font-family: 'Noto Sans Anatolian Hieroglyphs', Anatolian, sans-serif; font-size: 200%; } /* Pahawh Hmong */ .Hmng { font-family: 'Noto Sans Pahawh Hmong', sans-serif; } /* Nyiakeng Puachue Hmong */ .Hmnp { font-family: 'Noto Serif Nyiakeng Puachue Hmong', serif; } /* Old Hungarian */ .Hung { font-family: 'Noto Sans Old Hungarian', sans-serif; } /* Italic */ .Ital { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Old Italic', sans-serif; font-size: 125%; } /* Javanese */ .Java { font-family: 'Tuladha Jejeg', 'Javanese Text', adjisaka, 'Noto Sans Javanese', sans-serif; } /* Japanese scripts .Hira = Hiragana .Kana = Katakana (used for Ainu language) .Jpan = Hiragana + Katakana + Kanji */ .Hira, .Jpan, .Kana { font-family: 'Hiragino Kaku Gothic Pro', Osaka, 'Yu Gothic', Meiryo, 'Source Han Sans J', 'Source Han Sans JP', 'Noto Sans CJK JP', 'Droid Sans Japanese', 'MS PGothic', 'MS Gothic', 'MS PMincho', 'MS Mincho', HanaMinA, HanaMinB, sans-serif; font-size: 120%; line-height: 1; } .Jpan ruby rt { font-family: 'Yu Gothic UI', 'Meiryo UI', 'MS UI Gothic', sans-serif; font-size: 60%; } /* Kayah Li */ .Kali { font-family: 'Code2000', 'Noto Sans Kayah Li', sans-serif; } /* Katakana: see .Jpan */ /* Kharoshthi */ .Khar { font-family: 'Segoe UI Historic', 'MPH 2B Damase', 'Noto Sans Kharoshthi', sans-serif; font-size: 110%; direction: rtl; unicode-bidi: isolate; } /* Khmer */ .Khmr { font-family: 'Khmer OS', 'Khmer OS Content', 'Leelawadee UI', 'Noto Sans Khmer', 'Code2000', 'Khmer Mondulkiri U OT ls', sans-serif; font-size: 125%; } /* Khojki */ .Khoj { font-family: 'Noto Sans Khojki', sans-serif; } /* Khitan small script */ .Kits { font-family: 'Noto Serif Khitan Small Script', serif; } /* Kannada */ .Knda { font-family: 'Kannada Sangam MN', JanaKannada, Tunga, Kedage, RaghuKannada, Sampige, 'Arial Unicode MS', 'Code2000', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Noto Sans Kannada', sans-serif; font-size: 125%; } /* Korean */ .Kore, .Hang { font-family: 'Apple SD Gothic Neo', 'Malgun Gothic', Dotum, Gulim, 'NanumBarunGothic YetHangul', NanumBarunGothic, UnDotum, 'Source Han Sans K', 'Source Han Sans KR', 'Noto Sans CJK KR', NanumGothic, 'NanumMyeongjo YetHangul', NanumMyeongjo, Batang, UnBatang, sans-serif; font-size: 120%; line-height: 1; } /* Kaithi */ .Kthi { font-family: 'Noto Sans Kaithi', sans-serif; } /* Lanna */ .Lana { font-family: 'Lanna Alif', 'Noto Sans Tai Tham', sans-serif; } /* Lao */ .Laoo { font-family: 'Phetsarath OT', 'Saysettha OT', 'JG Basic Lao Opentype', 'JG Basic2 Lao Opentype', 'JG LaoTimes Opentype', 'Phagnoum Lao Unicode Opentype', 'JG Lao Old Arial Opentype', DokChampa, 'Code2000', 'JG Lao Classic Opentype', 'Alice0 Unicode', 'Alice1 Unicode', 'Alice2 Unicode', 'Alice3 Unicode', 'Alice4 Unicode', 'Alice5 Unicode', 'Noto Sans Lao', 'Noto Sans Lao Looped', sans-serif; font-size: 125%; } /* Lepcha */ .Lepc { font-family: 'Noto Sans Lepcha', Mingzat, sans-serif; } /* Limbu */ .Limb { font-family: 'Code2000', 'MPH 2B Damase', 'Noto Sans Limbu', sans-serif; } /* Linear A */ .Lina { font-family: Aegean, 'Noto Sans Linear A', sans-serif; font-size: 125%; } /* Linear B */ .Linb { font-family: Aegean, 'Noto Sans Linear B', sans-serif; font-size: 125%; } /* Lisu */ .Lisu { font-family: 'Noto Sans Lisu', Quivira, sans-serif; } /* Lycian */ .Lyci { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Lycian', sans-serif; font-size: 125%; } /* Lydian */ .Lydi { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Lydian', sans-serif; font-size: 125%; } /* Mahajani */ .Mahj { font-family: 'Noto Sans Mahajani', sans-serif; font-size: 125%; } /* Makasar */ .Maka { font-family: 'Noto Serif Makasar', serif; } /* Mandaic */ .Mand { font-family: 'Noto Sans Mandaic', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Manichaean */ .Mani { font-family: 'Noto Sans Manichaean', sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Marchen */ .Marc { font-family: 'Noto Sans Marchen', sans-serif; } /* Medefaidrin */ .Medf { font-family: 'Noto Sans Medefaidrin', sans-serif; } /* Mende */ .Mend { font-family: 'Noto Sans Mende Kikakui', sans-serif; } /* Meroitic cursive */ .Merc { font-family: 'Segoe UI Historic', Aegyptus, 'Noto Sans Meroitic', sans-serif; font-size: 150%; } /* Meroitic hieroglyphs */ .Mero { font-family: Aegyptus, 'Noto Sans Meroitic', sans-serif; font-size: 150%; } /* Malayalam */ .Mlym { font-family: 'Malayalam Sangam MN', Kartika, 'Code2000', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', 'Noto Sans Malayalam', sans-serif; font-size: 125%; } /* Modi */ .Modi { font-family: 'Noto Sans Modi', sans-serif; } /* Classical Mongolian, Manchu, Xibe, Clear Script */ .Mong, .mnc-Mong, /* Manchu */ .sjo-Mong, /* Xibe */ .xwo-Mong /* Clear Script, Todo */ { font-family: 'Mongolian Baiti', 'Noto Sans Mongolian', sans-serif; font-size: 140%; -webkit-writing-mode: vertical-lr; -moz-writing-mode: vertical-lr; writing-mode: vertical-lr; } /* Mro */ .Mroo { font-family: 'Noto Sans Mro', sans-serif; } /* Meitei Mayek */ .Mtei { font-family: 'Eeyek Unicode', 'Noto Sans Meetei Mayek', sans-serif; } /* Multani */ .Mult { font-family: 'Noto Sans Multani', sans-serif; } /* Burmese */ .Mymr { font-family: TharLon, Padauk, 'Myanmar Text', 'Myanmar3', 'Myanmar2', 'Myanmar1', ParabaikSans, MyMyanmar, 'Noto Sans Myanmar', sans-serif; font-size: 130%; } big.Mymr, strong.Mymr, b.Mymr { font-size: 162%; } .Mymr b { font-size: 130%; } /* Nandinagari */ .Nand { font-family: 'Noto Sans Nandinagari', sans-serif; } /* North Arabian */ .Narb { font-family: 'Noto Sans Old North Arabian', sans-serif; } /* Newa */ .Newa { font-family: 'Noto Sans Newa', sans-serif; } /* N'Ko */ .Nkoo { font-family: "Noto Sans N'Ko", sans-serif; } /* Nüshu or Nushu */ .Nshu { font-family: 'Noto Sans Nushu', 'Noto Traditional Nushu', 'Unicode Nushu', sans-serif; font-size: 130%; } /* Ogham */ .Ogam { font-family: 'Segoe UI Historic', Beth-Luis-Nion, Pollach, 'Maigh Nuad', 'Craobh Ruadh', 'Everson Mono Ogham', Cog, Crosta, 'TITUS Ogham', 'Ragnarok Ogham', 'Noto Sans Ogham', sans-serif; font-size: 125%; } big.Ogam, strong.Ogam, b.Ogam, b .Ogam { font-size: 156%; } .Ogam b { font-size: 125%; } /* Ol Chiki */ .Olck { font-family: 'Code2000', 'Noto Sans Ol Chiki', sans-serif; } /* Orkhon Runes */ .Orkh { font-family: 'Segoe UI Historic', Orkun, 'Old Turkic', 'Noto Sans Old Turkic', sans-serif; } /* Odia */ .Orya { font-family: 'Oriya Sangam MN', 'Noto Sans Oriya', sans-serif; font-size: 125%; } /* Osage */ .Osge { font-family: 'Noto Sans Osage', sans-serif; } /* Osmanya */ .Osma { font-family: 'Noto Sans Osmanya', sans-serif; } /* Old Uyghur */ .Ougr { font-family: 'Noto Serif Old Uyghur', serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Palmyrene */ .Palm { font-family: 'Noto Sans Palmyrene', sans-serif; } /* Pau Cin Hau */ .Pauc { font-family: 'Noto Sans Pau Cin Hau', sans-serif; } /* Old Permic */ .Perm { font-family: 'Noto Sans Old Permic', sans-serif; } /* Phags-pa */ .Phag { font-family: 'BabelStone Phags-pa Book', 'Microsoft PhagsPa', 'Noto Sans Phags-pa', sans-serif; -webkit-writing-mode: vertical-lr; -moz-writing-mode: vertical-lr; writing-mode: vertical-lr; layout-flow: vertical-ideographic; } /* Inscriptional Pahlavi */ .Phli { font-family: 'Segoe UI Historic', 'Noto Sans Inscriptional Pahlavi', Shapour, 'ZH Mono', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Psalter Pahlavi */ .Phlp { font-family: 'Noto Sans Psalter Pahlavi', sans-serif; } /* Phoenician */ .Phnx { font-family: 'Segoe UI Historic', 'ALPHABETUM Unicode', 'MPH 2B Damase', Aegean, 'Code2001', 'Free Sans', 'Noto Sans Phoenician', sans-serif; font-size: 125%; direction: rtl; unicode-bidi: isolate; } /* Pollard */ .Plrd { font-family: 'Noto Sans Miao', sans-serif; } /* Inscriptional Parthian */ .Prti { font-family: 'Segoe UI Historic', 'Noto Sans Inscriptional Parthian', 'ZH Mono', sans-serif; } /* Rejang */ .Rjng { font-family: 'Noto Sans Rejang', 'Code2000', sans-serif; } /* Hanifi Rohingya */ .Rohg { font-family: 'Noto Sans Hanifi Rohingya', sans-serif; } /* Runic (Germanic) */ .Runr { font-family: 'Segoe UI Historic', Junicode, 'Free Mono', 'Caslon Roman', 'Segoe UI Symbol', 'Code2000', 'Everson Mono', 'TITUS Cyberbit Basic', 'Noto Sans Runic', sans-serif; font-size: 130%; } /* Samaritan */ .Samr { font-family: 'Noto Sans Samaritan', Quivira, 'Everson Mono', Unifont, sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* South Arabian */ .Sarb { font-family: 'Segoe UI Historic', Qataban, 'Noto Sans Old South Arabian', sans-serif; } /* Saurashtra */ .Saur { font-family: Pagul, 'Noto Sans Saurashtra', sans-serif; } /* SignWriting */ .Sgnw { font-family: 'Noto Sans SignWriting', sans-serif; } /* Shavian */ .Shaw { font-family: 'Segoe UI Historic', 'Code2001', 'Everson Mono', 'Noto Sans Shavian', sans-serif; } /* Sharada */ .Shrd { font-family: 'Noto Sans Sharada', sans-serif; font-size: 125%; } /* Siddham */ .Sidd { font-family: 'Noto Sans Siddham', sans-serif; } /* Sinhalese */ .Sinh { font-family: 'Sinhala Sangam MN', KaputaUnicode, KandyUnicode, Dinamina, DinaminaUniWeb, Potha, Madhura, 'Noto Sans Sinhala', sans-serif; font-size: 125%; } /* Sogdian */ .Sogd { font-family: 'Noto Sans Sogdian', sans-serif; } /* Old Sogdian */ .Sogo { font-family: 'Noto Sans Old Sogdian', sans-serif; } /* Sorang Sompeng */ .Sora { font-family: 'Noto Sans Sora Sompeng', sans-serif; } /* Soyombo */ .Soyo { font-family: 'Noto Sans Soyombo', sans-serif; } /* Sundanese */ .Sund { font-family: 'Sundanese Unicode', 'Noto Sans Sundanese', sans-serif; } /* Sunuwar */ .Sunu { font-family: 'Noto Sans Sunuwar', sans-serif; } /* Syloti Nagri */ .Sylo { font-family: 'Noto Sans Syloti Nagri', sans-serif; } /* Syriac */ .Syrc { font-family: 'Estrangelo Edessa', 'San Francisco', 'Code2000', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'TITUS Cyberbit Basic', sans-serif; font-size: 130%; direction: rtl; unicode-bidi: isolate; } /* Serto or Western form of Syriac */ .Syrc:lang(tru), .Syrc:lang(amw) { font-family: 'Noto Sans Syriac Western', 'Serto Jerusalem', 'Noto Sans Syriac', sans-serif; } /* Madnhaya or Eastern form of Syriac */ .Syrc:lang(aii) { font-family: 'Noto Sans Syriac Eastern', 'Noto Sans Syriac', sans-serif; } /* Tagbanwa */ .Tagb { font-family: Quivira, Tagbanwa, 'Noto Sans Tagbanwa', sans-serif; font-size: 110%; } /* Takri */ .Takr { font-family: 'Noto Sans Takri', sans-serif; } /* Tai Le */ .Tale { font-family: 'Microsoft Tai Le', 'Tai Le Valentinium', 'MPH 2B Damase', 'Noto Sans Tai Le', sans-serif; } /* New Tai Lue */ .Talu { font-family: 'Noto Sans New Tai Lue', 'Microsoft New Tai Lue', 'Dai Banna SIL Book', 'Husb_New_Tai_Lue_WB', sans-serif; } /* Tamil */ .Taml { font-family: 'Tamil Sangam MN', InaiMathi, Vijaya, Akshar, JanaTamil, 'Code2000', ETTamilNew, 'Lohit Tamil', 'Arial Unicode MS', 'Free Serif', Latha, 'Noto Sans Tamil', 'Noto Sans Tamil Supplement', sans-serif; font-size: 125%; } /* Tangut */ .Tang { font-family: 'BabelStone Tangut Wenhai', 'Tangut N4694', 'Tangut Yinchuan', 'New Tangut', 'New Tangut Std', 'Tangut TWU', 'Babelstone Tangut Wenhai', sans-serif; font-size: 120%; text-orientation: upright; -webkit-text-orientation: upright } /* Tai Viet */ .Tavt { font-family: 'Tai Heritage Pro', 'Noto Sans Tai Viet', sans-serif; } /* Lai Tay */ .Tayo { -webkit-writing-mode: vertical-rl; -moz-writing-mode: vertical-rl; writing-mode: vertical-rl; layout-flow: vertical-ideographic; } /* Telugu */ .Telu { font-family: 'Telugu Sangam MN', 'Noto Sans Telugu', sans-serif; font-size: 125%; } /* Tifinagh */ .Tfng { font-family: 'Hapax Berbère', Ebrima, 'Code2000', DejaVu, 'Noto Sans Tifinagh', sans-serif; font-size: 120%; } /* Baybayin */ .Tglg { font-family: 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } .Tglg:lang(bcl) { font-family: 'Bikol Mintz', 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } .Tglg:lang(ceb) { font-family: 'Bisaya Hervas', 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } /* Thaana */ .Thaa { font-family: 'Noto Sans Thaana', sans-serif; } /* Thai */ .Thai { font-family: 'Leelawadee UI', Leelawadee, 'Arial Unicode MS', 'Code2000', 'Noto Sans Thai', 'Noto Sans Thai Looped', sans-serif; font-size: 125%; } /* Tibetan */ .Tibt { font-family: 'Noto Serif Tibetan', 'Noto Sans Tibetan', Jomolhari-ID, 'Tibetan Machine Uni', 'Tibetan Machine Web', Jomolhari, 'Microsoft Himalaya', sans-serif; font-size: 130%; } /* Tirhuta */ .Tirh { font-family: 'Noto Sans Tirhuta', sans-serif; } /* Toto */ .Toto { font-family: 'Noto Serif Toto', serif; } /* Ugaritic */ .Ugar { font-family: 'Oxford Ugaritic', 'Segoe UI Historic', Aegean, 'Code2001', 'Noto Sans Ugaritic', sans-serif; } /* Vai */ .Vaii { font-family: Ebrima, 'Code2000', 'Noto Sans Vai', sans-serif; font-size: 110%; } /* Vithkuqi */ .Vith { font-family: 'Noto Serif Vithkuqi', 'Noto Sans Vithkuqi', sans-serif; } /* Varang Kshiti */ .Wara { font-family: 'Noto Sans Warang Citi', sans-serif; } /* Wancho */ .Wcho { font-family: 'Noto Sans Wancho', sans-serif; } /* Old Persian cuneiform */ .Xpeo { font-family: 'Segoe UI Historic', Aegean, Xerxes, 'Code2001', 'Noto Sans Old Persian', sans-serif; } /* Sumero-Akkadian cuneiform */ .Xsux { font-family: Akkadian, FreeIdgSerif, CuneiformComposite, 'Segoe UI Historic', sans-serif; /* Neo-Assyrian form */ /* font-family: FreeIdgSerif, Akkadian, CuneiformComposite, 'Segoe UI Historic', sans-serif; */ /* Old Assyrian form */ /* font-family: Akkadian, CuneiformComposite, FreeIdgSerif, 'Segoe UI Historic', sans-serif; /* /* Neo-Sumerian form */ /* font-family: Akkadian, CuneiformComposite, FreeIdgSerif, 'Segoe UI Historic', sans-serif; /* /* Classical Sumerian form */ font-size: 125%; } /* Specify Hittite fonts */ .Xsux:lang(hit) { font-family: UllikummiA, Akkadian, FreeIdgSerif, CuneiformComposite, 'Segoe UI Historic', sans-serif; } /* Specify Sumerian fonts */ .Xsux:lang(sux) { font-family: CuneiformComposite, Akkadian, 'Segoe UI Historic', sans-serif; } /* Yezidi */ .Yezi { font-family: 'Noto Serif Yezidi', serif; } /* Yi */ .Yiii { font-family: 'Noto Sans Yi', sans-serif; } /* Zanabazar Square */ .Zanb { font-family: 'Noto Sans Zanabazar Square', sans-serif; } /* Symbols */ .Zsym { font-family: Symbola, sans-serif; font-size: 150%; } /* Rumi numerals; see <https://en.wikipedia.org/wiki/Rumi_Numeral_Symbols> */ .Rumin, .Ruminumerals { font-size: 120%; } /* Multilingual writing systems and notations */ /* English Phonemic Representation (AHD) */ .enPR { font-family: 'Arial Unicode MS', 'Lucida Grande', 'Gentium Plus', Gentium, 'Gentium Alternative', 'TITUS Cyberbit Basic', 'Lucida Sans Unicode', sans-serif; } /* International Phonetic Alphabet */ .IPA, .Ipach, .IPAchar { font-family: 'Gentium Plus', Gentium, GentiumAlt, 'DejaVu Sans', 'Segoe UI', 'Lucida Grande', 'Charis SIL', 'Doulos SIL', 'TITUS Cyberbit Basic', 'Code2000', 'Lucida Sans Unicode', sans-serif; font-size: 110%; font-variant-ligatures: no-common-ligatures; } /* Musical notation */ .Music, .musical { font-family: Musica, 'Musical Symbols', Euterpe, 'Noto Music', sans-serif; font-size: 140%; } /* Znamenny musical notation */ .Zname { font-family: 'Mezenets Unicode', Slavonic, Voskresensky, Smolensky, Symbola, 'Noto Znamenny Musical Notation', sans-serif; } ow6904ikl8aoe8vsjbhn9i0aobnyckr 88869 88868 2026-08-06T23:08:01Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-LanguagesAndScripts.css]] 88868 css text/css /* Support for scripts. See [[Wiktionary:Scripts]]. */ /* Default style for mentions outside of "form of" definitions. See [[Wiktionary:Votes/2007-10/style for mentioned terms]] */ .mention { font-style: italic; } .mention i, i .mention { font-style: normal; } /* The following scripts do not support italic text, but do support bold text. Note: we repeat the first class selector twice to increase CSS 'specificity'. */ .Aghb.Aghb, .Aghb *, .Ahom.Ahom, .Ahom *, .Armi.Armi, .Armi *, .Armn.Armn, .Armn *, .Avst.Avst, .Avst *, .Bali.Bali, .Bali *, .Bamu.Bamu, .Bamu *, .Batk.Batk, .Batk *, .Beng.Beng, .Beng *, .as-Beng.as-Beng, .as-Beng *, .Bopo.Bopo, .Bopo *, .Brai.Brai, .Brai *, .Bugi.Bugi, .Bugi *, .Buhd.Buhd, .Buhd *, .Cakm.Cakm, .Cakm *, .Cans.Cans, .Cans *, .Cari.Cari, .Cari *, .Cham.Cham, .Cham *, .Cher.Cher, .Cher *, .Copt.Copt, .Copt *, .Cprt.Cprt, .Cprt *, .Cyrl.Cyrl, /* .Cyrl *, */ .Cyrs.Cyrs, .Cyrs *, .Deva.Deva, .Deva *, .Dsrt.Dsrt, .Dsrt *, .Egyp.Egyp, .Egyp *, .Ethi.Ethi, .Ethi *, .Geok.Geok, .Geok *, .Geor.Geor, .Geor *, .Glag.Glag, .Glag *, .Goth.Goth, .Goth *, .Grek.Grek, /* .Grek *, */ .Gujr.Gujr, .Gujr *, .Guru.Guru, .Guru *, .Hang.Hang, .Hang *, .Hani.Hani, .Hani *, .Hano.Hano, .Hano *, .Hans.Hans, .Hans *, .Hant.Hant, .Hant *, .Hira.Hira, .Hira *, .Hluw.Hluw, .Hluw *, .IPA.IPA, .IPA *, .Ipach.Ipach, .Ipach *, .IPAchar.IPAchar, .IPAchar *, .Ital.Ital, .Ital *, .Java.Java, .Java *, .Jpan.Jpan, .Jpan *, .Kali.Kali, .Kali *, .Kana.Kana, .Kana *, .Khar.Khar, .Khar *, .Khmr.Khmr, .Khmr *, .Knda.Knda, .Knda *, .Kore.Kore, .Kore *, .Kthi.Kthi, .Kthi *, .Lana.Lana, .Lana *, .Laoo.Laoo, .Laoo *, .Lepc.Lepc, .Lepc *, .Limb.Limb, .Limb *, .Lisu.Lisu, .Lisu *, .Lyci.Lyci, .Lyci *, .Lydi.Lydi, .Lydi *, .Mand.Mand, .Mand *, .Merc.Merc, .Merc *, .Mero.Mero, .Mero *, .Mlym.Mlym, .Mlym *, .Modi.Modi, .Modi *, .Mtei.Mtei, .Mtei *, .Music.Music, .Music *, .musical.musical, .musical *, .Narb.Narb, .Narb *, .Nkoo.Nkoo, .Nkoo *, .Olck.Olck, .Olck *, .Orya.Orya, .Orya *, .Osma.Osma, .Osma *, .Phag.Phag, .Phag *, .Phli.Phli, .Phli *, .Phlv.Phlv, .Phlv *, .Phnx.Phnx, .Phnx *, .Plrd.Plrd, .Plrd *, .Polyt.Polyt, .Polyt *, .polytonic.polytonic, .polytonic *, .Prti.Prti, .Prti *, .Rjng.Rjng, .Rjng *, .Samr.Samr, .Samr *, .Sarb.Sarb, .Sarb *, .Saur.Saur, .Saur *, .Sgnw.Sgnw, .Sgnw *, .Shaw.Shaw, .Shaw *, .Shrd.Shrd, .Shrd *, .Sinh.Sinh, .Sinh *, .Sora.Sora, .Sora *, .Sund.Sund, .Sund *, .Sylo.Sylo, .Sylo *, .Tagb.Tagb, .Tagb *, .Tale.Tale, .Tale *, .Talu.Talu, .Talu *, .Taml.Taml, .Taml *, .Tavt.Tavt, .Tavt *, .Tayo.Tayo, .Tayo *, .Telu.Telu, .Telu *, .Tfng.Tfng, .Tfng *, .Tglg.Tglg, .Tglg *, .Thaa.Thaa, .Thaa *, .Thai.Thai, .Thai *, .Tibt.Tibt, .Tibt *, .Ugar.Ugar, .Ugar *, .Vaii.Vaii, .Vaii *, .Xpeo.Xpeo, .Xpeo *, .Yiii.Yiii, .Yiii *, .Zmth.Zmth, .Zmth *, .Zname.Zname, .Zname *, .Zsym.Zsym, .Zsym * { font-style: normal; } /* The following scripts do not support neither bold nor italic text. Note: we repeat the first class selector twice to increase CSS 'specificity'. */ .Arab.Arab, .Arab *, .fa-Arab.fa-Arab, .fa-Arab *, .glk-Arab.glk-Arab, .glk-Arab *, .kk-Arab.kk-Arab, .kk-Arab *, .ks-Arab.ks-Arab, .ks-Arab *, .ku-Arab.ku-Arab, .ku-Arab *, .mzn-Arab.mzn-Arab, .mzn-Arab *, .ota-Arab.ota-Arab, .ota-Arab *, .pa-Arab.pa-Arab, .pa-Arab *, .ps-Arab.ps-Arab, .ps-Arab *, .sd-Arab.sd-Arab, .sd-Arab *, .tt-Arab.tt-Arab, .tt-Arab *, .ug-Arab.ug-Arab, .ug-Arab *, .ur-Arab.ur-Arab, .ur-Arab *, .ms-Arab.ms-Arab, .ms-Arab *, .Brah.Brah, .Brah *, .Elba.Elba, .Elba *, .Hebr.Hebr, .Hebr *, .Lina.Lina, .Lina *, .Linb.Linb, .Linb *, .Mani.Mani, .Mani *, .Mymr.Mymr, .Mymr *, .Mong.Mong, .Mong *, .mnc-Mong.mnc-Mong, .mnc-Mong *, .sjo-Mong.sjo-Mong, .sjo-Mong *, .xwo-Mong.xwo-Mong, .xwo-Mong *, .Ogam.Ogam, .Ogam *, .Orkh.Orkh, .Orkh *, .Ougr.Ougr, .Ougr *, .Runr.Runr, .Runr *, .Sogd.Sogd, .Sogd *, .Syrc.Syrc, .Syrc *, .Tang.Tang, .Tang *, .Vith.Vith, .Vith *, .Xsux.Xsux, .Xsux * { font-style: normal; font-weight: normal; } /* For scripts where bolding is not used or can be hard to see, the quoted word is highlighted in pink. */ .Arab.e-example b, .Arab.e-quotation b, .Arab.e-normalization b, .Brah.e-example b, .Brah.e-quotation b, .Brah.e-normalization b, .Deva.e-example b, .Deva.e-quotation b, .Deva.e-normalization b, .Elba.e-example b, .Elba.e-quotation b, .Elba.e-normalization b, .Hebr.e-example b, .Hebr.e-quotation b, .Hebr.e-normalization b, .Lina.e-example b, .Lina.e-quotation b, .Lina.e-normalization b, .Linb.e-example b, .Linb.e-quotation b, .Linb.e-normalization b, .Mani.e-example b, .Mani.e-quotation b, .Mani.e-normalization b, .Mong.e-example b, .Mong.e-quotation b, .Mong.e-normalization b, .Ogam.e-example b, .Ogam.e-quotation b, .Ogam.e-normalization b, .Orkh.e-example b, .Orkh.e-quotation b, .Orkh.e-normalization b, .Ougr.e-example b, .Ougr.e-quotation b, .Ougr.e-normalization b, .Runr.e-example b, .Runr.e-quotation b, .Runr.e-normalization b, .Sogd.e-example b, .Sogd.e-quotation b, .Sogd.e-normalization b, .Syrc.e-example b, .Syrc.e-quotation b, .Syrc.e-normalization b, .Ugar.e-example b, .Ugar.e-quotation b, .Ugar.e-normalization b, .Vith.e-example b, .Vith.e-quotation b, .Vith.e-normalization b, .Xpeo.e-example b, .Xpeo.e-quotation b, .Xpeo.e-normalization b, .Xsux.e-example b, .Xsux.e-quotation b, .Xsux.e-normalization b { background-color: var(--wikt-palette-pink, #ffe0f0); font-size: inherit; } /* Latin (.Latn) This is the default script, so it has no definitions. */ /* This is needed to overcome the "smartness" of certain web browsers */ .Latn:lang(ja), .Latn:lang(ko), .Latn:lang(zh) { font-family: inherit; } /* Latin Fraktur */ .Latf { font-family: UnifrakturMaguntia, UnifrakturCook, Unifraktur, sans-serif; font-size: 125%; } /* Navajo */ .nv-Latn { font-family: Calibri, 'Aboriginal Sans', 'DejaVu Sans', 'Arial Unicode MS', sans-serif !important; } /* Pitjantjatjara (ḻ ṉ ṟ ṯ and capitals) */ .pjt-Latn { font-family: Arial, 'Microsoft Sans Serif', Tahoma, sans-serif; } /* Latin extended */ /* no styles for .Latnx, .Latinx, .unicode, .Unicode */ /* Adlam */ .Adlm { font-family: 'Noto Sans Adlam', sans-serif; } /* Aghwan */ .Aghb { font-family: OptimaModoki, 'Noto Sans Caucasian Albanian', sans-serif; } /* Ahom */ .Ahom { font-family: AhomUnicode, 'Noto Serif Ahom', 'Unifont Upper', sans-serif; } /* Arabic */ .Arab, .fa-Arab, .glk-Arab, .kk-Arab, .ks-Arab, .ku-Arab, .mzn-Arab, .ota-Arab, .pa-Arab, .ps-Arab, .sd-Arab, .tt-Arab, .ug-Arab, .ur-Arab, .ms-Arab { font-family: 'Noto Naskh Arabic', 'Iranian Sans', Tahoma, 'Microsoft Sans Serif', 'Arial Unicode MS', sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Persian */ .fa-Arab { font-family: 'Iranian Sans', 'Geeza Pro', Tahoma, sans-serif; } /* Kashmiri */ .ks-Arab { font-family: 'Noto Naskh Arabic', Amiri, Mirza, 'Scheherazade New', Scheherazade, 'Geeza Pro', Tahoma, sans-serif; } /* Kurdish */ .ku-Arab { font-family: 'Noto Naskh Arabic', Tahoma, 'Arial Unicode MS', 'UT Cairo', 'UT Naskh', sans-serif; } /* Punjabi Shahmukhi, Urdu */ .pa-Arab, .ur-Arab { font-family: 'Noto Nastaliq Urdu', Tahoma, 'Arial Unicode MS', 'UT Cairo', 'UT Naskh', sans-serif; } /* Pashto */ .ps-Arab { font-family: Pokhto, 'Pashto Kror Asiatype', 'Scheherazade New', Scheherazade, sans-serif; } /* Sindhi */ .sd-Arab { font-family: 'MB Sindhi', Tahoma, 'MBSarang Sattar', 'MB Bhitai Sattar', 'MB Lateefi', 'Ayaz Gul', sans-serif; } /* Uyghur */ .ug-Arab { font-family: 'UKIJ Tuz', 'Microsoft Uighur', 'Scheherazade New', Scheherazade, sans-serif; } /* Imperial Aramaic */ .Armi { font-family: 'Segoe UI Historic', 'Aramaic Imperial Yeb', 'Noto Sans Imperial Aramaic', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Armenian */ .Armn { font-family: Mshtakan, Arial, 'Segoe UI', Tahoma, 'Arian AMU', 'DejaVu Sans', sans-serif; } /* Avestan */ .Avst { font-family: Avestan, Ahuramzda, 'Noto Sans Avestan', sans-serif; font-size: 125%; direction: rtl; unicode-bidi: isolate; font-variant-ligatures: none; /* Avestan language */ } .Avst:lang(pal) { /* Pazend (Middle Persian in Avestan script) */ font-variant-ligatures: normal; } /* Balinese */ .Bali { font-family: 'Noto Sans Balinese', sans-serif; } /* Bamum */ .Bamu { font-family: 'Noto Sans Bamum', sans-serif; } /* Bassa */ .Bass { font-family: 'Noto Sans Bassa Vah', sans-serif; } /* Batak */ .Batk { font-family: Batak-Unicode, 'Noto Sans Batak', sans-serif; } /* Bengali, Assamese */ .Beng, .as-Beng { font-family: 'Bangla Sangam MN', UniBangla, 'Code2000', Likhan, 'UT Bengali Dhaka', Vrinda, 'Noto Sans Bengali', sans-serif; font-size: 130%; } /* Bhaiksuki */ .Bhks { font-family: 'Noto Sans Bhaiksuki', sans-serif; } /* Zhuyin (Bopomofo) */ .Bopo { font-family: MOESongUN, DFKai-SB, 'Microsoft Yahei', 'Microsoft Jhenghei', 'Source Han Sans TC', 'Source Han Sans TW', 'Noto Sans CJK TC', sans-serif; } /* Brahmi */ .Brah { font-family: 'Segoe UI Historic', 'Noto Sans Brahmi', sans-serif; } /* Braille */ .Brai { font-size: 150%; } /* Buginese */ .Bugi { font-family: Saweri, 'Noto Sans Buginese', sans-serif; } /* Buhid [[Wiktionary:Grease pit/2025/February#Buhid]] */ .Buhd { font-family: 'Noto Sans Buhid', Quivira, sans-serif; font-size: 110%; } /* Chakma */ .Cakm { font-family: RibengUni, 'Noto Sans Chakma', sans-serif; } /* Unified Canadian Aboriginal Syllabics */ .Cans { font-family: 'Euphemia UCAS', Euphemia, 'Aboriginal Sans', OskiBlackfoot, 'Code2000', 'Everson Mono Unicode', 'Noto Sans Canadian Aboriginal', sans-serif; font-size: 110%; } /* Carian */ .Cari { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Carian', sans-serif; font-size: 125%; } /* Cham */ .Cham { font-family: 'Code2000', 'JG ChamCambodia', 'Noto Sans Cham', sans-serif; font-size: 110%; } /* Cherokee */ .Cher { font-family: Digohweli, 'Aboriginal Sans', 'Code2000', Marin, 'Rotinonhsonni Sans', 'Everson Mono Unicode', 'Noto Sans Cherokee', sans-serif; font-size: 110%; } /* Khwarezmian */ .Chrs { font-family: 'Noto Sans Chorasmian', sans-serif; } /* Coptic */ .Copt { font-family: Quivira, Antinoou, 'New Athena Unicode', Analecta, FreeSerifAvvaShenouda, 'Arial Coptic', 'Sophia Nubian', 'Code2000', 'Noto Sans Coptic', sans-serif; font-size: 130%; } /* Cypro-Minoan */ .Cpmn { font-family: 'Noto Sans Cypro Minoan', sans-serif; } /* Cypriot */ .Cprt { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Cypriot', sans-serif; font-size: 115%; direction: rtl; unicode-bidi: isolate; } /* Cyrillic */ .Cyrl { font-family: Helvetica, Geneva, 'Arial Unicode MS', 'Lucida Sans Unicode', sans-serif; } /* Old Cyrillic (Old Church Slavonic, Old East Slavic) */ .Cyrs { font-family: Monomakh, 'Monomakh Unicode', 'Monomakh Unicode TT', Menaion, 'Menaion Unicode', 'Menaion Unicode TT', Ponomar, 'Ponomar Unicode', 'Ponomar Unicode TT', Fedorovsk, 'Fedorovsk Unicode', 'Fedorovsk Unicode TT', Pochaevsk, 'Pochaevsk Unicode', 'Pochaevsk Unicode TT', Triodion, 'Triodion Unicode', 'Triodion Unicode TT', 'Acathist', 'Shafarik', Vilnius, BukyVede, 'Kliment Std', 'RomanCyrillic Std', 'Monomachus', 'Old Standard', 'Old Standard TT', Dilyana, 'Hirmos Ponomar', 'Hirmos Ponomar TT', 'Menaion Medieval', Lazov, 'DejaVu Sans', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', sans-serif; font-size: 125%; } /* Devanagari */ .Deva { font-family: 'Tiro Devanagari Sanskrit', 'Sanskrit Text', 'Adobe Devanagari', 'Noto Serif Devanagari', Utsaah, 'Devanagari MT', Raghu, Gargi, JanaSanskrit, JanaHindi, Siddhanta, 'Noto Sans Devanagari', sans-serif; font-size: 120%; } /* Dhives Akuru */ .Diak { font-family: 'Noto Serif Dives Akuru', serif; } /* Dogra */ .Dogr { font-family: 'Noto Serif Dogra', sans-serif; } /* Deseret */ .Dsrt { font-family: 'Segoe UI Symbol', 'Code2001', 'MPH 2B Damase', 'Everson Mono', sans-serif; } /* Duployan */ .Dupl { font-family: 'Noto Sans Duployan', sans-serif; } /* Demotic (Egyptian) */ .Egyd, .Egyd * { font-style: normal; direction: rtl; } /* Egyptian hieroglyphs */ .Egyp { font-family: 'NewGardiner', 'Noto Sans Egyptian Hieroglyphs', Abydos, Aegyptus, 'Segoe UI Historic', sans-serif; font-size: 150%; } /* Elbasan */ .Elba { font-family: 'Noto Sans Elbasan', sans-serif; } /* Elymaic */ .Elym { font-family: 'Noto Sans Elymaic', sans-serif; } /* Ethiopic (Ge'ez) */ .Ethi { font-family: 'Abyssinica SIL', Nyala, 'Code2000', 'Ethiopia Jiret', 'GF Zemen Unicode', 'TITUS Cyberbit Basic', 'Visual Geez Unicode', 'Visual Geez Unicode Agazian', 'Visual Geez Unicode Title', 'Noto Sans Ethiopic', sans-serif; font-size: 120%; } /* Georgian */ .Geor { font-family: 'DejaVu Sans', 'Arial Unicode MS', Sylfaen, sans-serif; } /* Glagolitic */ .Glag { font-family: Shafarik, Menaion, 'Menaion Unicode', 'Menaion Unicode TT', 'Segoe UI Historic', BukyVede, Dilyana, 'Noto Sans Glagolitic', sans-serif; font-size: 150%; } /* Gunjala Gondi */ .Gong { font-family: 'Noto Sans Gunjala Gondi', sans-serif; } /* Masaram Gondi */ .Gonm { font-family: 'Noto Sans Masaram Gondi', sans-serif; } /* Gothic */ .Goth { font-family: 'Segoe UI Historic', 'Code2001', Skeirs, 'MPH 2B Damase', 'Noto Sans Gothic', sans-serif; } b.Goth, strong.Goth { font-size: larger; } /* Grantha */ .Gran { font-family: 'Noto Sans Grantha', sans-serif; } /* Greek (.Grek) removed - [[Wiktionary:Grease pit/2025/February#Sans-serif Greek font]] */ /* Albanian, Pontic and Tsakonian in Greek script */ .Grek:lang(sq), .Grek:lang(pnt), .Grek:lang(tsd) { font-family: 'Gentium Plus', 'Gentium', 'Lucida Sans Unicode', sans-serif; } /* Polytonic Greek */ .polytonic, .Polyt { font-family: 'SBL Greek', 'SBL BibLit', 'New Athena Unicode', 'DejaVu Sans', Athena, 'Gentium Plus', Gentium, 'Palatino Linotype', Menaion, Times, 'Arial Unicode MS', 'Lucida Sans Unicode', 'Lucida Grande', sans-serif; } /* Messapic */ .Polyt:lang(cms) { font-family: 'Noto Serif', 'Lucida Sans Unicode', 'Gentium Plus', 'Gentium', 'Noto Sans', sans-serif; } /* Gujarati */ .Gujr { font-family: 'Noto Sans Gujarati', 'Gujarati Sangam MN', 'Gujarati MT', Shruti, 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'Code2000', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', sans-serif; font-size: 125%; } /* Gurmukhi */ .Guru { font-family: 'Gurmukhi MN', 'Gurmukhi MT', 'UT Punjabi Amritsar', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'Code2000', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', 'Noto Sans Gurmukhi', sans-serif; font-size: 125%; } /* Chinese (Han) .Hani = generic .Hans = simplified .Hant = traditional */ .Hans { font-family: 'PingFang SC', DengXian, 'Source Han Sans SC', 'Source Han Sans CN', 'Noto Sans CJK SC', 'Microsoft Yahei', SimHei, SimSun, NSimSun, SimSun-ExtB, Song, 'Heiti SC', HanaMinA, HanaMinB, sans-serif; } .Hani, .Hant { font-family: 'PingFang TC', 'Source Han Sans TC', 'Source Han Sans TW', 'Noto Sans CJK TC', 'Microsoft Jhenghei', MOESongUN, PMingLiU, PMingLiU-ExtB, MingLiU, MingLiU-ExtB, Ming, 'Heiti TC', HanaMinA, HanaMinB, sans-serif; } .Hani, .Hans, .Hant { font-size: 120%; line-height: 1; } .Hani:lang(vi), .Hani:lang(tyz) { font-family: 'Nom Na Tong', 'HAN NOM A', 'HAN NOM B', Sun-ExtA, Sun-ExtB, Ming-Lt-HKSCS-UNI-H, Ming-Lt-HKSCS-ExtB, HanaMinA, HanaMinB, HanaMin, 'PingFang TC', MingLiU, MingLiU-ExtB, 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', SimSun, SimSun-ExtB, 'Arial Unicode MS', 'TITUS Cyberbit Basic', sans-serif; /* CJK Unified Ideographs Extension C and Extension D (U+2A700..U+2B734, U+2B740..U+2B81F) font-family: Sun-ExtB, 'MingLiU_HKSCS-ExtB', Ming-Lt-HKSCS-ExtB, HanaMinB, sans-serif; **/ } /* Hanunoo */ .Hano { font-family: 'Noto Sans Hanunoo', Quivira, 'MPH 2B Damase', sans-serif; font-size: 110%; } /* Hatran */ .Hatr { font-family: 'Noto Sans Hatran', sans-serif; direction: rtl; } /* Hebrew */ .Hebr { font-family: 'SBL Hebrew', 'SBL BibLit', 'Taamey David CLM', 'Taamey Frank CLM', Alef, 'Noto Sans Hebrew', Narkisim, Miriam, Kinryu, 'Arial Hebrew', Arial, 'Adobe Hebrew', serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Hiragana: see .Jpan */ /* Anatolian Hieroglyphs */ .Hluw { font-family: 'Noto Sans Anatolian Hieroglyphs', Anatolian, sans-serif; font-size: 200%; } /* Pahawh Hmong */ .Hmng { font-family: 'Noto Sans Pahawh Hmong', sans-serif; } /* Nyiakeng Puachue Hmong */ .Hmnp { font-family: 'Noto Serif Nyiakeng Puachue Hmong', serif; } /* Old Hungarian */ .Hung { font-family: 'Noto Sans Old Hungarian', sans-serif; } /* Italic */ .Ital { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Old Italic', sans-serif; font-size: 125%; } /* Javanese */ .Java { font-family: 'Tuladha Jejeg', 'Javanese Text', adjisaka, 'Noto Sans Javanese', sans-serif; } /* Japanese scripts .Hira = Hiragana .Kana = Katakana (used for Ainu language) .Jpan = Hiragana + Katakana + Kanji */ .Hira, .Jpan, .Kana { font-family: 'Hiragino Kaku Gothic Pro', Osaka, 'Yu Gothic', Meiryo, 'Source Han Sans J', 'Source Han Sans JP', 'Noto Sans CJK JP', 'Droid Sans Japanese', 'MS PGothic', 'MS Gothic', 'MS PMincho', 'MS Mincho', HanaMinA, HanaMinB, sans-serif; font-size: 120%; line-height: 1; } .Jpan ruby rt { font-family: 'Yu Gothic UI', 'Meiryo UI', 'MS UI Gothic', sans-serif; font-size: 60%; } /* Kayah Li */ .Kali { font-family: 'Code2000', 'Noto Sans Kayah Li', sans-serif; } /* Katakana: see .Jpan */ /* Kharoshthi */ .Khar { font-family: 'Segoe UI Historic', 'MPH 2B Damase', 'Noto Sans Kharoshthi', sans-serif; font-size: 110%; direction: rtl; unicode-bidi: isolate; } /* Khmer */ .Khmr { font-family: 'Khmer OS', 'Khmer OS Content', 'Leelawadee UI', 'Noto Sans Khmer', 'Code2000', 'Khmer Mondulkiri U OT ls', sans-serif; font-size: 125%; } /* Khojki */ .Khoj { font-family: 'Noto Sans Khojki', sans-serif; } /* Khitan small script */ .Kits { font-family: 'Noto Serif Khitan Small Script', serif; } /* Kannada */ .Knda { font-family: 'Kannada Sangam MN', JanaKannada, Tunga, Kedage, RaghuKannada, Sampige, 'Arial Unicode MS', 'Code2000', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Noto Sans Kannada', sans-serif; font-size: 125%; } /* Korean */ .Kore, .Hang { font-family: 'Apple SD Gothic Neo', 'Malgun Gothic', Dotum, Gulim, 'NanumBarunGothic YetHangul', NanumBarunGothic, UnDotum, 'Source Han Sans K', 'Source Han Sans KR', 'Noto Sans CJK KR', NanumGothic, 'NanumMyeongjo YetHangul', NanumMyeongjo, Batang, UnBatang, sans-serif; font-size: 120%; line-height: 1; } /* Kaithi */ .Kthi { font-family: 'Noto Sans Kaithi', sans-serif; } /* Lanna */ .Lana { font-family: 'Lanna Alif', 'Noto Sans Tai Tham', sans-serif; } /* Lao */ .Laoo { font-family: 'Phetsarath OT', 'Saysettha OT', 'JG Basic Lao Opentype', 'JG Basic2 Lao Opentype', 'JG LaoTimes Opentype', 'Phagnoum Lao Unicode Opentype', 'JG Lao Old Arial Opentype', DokChampa, 'Code2000', 'JG Lao Classic Opentype', 'Alice0 Unicode', 'Alice1 Unicode', 'Alice2 Unicode', 'Alice3 Unicode', 'Alice4 Unicode', 'Alice5 Unicode', 'Noto Sans Lao', 'Noto Sans Lao Looped', sans-serif; font-size: 125%; } /* Lepcha */ .Lepc { font-family: 'Noto Sans Lepcha', Mingzat, sans-serif; } /* Limbu */ .Limb { font-family: 'Code2000', 'MPH 2B Damase', 'Noto Sans Limbu', sans-serif; } /* Linear A */ .Lina { font-family: Aegean, 'Noto Sans Linear A', sans-serif; font-size: 125%; } /* Linear B */ .Linb { font-family: Aegean, 'Noto Sans Linear B', sans-serif; font-size: 125%; } /* Lisu */ .Lisu { font-family: 'Noto Sans Lisu', Quivira, sans-serif; } /* Lycian */ .Lyci { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Lycian', sans-serif; font-size: 125%; } /* Lydian */ .Lydi { font-family: 'Segoe UI Historic', Aegean, 'Noto Sans Lydian', sans-serif; font-size: 125%; } /* Mahajani */ .Mahj { font-family: 'Noto Sans Mahajani', sans-serif; font-size: 125%; } /* Makasar */ .Maka { font-family: 'Noto Serif Makasar', serif; } /* Mandaic */ .Mand { font-family: 'Noto Sans Mandaic', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Manichaean */ .Mani { font-family: 'Noto Sans Manichaean', sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Marchen */ .Marc { font-family: 'Noto Sans Marchen', sans-serif; } /* Medefaidrin */ .Medf { font-family: 'Noto Sans Medefaidrin', sans-serif; } /* Mende */ .Mend { font-family: 'Noto Sans Mende Kikakui', sans-serif; } /* Meroitic cursive */ .Merc { font-family: 'Segoe UI Historic', Aegyptus, 'Noto Sans Meroitic', sans-serif; font-size: 150%; } /* Meroitic hieroglyphs */ .Mero { font-family: Aegyptus, 'Noto Sans Meroitic', sans-serif; font-size: 150%; } /* Malayalam */ .Mlym { font-family: 'Malayalam Sangam MN', Kartika, 'Code2000', 'Lucida Grande', 'Arial Unicode MS', 'Lucida Sans Unicode', 'TITUS Cyberbit Basic', 'Chrysanthi Unicode', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'Visual Geez Unicode', 'Noto Sans Malayalam', sans-serif; font-size: 125%; } /* Modi */ .Modi { font-family: 'Noto Sans Modi', sans-serif; } /* Classical Mongolian, Manchu, Xibe, Clear Script */ .Mong, .mnc-Mong, /* Manchu */ .sjo-Mong, /* Xibe */ .xwo-Mong /* Clear Script, Todo */ { font-family: 'Mongolian Baiti', 'Noto Sans Mongolian', sans-serif; font-size: 140%; -webkit-writing-mode: vertical-lr; -moz-writing-mode: vertical-lr; writing-mode: vertical-lr; } /* Mro */ .Mroo { font-family: 'Noto Sans Mro', sans-serif; } /* Meitei Mayek */ .Mtei { font-family: 'Eeyek Unicode', 'Noto Sans Meetei Mayek', sans-serif; } /* Multani */ .Mult { font-family: 'Noto Sans Multani', sans-serif; } /* Burmese */ .Mymr { font-family: TharLon, Padauk, 'Myanmar Text', 'Myanmar3', 'Myanmar2', 'Myanmar1', ParabaikSans, MyMyanmar, 'Noto Sans Myanmar', sans-serif; font-size: 130%; } big.Mymr, strong.Mymr, b.Mymr { font-size: 162%; } .Mymr b { font-size: 130%; } /* Nandinagari */ .Nand { font-family: 'Noto Sans Nandinagari', sans-serif; } /* North Arabian */ .Narb { font-family: 'Noto Sans Old North Arabian', sans-serif; } /* Newa */ .Newa { font-family: 'Noto Sans Newa', sans-serif; } /* N'Ko */ .Nkoo { font-family: "Noto Sans N'Ko", sans-serif; } /* Nüshu or Nushu */ .Nshu { font-family: 'Noto Sans Nushu', 'Noto Traditional Nushu', 'Unicode Nushu', sans-serif; font-size: 130%; } /* Ogham */ .Ogam { font-family: 'Segoe UI Historic', Beth-Luis-Nion, Pollach, 'Maigh Nuad', 'Craobh Ruadh', 'Everson Mono Ogham', Cog, Crosta, 'TITUS Ogham', 'Ragnarok Ogham', 'Noto Sans Ogham', sans-serif; font-size: 125%; } big.Ogam, strong.Ogam, b.Ogam, b .Ogam { font-size: 156%; } .Ogam b { font-size: 125%; } /* Ol Chiki */ .Olck { font-family: 'Code2000', 'Noto Sans Ol Chiki', sans-serif; } /* Orkhon Runes */ .Orkh { font-family: 'Segoe UI Historic', Orkun, 'Old Turkic', 'Noto Sans Old Turkic', sans-serif; } /* Odia */ .Orya { font-family: 'Oriya Sangam MN', 'Noto Sans Oriya', sans-serif; font-size: 125%; } /* Osage */ .Osge { font-family: 'Noto Sans Osage', sans-serif; } /* Osmanya */ .Osma { font-family: 'Noto Sans Osmanya', sans-serif; } /* Old Uyghur */ .Ougr { font-family: 'Noto Serif Old Uyghur', serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* Palmyrene */ .Palm { font-family: 'Noto Sans Palmyrene', sans-serif; } /* Pau Cin Hau */ .Pauc { font-family: 'Noto Sans Pau Cin Hau', sans-serif; } /* Old Permic */ .Perm { font-family: 'Noto Sans Old Permic', sans-serif; } /* Phags-pa */ .Phag { font-family: 'BabelStone Phags-pa Book', 'Microsoft PhagsPa', 'Noto Sans Phags-pa', sans-serif; -webkit-writing-mode: vertical-lr; -moz-writing-mode: vertical-lr; writing-mode: vertical-lr; layout-flow: vertical-ideographic; } /* Inscriptional Pahlavi */ .Phli { font-family: 'Segoe UI Historic', 'Noto Sans Inscriptional Pahlavi', Shapour, 'ZH Mono', sans-serif; direction: rtl; unicode-bidi: isolate; } /* Psalter Pahlavi */ .Phlp { font-family: 'Noto Sans Psalter Pahlavi', sans-serif; } /* Phoenician */ .Phnx { font-family: 'Segoe UI Historic', 'ALPHABETUM Unicode', 'MPH 2B Damase', Aegean, 'Code2001', 'Free Sans', 'Noto Sans Phoenician', sans-serif; font-size: 125%; direction: rtl; unicode-bidi: isolate; } /* Pollard */ .Plrd { font-family: 'Noto Sans Miao', sans-serif; } /* Inscriptional Parthian */ .Prti { font-family: 'Segoe UI Historic', 'Noto Sans Inscriptional Parthian', 'ZH Mono', sans-serif; } /* Rejang */ .Rjng { font-family: 'Noto Sans Rejang', 'Code2000', sans-serif; } /* Hanifi Rohingya */ .Rohg { font-family: 'Noto Sans Hanifi Rohingya', sans-serif; } /* Runic (Germanic) */ .Runr { font-family: 'Segoe UI Historic', Junicode, 'Free Mono', 'Caslon Roman', 'Segoe UI Symbol', 'Code2000', 'Everson Mono', 'TITUS Cyberbit Basic', 'Noto Sans Runic', sans-serif; font-size: 130%; } /* Samaritan */ .Samr { font-family: 'Noto Sans Samaritan', Quivira, 'Everson Mono', Unifont, sans-serif; font-size: 133%; direction: rtl; unicode-bidi: isolate; } /* South Arabian */ .Sarb { font-family: 'Segoe UI Historic', Qataban, 'Noto Sans Old South Arabian', sans-serif; } /* Saurashtra */ .Saur { font-family: Pagul, 'Noto Sans Saurashtra', sans-serif; } /* SignWriting */ .Sgnw { font-family: 'Noto Sans SignWriting', sans-serif; } /* Shavian */ .Shaw { font-family: 'Segoe UI Historic', 'Code2001', 'Everson Mono', 'Noto Sans Shavian', sans-serif; } /* Sharada */ .Shrd { font-family: 'Noto Sans Sharada', sans-serif; font-size: 125%; } /* Siddham */ .Sidd { font-family: 'Noto Sans Siddham', sans-serif; } /* Sinhalese */ .Sinh { font-family: 'Sinhala Sangam MN', KaputaUnicode, KandyUnicode, Dinamina, DinaminaUniWeb, Potha, Madhura, 'Noto Sans Sinhala', sans-serif; font-size: 125%; } /* Sogdian */ .Sogd { font-family: 'Noto Sans Sogdian', sans-serif; } /* Old Sogdian */ .Sogo { font-family: 'Noto Sans Old Sogdian', sans-serif; } /* Sorang Sompeng */ .Sora { font-family: 'Noto Sans Sora Sompeng', sans-serif; } /* Soyombo */ .Soyo { font-family: 'Noto Sans Soyombo', sans-serif; } /* Sundanese */ .Sund { font-family: 'Sundanese Unicode', 'Noto Sans Sundanese', sans-serif; } /* Sunuwar */ .Sunu { font-family: 'Noto Sans Sunuwar', sans-serif; } /* Syloti Nagri */ .Sylo { font-family: 'Noto Sans Syloti Nagri', sans-serif; } /* Syriac */ .Syrc { font-family: 'Estrangelo Edessa', 'San Francisco', 'Code2000', 'Bitstream Cyberbit', 'Bitstream CyberBase', 'Bitstream Vera', 'TITUS Cyberbit Basic', sans-serif; font-size: 130%; direction: rtl; unicode-bidi: isolate; } /* Serto or Western form of Syriac */ .Syrc:lang(tru), .Syrc:lang(amw) { font-family: 'Noto Sans Syriac Western', 'Serto Jerusalem', 'Noto Sans Syriac', sans-serif; } /* Madnhaya or Eastern form of Syriac */ .Syrc:lang(aii) { font-family: 'Noto Sans Syriac Eastern', 'Noto Sans Syriac', sans-serif; } /* Tagbanwa */ .Tagb { font-family: Quivira, Tagbanwa, 'Noto Sans Tagbanwa', sans-serif; font-size: 110%; } /* Takri */ .Takr { font-family: 'Noto Sans Takri', sans-serif; } /* Tai Le */ .Tale { font-family: 'Microsoft Tai Le', 'Tai Le Valentinium', 'MPH 2B Damase', 'Noto Sans Tai Le', sans-serif; } /* New Tai Lue */ .Talu { font-family: 'Noto Sans New Tai Lue', 'Microsoft New Tai Lue', 'Dai Banna SIL Book', 'Husb_New_Tai_Lue_WB', sans-serif; } /* Tamil */ .Taml { font-family: 'Tamil Sangam MN', InaiMathi, Vijaya, Akshar, JanaTamil, 'Code2000', ETTamilNew, 'Lohit Tamil', 'Arial Unicode MS', 'Free Serif', Latha, 'Noto Sans Tamil', 'Noto Sans Tamil Supplement', sans-serif; font-size: 125%; } /* Tangut */ .Tang { font-family: 'BabelStone Tangut Wenhai', 'Tangut N4694', 'Tangut Yinchuan', 'New Tangut', 'New Tangut Std', 'Tangut TWU', 'Babelstone Tangut Wenhai', sans-serif; font-size: 120%; text-orientation: upright; -webkit-text-orientation: upright } /* Tai Viet */ .Tavt { font-family: 'Tai Heritage Pro', 'Noto Sans Tai Viet', sans-serif; } /* Lai Tay */ .Tayo { -webkit-writing-mode: vertical-rl; -moz-writing-mode: vertical-rl; writing-mode: vertical-rl; layout-flow: vertical-ideographic; } /* Telugu */ .Telu { font-family: 'Telugu Sangam MN', 'Noto Sans Telugu', sans-serif; font-size: 125%; } /* Tifinagh */ .Tfng { font-family: 'Hapax Berbère', Ebrima, 'Code2000', DejaVu, 'Noto Sans Tifinagh', sans-serif; font-size: 120%; } /* Baybayin */ .Tglg { font-family: 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } .Tglg:lang(bcl) { font-family: 'Bikol Mintz', 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } .Tglg:lang(ceb) { font-family: 'Bisaya Hervas', 'Noto Sans Tagalog', 'Tagalog Stylized', 'Baybayin Lopez', 'Tagalog Doctrina 1593', Quivira, sans-serif; } /* Thaana */ .Thaa { font-family: 'Noto Sans Thaana', sans-serif; } /* Thai */ .Thai { font-family: 'Leelawadee UI', Leelawadee, 'Arial Unicode MS', 'Code2000', 'Noto Sans Thai', 'Noto Sans Thai Looped', sans-serif; font-size: 125%; } /* Tibetan */ .Tibt { font-family: 'Noto Serif Tibetan', 'Noto Sans Tibetan', Jomolhari-ID, 'Tibetan Machine Uni', 'Tibetan Machine Web', Jomolhari, 'Microsoft Himalaya', sans-serif; font-size: 130%; } /* Tirhuta */ .Tirh { font-family: 'Noto Sans Tirhuta', sans-serif; } /* Toto */ .Toto { font-family: 'Noto Serif Toto', serif; } /* Ugaritic */ .Ugar { font-family: 'Oxford Ugaritic', 'Segoe UI Historic', Aegean, 'Code2001', 'Noto Sans Ugaritic', sans-serif; } /* Vai */ .Vaii { font-family: Ebrima, 'Code2000', 'Noto Sans Vai', sans-serif; font-size: 110%; } /* Vithkuqi */ .Vith { font-family: 'Noto Serif Vithkuqi', 'Noto Sans Vithkuqi', sans-serif; } /* Varang Kshiti */ .Wara { font-family: 'Noto Sans Warang Citi', sans-serif; } /* Wancho */ .Wcho { font-family: 'Noto Sans Wancho', sans-serif; } /* Old Persian cuneiform */ .Xpeo { font-family: 'Segoe UI Historic', Aegean, Xerxes, 'Code2001', 'Noto Sans Old Persian', sans-serif; } /* Sumero-Akkadian cuneiform */ .Xsux { font-family: Akkadian, FreeIdgSerif, CuneiformComposite, 'Segoe UI Historic', sans-serif; /* Neo-Assyrian form */ /* font-family: FreeIdgSerif, Akkadian, CuneiformComposite, 'Segoe UI Historic', sans-serif; */ /* Old Assyrian form */ /* font-family: Akkadian, CuneiformComposite, FreeIdgSerif, 'Segoe UI Historic', sans-serif; /* /* Neo-Sumerian form */ /* font-family: Akkadian, CuneiformComposite, FreeIdgSerif, 'Segoe UI Historic', sans-serif; /* /* Classical Sumerian form */ font-size: 125%; } /* Specify Hittite fonts */ .Xsux:lang(hit) { font-family: UllikummiA, Akkadian, FreeIdgSerif, CuneiformComposite, 'Segoe UI Historic', sans-serif; } /* Specify Sumerian fonts */ .Xsux:lang(sux) { font-family: CuneiformComposite, Akkadian, 'Segoe UI Historic', sans-serif; } /* Yezidi */ .Yezi { font-family: 'Noto Serif Yezidi', serif; } /* Yi */ .Yiii { font-family: 'Noto Sans Yi', sans-serif; } /* Zanabazar Square */ .Zanb { font-family: 'Noto Sans Zanabazar Square', sans-serif; } /* Symbols */ .Zsym { font-family: Symbola, sans-serif; font-size: 150%; } /* Rumi numerals; see <https://en.wikipedia.org/wiki/Rumi_Numeral_Symbols> */ .Rumin, .Ruminumerals { font-size: 120%; } /* Multilingual writing systems and notations */ /* English Phonemic Representation (AHD) */ .enPR { font-family: 'Arial Unicode MS', 'Lucida Grande', 'Gentium Plus', Gentium, 'Gentium Alternative', 'TITUS Cyberbit Basic', 'Lucida Sans Unicode', sans-serif; } /* International Phonetic Alphabet */ .IPA, .Ipach, .IPAchar { font-family: 'Gentium Plus', Gentium, GentiumAlt, 'DejaVu Sans', 'Segoe UI', 'Lucida Grande', 'Charis SIL', 'Doulos SIL', 'TITUS Cyberbit Basic', 'Code2000', 'Lucida Sans Unicode', sans-serif; font-size: 110%; font-variant-ligatures: no-common-ligatures; } /* Musical notation */ .Music, .musical { font-family: Musica, 'Musical Symbols', Euterpe, 'Noto Music', sans-serif; font-size: 140%; } /* Znamenny musical notation */ .Zname { font-family: 'Mezenets Unicode', Slavonic, Voskresensky, Smolensky, Symbola, 'Noto Znamenny Musical Notation', sans-serif; } ow6904ikl8aoe8vsjbhn9i0aobnyckr MediaWiki:Gadget-VectorClassic.css 8 17934 88870 2014-04-30T16:31:14Z en>Kephir 0 sync with [[w:MediaWiki:Gadget-VectorClassic.css]] 88870 css text/css html, body { font-family: sans-serif; } div#content { color: black; } div#content h1, div#content h2, div#content #firstHeading, div#content .mw-editsection { font-family: inherit; } div#content h1, div#content h2, div#content h3, div#content h4, div#content h5, div#content h6 { line-height: inherit; margin: 0; padding-top: 0.5em; padding-bottom: 0.17em; } div#content #firstHeading { font-size: 1.6em; line-height: 1.2em; margin-bottom: 0.1em; padding-bottom: 0; } div#content h1 { font-size: 188%; margin-bottom: 0.6em; } div#content h2 { font-size: 150%; margin-bottom: 0.6em; } div#content h3 { font-size: 132%; } div#content h4 { font-size: 116%; } div#content h5 { font-size: 108%; } div#content h6 { font-size: 100%; } .mw-body-content, #bodyContent { font-size: 0.8125em; line-height: 1.5em; } leq64ddey8crira5cds9ixyluyb5zix 88871 88870 2026-08-06T23:08:10Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-VectorClassic.css]] 88870 css text/css html, body { font-family: sans-serif; } div#content { color: black; } div#content h1, div#content h2, div#content #firstHeading, div#content .mw-editsection { font-family: inherit; } div#content h1, div#content h2, div#content h3, div#content h4, div#content h5, div#content h6 { line-height: inherit; margin: 0; padding-top: 0.5em; padding-bottom: 0.17em; } div#content #firstHeading { font-size: 1.6em; line-height: 1.2em; margin-bottom: 0.1em; padding-bottom: 0; } div#content h1 { font-size: 188%; margin-bottom: 0.6em; } div#content h2 { font-size: 150%; margin-bottom: 0.6em; } div#content h3 { font-size: 132%; } div#content h4 { font-size: 116%; } div#content h5 { font-size: 108%; } div#content h6 { font-size: 100%; } .mw-body-content, #bodyContent { font-size: 0.8125em; line-height: 1.5em; } leq64ddey8crira5cds9ixyluyb5zix MediaWiki:Gadget-CatchMyAttention.css 8 17935 88872 2025-11-09T12:16:04Z en>Surjection 0 88872 css text/css /* <nowiki> */ .attentionseeking { border: 1px solid var(--wikt-palette-red, #d73333); padding: 0.5em; background: var(--wikt-palette-lightred, #fee7e6); color: var(--color-base, black); border-radius: 5px; } .attentionseeking::before { content: '⚠️ {{attention|' attr(data-lang) '}}'; font-family: monospace, 'something'; } .attentionseeking::after { content: ' ' attr(title); } /* </nowiki> */ 2hn8q0db31m98ro5jhjsfal6q5ubgwx 88873 88872 2026-08-06T23:08:18Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-CatchMyAttention.css]] 88872 css text/css /* <nowiki> */ .attentionseeking { border: 1px solid var(--wikt-palette-red, #d73333); padding: 0.5em; background: var(--wikt-palette-lightred, #fee7e6); color: var(--color-base, black); border-radius: 5px; } .attentionseeking::before { content: '⚠️ {{attention|' attr(data-lang) '}}'; font-family: monospace, 'something'; } .attentionseeking::after { content: ' ' attr(title); } /* </nowiki> */ 2hn8q0db31m98ro5jhjsfal6q5ubgwx MediaWiki:Gadget-HideLogo.css 8 17936 88874 2014-07-31T06:05:54Z en>Kephir 0 Migrating pure-CSS gadgets from [[WT:PREFS]] 88874 css text/css #p-logo { display: none;} #column-one { padding-top: 0;} #mw-panel { top:0 !important;} t0f2pppo06r0eh9xpagcpod6hm7bext 88875 88874 2026-08-06T23:08:35Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-HideLogo.css]] 88874 css text/css #p-logo { display: none;} #column-one { padding-top: 0;} #mw-panel { top:0 !important;} t0f2pppo06r0eh9xpagcpod6hm7bext MediaWiki:Gadget-vectorTabs.js 8 17937 88876 2017-08-19T19:51:01Z en>Dixtosa 0 88876 javascript text/javascript // {{documentation}} $(function() { $("#p-cactions").remove().find("li").insertBefore("#ca-watch,#ca-unwatch").find("a").wrap("<span>"); }); bzkksiyyf8g2iaqdoxvrx59s6gdq2l5 88877 88876 2026-08-06T23:08:46Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-vectorTabs.js]] 88876 javascript text/javascript // {{documentation}} $(function() { $("#p-cactions").remove().find("li").insertBefore("#ca-watch,#ca-unwatch").find("a").wrap("<span>"); }); bzkksiyyf8g2iaqdoxvrx59s6gdq2l5 MediaWiki:Gadget-vectorTabs.css 8 17938 88878 2017-08-15T15:28:59Z en>Dixtosa 0 88878 css text/css /*.menu li{background-color: #F3F3F3;background-image: url(/w/skins/Vector/images/tab-normal-fade.png);background-position: 0% 100%;background-repeat: repeat-x;float: left;line-height: 1.125em !important;} .menu{display:block !important;clear:none !important;} .menu ul{position:static !important;margin-top:10px !important;} #p-cactions h5{display:none;} .menu li a{background-image: url(/w/skins/Vector/images/tab-break.png);background-position: 100% 100%;background-repeat: no-repeat;} */ #p-cactions { display:none; } fsmgox7en3feoembh09cc0xuc4gqqsw 88879 88878 2026-08-06T23:08:55Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-vectorTabs.css]] 88878 css text/css /*.menu li{background-color: #F3F3F3;background-image: url(/w/skins/Vector/images/tab-normal-fade.png);background-position: 0% 100%;background-repeat: repeat-x;float: left;line-height: 1.125em !important;} .menu{display:block !important;clear:none !important;} .menu ul{position:static !important;margin-top:10px !important;} #p-cactions h5{display:none;} .menu li a{background-image: url(/w/skins/Vector/images/tab-break.png);background-position: 100% 100%;background-repeat: no-repeat;} */ #p-cactions { display:none; } fsmgox7en3feoembh09cc0xuc4gqqsw MediaWiki:Gadget-WiktCountryFlags.css 8 17939 88880 2026-08-06T09:42:57Z en>Surjection 0 manually update Alemannic from 36px to 40px 88880 css text/css /* * flags.css - adds flags to language headers. * originally created by [[User:Prince Kassad]] * this version is auto-generated from the list at [[Wiktionary:Language flags list]] * ([[Special:Permalink/91668618]]) */ .ns-0 h2 #Translingual::before, .ns-0 h2#Translingual::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Earth_Day_Flag.png/40px-Earth_Day_Flag.png');} .ns-0 h2 #English::before, .ns-0 h2#English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/English_language.svg/40px-English_language.svg.png');} .ns-0 h2 #\'Are\'are::before, .ns-0 h2#\'Are\'are::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Flag_of_Guadalcanal.svg/40px-Flag_of_Guadalcanal.svg.png');} .ns-0 h2 #Aari::before, .ns-0 h2#Aari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Flag_of_Southern_Ethiopia.svg/40px-Flag_of_Southern_Ethiopia.svg.png');} .ns-0 h2 #Abau::before, .ns-0 h2#Abau::before, .ns-0 h2 #Krisa::before, .ns-0 h2#Krisa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_Sandaun.svg/40px-Flag_of_Sandaun.svg.png');} .ns-0 h2 #Abaza::before, .ns-0 h2#Abaza::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Abazinia.svg/40px-Flag_of_Abazinia.svg.png');} .ns-0 h2 #Abenaki::before, .ns-0 h2#Abenaki::before, .ns-0 h2 #Malecite-Passamaquoddy::before, .ns-0 h2#Malecite-Passamaquoddy::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Wabanaki_Seal.png/40px-Wabanaki_Seal.png');} .ns-0 h2 #Abkhaz::before, .ns-0 h2#Abkhaz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_the_Republic_of_Abkhazia.svg/40px-Flag_of_the_Republic_of_Abkhazia.svg.png');} .ns-0 h2 #Acehnese::before, .ns-0 h2#Acehnese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Aceh_Sultanate.svg/40px-Flag_of_Aceh_Sultanate.svg.png');} .ns-0 h2 #Acholi::before, .ns-0 h2#Acholi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Acholi.svg/40px-Flag_of_Acholi.svg.png');} .ns-0 h2 #Adzera::before, .ns-0 h2#Adzera::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Flag_of_Morobe.png/40px-Flag_of_Morobe.png');} .ns-0 h2 #Afar::before, .ns-0 h2#Afar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/34/Flag_of_Djibouti.svg/40px-Flag_of_Djibouti.svg.png');} .ns-0 h2 #Afrikaans::before, .ns-0 h2#Afrikaans::before, .ns-0 h2 #Fanagalo::before, .ns-0 h2#Fanagalo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/af/Flag_of_South_Africa.svg/40px-Flag_of_South_Africa.svg.png');} .ns-0 h2 #Agutaynen::before, .ns-0 h2#Agutaynen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_Agutaya,_Palawan.png/40px-Flag_of_Agutaya,_Palawan.png');} .ns-0 h2 #Ahom::before, .ns-0 h2#Ahom::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Ahom_insignia_plain.svg/40px-Ahom_insignia_plain.svg.png');} .ns-0 h2 #Ainu::before, .ns-0 h2#Ainu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Ainu.svg/40px-Flag_of_Ainu.svg.png');} .ns-0 h2 #Akan::before, .ns-0 h2#Akan::before, .ns-0 h2 #Dagbani::before, .ns-0 h2#Dagbani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Ghana.svg/40px-Flag_of_Ghana.svg.png');} .ns-0 h2 #Akha::before, .ns-0 h2#Akha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_the_Akha_National_Development_Party.svg/40px-Flag_of_the_Akha_National_Development_Party.svg.png');} .ns-0 h2 #Akkala_Sami::before, .ns-0 h2#Akkala_Sami::before, .ns-0 h2 #Inari_Sami::before, .ns-0 h2#Inari_Sami::before, .ns-0 h2 #Kemi_Sami::before, .ns-0 h2#Kemi_Sami::before, .ns-0 h2 #Kildin_Sami::before, .ns-0 h2#Kildin_Sami::before, .ns-0 h2 #Lule_Sami::before, .ns-0 h2#Lule_Sami::before, .ns-0 h2 #Northern_Sami::before, .ns-0 h2#Northern_Sami::before, .ns-0 h2 #Pite_Sami::before, .ns-0 h2#Pite_Sami::before, .ns-0 h2 #Skolt_Sami::before, .ns-0 h2#Skolt_Sami::before, .ns-0 h2 #Southern_Sami::before, .ns-0 h2#Southern_Sami::before, .ns-0 h2 #Ter_Sami::before, .ns-0 h2#Ter_Sami::before, .ns-0 h2 #Ume_Sami::before, .ns-0 h2#Ume_Sami::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Sami_flag.svg/40px-Sami_flag.svg.png');} .ns-0 h2 #Aklanon::before, .ns-0 h2#Aklanon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/90/PH-AKL_Flag.png/40px-PH-AKL_Flag.png');} .ns-0 h2 #Albanian::before, .ns-0 h2#Albanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_Albania.svg/40px-Flag_of_Albania.svg.png');} .ns-0 h2 #Alemannic_German::before, .ns-0 h2#Alemannic_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_Switzerland_(Pantone).svg/40px-Flag_of_Switzerland_(Pantone).svg.png');} .ns-0 h2 #Aleut::before, .ns-0 h2#Aleut::before, .ns-0 h2 #Inupiaq::before, .ns-0 h2#Inupiaq::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Alaska.svg/40px-Flag_of_Alaska.svg.png');} .ns-0 h2 #Algerian_Arabic::before, .ns-0 h2#Algerian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Algeria.svg/40px-Flag_of_Algeria.svg.png');} .ns-0 h2 #Ambonese_Malay::before, .ns-0 h2#Ambonese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Lambang_Ambon.png/28px-Lambang_Ambon.png');} .ns-0 h2 #American_Sign_Language::before, .ns-0 h2#American_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Flag_of_the_United_States.svg/40px-Flag_of_the_United_States.svg.png');} .ns-0 h2 #Amharic::before, .ns-0 h2#Amharic::before, .ns-0 h2 #Argobba::before, .ns-0 h2#Argobba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_Ethiopia.svg/40px-Flag_of_Ethiopia.svg.png');} .ns-0 h2 #Amis::before, .ns-0 h2#Amis::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Emblem_of_Hualien_County_2010.svg/37px-Emblem_of_Hualien_County_2010.svg.png');} .ns-0 h2 #Ancient_Greek::before, .ns-0 h2#Ancient_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/58/Byzantine_imperial_flag,_14th_century,_square.svg/37px-Byzantine_imperial_flag,_14th_century,_square.svg.png');} .ns-0 h2 #Andalusian_Arabic::before, .ns-0 h2#Andalusian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Green-White_Flag.svg/40px-Green-White_Flag.svg.png');} .ns-0 h2 #Angevin::before, .ns-0 h2#Angevin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ad/Flag_of_Anjou.svg/40px-Flag_of_Anjou.svg.png');} .ns-0 h2 #Angika::before, .ns-0 h2#Angika::before, .ns-0 h2 #Magahi::before, .ns-0 h2#Magahi::before, .ns-0 h2 #Maithili::before, .ns-0 h2#Maithili::before, .ns-0 h2 #Santali::before, .ns-0 h2#Santali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Jharkhand_Rajakiya_Chihna.svg/40px-Jharkhand_Rajakiya_Chihna.svg.png');} .ns-0 h2 #Angolar::before, .ns-0 h2#Angolar::before, .ns-0 h2 #Sãotomense::before, .ns-0 h2#Sãotomense::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_São_Tomé_and_Príncipe.svg/40px-Flag_of_São_Tomé_and_Príncipe.svg.png');} .ns-0 h2 #Anguthimri::before, .ns-0 h2#Anguthimri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/04/Flag_of_Queensland.svg/40px-Flag_of_Queensland.svg.png');} .ns-0 h2 #Annobonese::before, .ns-0 h2#Annobonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Bandera_Annobon.png/40px-Bandera_Annobon.png');} .ns-0 h2 #Antigua_and_Barbuda_Creole_English::before, .ns-0 h2#Antigua_and_Barbuda_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Antigua_and_Barbuda.svg/40px-Flag_of_Antigua_and_Barbuda.svg.png');} .ns-0 h2 #Antillean_Creole::before, .ns-0 h2#Antillean_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Saint_Lucia.svg/40px-Flag_of_Saint_Lucia.svg.png');} .ns-0 h2 #Ao::before, .ns-0 h2#Ao::before, .ns-0 h2 #Naga_Pidgin::before, .ns-0 h2#Naga_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Unofficial_flag_of_Nagaland.svg/40px-Unofficial_flag_of_Nagaland.svg.png');} .ns-0 h2 #Arabic::before, .ns-0 h2#Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Flag_of_the_Arab_League.svg/40px-Flag_of_the_Arab_League.svg.png');} .ns-0 h2 #Aragonese::before, .ns-0 h2#Aragonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/18/Flag_of_Aragon.svg/40px-Flag_of_Aragon.svg.png');} .ns-0 h2 #Arapaho::before, .ns-0 h2#Arapaho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/85/Flag_of_Arapaho_Nation.svg/40px-Flag_of_Arapaho_Nation.svg.png');} .ns-0 h2 #Armenian::before, .ns-0 h2#Armenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Armenia.svg/40px-Flag_of_Armenia.svg.png');} .ns-0 h2 #Aromanian::before, .ns-0 h2#Aromanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/97/Aromanian_flag.svg/40px-Aromanian_flag.svg.png');} .ns-0 h2 #Asi::before, .ns-0 h2#Asi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/39/Flag_of_Banton,_Romblon.png/40px-Flag_of_Banton,_Romblon.png');} .ns-0 h2 #Assamese::before, .ns-0 h2#Assamese::before, .ns-0 h2 #Bodo_\(India\)::before, .ns-0 h2#Bodo_\(India\)::before, .ns-0 h2 #Gujarati::before, .ns-0 h2#Gujarati::before, .ns-0 h2 #Hindi::before, .ns-0 h2#Hindi::before, .ns-0 h2 #Malayalam::before, .ns-0 h2#Malayalam::before, .ns-0 h2 #Marathi::before, .ns-0 h2#Marathi::before, .ns-0 h2 #Telugu::before, .ns-0 h2#Telugu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_India.svg/40px-Flag_of_India.svg.png');} .ns-0 h2 #Assyrian_Neo-Aramaic::before, .ns-0 h2#Assyrian_Neo-Aramaic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_the_Assyrians_(gold_and_blue_Assur).svg/40px-Flag_of_the_Assyrians_(gold_and_blue_Assur).svg.png');} .ns-0 h2 #Asturian::before, .ns-0 h2#Asturian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_Asturias.svg/40px-Flag_of_Asturias.svg.png');} .ns-0 h2 #Atayal::before, .ns-0 h2#Atayal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_New_Taipei_City.svg/40px-Flag_of_New_Taipei_City.svg.png');} .ns-0 h2 #Atikamekw::before, .ns-0 h2#Atikamekw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Flag_of_Quebec.svg/40px-Flag_of_Quebec.svg.png');} .ns-0 h2 #Aukan::before, .ns-0 h2#Aukan::before, .ns-0 h2 #Saramaccan::before, .ns-0 h2#Saramaccan::before, .ns-0 h2 #Sranan_Tongo::before, .ns-0 h2#Sranan_Tongo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/60/Flag_of_Suriname.svg/40px-Flag_of_Suriname.svg.png');} .ns-0 h2 #Australian_Kriol::before, .ns-0 h2#Australian_Kriol::before, .ns-0 h2 #Torres_Strait_Creole::before, .ns-0 h2#Torres_Strait_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Australian_Aboriginal_Flag.svg/40px-Australian_Aboriginal_Flag.svg.png');} .ns-0 h2 #Avar::before, .ns-0 h2#Avar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Flag_of_Avars.svg/40px-Flag_of_Avars.svg.png');} .ns-0 h2 #Avestan::before, .ns-0 h2#Avestan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Faravahar-Gold.svg/40px-Faravahar-Gold.svg.png');} .ns-0 h2 #Awadhi::before, .ns-0 h2#Awadhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Flag_of_Awadh.svg/40px-Flag_of_Awadh.svg.png');} .ns-0 h2 #Aymara::before, .ns-0 h2#Aymara::before, .ns-0 h2 #Bolivian_Sign_Language::before, .ns-0 h2#Bolivian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_Bolivia_(state).svg/40px-Flag_of_Bolivia_(state).svg.png');} .ns-0 h2 #Azerbaijani::before, .ns-0 h2#Azerbaijani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_Azerbaijan.svg/40px-Flag_of_Azerbaijan.svg.png');} .ns-0 h2 #Baba_Malay::before, .ns-0 h2#Baba_Malay::before, .ns-0 h2 #Singapore_Sign_Language::before, .ns-0 h2#Singapore_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Singapore.svg/40px-Flag_of_Singapore.svg.png');} .ns-0 h2 #Bacanese_Malay::before, .ns-0 h2#Bacanese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Bendera_Sultan_Bacan.svg/40px-Bendera_Sultan_Bacan.svg.png');} .ns-0 h2 #Badaga::before, .ns-0 h2#Badaga::before, .ns-0 h2 #Tamil::before, .ns-0 h2#Tamil::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Seal_of_Tamil_Nadu.svg/40px-Seal_of_Tamil_Nadu.svg.png');} .ns-0 h2 #Bagheli::before, .ns-0 h2#Bagheli::before, .ns-0 h2 #Bundeli::before, .ns-0 h2#Bundeli::before, .ns-0 h2 #Korku::before, .ns-0 h2#Korku::before, .ns-0 h2 #Malvi::before, .ns-0 h2#Malvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Emblem_of_Madhya_Pradesh.svg/40px-Emblem_of_Madhya_Pradesh.svg.png');} .ns-0 h2 #Baharna_Arabic::before, .ns-0 h2#Baharna_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Bahrain.svg/40px-Flag_of_Bahrain.svg.png');} .ns-0 h2 #Bahnar::before, .ns-0 h2#Bahnar::before, .ns-0 h2 #Hrê::before, .ns-0 h2#Hrê::before, .ns-0 h2 #Vietnamese::before, .ns-0 h2#Vietnamese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Vietnam.svg/40px-Flag_of_Vietnam.svg.png');} .ns-0 h2 #Bajan::before, .ns-0 h2#Bajan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Flag_of_Barbados.svg/40px-Flag_of_Barbados.svg.png');} .ns-0 h2 #Balinese::before, .ns-0 h2#Balinese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Historical_Flag_of_Bali.png/40px-Historical_Flag_of_Bali.png');} .ns-0 h2 #Balinese_Malay::before, .ns-0 h2#Balinese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Coat_of_arms_of_Bali.svg/35px-Coat_of_arms_of_Bali.svg.png');} .ns-0 h2 #Balti::before, .ns-0 h2#Balti::before, .ns-0 h2 #Burushaski::before, .ns-0 h2#Burushaski::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Hunza.svg/40px-Flag_of_Hunza.svg.png');} .ns-0 h2 #Baluchi::before, .ns-0 h2#Baluchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Balochistan.svg/40px-Flag_of_Balochistan.svg.png');} .ns-0 h2 #Bambara::before, .ns-0 h2#Bambara::before, .ns-0 h2 #Soninke::before, .ns-0 h2#Soninke::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_Mali.svg/40px-Flag_of_Mali.svg.png');} .ns-0 h2 #Banjarese::before, .ns-0 h2#Banjarese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Banjar_Sultanate_Flag.svg/40px-Banjar_Sultanate_Flag.svg.png');} .ns-0 h2 #Baoule::before, .ns-0 h2#Baoule::before, .ns-0 h2 #Dyula::before, .ns-0 h2#Dyula::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Côte_d'Ivoire.svg/40px-Flag_of_Côte_d'Ivoire.svg.png");} .ns-0 h2 #Bari::before, .ns-0 h2#Bari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Flag_of_the_Bari_people.svg/40px-Flag_of_the_Bari_people.svg.png');} .ns-0 h2 #Barikanchi::before, .ns-0 h2#Barikanchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Flag_of_the_Nigerian_Armed_Forces.svg/40px-Flag_of_the_Nigerian_Armed_Forces.svg.png');} .ns-0 h2 #Bashkir::before, .ns-0 h2#Bashkir::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Flag_of_Bashkortostan.svg/40px-Flag_of_Bashkortostan.svg.png');} .ns-0 h2 #Basque::before, .ns-0 h2#Basque::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Flag_of_the_Basque_Country.svg/40px-Flag_of_the_Basque_Country.svg.png');} .ns-0 h2 #Bavarian::before, .ns-0 h2#Bavarian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_Bavaria_(lozengy).svg/40px-Flag_of_Bavaria_(lozengy).svg.png');} .ns-0 h2 #Beja::before, .ns-0 h2#Beja::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_the_Beja_Congress.svg/40px-Flag_of_the_Beja_Congress.svg.png');} .ns-0 h2 #Belarusian::before, .ns-0 h2#Belarusian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/85/Flag_of_Belarus.svg/40px-Flag_of_Belarus.svg.png');} .ns-0 h2 #Belizean_Creole::before, .ns-0 h2#Belizean_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Flag_of_Belize.svg/40px-Flag_of_Belize.svg.png');} .ns-0 h2 #Bella_Coola::before, .ns-0 h2#Bella_Coola::before, .ns-0 h2 #Halkomelem::before, .ns-0 h2#Halkomelem::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_British_Columbia.svg/40px-Flag_of_British_Columbia.svg.png');} .ns-0 h2 #Bemba::before, .ns-0 h2#Bemba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_Zambia.svg/40px-Flag_of_Zambia.svg.png');} .ns-0 h2 #Bengali::before, .ns-0 h2#Bengali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Bengali_language.svg/40px-Bengali_language.svg.png');} .ns-0 h2 #Berau_Malay::before, .ns-0 h2#Berau_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7f/East_Borneo_Sultanate_Flags.png/40px-East_Borneo_Sultanate_Flags.png');} .ns-0 h2 #Berbice_Creole_Dutch::before, .ns-0 h2#Berbice_Creole_Dutch::before, .ns-0 h2 #Skepi_Creole_Dutch::before, .ns-0 h2#Skepi_Creole_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_the_Dutch_West_India_Company.svg/40px-Flag_of_the_Dutch_West_India_Company.svg.png');} .ns-0 h2 #Betawi::before, .ns-0 h2#Betawi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Coat_of_arms_of_Jakarta.svg/30px-Coat_of_arms_of_Jakarta.svg.png');} .ns-0 h2 #Bhojpuri::before, .ns-0 h2#Bhojpuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Seal_of_Uttar_Pradesh.svg/40px-Seal_of_Uttar_Pradesh.svg.png');} .ns-0 h2 #Bihari::before, .ns-0 h2#Bihari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Seal_of_Bihar.svg/40px-Seal_of_Bihar.svg.png');} .ns-0 h2 #Bima::before, .ns-0 h2#Bima::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Bendera_Kesultanan_Bima.png/40px-Bendera_Kesultanan_Bima.png');} .ns-0 h2 #Binukid::before, .ns-0 h2#Binukid::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Flag_of_the_Province_of_Bukidnon.svg/40px-Flag_of_the_Province_of_Bukidnon.svg.png');} .ns-0 h2 #Bislama::before, .ns-0 h2#Bislama::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Vanuatu.svg/40px-Flag_of_Vanuatu.svg.png');} .ns-0 h2 #Blackfoot::before, .ns-0 h2#Blackfoot::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Flag_of_the_Blackfoot_Confederacy.jpg/40px-Flag_of_the_Blackfoot_Confederacy.jpg');} .ns-0 h2 #Boon::before, .ns-0 h2#Boon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Jubaland_(Somalia).svg/40px-Flag_of_Jubaland_(Somalia).svg.png');} .ns-0 h2 #Bourbonnais-Berrichon::before, .ns-0 h2#Bourbonnais-Berrichon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Flag_of_Bourbonnais.svg/40px-Flag_of_Bourbonnais.svg.png');} .ns-0 h2 #Bourguignon::before, .ns-0 h2#Bourguignon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Bourgogne.svg/40px-Flag_of_Bourgogne.svg.png');} .ns-0 h2 #Brahui::before, .ns-0 h2#Brahui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/FlagofKalat.svg/40px-FlagofKalat.svg.png');} .ns-0 h2 #Brazilian_Sign_Language::before, .ns-0 h2#Brazilian_Sign_Language::before, .ns-0 h2 #Old_Tupi::before, .ns-0 h2#Old_Tupi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/05/Flag_of_Brazil.svg/40px-Flag_of_Brazil.svg.png');} .ns-0 h2 #Breton::before, .ns-0 h2#Breton::before, .ns-0 h2 #Gallo::before, .ns-0 h2#Gallo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Flag_of_Brittany.svg/40px-Flag_of_Brittany.svg.png');} .ns-0 h2 #Brokkat::before, .ns-0 h2#Brokkat::before, .ns-0 h2 #Bumthangkha::before, .ns-0 h2#Bumthangkha::before, .ns-0 h2 #Chocangaca::before, .ns-0 h2#Chocangaca::before, .ns-0 h2 #Dzala::before, .ns-0 h2#Dzala::before, .ns-0 h2 #Dzongkha::before, .ns-0 h2#Dzongkha::before, .ns-0 h2 #Kurtöp::before, .ns-0 h2#Kurtöp::before, .ns-0 h2 #Tshangla::before, .ns-0 h2#Tshangla::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/91/Flag_of_Bhutan.svg/40px-Flag_of_Bhutan.svg.png');} .ns-0 h2 #Brooke\'s_Point_Palawano::before, .ns-0 h2#Brooke\'s_Point_Palawano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Flag_of_Palawan,_Philippines.svg/40px-Flag_of_Palawan,_Philippines.svg.png');} .ns-0 h2 #Brunei_Malay::before, .ns-0 h2#Brunei_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Flag_of_Brunei.svg/40px-Flag_of_Brunei.svg.png');} .ns-0 h2 #Bulgarian::before, .ns-0 h2#Bulgarian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Bulgaria.svg/40px-Flag_of_Bulgaria.svg.png');} .ns-0 h2 #Bunun::before, .ns-0 h2#Bunun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Nantou_County.svg/40px-Flag_of_Nantou_County.svg.png');} .ns-0 h2 #Burmese::before, .ns-0 h2#Burmese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Flag_of_Myanmar.svg/40px-Flag_of_Myanmar.svg.png');} .ns-0 h2 #Buryat::before, .ns-0 h2#Buryat::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/68/Flag_of_Buryatia.svg/40px-Flag_of_Buryatia.svg.png');} .ns-0 h2 #Butuanon::before, .ns-0 h2#Butuanon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Butuancityflag.jpg/40px-Butuancityflag.jpg');} .ns-0 h2 #Cahuilla::before, .ns-0 h2#Cahuilla::before, .ns-0 h2 #Northern_Valley_Yokuts::before, .ns-0 h2#Northern_Valley_Yokuts::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/40px-Flag_of_California.svg.png');} .ns-0 h2 #Calabrian_Greek::before, .ns-0 h2#Calabrian_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Flag_of_Calabria.svg/40px-Flag_of_Calabria.svg.png');} .ns-0 h2 #Caluyanun::before, .ns-0 h2#Caluyanun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Caluya,_Antique.png/40px-Flag_of_Caluya,_Antique.png');} .ns-0 h2 #Caló::before, .ns-0 h2#Caló::before, .ns-0 h2 #Romani::before, .ns-0 h2#Romani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_the_Romani_people.svg/40px-Flag_of_the_Romani_people.svg.png');} .ns-0 h2 #Cameroon_Pidgin::before, .ns-0 h2#Cameroon_Pidgin::before, .ns-0 h2 #Ghomala\'::before, .ns-0 h2#Ghomala\'::before, .ns-0 h2 #Matal::before, .ns-0 h2#Matal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Flag_of_Cameroon.svg/40px-Flag_of_Cameroon.svg.png');} .ns-0 h2 #Cantonese::before, .ns-0 h2#Cantonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_Hong_Kong.svg/40px-Flag_of_Hong_Kong.svg.png');} .ns-0 h2 #Caribbean_Hindustani::before, .ns-0 h2#Caribbean_Hindustani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Suriname_and_Guyana.png/40px-Flag_of_Suriname_and_Guyana.png');} .ns-0 h2 #Carolinian::before, .ns-0 h2#Carolinian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_the_Northern_Mariana_Islands.svg/40px-Flag_of_the_Northern_Mariana_Islands.svg.png');} .ns-0 h2 #Carpathian_Rusyn::before, .ns-0 h2#Carpathian_Rusyn::before, .ns-0 h2 #Pannonian_Rusyn::before, .ns-0 h2#Pannonian_Rusyn::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Rusyns_2007.svg/40px-Flag_of_Rusyns_2007.svg.png');} .ns-0 h2 #Catalan::before, .ns-0 h2#Catalan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Catalonia.svg/40px-Flag_of_Catalonia.svg.png');} .ns-0 h2 #Cavineña::before, .ns-0 h2#Cavineña::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Beni.svg/40px-Flag_of_Beni.svg.png');} .ns-0 h2 #Cebuano::before, .ns-0 h2#Cebuano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Cebu_(province).svg/40px-Flag_of_Cebu_(province).svg.png');} .ns-0 h2 #Central_Atlas_Tamazight::before, .ns-0 h2#Central_Atlas_Tamazight::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Berber_flag.svg/40px-Berber_flag.svg.png');} .ns-0 h2 #Central_Bikol::before, .ns-0 h2#Central_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_the_Katipuneros_of_Bicol.svg/40px-Flag_of_the_Katipuneros_of_Bicol.svg.png');} .ns-0 h2 #Central_Dusun::before, .ns-0 h2#Central_Dusun::before, .ns-0 h2 #Sabah_Malay::before, .ns-0 h2#Sabah_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b5/Flag_of_Sabah.svg/40px-Flag_of_Sabah.svg.png');} .ns-0 h2 #Central_Kurdish::before, .ns-0 h2#Central_Kurdish::before, .ns-0 h2 #Northern_Kurdish::before, .ns-0 h2#Northern_Kurdish::before, .ns-0 h2 #Southern_Kurdish::before, .ns-0 h2#Southern_Kurdish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/35/Flag_of_Kurdistan.svg/40px-Flag_of_Kurdistan.svg.png');} .ns-0 h2 #Central_Mansi::before, .ns-0 h2#Central_Mansi::before, .ns-0 h2 #Eastern_Khanty::before, .ns-0 h2#Eastern_Khanty::before, .ns-0 h2 #Northern_Khanty::before, .ns-0 h2#Northern_Khanty::before, .ns-0 h2 #Northern_Mansi::before, .ns-0 h2#Northern_Mansi::before, .ns-0 h2 #Southern_Khanty::before, .ns-0 h2#Southern_Khanty::before, .ns-0 h2 #Southern_Mansi::before, .ns-0 h2#Southern_Mansi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Yugra.svg/40px-Flag_of_Yugra.svg.png');} .ns-0 h2 #Central_Nahuatl::before, .ns-0 h2#Central_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_Tlaxcala.svg/40px-Flag_of_Tlaxcala.svg.png');} .ns-0 h2 #Chadian_Arabic::before, .ns-0 h2#Chadian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Flag_of_Chad.svg/40px-Flag_of_Chad.svg.png');} .ns-0 h2 #Chakma::before, .ns-0 h2#Chakma::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Chakma_Flag.jpg/40px-Chakma_Flag.jpg');} .ns-0 h2 #Chaldean_Neo-Aramaic::before, .ns-0 h2#Chaldean_Neo-Aramaic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/95/Chaldean_flag.svg/40px-Chaldean_flag.svg.png');} .ns-0 h2 #Chamorro::before, .ns-0 h2#Chamorro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/07/Flag_of_Guam.svg/40px-Flag_of_Guam.svg.png');} .ns-0 h2 #Champenois::before, .ns-0 h2#Champenois::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Flag_of_Champagne-Ardenne.svg/40px-Flag_of_Champagne-Ardenne.svg.png');} .ns-0 h2 #Chavacano::before, .ns-0 h2#Chavacano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Zamboanga.jpg/40px-Flag_of_Zamboanga.jpg');} .ns-0 h2 #Chechen::before, .ns-0 h2#Chechen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Flag_of_the_Chechen_Republic.svg/40px-Flag_of_the_Chechen_Republic.svg.png');} .ns-0 h2 #Cherokee::before, .ns-0 h2#Cherokee::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_the_Cherokee_Nation.svg/40px-Flag_of_the_Cherokee_Nation.svg.png');} .ns-0 h2 #Cheyenne::before, .ns-0 h2#Cheyenne::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Flag_of_Northern_Cheyenne.svg/40px-Flag_of_Northern_Cheyenne.svg.png');} .ns-0 h2 #Chhattisgarhi::before, .ns-0 h2#Chhattisgarhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Coat_of_arms_of_Chhattisgarh.svg/40px-Coat_of_arms_of_Chhattisgarh.svg.png');} .ns-0 h2 #Chibcha::before, .ns-0 h2#Chibcha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Bandera_de_la_confederacion_muisca.png/33px-Bandera_de_la_confederacion_muisca.png');} .ns-0 h2 #Chichewa::before, .ns-0 h2#Chichewa::before, .ns-0 h2 #Tumbuka::before, .ns-0 h2#Tumbuka::before, .ns-0 h2 #Yao_\(Africa\)::before, .ns-0 h2#Yao_\(Africa\)::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Flag_of_Malawi.svg/40px-Flag_of_Malawi.svg.png');} .ns-0 h2 #Chickasaw::before, .ns-0 h2#Chickasaw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/74/Flag_of_the_Chickasaw_Nation.svg/40px-Flag_of_the_Chickasaw_Nation.svg.png');} .ns-0 h2 #Chimwiini::before, .ns-0 h2#Chimwiini::before, .ns-0 h2 #Maay::before, .ns-0 h2#Maay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Flag_of_South_West_State_of_Somalia.svg/40px-Flag_of_South_West_State_of_Somalia.svg.png');} .ns-0 h2 #Chinese::before, .ns-0 h2#Chinese::before, .ns-0 h2 #Chinese_Pidgin_English::before, .ns-0 h2#Chinese_Pidgin_English::before, .ns-0 h2 #Mandarin::before, .ns-0 h2#Mandarin::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_the_People's_Republic_of_China.svg/40px-Flag_of_the_People's_Republic_of_China.svg.png");} .ns-0 h2 #Chittagonian::before, .ns-0 h2#Chittagonian::before, .ns-0 h2 #Sylheti::before, .ns-0 h2#Sylheti::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Flag_of_Bangladesh.svg/40px-Flag_of_Bangladesh.svg.png');} .ns-0 h2 #Choctaw::before, .ns-0 h2#Choctaw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Choctaw_flag.svg/40px-Choctaw_flag.svg.png');} .ns-0 h2 #Chukchi::before, .ns-0 h2#Chukchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Flag_of_Chukotka.svg/40px-Flag_of_Chukotka.svg.png');} .ns-0 h2 #Church_Slavonic::before, .ns-0 h2#Church_Slavonic::before, .ns-0 h2 #Old_Church_Slavonic::before, .ns-0 h2#Old_Church_Slavonic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Bulgarian_Orthodox_Cross_6.svg/33px-Bulgarian_Orthodox_Cross_6.svg.png');} .ns-0 h2 #Chuukese::before, .ns-0 h2#Chuukese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Flag_of_Chuuk.svg/40px-Flag_of_Chuuk.svg.png');} .ns-0 h2 #Chuvash::before, .ns-0 h2#Chuvash::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Flag_of_Chuvashia.svg/40px-Flag_of_Chuvashia.svg.png');} .ns-0 h2 #Cimbrian::before, .ns-0 h2#Cimbrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_the_Province_of_Trento.svg/40px-Flag_of_the_Province_of_Trento.svg.png');} .ns-0 h2 #Classical_Nahuatl::before, .ns-0 h2#Classical_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Aztec_Triple_Alliance.png/40px-Aztec_Triple_Alliance.png');} .ns-0 h2 #Coptic::before, .ns-0 h2#Coptic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Coptic_cross.svg/35px-Coptic_cross.svg.png');} .ns-0 h2 #Cornish::before, .ns-0 h2#Cornish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Cornwall.svg/40px-Flag_of_Cornwall.svg.png');} .ns-0 h2 #Corsican::before, .ns-0 h2#Corsican::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Flag_of_Corsica.svg/40px-Flag_of_Corsica.svg.png');} .ns-0 h2 #Cree::before, .ns-0 h2#Cree::before, .ns-0 h2 #Dogrib::before, .ns-0 h2#Dogrib::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_the_Northwest_Territories.svg/40px-Flag_of_the_Northwest_Territories.svg.png');} .ns-0 h2 #Creek::before, .ns-0 h2#Creek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/State_of_Muskogee_(Florida,_1799-1803).svg/40px-State_of_Muskogee_(Florida,_1799-1803).svg.png');} .ns-0 h2 #Crimean_Tatar::before, .ns-0 h2#Crimean_Tatar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_the_Crimean_Tatar_people.svg/40px-Flag_of_the_Crimean_Tatar_people.svg.png');} .ns-0 h2 #Croatian_Sign_Language::before, .ns-0 h2#Croatian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Flag_of_Croatia.svg/40px-Flag_of_Croatia.svg.png');} .ns-0 h2 #Cuban_Sign_Language::before, .ns-0 h2#Cuban_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Flag_of_Cuba.svg/40px-Flag_of_Cuba.svg.png');} .ns-0 h2 #Cubeo::before, .ns-0 h2#Cubeo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Flag_of_Vaupés.svg/40px-Flag_of_Vaupés.svg.png');} .ns-0 h2 #Cuyunon::before, .ns-0 h2#Cuyunon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Cuyo,_Palawan.png/40px-Flag_of_Cuyo,_Palawan.png');} .ns-0 h2 #Cypriot_Arabic::before, .ns-0 h2#Cypriot_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_Cyprus.svg/40px-Flag_of_Cyprus.svg.png');} .ns-0 h2 #Czech::before, .ns-0 h2#Czech::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_Czech_Republic.svg/40px-Flag_of_the_Czech_Republic.svg.png');} .ns-0 h2 #Dahalik::before, .ns-0 h2#Dahalik::before, .ns-0 h2 #Tigre::before, .ns-0 h2#Tigre::before, .ns-0 h2 #Tigrinya::before, .ns-0 h2#Tigrinya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/29/Flag_of_Eritrea.svg/40px-Flag_of_Eritrea.svg.png');} .ns-0 h2 #Dakota::before, .ns-0 h2#Dakota::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ee/Flag_of_North_Dakota.svg/40px-Flag_of_North_Dakota.svg.png');} .ns-0 h2 #Dalmatian::before, .ns-0 h2#Dalmatian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Kingdom_of_Dalmatia_(1852-1860).svg/40px-Flag_of_Kingdom_of_Dalmatia_(1852-1860).svg.png');} .ns-0 h2 #Danish::before, .ns-0 h2#Danish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Flag_of_Denmark.svg/40px-Flag_of_Denmark.svg.png');} .ns-0 h2 #Dhivehi::before, .ns-0 h2#Dhivehi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Maldives.svg/40px-Flag_of_Maldives.svg.png');} .ns-0 h2 #Dhofari_Arabic::before, .ns-0 h2#Dhofari_Arabic::before, .ns-0 h2 #Omani_Arabic::before, .ns-0 h2#Omani_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_Oman.svg/40px-Flag_of_Oman.svg.png');} .ns-0 h2 #Dinka::before, .ns-0 h2#Dinka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Flag_of_Dinka_people.svg/40px-Flag_of_Dinka_people.svg.png');} .ns-0 h2 #Dutch::before, .ns-0 h2#Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_the_Netherlands.svg/40px-Flag_of_the_Netherlands.svg.png');} .ns-0 h2 #East_Circassian::before, .ns-0 h2#East_Circassian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Kabardino-Balkaria.svg/40px-Flag_of_Kabardino-Balkaria.svg.png');} .ns-0 h2 #East_Futuna::before, .ns-0 h2#East_Futuna::before, .ns-0 h2 #Wallisian::before, .ns-0 h2#Wallisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Flag_of_Wallis_and_Futuna.svg/40px-Flag_of_Wallis_and_Futuna.svg.png');} .ns-0 h2 #Eastern_Durango_Nahuatl::before, .ns-0 h2#Eastern_Durango_Nahuatl::before, .ns-0 h2 #Western_Durango_Nahuatl::before, .ns-0 h2#Western_Durango_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Coat_of_arms_of_Durango.svg/35px-Coat_of_arms_of_Durango.svg.png');} .ns-0 h2 #Eastern_Maninkakan::before, .ns-0 h2#Eastern_Maninkakan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Flag_of_Guinea.svg/40px-Flag_of_Guinea.svg.png');} .ns-0 h2 #Eastern_Mari::before, .ns-0 h2#Eastern_Mari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Flag_of_Mari_El.svg/40px-Flag_of_Mari_El.svg.png');} .ns-0 h2 #Edo::before, .ns-0 h2#Edo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Edo_State_Flag.png/40px-Edo_State_Flag.png');} .ns-0 h2 #Egyptian::before, .ns-0 h2#Egyptian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Ancient_Egyptian_Culture_Flag.webp/40px-Ancient_Egyptian_Culture_Flag.webp');} .ns-0 h2 #Egyptian_Arabic::before, .ns-0 h2#Egyptian_Arabic::before, .ns-0 h2 #Nobiin::before, .ns-0 h2#Nobiin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Egypt.svg/40px-Flag_of_Egypt.svg.png');} .ns-0 h2 #Elfdalian::before, .ns-0 h2#Elfdalian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Älvdalen_vapen.svg/33px-Älvdalen_vapen.svg.png');} .ns-0 h2 #Emilian::before, .ns-0 h2#Emilian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Flag_of_Bologna_2.png/40px-Flag_of_Bologna_2.png');} .ns-0 h2 #Erzya::before, .ns-0 h2#Erzya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Erzya_Flag.svg/40px-Erzya_Flag.svg.png');} .ns-0 h2 #Ese::before, .ns-0 h2#Ese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Flag_Oro_new.png/40px-Flag_of_Flag_Oro_new.png');} .ns-0 h2 #Esperanto::before, .ns-0 h2#Esperanto::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Flag_of_Esperanto.svg/40px-Flag_of_Esperanto.svg.png');} .ns-0 h2 #Estonian::before, .ns-0 h2#Estonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Flag_of_Estonia.svg/40px-Flag_of_Estonia.svg.png');} .ns-0 h2 #Evenki::before, .ns-0 h2#Evenki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_Evenks.svg/40px-Flag_of_Evenks.svg.png');} .ns-0 h2 #Ewe::before, .ns-0 h2#Ewe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_the_Ewe_people.svg/40px-Flag_of_the_Ewe_people.svg.png');} .ns-0 h2 #Extremaduran::before, .ns-0 h2#Extremaduran::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Flag_of_Extremadura,_Spain_(with_coat_of_arms).svg/40px-Flag_of_Extremadura,_Spain_(with_coat_of_arms).svg.png');} .ns-0 h2 #Fala::before, .ns-0 h2#Fala::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Bandera_de_Valverde_del_Fresno_(Cáceres).svg/40px-Bandera_de_Valverde_del_Fresno_(Cáceres).svg.png');} .ns-0 h2 #Fang_\(Bantu\)::before, .ns-0 h2#Fang_\(Bantu\)::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/04/Flag_of_Gabon.svg/40px-Flag_of_Gabon.svg.png');} .ns-0 h2 #Faroese::before, .ns-0 h2#Faroese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_Faroe_Islands.svg/40px-Flag_of_the_Faroe_Islands.svg.png');} .ns-0 h2 #Fiji_Hindi::before, .ns-0 h2#Fiji_Hindi::before, .ns-0 h2 #Fijian::before, .ns-0 h2#Fijian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Fiji.svg/40px-Flag_of_Fiji.svg.png');} .ns-0 h2 #Fingallian::before, .ns-0 h2#Fingallian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/22/Flag_of_County_Limerick.svg/40px-Flag_of_County_Limerick.svg.png');} .ns-0 h2 #Finnish::before, .ns-0 h2#Finnish::before, .ns-0 h2 #Finnish_Sign_Language::before, .ns-0 h2#Finnish_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Finland.svg/40px-Flag_of_Finland.svg.png');} .ns-0 h2 #Fon::before, .ns-0 h2#Fon::before, .ns-0 h2 #Gun::before, .ns-0 h2#Gun::before, .ns-0 h2 #Ifè::before, .ns-0 h2#Ifè::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_Benin.svg/40px-Flag_of_Benin.svg.png');} .ns-0 h2 #Forest_Nenets::before, .ns-0 h2#Forest_Nenets::before, .ns-0 h2 #Tundra_Nenets::before, .ns-0 h2#Tundra_Nenets::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/15/Flag_of_Nenets_Autonomous_District.svg/40px-Flag_of_Nenets_Autonomous_District.svg.png');} .ns-0 h2 #Franc-Comtois::before, .ns-0 h2#Franc-Comtois::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Franche-Comté.svg/40px-Flag_of_Franche-Comté.svg.png');} .ns-0 h2 #Franco-Provençal::before, .ns-0 h2#Franco-Provençal::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/9/90/Flag_of_Valle_d'Aosta.svg/40px-Flag_of_Valle_d'Aosta.svg.png");} .ns-0 h2 #French::before, .ns-0 h2#French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_France.svg/40px-Flag_of_France.svg.png');} .ns-0 h2 #Friulian::before, .ns-0 h2#Friulian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Bandiere_dal_Friûl.svg/40px-Bandiere_dal_Friûl.svg.png');} .ns-0 h2 #Fula::before, .ns-0 h2#Fula::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/NE-CM-BF-GM_flag.svg/40px-NE-CM-BF-GM_flag.svg.png');} .ns-0 h2 #Fur::before, .ns-0 h2#Fur::before, .ns-0 h2 #Sudanese_Arabic::before, .ns-0 h2#Sudanese_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Sudan.svg/40px-Flag_of_Sudan.svg.png');} .ns-0 h2 #Futuna-Aniwa::before, .ns-0 h2#Futuna-Aniwa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Tafea_Province_Flag.svg/40px-Tafea_Province_Flag.svg.png');} .ns-0 h2 #Fyam::before, .ns-0 h2#Fyam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Plateau_State_Flag.jpg/40px-Plateau_State_Flag.jpg');} .ns-0 h2 #Ga::before, .ns-0 h2#Ga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Flag_of_Accra.svg/40px-Flag_of_Accra.svg.png');} .ns-0 h2 #Gabadi::before, .ns-0 h2#Gabadi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Central_Province,_Papua_New_Guinea.svg/40px-Flag_of_Central_Province,_Papua_New_Guinea.svg.png');} .ns-0 h2 #Gagauz::before, .ns-0 h2#Gagauz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/69/Flag_of_Gagauzia.svg/40px-Flag_of_Gagauzia.svg.png');} .ns-0 h2 #Galician::before, .ns-0 h2#Galician::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_Galicia.svg/40px-Flag_of_Galicia.svg.png');} .ns-0 h2 #Gallo-Italic_of_Basilicata::before, .ns-0 h2#Gallo-Italic_of_Basilicata::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_for_the_Lombards_of_Basilicata.png/40px-Flag_for_the_Lombards_of_Basilicata.png');} .ns-0 h2 #Gallo-Italic_of_Sicily::before, .ns-0 h2#Gallo-Italic_of_Sicily::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/30/Flag_for_the_Lombards_of_Sicily.png/40px-Flag_for_the_Lombards_of_Sicily.png');} .ns-0 h2 #Gamilaraay::before, .ns-0 h2#Gamilaraay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_New_South_Wales.svg/40px-Flag_of_New_South_Wales.svg.png');} .ns-0 h2 #Garhwali::before, .ns-0 h2#Garhwali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Flag_of_the_Princely_State_of_Tehri_Garhwal.svg/40px-Flag_of_the_Princely_State_of_Tehri_Garhwal.svg.png');} .ns-0 h2 #Garifuna::before, .ns-0 h2#Garifuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_Garifuna.svg/40px-Flag_of_Garifuna.svg.png');} .ns-0 h2 #Garo::before, .ns-0 h2#Garo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Garo_hills.png/40px-Garo_hills.png');} .ns-0 h2 #Ge\'ez::before, .ns-0 h2#Ge\'ez::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Lion_of_Judah_emblem_of_the_Ethiopian_Empire.svg/40px-Lion_of_Judah_emblem_of_the_Ethiopian_Empire.svg.png');} .ns-0 h2 #Georgian::before, .ns-0 h2#Georgian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Georgia.svg/40px-Flag_of_Georgia.svg.png');} .ns-0 h2 #German::before, .ns-0 h2#German::before, .ns-0 h2 #German_Sign_Language::before, .ns-0 h2#German_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/40px-Flag_of_Germany.svg.png');} .ns-0 h2 #Ghadames::before, .ns-0 h2#Ghadames::before, .ns-0 h2 #Libyan_Arabic::before, .ns-0 h2#Libyan_Arabic::before, .ns-0 h2 #Nefusa::before, .ns-0 h2#Nefusa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/05/Flag_of_Libya.svg/40px-Flag_of_Libya.svg.png');} .ns-0 h2 #Gilbertese::before, .ns-0 h2#Gilbertese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Flag_of_Kiribati.svg/40px-Flag_of_Kiribati.svg.png');} .ns-0 h2 #Gorontalo::before, .ns-0 h2#Gorontalo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Coat_of_arms_of_Gorontalo.svg/35px-Coat_of_arms_of_Gorontalo.svg.png');} .ns-0 h2 #Greek::before, .ns-0 h2#Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Greece.svg/40px-Flag_of_Greece.svg.png');} .ns-0 h2 #Green_Hmong::before, .ns-0 h2#Green_Hmong::before, .ns-0 h2 #White_Hmong::before, .ns-0 h2#White_Hmong::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Hmong_Flag_(UNPO).svg/40px-Hmong_Flag_(UNPO).svg.png');} .ns-0 h2 #Greenlandic::before, .ns-0 h2#Greenlandic::before, .ns-0 h2 #West_Greenlandic_Pidgin::before, .ns-0 h2#West_Greenlandic_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Greenland.svg/40px-Flag_of_Greenland.svg.png');} .ns-0 h2 #Grenadian_Creole_English::before, .ns-0 h2#Grenadian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Grenada.svg/40px-Flag_of_Grenada.svg.png');} .ns-0 h2 #Guajajára::before, .ns-0 h2#Guajajára::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Bandeira_do_Maranhão.svg/40px-Bandeira_do_Maranhão.svg.png');} .ns-0 h2 #Guanche::before, .ns-0 h2#Guanche::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Flag_of_the_Canary_Islands.svg/40px-Flag_of_the_Canary_Islands.svg.png');} .ns-0 h2 #Guerrero_Amuzgo::before, .ns-0 h2#Guerrero_Amuzgo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Guerrero.svg/40px-Flag_of_Guerrero.svg.png');} .ns-0 h2 #Guianese_Creole::before, .ns-0 h2#Guianese_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/29/Flag_of_French_Guiana.svg/40px-Flag_of_French_Guiana.svg.png');} .ns-0 h2 #Guinea-Bissau_Creole::before, .ns-0 h2#Guinea-Bissau_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Guinea-Bissau.svg/40px-Flag_of_Guinea-Bissau.svg.png');} .ns-0 h2 #Gulf_Arabic::before, .ns-0 h2#Gulf_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_United_Arab_Emirates.svg/40px-Flag_of_the_United_Arab_Emirates.svg.png');} .ns-0 h2 #Gullah::before, .ns-0 h2#Gullah::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Black_American_Heritage_flag.svg/40px-Black_American_Heritage_flag.svg.png');} .ns-0 h2 #Gurindji::before, .ns-0 h2#Gurindji::before, .ns-0 h2 #Warlpiri::before, .ns-0 h2#Warlpiri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Flag_of_the_Northern_Territory.svg/40px-Flag_of_the_Northern_Territory.svg.png');} .ns-0 h2 #Gutnish::before, .ns-0 h2#Gutnish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Gotlands_län_vapenflagga.svg/37px-Gotlands_län_vapenflagga.svg.png');} .ns-0 h2 #Guyanese_Creole_English::before, .ns-0 h2#Guyanese_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Flag_of_Guyana.svg/40px-Flag_of_Guyana.svg.png');} .ns-0 h2 #Hadza::before, .ns-0 h2#Hadza::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/38/Flag_of_Tanzania.svg/40px-Flag_of_Tanzania.svg.png');} .ns-0 h2 #Haida::before, .ns-0 h2#Haida::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/CHN_Crest.png/33px-CHN_Crest.png');} .ns-0 h2 #Haitian_Creole::before, .ns-0 h2#Haitian_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/56/Flag_of_Haiti.svg/40px-Flag_of_Haiti.svg.png');} .ns-0 h2 #Hakka::before, .ns-0 h2#Hakka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Hakka_Party.svg/40px-Flag_of_Hakka_Party.svg.png');} .ns-0 h2 #Halia::before, .ns-0 h2#Halia::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e4/Flag_of_Bougainville.svg/40px-Flag_of_Bougainville.svg.png');} .ns-0 h2 #Harari::before, .ns-0 h2#Harari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Harari_Flag.svg/40px-Harari_Flag.svg.png');} .ns-0 h2 #Haryanvi::before, .ns-0 h2#Haryanvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Haryana.svg/40px-Flag_of_Haryana.svg.png');} .ns-0 h2 #Hassaniya_Arabic::before, .ns-0 h2#Hassaniya_Arabic::before, .ns-0 h2 #Zenaga::before, .ns-0 h2#Zenaga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/43/Flag_of_Mauritania.svg/40px-Flag_of_Mauritania.svg.png');} .ns-0 h2 #Hausa::before, .ns-0 h2#Hausa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_the_Hausa_people.svg/40px-Flag_of_the_Hausa_people.svg.png');} .ns-0 h2 #Hawaiian::before, .ns-0 h2#Hawaiian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Flag_of_Hawaii.svg/40px-Flag_of_Hawaii.svg.png');} .ns-0 h2 #Hebrew::before, .ns-0 h2#Hebrew::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_Israel.svg/40px-Flag_of_Israel.svg.png');} .ns-0 h2 #Herero::before, .ns-0 h2#Herero::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Namibia,_Botswana_and_Angola.gif/40px-Namibia,_Botswana_and_Angola.gif');} .ns-0 h2 #Higaonon::before, .ns-0 h2#Higaonon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Ph_seal_misamis_oriental.2.png/40px-Ph_seal_misamis_oriental.2.png');} .ns-0 h2 #Hijazi_Arabic::before, .ns-0 h2#Hijazi_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Flag_of_Hejaz_(1920).svg/40px-Flag_of_Hejaz_(1920).svg.png');} .ns-0 h2 #Hiligaynon::before, .ns-0 h2#Hiligaynon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Flag_of_the_Province_of_Iloilo.svg/40px-Flag_of_the_Province_of_Iloilo.svg.png');} .ns-0 h2 #Hiri_Motu::before, .ns-0 h2#Hiri_Motu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_Port_Moresby.png/40px-Flag_of_Port_Moresby.png');} .ns-0 h2 #Hokkien::before, .ns-0 h2#Hokkien::before, .ns-0 h2 #Min_Nan::before, .ns-0 h2#Min_Nan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_the_Republic_of_China.svg/40px-Flag_of_the_Republic_of_China.svg.png');} .ns-0 h2 #Hungarian::before, .ns-0 h2#Hungarian::before, .ns-0 h2 #Hungarian_Sign_Language::before, .ns-0 h2#Hungarian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_Hungary.svg/40px-Flag_of_Hungary.svg.png');} .ns-0 h2 #Hunsrik::before, .ns-0 h2#Hunsrik::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/63/Bandeira_do_Rio_Grande_do_Sul.svg/40px-Bandeira_do_Rio_Grande_do_Sul.svg.png');} .ns-0 h2 #Iban::before, .ns-0 h2#Iban::before, .ns-0 h2 #Sarawak_Malay::before, .ns-0 h2#Sarawak_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Flag_of_Sarawak.svg/40px-Flag_of_Sarawak.svg.png');} .ns-0 h2 #Ibanag::before, .ns-0 h2#Ibanag::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Cagayan.svg/40px-Flag_of_Cagayan.svg.png');} .ns-0 h2 #Icelandic::before, .ns-0 h2#Icelandic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Iceland.svg/40px-Flag_of_Iceland.svg.png');} .ns-0 h2 #Ido::before, .ns-0 h2#Ido::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Flag_of_Ido.svg/40px-Flag_of_Ido.svg.png');} .ns-0 h2 #Igala::before, .ns-0 h2#Igala::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Kogi_State_Flag.svg/40px-Kogi_State_Flag.svg.png');} .ns-0 h2 #Igbo::before, .ns-0 h2#Igbo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/82/Flag_of_Biafra.svg/40px-Flag_of_Biafra.svg.png');} .ns-0 h2 #Ilocano::before, .ns-0 h2#Ilocano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/PH-ILS_Flag.png/40px-PH-ILS_Flag.png');} .ns-0 h2 #Indo-Portuguese::before, .ns-0 h2#Indo-Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_Portugal_(1640).svg/40px-Flag_of_Portugal_(1640).svg.png');} .ns-0 h2 #Indonesian::before, .ns-0 h2#Indonesian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Indonesia.svg/40px-Flag_of_Indonesia.svg.png');} .ns-0 h2 #Ingrian::before, .ns-0 h2#Ingrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_igora.svg/40px-Flag_igora.svg.png');} .ns-0 h2 #Ingush::before, .ns-0 h2#Ingush::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Ingushetia.svg/40px-Flag_of_Ingushetia.svg.png');} .ns-0 h2 #Interlingua::before, .ns-0 h2#Interlingua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Bandiera_de_Interlingua.svg/40px-Bandiera_de_Interlingua.svg.png');} .ns-0 h2 #Interlingue::before, .ns-0 h2#Interlingue::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_Interlingue.svg/40px-Flag_of_Interlingue.svg.png');} .ns-0 h2 #Inuktitut::before, .ns-0 h2#Inuktitut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/90/Flag_of_Nunavut.svg/40px-Flag_of_Nunavut.svg.png');} .ns-0 h2 #Iranun::before, .ns-0 h2#Iranun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Seal_of_Maguindanao_del_Norte.png/40px-Seal_of_Maguindanao_del_Norte.png');} .ns-0 h2 #Iraqi_Arabic::before, .ns-0 h2#Iraqi_Arabic::before, .ns-0 h2 #North_Mesopotamian_Arabic::before, .ns-0 h2#North_Mesopotamian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Flag_of_Iraq.svg/40px-Flag_of_Iraq.svg.png');} .ns-0 h2 #Iraqw::before, .ns-0 h2#Iraqw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Iraqw_Flag.png/40px-Iraqw_Flag.png');} .ns-0 h2 #Irish::before, .ns-0 h2#Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Ireland.svg/40px-Flag_of_Ireland.svg.png');} .ns-0 h2 #Islander_Creole_English::before, .ns-0 h2#Islander_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_San_Andrés_y_Providencia.svg/40px-Flag_of_San_Andrés_y_Providencia.svg.png');} .ns-0 h2 #Istriot::before, .ns-0 h2#Istriot::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/HRV_Rovinj_flag.svg/40px-HRV_Rovinj_flag.svg.png');} .ns-0 h2 #Italian::before, .ns-0 h2#Italian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/03/Flag_of_Italy.svg/40px-Flag_of_Italy.svg.png');} .ns-0 h2 #Italiot_Greek::before, .ns-0 h2#Italiot_Greek::before, .ns-0 h2 #Tarantino::before, .ns-0 h2#Tarantino::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Apulia.svg/40px-Flag_of_Apulia.svg.png');} .ns-0 h2 #Itsekiri::before, .ns-0 h2#Itsekiri::before, .ns-0 h2 #Olukumi::before, .ns-0 h2#Olukumi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Flag_of_Delta_State.gif/40px-Flag_of_Delta_State.gif');} .ns-0 h2 #Jah_Hut::before, .ns-0 h2#Jah_Hut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Flag_of_Pahang.svg/40px-Flag_of_Pahang.svg.png');} .ns-0 h2 #Jamaican_Creole::before, .ns-0 h2#Jamaican_Creole::before, .ns-0 h2 #Maroon_Spirit_Language::before, .ns-0 h2#Maroon_Spirit_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_Jamaica.svg/40px-Flag_of_Jamaica.svg.png');} .ns-0 h2 #Jamtish::before, .ns-0 h2#Jamtish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Jämtlands_vapen.svg/35px-Jämtlands_vapen.svg.png');} .ns-0 h2 #Japanese::before, .ns-0 h2#Japanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Flag_of_Japan.svg/40px-Flag_of_Japan.svg.png');} .ns-0 h2 #Jaqaru::before, .ns-0 h2#Jaqaru::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Bandera_Provincia_Yauyos.jpg/40px-Bandera_Provincia_Yauyos.jpg');} .ns-0 h2 #Jaunsari::before, .ns-0 h2#Jaunsari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Seal_of_Uttarakhand.svg/35px-Seal_of_Uttarakhand.svg.png');} .ns-0 h2 #Javanese::before, .ns-0 h2#Javanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_the_Mataram_Sultanate.svg/40px-Flag_of_the_Mataram_Sultanate.svg.png');} .ns-0 h2 #Jeju::before, .ns-0 h2#Jeju::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b9/Flag_of_Jeju_Province.svg/40px-Flag_of_Jeju_Province.svg.png');} .ns-0 h2 #Jersey_Dutch::before, .ns-0 h2#Jersey_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_New_Jersey.svg/40px-Flag_of_New_Jersey.svg.png');} .ns-0 h2 #Jingpho::before, .ns-0 h2#Jingpho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/47/Kachin_People_Flag.svg/40px-Kachin_People_Flag.svg.png');} .ns-0 h2 #Juba_Arabic::before, .ns-0 h2#Juba_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_South_Sudan.svg/40px-Flag_of_South_Sudan.svg.png');} .ns-0 h2 #Judeo-Italian::before, .ns-0 h2#Judeo-Italian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_Italian_Jews.svg/40px-Flag_of_Italian_Jews.svg.png');} .ns-0 h2 #K\'iche\'::before, .ns-0 h2#K\'iche\'::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/El_Quiché_Flag_(GUATEMALA).png/40px-El_Quiché_Flag_(GUATEMALA).png');} .ns-0 h2 #Kabiye::before, .ns-0 h2#Kabiye::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_Togo_(3-2).svg/40px-Flag_of_Togo_(3-2).svg.png');} .ns-0 h2 #Kabuverdianu::before, .ns-0 h2#Kabuverdianu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/65/Flag_of_Cape_Verde_(10-17).svg/40px-Flag_of_Cape_Verde_(10-17).svg.png');} .ns-0 h2 #Kabyle::before, .ns-0 h2#Kabyle::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_the_Republic_of_Kabylia.svg/40px-Flag_of_the_Republic_of_Kabylia.svg.png');} .ns-0 h2 #Kaingang::before, .ns-0 h2#Kaingang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Bandeira_do_Paraná.svg/40px-Bandeira_do_Paraná.svg.png');} .ns-0 h2 #Kaitag::before, .ns-0 h2#Kaitag::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_Dagestan.svg/40px-Flag_of_Dagestan.svg.png');} .ns-0 h2 #Kalasha::before, .ns-0 h2#Kalasha::before, .ns-0 h2 #Khowar::before, .ns-0 h2#Khowar::before, .ns-0 h2 #Palula::before, .ns-0 h2#Palula::before, .ns-0 h2 #Ushojo::before, .ns-0 h2#Ushojo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Khyber_Pakhtunkhwa.svg/40px-Flag_of_Khyber_Pakhtunkhwa.svg.png');} .ns-0 h2 #Kalmyk::before, .ns-0 h2#Kalmyk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Kalmykia.svg/40px-Flag_of_Kalmykia.svg.png');} .ns-0 h2 #Kamayurá::before, .ns-0 h2#Kamayurá::before, .ns-0 h2 #Xavante::before, .ns-0 h2#Xavante::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Bandeira_de_Mato_Grosso.svg/40px-Bandeira_de_Mato_Grosso.svg.png');} .ns-0 h2 #Kankanaey::before, .ns-0 h2#Kankanaey::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Flag_of_Mountain_Province.png/40px-Flag_of_Mountain_Province.png');} .ns-0 h2 #Kannada::before, .ns-0 h2#Kannada::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Flag_of_Karnataka,_India.svg/40px-Flag_of_Karnataka,_India.svg.png');} .ns-0 h2 #Kanuri::before, .ns-0 h2#Kanuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/95/Flag_of_the_Kanuri_people.svg/40px-Flag_of_the_Kanuri_people.svg.png');} .ns-0 h2 #Kapampangan::before, .ns-0 h2#Kapampangan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Pampanga_Flag.png/40px-Pampanga_Flag.png');} .ns-0 h2 #Karachay-Balkar::before, .ns-0 h2#Karachay-Balkar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/Flag_of_Karachay-Cherkessia.svg/40px-Flag_of_Karachay-Cherkessia.svg.png');} .ns-0 h2 #Karakalpak::before, .ns-0 h2#Karakalpak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Karakalpakstan.svg/40px-Flag_of_Karakalpakstan.svg.png');} .ns-0 h2 #Karakhanid::before, .ns-0 h2#Karakhanid::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Flag_of_the_Kara-Khanids.svg/40px-Flag_of_the_Kara-Khanids.svg.png');} .ns-0 h2 #Karelian::before, .ns-0 h2#Karelian::before, .ns-0 h2 #Livvi::before, .ns-0 h2#Livvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Itäkarjalaisten_lippu.svg/40px-Itäkarjalaisten_lippu.svg.png');} .ns-0 h2 #Karipúna_Creole_French::before, .ns-0 h2#Karipúna_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Bandeira_do_Amapá.svg/40px-Bandeira_do_Amapá.svg.png');} .ns-0 h2 #Kashmiri::before, .ns-0 h2#Kashmiri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/32/Flag_of_Jammu_and_Kashmir_(1936-1953).svg/40px-Flag_of_Jammu_and_Kashmir_(1936-1953).svg.png');} .ns-0 h2 #Kashubian::before, .ns-0 h2#Kashubian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/POL_Kaszuby_flag.svg/40px-POL_Kaszuby_flag.svg.png');} .ns-0 h2 #Kazakh::before, .ns-0 h2#Kazakh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Flag_of_Kazakhstan.svg/40px-Flag_of_Kazakhstan.svg.png');} .ns-0 h2 #Kedah_Malay::before, .ns-0 h2#Kedah_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/67/Flag_of_Kedah_(18th_century_-_1821).svg/40px-Flag_of_Kedah_(18th_century_-_1821).svg.png');} .ns-0 h2 #Kelantan_Peranakan_Hokkien::before, .ns-0 h2#Kelantan_Peranakan_Hokkien::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Flag_of_Kelantan.svg/40px-Flag_of_Kelantan.svg.png');} .ns-0 h2 #Ket::before, .ns-0 h2#Ket::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Flag_of_Krasnoyarsk_Krai.svg/40px-Flag_of_Krasnoyarsk_Krai.svg.png');} .ns-0 h2 #Khakas::before, .ns-0 h2#Khakas::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Flag_of_Khakassia.svg/40px-Flag_of_Khakassia.svg.png');} .ns-0 h2 #Khasi::before, .ns-0 h2#Khasi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Seng-Khasi.png/40px-Seng-Khasi.png');} .ns-0 h2 #Khmer::before, .ns-0 h2#Khmer::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Flag_of_Cambodia.svg/40px-Flag_of_Cambodia.svg.png');} .ns-0 h2 #Khoekhoe::before, .ns-0 h2#Khoekhoe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Namibia.svg/40px-Flag_of_Namibia.svg.png');} .ns-0 h2 #Kikuyu::before, .ns-0 h2#Kikuyu::before, .ns-0 h2 #Maasai::before, .ns-0 h2#Maasai::before, .ns-0 h2 #Swahili::before, .ns-0 h2#Swahili::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Kenya.svg/40px-Flag_of_Kenya.svg.png');} .ns-0 h2 #Kimbundu::before, .ns-0 h2#Kimbundu::before, .ns-0 h2 #Umbundu::before, .ns-0 h2#Umbundu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Flag_of_Angola.svg/40px-Flag_of_Angola.svg.png');} .ns-0 h2 #Kiowa::before, .ns-0 h2#Kiowa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_Oklahoma.svg/40px-Flag_of_Oklahoma.svg.png');} .ns-0 h2 #Kituba::before, .ns-0 h2#Kituba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_the_Republic_of_the_Congo.svg/40px-Flag_of_the_Republic_of_the_Congo.svg.png');} .ns-0 h2 #Klingon::before, .ns-0 h2#Klingon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Klingon_Empire_Flag.svg/40px-Klingon_Empire_Flag.svg.png');} .ns-0 h2 #Kokborok::before, .ns-0 h2#Kokborok::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_the_National_Liberation_Front_of_Tripura.svg/40px-Flag_of_the_National_Liberation_Front_of_Tripura.svg.png');} .ns-0 h2 #Komi-Permyak::before, .ns-0 h2#Komi-Permyak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Flag_of_Permyakia.svg/40px-Flag_of_Permyakia.svg.png');} .ns-0 h2 #Komi-Zyrian::before, .ns-0 h2#Komi-Zyrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Komi.svg/40px-Flag_of_Komi.svg.png');} .ns-0 h2 #Kongo::before, .ns-0 h2#Kongo::before, .ns-0 h2 #Lingala::before, .ns-0 h2#Lingala::before, .ns-0 h2 #Luba-Kasai::before, .ns-0 h2#Luba-Kasai::before, .ns-0 h2 #Luba-Katanga::before, .ns-0 h2#Luba-Katanga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_the_Democratic_Republic_of_the_Congo.svg/40px-Flag_of_the_Democratic_Republic_of_the_Congo.svg.png');} .ns-0 h2 #Konzo::before, .ns-0 h2#Konzo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Rwenzururu.svg/40px-Flag_of_Rwenzururu.svg.png');} .ns-0 h2 #Korean::before, .ns-0 h2#Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Unification_flag_of_Korea.svg/40px-Unification_flag_of_Korea.svg.png');} .ns-0 h2 #Korlai_Creole_Portuguese::before, .ns-0 h2#Korlai_Creole_Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Seal_of_Maharashtra.svg/35px-Seal_of_Maharashtra.svg.png');} .ns-0 h2 #Koryak::before, .ns-0 h2#Koryak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Flag_of_Koryakia.svg/40px-Flag_of_Koryakia.svg.png');} .ns-0 h2 #Kosraean::before, .ns-0 h2#Kosraean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/23/Flag_of_Kosrae.svg/40px-Flag_of_Kosrae.svg.png');} .ns-0 h2 #Krio::before, .ns-0 h2#Krio::before, .ns-0 h2 #Mende_\(Sierra_Leone\)::before, .ns-0 h2#Mende_\(Sierra_Leone\)::before, .ns-0 h2 #Temne::before, .ns-0 h2#Temne::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Flag_of_Sierra_Leone.svg/40px-Flag_of_Sierra_Leone.svg.png');} .ns-0 h2 #Kristang::before, .ns-0 h2#Kristang::before, .ns-0 h2 #Malaccan_Creole_Malay::before, .ns-0 h2#Malaccan_Creole_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Malacca.svg/40px-Flag_of_Malacca.svg.png');} .ns-0 h2 #Kumaoni::before, .ns-0 h2#Kumaoni::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Flag_of_the_Kumaon_Kingdom.svg/40px-Flag_of_the_Kumaon_Kingdom.svg.png');} .ns-0 h2 #Kumyk::before, .ns-0 h2#Kumyk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_Kumyks.svg/40px-Flag_of_Kumyks.svg.png');} .ns-0 h2 #Kuna::before, .ns-0 h2#Kuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Bandera_de_la_Comarca_Guna_Yala.svg/40px-Bandera_de_la_Comarca_Guna_Yala.svg.png');} .ns-0 h2 #Kunigami::before, .ns-0 h2#Kunigami::before, .ns-0 h2 #Miyako::before, .ns-0 h2#Miyako::before, .ns-0 h2 #Okinawan::before, .ns-0 h2#Okinawan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Okinawa_Prefecture.svg/40px-Flag_of_Okinawa_Prefecture.svg.png');} .ns-0 h2 #Kupang_Malay::before, .ns-0 h2#Kupang_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c6/Flag_of_Kupang_City.png/40px-Flag_of_Kupang_City.png');} .ns-0 h2 #Kven::before, .ns-0 h2#Kven::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_the_Kven_people.svg/40px-Flag_of_the_Kven_people.svg.png');} .ns-0 h2 #Kwanyama::before, .ns-0 h2#Kwanyama::before, .ns-0 h2 #Ndonga::before, .ns-0 h2#Ndonga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Flag_of_Ovamboland.svg/40px-Flag_of_Ovamboland.svg.png');} .ns-0 h2 #Kyrgyz::before, .ns-0 h2#Kyrgyz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Kyrgyzstan.svg/40px-Flag_of_Kyrgyzstan.svg.png');} .ns-0 h2 #Laboya::before, .ns-0 h2#Laboya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Coat_of_Arms_of_East_Nusa_Tenggara_NEW.png/35px-Coat_of_Arms_of_East_Nusa_Tenggara_NEW.png');} .ns-0 h2 #Ladakhi::before, .ns-0 h2#Ladakhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Flag_of_the_Ladakh_Nationalist_Movement.svg/40px-Flag_of_the_Ladakh_Nationalist_Movement.svg.png');} .ns-0 h2 #Ladin::before, .ns-0 h2#Ladin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Ladinia.svg/40px-Flag_of_Ladinia.svg.png');} .ns-0 h2 #Ladino::before, .ns-0 h2#Ladino::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Spanish_Jewish_flag.png/40px-Spanish_Jewish_flag.png');} .ns-0 h2 #Lahu::before, .ns-0 h2#Lahu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Lahu_flag.svg/40px-Lahu_flag.svg.png');} .ns-0 h2 #Lai::before, .ns-0 h2#Lai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/af/Emblem_of_Lai_Autonomous_Council.png/40px-Emblem_of_Lai_Autonomous_Council.png');} .ns-0 h2 #Lakota::before, .ns-0 h2#Lakota::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Pine_Ridge_Flag.svg/40px-Pine_Ridge_Flag.svg.png');} .ns-0 h2 #Lao::before, .ns-0 h2#Lao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/56/Flag_of_Laos.svg/40px-Flag_of_Laos.svg.png');} .ns-0 h2 #Latgalian::before, .ns-0 h2#Latgalian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Official_flag_of_Latgale.svg/40px-Official_flag_of_Latgale.svg.png');} .ns-0 h2 #Latin::before, .ns-0 h2#Latin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Rome.svg/40px-Flag_of_Rome.svg.png');} .ns-0 h2 #Latvian::before, .ns-0 h2#Latvian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Latvia.svg/40px-Flag_of_Latvia.svg.png');} .ns-0 h2 #Leonese::before, .ns-0 h2#Leonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/75/Bandera_del_País_Leonés.svg/40px-Bandera_del_País_Leonés.svg.png');} .ns-0 h2 #Lepcha::before, .ns-0 h2#Lepcha::before, .ns-0 h2 #Sherpa::before, .ns-0 h2#Sherpa::before, .ns-0 h2 #Thulung::before, .ns-0 h2#Thulung::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Seal_of_Sikkim.svg/40px-Seal_of_Sikkim.svg.png');} .ns-0 h2 #Lezgi::before, .ns-0 h2#Lezgi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Lezgian_flag.svg/40px-Lezgian_flag.svg.png');} .ns-0 h2 #Ligurian::before, .ns-0 h2#Ligurian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/88/Flag_of_Liguria.svg/40px-Flag_of_Liguria.svg.png');} .ns-0 h2 #Limbu::before, .ns-0 h2#Limbu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Flag_of_Limbuwan.svg/40px-Flag_of_Limbuwan.svg.png');} .ns-0 h2 #Limburgish::before, .ns-0 h2#Limburgish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Flag_of_Limburg_(Netherlands).svg/40px-Flag_of_Limburg_(Netherlands).svg.png');} .ns-0 h2 #Limos_Kalinga::before, .ns-0 h2#Limos_Kalinga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Ph_seal_kalinga.png/40px-Ph_seal_kalinga.png');} .ns-0 h2 #Lindu::before, .ns-0 h2#Lindu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Coat_of_arms_of_Central_Sulawesi.svg/30px-Coat_of_arms_of_Central_Sulawesi.svg.png');} .ns-0 h2 #Lithuanian::before, .ns-0 h2#Lithuanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Lithuania.svg/40px-Flag_of_Lithuania.svg.png');} .ns-0 h2 #Livonian::before, .ns-0 h2#Livonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Flag_of_the_Livonians.svg/40px-Flag_of_the_Livonians.svg.png');} .ns-0 h2 #Lojban::before, .ns-0 h2#Lojban::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Lojban_logo.svg/40px-Lojban_logo.svg.png');} .ns-0 h2 #Lombard::before, .ns-0 h2#Lombard::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_Lombardy.svg/40px-Flag_of_Lombardy.svg.png');} .ns-0 h2 #Louisiana_Creole::before, .ns-0 h2#Louisiana_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_Louisiana.svg/40px-Flag_of_Louisiana.svg.png');} .ns-0 h2 #Lovono::before, .ns-0 h2#Lovono::before, .ns-0 h2 #Äiwoo::before, .ns-0 h2#Äiwoo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Temotu_province_flag.svg/40px-Temotu_province_flag.svg.png');} .ns-0 h2 #Lower_Sorbian::before, .ns-0 h2#Lower_Sorbian::before, .ns-0 h2 #Upper_Sorbian::before, .ns-0 h2#Upper_Sorbian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Flag_of_Sorbs.svg/40px-Flag_of_Sorbs.svg.png');} .ns-0 h2 #Lozi::before, .ns-0 h2#Lozi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Barotseland.svg/40px-Flag_of_Barotseland.svg.png');} .ns-0 h2 #Ludian::before, .ns-0 h2#Ludian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Ludic_flag.svg/40px-Ludic_flag.svg.png');} .ns-0 h2 #Luganda::before, .ns-0 h2#Luganda::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Uganda.svg/40px-Flag_of_Uganda.svg.png');} .ns-0 h2 #Lushootseed::before, .ns-0 h2#Lushootseed::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Washington.svg/40px-Flag_of_Washington.svg.png');} .ns-0 h2 #Lutuv::before, .ns-0 h2#Lutuv::before, .ns-0 h2 #Zou::before, .ns-0 h2#Zou::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Chin_State.svg/40px-Flag_of_Chin_State.svg.png');} .ns-0 h2 #Luxembourgish::before, .ns-0 h2#Luxembourgish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Flag_of_Luxembourg.svg/40px-Flag_of_Luxembourg.svg.png');} .ns-0 h2 #Macanese::before, .ns-0 h2#Macanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/63/Flag_of_Macau.svg/40px-Flag_of_Macau.svg.png');} .ns-0 h2 #Macedonian::before, .ns-0 h2#Macedonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_North_Macedonia.svg/40px-Flag_of_North_Macedonia.svg.png');} .ns-0 h2 #Maguindanao::before, .ns-0 h2#Maguindanao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Flag_of_Maguindanao.svg/40px-Flag_of_Maguindanao.svg.png');} .ns-0 h2 #Makasar::before, .ns-0 h2#Makasar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_the_Sultanate_of_Gowa.svg/40px-Flag_of_the_Sultanate_of_Gowa.svg.png');} .ns-0 h2 #Malagasy::before, .ns-0 h2#Malagasy::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Madagascar.svg/40px-Flag_of_Madagascar.svg.png');} .ns-0 h2 #Malay::before, .ns-0 h2#Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Malaysia_and_Indonesia.svg/40px-Flag_of_Malaysia_and_Indonesia.svg.png');} .ns-0 h2 #Maltese::before, .ns-0 h2#Maltese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Malta.svg/40px-Flag_of_Malta.svg.png');} .ns-0 h2 #Manado_Malay::before, .ns-0 h2#Manado_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Lambang_Kota_Manado.png/30px-Lambang_Kota_Manado.png');} .ns-0 h2 #Manchu::before, .ns-0 h2#Manchu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/86/Flag_of_China_(1862–1889).svg/40px-Flag_of_China_(1862–1889).svg.png');} .ns-0 h2 #Mandinka::before, .ns-0 h2#Mandinka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_The_Gambia.svg/40px-Flag_of_The_Gambia.svg.png');} .ns-0 h2 #Manipuri::before, .ns-0 h2#Manipuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Manipur.svg/40px-Flag_of_Manipur.svg.png');} .ns-0 h2 #Mansaka::before, .ns-0 h2#Mansaka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Davao_De_Oro_Flag.jpg/40px-Davao_De_Oro_Flag.jpg');} .ns-0 h2 #Manx::before, .ns-0 h2#Manx::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_the_Isle_of_Man.svg/40px-Flag_of_the_Isle_of_Man.svg.png');} .ns-0 h2 #Maore_Comorian::before, .ns-0 h2#Maore_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Coat_of_Arms_of_Mayotte.svg/40px-Coat_of_Arms_of_Mayotte.svg.png');} .ns-0 h2 #Mapudungun::before, .ns-0 h2#Mapudungun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_the_Mapuches_(1992).svg/40px-Flag_of_the_Mapuches_(1992).svg.png');} .ns-0 h2 #Maranao::before, .ns-0 h2#Maranao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/PH-LAS_Flag.png/40px-PH-LAS_Flag.png');} .ns-0 h2 #Margi::before, .ns-0 h2#Margi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Borno_State_Flag.gif/40px-Borno_State_Flag.gif');} .ns-0 h2 #Marshallese::before, .ns-0 h2#Marshallese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2e/Flag_of_the_Marshall_Islands.svg/40px-Flag_of_the_Marshall_Islands.svg.png');} .ns-0 h2 #Masalit::before, .ns-0 h2#Masalit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Flag_of_the_Masalit.svg/40px-Flag_of_the_Masalit.svg.png');} .ns-0 h2 #Masbatenyo::before, .ns-0 h2#Masbatenyo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/PH-MAS_Flag.png/40px-PH-MAS_Flag.png');} .ns-0 h2 #Mauritian_Creole::before, .ns-0 h2#Mauritian_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Mauritius.svg/40px-Flag_of_Mauritius.svg.png');} .ns-0 h2 #Maybrat::before, .ns-0 h2#Maybrat::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/43/Flag_of_Southwest_Papua.svg/40px-Flag_of_Southwest_Papua.svg.png');} .ns-0 h2 #Mbya_Guarani::before, .ns-0 h2#Mbya_Guarani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/24/Flag_of_Uruguay,_Brazil_and_Argentina.png/40px-Flag_of_Uruguay,_Brazil_and_Argentina.png');} .ns-0 h2 #Media_Lengua::before, .ns-0 h2#Media_Lengua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Bandera_Provincia_Imbabura.svg/40px-Bandera_Provincia_Imbabura.svg.png');} .ns-0 h2 #Megleno-Romanian::before, .ns-0 h2#Megleno-Romanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Flag_of_Greek_Macedonia.svg/40px-Flag_of_Greek_Macedonia.svg.png');} .ns-0 h2 #Mehri::before, .ns-0 h2#Mehri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_the_Mahra_Sultanate.svg/40px-Flag_of_the_Mahra_Sultanate.svg.png');} .ns-0 h2 #Meriam::before, .ns-0 h2#Meriam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/37/Flag_of_Murray_Island_(Mer).svg/40px-Flag_of_Murray_Island_(Mer).svg.png');} .ns-0 h2 #Meru::before, .ns-0 h2#Meru::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Meru_County.png/40px-Flag_of_Meru_County.png');} .ns-0 h2 #Meänkieli::before, .ns-0 h2#Meänkieli::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_Tornedalians_(2007).svg/40px-Flag_of_Tornedalians_(2007).svg.png');} .ns-0 h2 #Mi\'kmaq::before, .ns-0 h2#Mi\'kmaq::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Mikmaq_State_Flag.svg/40px-Mikmaq_State_Flag.svg.png');} .ns-0 h2 #Michif::before, .ns-0 h2#Michif::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Metis_Blue.svg/40px-Metis_Blue.svg.png');} .ns-0 h2 #Michoacán_Nahuatl::before, .ns-0 h2#Michoacán_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Coat_of_arms_of_Michoacan.svg/32px-Coat_of_arms_of_Michoacan.svg.png');} .ns-0 h2 #Middle_Dutch::before, .ns-0 h2#Middle_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_prince-bishopric_of_Utrecht.svg/36px-Flag_of_the_prince-bishopric_of_Utrecht.svg.png');} .ns-0 h2 #Middle_English::before, .ns-0 h2#Middle_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/be/Flag_of_England.svg/40px-Flag_of_England.svg.png');} .ns-0 h2 #Middle_French::before, .ns-0 h2#Middle_French::before, .ns-0 h2 #Old_French::before, .ns-0 h2#Old_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/82/Royal_flag_of_France.svg/40px-Royal_flag_of_France.svg.png');} .ns-0 h2 #Middle_Irish::before, .ns-0 h2#Middle_Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Flag_of_Leinster.svg/40px-Flag_of_Leinster.svg.png');} .ns-0 h2 #Middle_Korean::before, .ns-0 h2#Middle_Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Royal_flag_of_Goryeo_(Bong-gi).svg/40px-Royal_flag_of_Goryeo_(Bong-gi).svg.png');} .ns-0 h2 #Middle_Mongol::before, .ns-0 h2#Middle_Mongol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_the_Mongol_Empire_3.svg/40px-Flag_of_the_Mongol_Empire_3.svg.png');} .ns-0 h2 #Middle_Norwegian::before, .ns-0 h2#Middle_Norwegian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Royal_Banner_of_Norway_(14th_Century).svg/34px-Royal_Banner_of_Norway_(14th_Century).svg.png');} .ns-0 h2 #Middle_Persian::before, .ns-0 h2#Middle_Persian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Derafsh_kaviani.svg/38px-Derafsh_kaviani.svg.png');} .ns-0 h2 #Middle_Scots::before, .ns-0 h2#Middle_Scots::before, .ns-0 h2 #Scottish_Gaelic::before, .ns-0 h2#Scottish_Gaelic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Royal_Banner_of_Scotland.svg/40px-Royal_Banner_of_Scotland.svg.png');} .ns-0 h2 #Mikasuki::before, .ns-0 h2#Mikasuki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/34/Flag_of_the_Miccosukee_Tribe_of_Indians_of_Florida.svg/40px-Flag_of_the_Miccosukee_Tribe_of_Indians_of_Florida.svg.png');} .ns-0 h2 #Minangkabau::before, .ns-0 h2#Minangkabau::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Flag_of_Minang.svg/40px-Flag_of_Minang.svg.png');} .ns-0 h2 #Mingrelian::before, .ns-0 h2#Mingrelian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Flag_of_The_Principality_of_Mingrelia_(Portolan_1560).svg/40px-Flag_of_The_Principality_of_Mingrelia_(Portolan_1560).svg.png');} .ns-0 h2 #Mirandese::before, .ns-0 h2#Mirandese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Bandeira-de-Miranda-do-Douro.png/36px-Bandeira-de-Miranda-do-Douro.png');} .ns-0 h2 #Miskito::before, .ns-0 h2#Miskito::before, .ns-0 h2 #Nicaraguan_Creole::before, .ns-0 h2#Nicaraguan_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Nicaragua.svg/40px-Flag_of_Nicaragua.svg.png');} .ns-0 h2 #Mohawk::before, .ns-0 h2#Mohawk::before, .ns-0 h2 #Oneida::before, .ns-0 h2#Oneida::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_the_Iroquois_Confederacy.svg/40px-Flag_of_the_Iroquois_Confederacy.svg.png');} .ns-0 h2 #Mokilese::before, .ns-0 h2#Mokilese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Mwoakilloa.svg/40px-Flag_of_Mwoakilloa.svg.png');} .ns-0 h2 #Moksha::before, .ns-0 h2#Moksha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Flag_of_the_Moksha_people.svg/40px-Flag_of_the_Moksha_people.svg.png');} .ns-0 h2 #Mon::before, .ns-0 h2#Mon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/03/Flag_of_Mon_State_(2018).svg/40px-Flag_of_Mon_State_(2018).svg.png');} .ns-0 h2 #Mongolian::before, .ns-0 h2#Mongolian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Flag_of_Mongolia.svg/40px-Flag_of_Mongolia.svg.png');} .ns-0 h2 #Mongondow::before, .ns-0 h2#Mongondow::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Lambang_Kabupaten_Bolaang_Mongondow.png/35px-Lambang_Kabupaten_Bolaang_Mongondow.png');} .ns-0 h2 #Moore::before, .ns-0 h2#Moore::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Burkina_Faso.svg/40px-Flag_of_Burkina_Faso.svg.png');} .ns-0 h2 #Morelos_Nahuatl::before, .ns-0 h2#Morelos_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Coat_of_arms_of_Morelos.svg/32px-Coat_of_arms_of_Morelos.svg.png');} .ns-0 h2 #Moroccan_Amazigh::before, .ns-0 h2#Moroccan_Amazigh::before, .ns-0 h2 #Moroccan_Arabic::before, .ns-0 h2#Moroccan_Arabic::before, .ns-0 h2 #Tashelhit::before, .ns-0 h2#Tashelhit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Morocco.svg/40px-Flag_of_Morocco.svg.png');} .ns-0 h2 #Muong::before, .ns-0 h2#Muong::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/14/Flag_of_Muong_Autonomous_Region.svg/40px-Flag_of_Muong_Autonomous_Region.svg.png');} .ns-0 h2 #Mwali_Comorian::before, .ns-0 h2#Mwali_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Flag_of_Mohéli_(official).svg/40px-Flag_of_Mohéli_(official).svg.png');} .ns-0 h2 #Mwani::before, .ns-0 h2#Mwani::before, .ns-0 h2 #Ronga::before, .ns-0 h2#Ronga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_Mozambique.svg/40px-Flag_of_Mozambique.svg.png');} .ns-0 h2 #Mòcheno::before, .ns-0 h2#Mòcheno::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/51/Flag_of_Comunità_Alta_Valsugana_e_Bersntol.png/40px-Flag_of_Comunità_Alta_Valsugana_e_Bersntol.png');} .ns-0 h2 #Māori::before, .ns-0 h2#Māori::before, .ns-0 h2 #New_Zealand_Sign_Language::before, .ns-0 h2#New_Zealand_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_New_Zealand.svg/40px-Flag_of_New_Zealand.svg.png');} .ns-0 h2 #Najdi_Arabic::before, .ns-0 h2#Najdi_Arabic::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Flag_of_the_Emirate_of_Ha'il.svg/40px-Flag_of_the_Emirate_of_Ha'il.svg.png");} .ns-0 h2 #Nauruan::before, .ns-0 h2#Nauruan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/30/Flag_of_Nauru.svg/40px-Flag_of_Nauru.svg.png');} .ns-0 h2 #Navajo::before, .ns-0 h2#Navajo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Official_design_of_the_Navajo_Nation_flag_as_it_was_adopted_on_May_21,_1968.svg/40px-Official_design_of_the_Navajo_Nation_flag_as_it_was_adopted_on_May_21,_1968.svg.png');} .ns-0 h2 #Ndzwani_Comorian::before, .ns-0 h2#Ndzwani_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Anjouan_(official).svg/40px-Flag_of_Anjouan_(official).svg.png');} .ns-0 h2 #Neapolitan::before, .ns-0 h2#Neapolitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Flag_of_Campania.svg/40px-Flag_of_Campania.svg.png');} .ns-0 h2 #Negeri_Sembilan_Malay::before, .ns-0 h2#Negeri_Sembilan_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/db/Flag_of_Negeri_Sembilan.svg/40px-Flag_of_Negeri_Sembilan.svg.png');} .ns-0 h2 #Nepali::before, .ns-0 h2#Nepali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Nepal.svg/20px-Flag_of_Nepal.svg.png');} .ns-0 h2 #Newar::before, .ns-0 h2#Newar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_Kathmandu,_Nepal.svg/40px-Flag_of_Kathmandu,_Nepal.svg.png');} .ns-0 h2 #Ngazidja_Comorian::before, .ns-0 h2#Ngazidja_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Comoros.svg/40px-Flag_of_the_Comoros.svg.png');} .ns-0 h2 #Nheengatu::before, .ns-0 h2#Nheengatu::before, .ns-0 h2 #Trió::before, .ns-0 h2#Trió::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Bandeira_do_Pará.svg/40px-Bandeira_do_Pará.svg.png');} .ns-0 h2 #Nias::before, .ns-0 h2#Nias::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Coat_of_arms_of_North_Sumatra.svg/30px-Coat_of_arms_of_North_Sumatra.svg.png');} .ns-0 h2 #Nigerian_Pidgin::before, .ns-0 h2#Nigerian_Pidgin::before, .ns-0 h2 #Nigerian_Sign_Language::before, .ns-0 h2#Nigerian_Sign_Language::before, .ns-0 h2 #Yoruba::before, .ns-0 h2#Yoruba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_Nigeria.svg/40px-Flag_of_Nigeria.svg.png');} .ns-0 h2 #Niuean::before, .ns-0 h2#Niuean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Niue.svg/40px-Flag_of_Niue.svg.png');} .ns-0 h2 #Nivkh::before, .ns-0 h2#Nivkh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Flag_of_Sakhalin_Oblast.svg/40px-Flag_of_Sakhalin_Oblast.svg.png');} .ns-0 h2 #Norman::before, .ns-0 h2#Norman::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_Normandie.svg/40px-Flag_of_Normandie.svg.png');} .ns-0 h2 #North_Frisian::before, .ns-0 h2#North_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Nordfriesischeflagge.svg/40px-Nordfriesischeflagge.svg.png');} .ns-0 h2 #North_Moluccan_Malay::before, .ns-0 h2#North_Moluccan_Malay::before, .ns-0 h2 #West_Makian::before, .ns-0 h2#West_Makian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Coat_of_arms_of_North_Maluku.svg/35px-Coat_of_arms_of_North_Maluku.svg.png');} .ns-0 h2 #Northern_Altai::before, .ns-0 h2#Northern_Altai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Flag_of_Altai_Krai.svg/40px-Flag_of_Altai_Krai.svg.png');} .ns-0 h2 #Northern_Catanduanes_Bikol::before, .ns-0 h2#Northern_Catanduanes_Bikol::before, .ns-0 h2 #Southern_Catanduanes_Bikol::before, .ns-0 h2#Southern_Catanduanes_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/PH-CAT_Flag.png/40px-PH-CAT_Flag.png');} .ns-0 h2 #Northern_Ndebele::before, .ns-0 h2#Northern_Ndebele::before, .ns-0 h2 #Shona::before, .ns-0 h2#Shona::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Flag_of_Zimbabwe.svg/40px-Flag_of_Zimbabwe.svg.png');} .ns-0 h2 #Northern_Sotho::before, .ns-0 h2#Northern_Sotho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/52/Flag_of_Lebowa.svg/40px-Flag_of_Lebowa.svg.png');} .ns-0 h2 #Northern_Thai::before, .ns-0 h2#Northern_Thai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Seal_of_Lanna_Kingdom.png/40px-Seal_of_Lanna_Kingdom.png');} .ns-0 h2 #Norwegian::before, .ns-0 h2#Norwegian::before, .ns-0 h2 #Norwegian_Bokmål::before, .ns-0 h2#Norwegian_Bokmål::before, .ns-0 h2 #Norwegian_Nynorsk::before, .ns-0 h2#Norwegian_Nynorsk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Flag_of_Norway.svg/40px-Flag_of_Norway.svg.png');} .ns-0 h2 #Novial::before, .ns-0 h2#Novial::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Flag_of_Novial.svg/40px-Flag_of_Novial.svg.png');} .ns-0 h2 #Nubi::before, .ns-0 h2#Nubi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Kenia-Uganda-Flagge.png/40px-Kenia-Uganda-Flagge.png');} .ns-0 h2 #Nuosu::before, .ns-0 h2#Nuosu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Proposed_Yi_flag.svg/40px-Proposed_Yi_flag.svg.png');} .ns-0 h2 #Nupe::before, .ns-0 h2#Nupe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Niger_state_flag.png/40px-Niger_state_flag.png');} .ns-0 h2 #Nyankole::before, .ns-0 h2#Nyankole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Ankole.svg/40px-Flag_of_Ankole.svg.png');} .ns-0 h2 #Nyoro::before, .ns-0 h2#Nyoro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Bunyoro-Kitara_Kingdom_Flag.png/40px-Bunyoro-Kitara_Kingdom_Flag.png');} .ns-0 h2 #Nùng::before, .ns-0 h2#Nùng::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/75/Flag_of_the_Nùng_Autonomous_Territory.svg/40px-Flag_of_the_Nùng_Autonomous_Territory.svg.png');} .ns-0 h2 #O\'odham::before, .ns-0 h2#O\'odham::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/0/05/O'odham_unofficial_flag.svg/40px-O'odham_unofficial_flag.svg.png");} .ns-0 h2 #Occitan::before, .ns-0 h2#Occitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Flag_of_Occitania_(with_star).svg/40px-Flag_of_Occitania_(with_star).svg.png');} .ns-0 h2 #Odia::before, .ns-0 h2#Odia::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Mayurbhanj.png/40px-Flag_of_Mayurbhanj.png');} .ns-0 h2 #Ojibwe::before, .ns-0 h2#Ojibwe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Peguis_First_Nation.svg/40px-Flag_of_the_Peguis_First_Nation.svg.png');} .ns-0 h2 #Old_Armenian::before, .ns-0 h2#Old_Armenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Standard_of_the_Artaxiad_dynasty.svg/40px-Standard_of_the_Artaxiad_dynasty.svg.png');} .ns-0 h2 #Old_Catalan::before, .ns-0 h2#Old_Catalan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/58/Bandera_del_Principat_de_Catalunya_(1200_dC).svg/40px-Bandera_del_Principat_de_Catalunya_(1200_dC).svg.png');} .ns-0 h2 #Old_Czech::before, .ns-0 h2#Old_Czech::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Banner_of_Přemyslid_family.svg/40px-Banner_of_Přemyslid_family.svg.png');} .ns-0 h2 #Old_English::before, .ns-0 h2#Old_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_Wessex.svg/40px-Flag_of_Wessex.svg.png');} .ns-0 h2 #Old_Galician-Portuguese::before, .ns-0 h2#Old_Galician-Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/25/PortugueseFlag1143.svg/40px-PortugueseFlag1143.svg.png');} .ns-0 h2 #Old_Georgian::before, .ns-0 h2#Old_Georgian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Kartli_-_drosha_jvari.svg/40px-Kartli_-_drosha_jvari.svg.png');} .ns-0 h2 #Old_High_German::before, .ns-0 h2#Old_High_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_East_Francia_(843–962).png/40px-Flag_of_East_Francia_(843–962).png');} .ns-0 h2 #Old_Irish::before, .ns-0 h2#Old_Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Triskele-Symbol1.svg/40px-Triskele-Symbol1.svg.png');} .ns-0 h2 #Old_Javanese::before, .ns-0 h2#Old_Javanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Naval_flag_of_Majapahit_Kingdom.svg/40px-Naval_flag_of_Majapahit_Kingdom.svg.png');} .ns-0 h2 #Old_Korean::before, .ns-0 h2#Old_Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Military_Banner_of_Silla.svg/40px-Military_Banner_of_Silla.svg.png');} .ns-0 h2 #Old_Leonese::before, .ns-0 h2#Old_Leonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Royal_Banner_of_Leon_(Variant).svg/40px-Royal_Banner_of_Leon_(Variant).svg.png');} .ns-0 h2 #Old_Navarro-Aragonese::before, .ns-0 h2#Old_Navarro-Aragonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Navarro-Aragonese_flag.png/40px-Navarro-Aragonese_flag.png');} .ns-0 h2 #Old_Norse::before, .ns-0 h2#Old_Norse::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Raven_Banner.svg/40px-Raven_Banner.svg.png');} .ns-0 h2 #Old_Novgorodian::before, .ns-0 h2#Old_Novgorodian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Banner_of_the_Novgorod_Republic_(c._1385).svg/40px-Banner_of_the_Novgorod_Republic_(c._1385).svg.png');} .ns-0 h2 #Old_Nubian::before, .ns-0 h2#Old_Nubian::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/4/47/The_flag_of_the_'Kingdom_of_Dongola'_(Makuria)_in_the_%22Book_of_all_kingdoms%22_(C._1350).svg/40px-The_flag_of_the_'Kingdom_of_Dongola'_(Makuria)_in_the_%22Book_of_all_kingdoms%22_(C._1350).svg.png");} .ns-0 h2 #Old_Occitan::before, .ns-0 h2#Old_Occitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_Provence.svg/40px-Flag_of_Provence.svg.png');} .ns-0 h2 #Old_Polish::before, .ns-0 h2#Old_Polish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/12/Flag_of_the_Kingdom_of_Poland.svg/40px-Flag_of_the_Kingdom_of_Poland.svg.png');} .ns-0 h2 #Old_Ruthenian::before, .ns-0 h2#Old_Ruthenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Royal_banner_of_the_Grand_Duchy_of_Lithuania.svg/40px-Royal_banner_of_the_Grand_Duchy_of_Lithuania.svg.png');} .ns-0 h2 #Old_Saxon::before, .ns-0 h2#Old_Saxon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Flag_of_Old_Saxony.svg/40px-Flag_of_Old_Saxony.svg.png');} .ns-0 h2 #Old_Spanish::before, .ns-0 h2#Old_Spanish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_Castile.svg/40px-Flag_of_Castile.svg.png');} .ns-0 h2 #Old_Swedish::before, .ns-0 h2#Old_Swedish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/25/Royal_Banner_of_Sweden_(14th_Century).svg/30px-Royal_Banner_of_Sweden_(14th_Century).svg.png');} .ns-0 h2 #Old_Welsh::before, .ns-0 h2#Old_Welsh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_Gwynedd_(3-2).svg/40px-Flag_of_Gwynedd_(3-2).svg.png');} .ns-0 h2 #Orizaba_Nahuatl::before, .ns-0 h2#Orizaba_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Escudo_de_Armas_de_la_Ciudad_de_Orizaba.svg/35px-Escudo_de_Armas_de_la_Ciudad_de_Orizaba.svg.png');} .ns-0 h2 #Oromo::before, .ns-0 h2#Oromo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_Oromia_Region.svg/40px-Flag_of_the_Oromia_Region.svg.png');} .ns-0 h2 #Osage::before, .ns-0 h2#Osage::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_the_Osage_Nation.svg/40px-Flag_of_the_Osage_Nation.svg.png');} .ns-0 h2 #Ossetian::before, .ns-0 h2#Ossetian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_North_Ossetia.svg/40px-Flag_of_North_Ossetia.svg.png');} .ns-0 h2 #Ottoman_Turkish::before, .ns-0 h2#Ottoman_Turkish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_the_Ottoman_Empire_(Thicker_Crescent).svg/40px-Flag_of_the_Ottoman_Empire_(Thicker_Crescent).svg.png');} .ns-0 h2 #Pa\'o_Karen::before, .ns-0 h2#Pa\'o_Karen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_the_Pa-O_National_Organisation.svg/40px-Flag_of_the_Pa-O_National_Organisation.svg.png');} .ns-0 h2 #Pahari-Potwari::before, .ns-0 h2#Pahari-Potwari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_Azad_Kashmir.svg/40px-Flag_of_Azad_Kashmir.svg.png');} .ns-0 h2 #Palauan::before, .ns-0 h2#Palauan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Palau.svg/40px-Flag_of_Palau.svg.png');} .ns-0 h2 #Palenquero::before, .ns-0 h2#Palenquero::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Colombia.svg/40px-Flag_of_Colombia.svg.png');} .ns-0 h2 #Pali::before, .ns-0 h2#Pali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Buddhism_dham_jak.svg/35px-Buddhism_dham_jak.svg.png');} .ns-0 h2 #Panamanian_Sign_Language::before, .ns-0 h2#Panamanian_Sign_Language::before, .ns-0 h2 #San_Miguel_Creole_French::before, .ns-0 h2#San_Miguel_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Flag_of_Panama.svg/40px-Flag_of_Panama.svg.png');} .ns-0 h2 #Pangasinan::before, .ns-0 h2#Pangasinan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Flag_of_Pangasinan.svg/40px-Flag_of_Pangasinan.svg.png');} .ns-0 h2 #Papiamentu::before, .ns-0 h2#Papiamentu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Flag_of_the_Netherlands_Antilles_(1986–2010).svg/40px-Flag_of_the_Netherlands_Antilles_(1986–2010).svg.png');} .ns-0 h2 #Papuan_Malay::before, .ns-0 h2#Papuan_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Kerajaan_Kaimana_Papua.gif/40px-Kerajaan_Kaimana_Papua.gif');} .ns-0 h2 #Paraguayan_Guarani::before, .ns-0 h2#Paraguayan_Guarani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Paraguay.svg/40px-Flag_of_Paraguay.svg.png');} .ns-0 h2 #Parauk::before, .ns-0 h2#Parauk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Wa_State.svg/40px-Flag_of_Wa_State.svg.png');} .ns-0 h2 #Pashto::before, .ns-0 h2#Pashto::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Pashto_Banner_flag_(Neutral).png/40px-Pashto_Banner_flag_(Neutral).png');} .ns-0 h2 #Pennsylvania_German::before, .ns-0 h2#Pennsylvania_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Flag_of_Pennsylvania.svg/40px-Flag_of_Pennsylvania.svg.png');} .ns-0 h2 #Penrhyn::before, .ns-0 h2#Penrhyn::before, .ns-0 h2 #Pukapukan::before, .ns-0 h2#Pukapukan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/35/Flag_of_the_Cook_Islands.svg/40px-Flag_of_the_Cook_Islands.svg.png');} .ns-0 h2 #Persian::before, .ns-0 h2#Persian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Flag_of_Iran.svg/40px-Flag_of_Iran.svg.png');} .ns-0 h2 #Phuthi::before, .ns-0 h2#Phuthi::before, .ns-0 h2 #Sotho::before, .ns-0 h2#Sotho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Flag_of_Lesotho.svg/40px-Flag_of_Lesotho.svg.png');} .ns-0 h2 #Picard::before, .ns-0 h2#Picard::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/50/Picardy_flag.png/40px-Picardy_flag.png');} .ns-0 h2 #Pichinglis::before, .ns-0 h2#Pichinglis::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Equatorial_Guinea.svg/40px-Flag_of_Equatorial_Guinea.svg.png');} .ns-0 h2 #Piedmontese::before, .ns-0 h2#Piedmontese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b9/Flag_of_Piedmont.svg/40px-Flag_of_Piedmont.svg.png');} .ns-0 h2 #Pijin::before, .ns-0 h2#Pijin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/74/Flag_of_the_Solomon_Islands.svg/40px-Flag_of_the_Solomon_Islands.svg.png');} .ns-0 h2 #Pitcairn-Norfolk::before, .ns-0 h2#Pitcairn-Norfolk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Norfolk_Island.svg/40px-Flag_of_Norfolk_Island.svg.png');} .ns-0 h2 #Pitjantjatjara::before, .ns-0 h2#Pitjantjatjara::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_South_Australia.svg/40px-Flag_of_South_Australia.svg.png');} .ns-0 h2 #Pnar::before, .ns-0 h2#Pnar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Emblem_of_Jaintia_Hills_Autonomous_District_Council.png/40px-Emblem_of_Jaintia_Hills_Autonomous_District_Council.png');} .ns-0 h2 #Pohnpeian::before, .ns-0 h2#Pohnpeian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Flag_of_Pohnpei_(1977-1992).svg/40px-Flag_of_Pohnpei_(1977-1992).svg.png');} .ns-0 h2 #Polabian::before, .ns-0 h2#Polabian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Banner_of_Wends.png/40px-Banner_of_Wends.png');} .ns-0 h2 #Polish::before, .ns-0 h2#Polish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/12/Flag_of_Poland.svg/40px-Flag_of_Poland.svg.png');} .ns-0 h2 #Pontic_Greek::before, .ns-0 h2#Pontic_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Flag_of_Pontus.svg/40px-Flag_of_Pontus.svg.png');} .ns-0 h2 #Portuguese::before, .ns-0 h2#Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Portuguese_language_(PT-BR).svg/40px-Flag_of_Portuguese_language_(PT-BR).svg.png');} .ns-0 h2 #Principense::before, .ns-0 h2#Principense::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Príncipe_Autonomous_Region.svg/40px-Flag_of_Príncipe_Autonomous_Region.svg.png');} .ns-0 h2 #Puerto_Rican_Sign_Language::before, .ns-0 h2#Puerto_Rican_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Puerto_Rico.svg/40px-Flag_of_Puerto_Rico.svg.png');} .ns-0 h2 #Punjabi::before, .ns-0 h2#Punjabi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_Punjab_(Paired).png/40px-Flag_of_Punjab_(Paired).png');} .ns-0 h2 #Quechua::before, .ns-0 h2#Quechua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Quechuas_flag.svg/40px-Quechuas_flag.svg.png');} .ns-0 h2 #Rakhine::before, .ns-0 h2#Rakhine::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_Rakhine.svg/40px-Flag_of_Rakhine.svg.png');} .ns-0 h2 #Rapa_Nui::before, .ns-0 h2#Rapa_Nui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Rapa_Nui,_Chile.svg/40px-Flag_of_Rapa_Nui,_Chile.svg.png');} .ns-0 h2 #Ratagnon::before, .ns-0 h2#Ratagnon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Province_of_Occidental_Mindoro_seal.svg/40px-Province_of_Occidental_Mindoro_seal.svg.png');} .ns-0 h2 #Rennellese::before, .ns-0 h2#Rennellese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Flag_of_Rennell_and_Bellona_Province.svg/40px-Flag_of_Rennell_and_Bellona_Province.svg.png');} .ns-0 h2 #Rohingya::before, .ns-0 h2#Rohingya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Rohingya_flag.svg/40px-Rohingya_flag.svg.png');} .ns-0 h2 #Romagnol::before, .ns-0 h2#Romagnol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_San_Marino.svg/40px-Flag_of_San_Marino.svg.png');} .ns-0 h2 #Romanian::before, .ns-0 h2#Romanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Romania.svg/40px-Flag_of_Romania.svg.png');} .ns-0 h2 #Romansh::before, .ns-0 h2#Romansh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Canton_of_Graubünden.svg/40px-Flag_of_Canton_of_Graubünden.svg.png');} .ns-0 h2 #Rotuman::before, .ns-0 h2#Rotuman::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bb/Flag_of_Rotuma_(1987-1988).svg/40px-Flag_of_Rotuma_(1987-1988).svg.png');} .ns-0 h2 #Russian::before, .ns-0 h2#Russian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Flag_of_Russia.svg/40px-Flag_of_Russia.svg.png');} .ns-0 h2 #Rutul::before, .ns-0 h2#Rutul::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Flag_of_the_Rutul_People.svg/40px-Flag_of_the_Rutul_People.svg.png');} .ns-0 h2 #Rwanda-Rundi::before, .ns-0 h2#Rwanda-Rundi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Flag_of_Rwanda_and_Burundi.svg/40px-Flag_of_Rwanda_and_Burundi.svg.png');} .ns-0 h2 #Réunion_Creole_French::before, .ns-0 h2#Réunion_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Proposed_flag_of_Réunion_(VAR).svg/40px-Proposed_flag_of_Réunion_(VAR).svg.png');} .ns-0 h2 #S\'gaw_Karen::before, .ns-0 h2#S\'gaw_Karen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_the_Karen_National_Union.svg/40px-Flag_of_the_Karen_National_Union.svg.png');} .ns-0 h2 #Saho::before, .ns-0 h2#Saho::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Flag_of_the_Saho_People's_Democratic_Movement.svg/40px-Flag_of_the_Saho_People's_Democratic_Movement.svg.png");} .ns-0 h2 #Sambali::before, .ns-0 h2#Sambali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Seal_of_Zambales.svg/40px-Seal_of_Zambales.svg.png');} .ns-0 h2 #Samoan::before, .ns-0 h2#Samoan::before, .ns-0 h2 #Samoan_Plantation_Pidgin::before, .ns-0 h2#Samoan_Plantation_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Samoa.svg/40px-Flag_of_Samoa.svg.png');} .ns-0 h2 #Samogitian::before, .ns-0 h2#Samogitian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Flag_of_Žemaitija.svg/40px-Flag_of_Žemaitija.svg.png');} .ns-0 h2 #Sanaviron::before, .ns-0 h2#Sanaviron::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Bandera_de_la_Ciudad_de_Córdoba.svg/40px-Bandera_de_la_Ciudad_de_Córdoba.svg.png');} .ns-0 h2 #Sango::before, .ns-0 h2#Sango::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_the_Central_African_Republic.svg/40px-Flag_of_the_Central_African_Republic.svg.png');} .ns-0 h2 #Sanskrit::before, .ns-0 h2#Sanskrit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Red_om_symbol.png/35px-Red_om_symbol.png');} .ns-0 h2 #Sardinian::before, .ns-0 h2#Sardinian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Sardinia,_Italy.svg/40px-Flag_of_Sardinia,_Italy.svg.png');} .ns-0 h2 #Sassarese::before, .ns-0 h2#Sassarese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Sassari.svg/40px-Flag_of_Sassari.svg.png');} .ns-0 h2 #Saterland_Frisian::before, .ns-0 h2#Saterland_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/DEU_Saterland_Flag.svg/40px-DEU_Saterland_Flag.svg.png');} .ns-0 h2 #Scanian::before, .ns-0 h2#Scanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Banner_of_Arms_of_Scania.svg/35px-Banner_of_Arms_of_Scania.svg.png');} .ns-0 h2 #Scots::before, .ns-0 h2#Scots::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_Scotland.svg/40px-Flag_of_Scotland.svg.png');} .ns-0 h2 #Sedang::before, .ns-0 h2#Sedang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Sedang.svg/36px-Flag_of_Sedang.svg.png');} .ns-0 h2 #Selk\'nam::before, .ns-0 h2#Selk\'nam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Bandera_de_la_Provincia_de_Tierra_del_Fuego.svg/40px-Bandera_de_la_Provincia_de_Tierra_del_Fuego.svg.png');} .ns-0 h2 #Serbo-Croatian::before, .ns-0 h2#Serbo-Croatian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/HR-BA-ME-RS_flag.svg/40px-HR-BA-ME-RS_flag.svg.png');} .ns-0 h2 #Serer::before, .ns-0 h2#Serer::before, .ns-0 h2 #Wolof::before, .ns-0 h2#Wolof::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_Senegal.svg/40px-Flag_of_Senegal.svg.png');} .ns-0 h2 #Seri::before, .ns-0 h2#Seri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Bandera_de_la_Nacion_Comcaac.svg/40px-Bandera_de_la_Nacion_Comcaac.svg.png');} .ns-0 h2 #Seychellois_Creole::before, .ns-0 h2#Seychellois_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Flag_of_Seychelles.svg/40px-Flag_of_Seychelles.svg.png');} .ns-0 h2 #Shan::before, .ns-0 h2#Shan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/68/Flag_of_Shan_State.svg/40px-Flag_of_Shan_State.svg.png');} .ns-0 h2 #Shihhi_Arabic::before, .ns-0 h2#Shihhi_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Sharjah_and_Ras_Al_Khaimah.svg/40px-Flag_of_Sharjah_and_Ras_Al_Khaimah.svg.png');} .ns-0 h2 #Sicilian::before, .ns-0 h2#Sicilian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_Sicily.svg/40px-Flag_of_Sicily.svg.png');} .ns-0 h2 #Sidamo::before, .ns-0 h2#Sidamo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/Flag_of_Sidama.svg/40px-Flag_of_Sidama.svg.png');} .ns-0 h2 #Sikkimese::before, .ns-0 h2#Sikkimese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Flag_of_Sikkim_(1967-1975).svg/40px-Flag_of_Sikkim_(1967-1975).svg.png');} .ns-0 h2 #Silesian::before, .ns-0 h2#Silesian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_Upper_Silesia.svg/40px-Flag_of_Upper_Silesia.svg.png');} .ns-0 h2 #Sindhi::before, .ns-0 h2#Sindhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_Sindh.svg/40px-Flag_of_Sindh.svg.png');} .ns-0 h2 #Sinhalese::before, .ns-0 h2#Sinhalese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Sri_Lanka.svg/40px-Flag_of_Sri_Lanka.svg.png');} .ns-0 h2 #Slavomolisano::before, .ns-0 h2#Slavomolisano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Molise.svg/40px-Flag_of_Molise.svg.png');} .ns-0 h2 #Slovak::before, .ns-0 h2#Slovak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Slovakia.svg/40px-Flag_of_Slovakia.svg.png');} .ns-0 h2 #Slovene::before, .ns-0 h2#Slovene::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Flag_of_Slovenia.svg/40px-Flag_of_Slovenia.svg.png');} .ns-0 h2 #Slovincian::before, .ns-0 h2#Slovincian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Wappen_Pommern.svg/35px-Wappen_Pommern.svg.png');} .ns-0 h2 #Soga::before, .ns-0 h2#Soga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Busoga_(royal_standard).png/40px-Flag_of_Busoga_(royal_standard).png');} .ns-0 h2 #Solombala_English::before, .ns-0 h2#Solombala_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Coat_of_Arms_of_Arkhangelsk.svg/32px-Coat_of_Arms_of_Arkhangelsk.svg.png');} .ns-0 h2 #Somali::before, .ns-0 h2#Somali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Flag_of_Somalia.svg/40px-Flag_of_Somalia.svg.png');} .ns-0 h2 #South_Levantine_Arabic::before, .ns-0 h2#South_Levantine_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Palestine.svg/40px-Flag_of_Palestine.svg.png');} .ns-0 h2 #Southern_Altai::before, .ns-0 h2#Southern_Altai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Flag_of_Altai_Republic.svg/40px-Flag_of_Altai_Republic.svg.png');} .ns-0 h2 #Southern_Ndebele::before, .ns-0 h2#Southern_Ndebele::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Flag_of_Mpumalanga_Province.svg/40px-Flag_of_Mpumalanga_Province.svg.png');} .ns-0 h2 #Spanish::before, .ns-0 h2#Spanish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Spanish_language_(ES-MX).svg/40px-Flag_of_Spanish_language_(ES-MX).svg.png');} .ns-0 h2 #Sri_Lankan_Creole_Malay::before, .ns-0 h2#Sri_Lankan_Creole_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Flag_of_the_Southern_Province_(Sri_Lanka).PNG/40px-Flag_of_the_Southern_Province_(Sri_Lanka).PNG');} .ns-0 h2 #Sudovian::before, .ns-0 h2#Sudovian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Suvalkija.svg/40px-Flag_of_Suvalkija.svg.png');} .ns-0 h2 #Sumerian::before, .ns-0 h2#Sumerian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Cuneiform_sumer_dingir.svg/28px-Cuneiform_sumer_dingir.svg.png');} .ns-0 h2 #Sundanese::before, .ns-0 h2#Sundanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_West_Java_(vectorised).svg/40px-Flag_of_West_Java_(vectorised).svg.png');} .ns-0 h2 #Surigaonon::before, .ns-0 h2#Surigaonon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Flag_of_Surigao_del_Norte.svg/40px-Flag_of_Surigao_del_Norte.svg.png');} .ns-0 h2 #Swabian::before, .ns-0 h2#Swabian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/14/Flagge_Königreich_Württemberg.svg/40px-Flagge_Königreich_Württemberg.svg.png');} .ns-0 h2 #Swazi::before, .ns-0 h2#Swazi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Flag_of_Eswatini.svg/40px-Flag_of_Eswatini.svg.png');} .ns-0 h2 #Swedish::before, .ns-0 h2#Swedish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Flag_of_Sweden.svg/40px-Flag_of_Sweden.svg.png');} .ns-0 h2 #Tabasaran::before, .ns-0 h2#Tabasaran::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Ethnic_flag_of_Tabasarans.svg/40px-Ethnic_flag_of_Tabasarans.svg.png');} .ns-0 h2 #Tabasco_Nahuatl::before, .ns-0 h2#Tabasco_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Coat_of_arms_of_Tabasco_(México).svg/32px-Coat_of_arms_of_Tabasco_(México).svg.png');} .ns-0 h2 #Tachawit::before, .ns-0 h2#Tachawit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_Chaouia.svg/40px-Flag_of_Chaouia.svg.png');} .ns-0 h2 #Tagalog::before, .ns-0 h2#Tagalog::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Flag_of_the_Philippines.svg/40px-Flag_of_the_Philippines.svg.png');} .ns-0 h2 #Tahitian::before, .ns-0 h2#Tahitian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/db/Flag_of_French_Polynesia.svg/40px-Flag_of_French_Polynesia.svg.png');} .ns-0 h2 #Tai_Dam::before, .ns-0 h2#Tai_Dam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Flag_of_the_Tai_Dam_People.svg/40px-Flag_of_the_Tai_Dam_People.svg.png');} .ns-0 h2 #Tai_Dón::before, .ns-0 h2#Tai_Dón::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/86/Flag_of_Tay_Khao.png/40px-Flag_of_Tay_Khao.png');} .ns-0 h2 #Taimyr_Pidgin_Russian::before, .ns-0 h2#Taimyr_Pidgin_Russian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_the_Siberian_Federal_District.png/40px-Flag_of_the_Siberian_Federal_District.png');} .ns-0 h2 #Tajik::before, .ns-0 h2#Tajik::before, .ns-0 h2 #Tajiki_Arabic::before, .ns-0 h2#Tajiki_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_Tajikistan.svg/40px-Flag_of_Tajikistan.svg.png');} .ns-0 h2 #Talysh::before, .ns-0 h2#Talysh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_the_Talysh_National_Movement.svg/40px-Flag_of_the_Talysh_National_Movement.svg.png');} .ns-0 h2 #Tarifit::before, .ns-0 h2#Tarifit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Flag_of_the_Republic_of_the_Rif.svg/40px-Flag_of_the_Republic_of_the_Rif.svg.png');} .ns-0 h2 #Tarjumo::before, .ns-0 h2#Tarjumo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Kanem_flag_from_dulcerta_1339-pt.svg/40px-Kanem_flag_from_dulcerta_1339-pt.svg.png');} .ns-0 h2 #Tatar::before, .ns-0 h2#Tatar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Tatarstan.svg/40px-Flag_of_Tatarstan.svg.png');} .ns-0 h2 #Tausug::before, .ns-0 h2#Tausug::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Late_19th_Century_Flag_of_Sulu.svg/40px-Late_19th_Century_Flag_of_Sulu.svg.png');} .ns-0 h2 #Tayo::before, .ns-0 h2#Tayo::before, .ns-0 h2 #Xârâcùù::before, .ns-0 h2#Xârâcùù::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_FLNKS.svg/40px-Flag_of_FLNKS.svg.png');} .ns-0 h2 #Tboli::before, .ns-0 h2#Tboli::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7f/South_Cotabato_Flag.png/40px-South_Cotabato_Flag.png');} .ns-0 h2 #Temascaltepec_Nahuatl::before, .ns-0 h2#Temascaltepec_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/TEMASCALTEPEC.svg/35px-TEMASCALTEPEC.svg.png');} .ns-0 h2 #Terengganu_Malay::before, .ns-0 h2#Terengganu_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Flag_of_Terengganu.svg/40px-Flag_of_Terengganu.svg.png');} .ns-0 h2 #Ternate::before, .ns-0 h2#Ternate::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Bendera_Ternate_-_Almulk_Buldan_Ternate.svg/40px-Bendera_Ternate_-_Almulk_Buldan_Ternate.svg.png');} .ns-0 h2 #Tetum::before, .ns-0 h2#Tetum::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_East_Timor.svg/40px-Flag_of_East_Timor.svg.png');} .ns-0 h2 #Thai::before, .ns-0 h2#Thai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Flag_of_Thailand.svg/40px-Flag_of_Thailand.svg.png');} .ns-0 h2 #Tibetan::before, .ns-0 h2#Tibetan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Tibet.svg/40px-Flag_of_Tibet.svg.png');} .ns-0 h2 #Ticuna::before, .ns-0 h2#Ticuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Bandeira_do_Amazonas.svg/40px-Bandeira_do_Amazonas.svg.png');} .ns-0 h2 #Tlingit::before, .ns-0 h2#Tlingit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Organized_Village_of_Kake.svg/40px-Flag_of_the_Organized_Village_of_Kake.svg.png');} .ns-0 h2 #Toba_Batak::before, .ns-0 h2#Toba_Batak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Flag_of_Batak_WRB.svg/40px-Flag_of_Batak_WRB.svg.png');} .ns-0 h2 #Tobagonian_Creole_English::before, .ns-0 h2#Tobagonian_Creole_English::before, .ns-0 h2 #Trinidadian_Creole_English::before, .ns-0 h2#Trinidadian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_Trinidad_and_Tobago.svg/40px-Flag_of_Trinidad_and_Tobago.svg.png');} .ns-0 h2 #Tok_Pisin::before, .ns-0 h2#Tok_Pisin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Flag_of_Papua_New_Guinea.svg/40px-Flag_of_Papua_New_Guinea.svg.png');} .ns-0 h2 #Tokelauan::before, .ns-0 h2#Tokelauan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Flag_of_Tokelau.svg/40px-Flag_of_Tokelau.svg.png');} .ns-0 h2 #Tongan::before, .ns-0 h2#Tongan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Tonga.svg/40px-Flag_of_Tonga.svg.png');} .ns-0 h2 #Tooro::before, .ns-0 h2#Tooro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Toro.gif/40px-Flag_of_Toro.gif');} .ns-0 h2 #Transylvanian_Saxon::before, .ns-0 h2#Transylvanian_Saxon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Flag_of_Transylvania_Saxons.svg/40px-Flag_of_Transylvania_Saxons.svg.png');} .ns-0 h2 #Tsonga::before, .ns-0 h2#Tsonga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Tsonga_language.svg/40px-Flag_of_Tsonga_language.svg.png');} .ns-0 h2 #Tsou::before, .ns-0 h2#Tsou::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_Chiayi_County.svg/40px-Flag_of_Chiayi_County.svg.png');} .ns-0 h2 #Tswana::before, .ns-0 h2#Tswana::before, .ns-0 h2 #ǃXóõ::before, .ns-0 h2#ǃXóõ::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_Botswana.svg/40px-Flag_of_Botswana.svg.png');} .ns-0 h2 #Tuareg::before, .ns-0 h2#Tuareg::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Touareg_People_Flag.svg/40px-Touareg_People_Flag.svg.png');} .ns-0 h2 #Tunisian_Arabic::before, .ns-0 h2#Tunisian_Arabic::before, .ns-0 h2 #Tunisian_Berber::before, .ns-0 h2#Tunisian_Berber::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Tunisia.svg/40px-Flag_of_Tunisia.svg.png');} .ns-0 h2 #Turkana::before, .ns-0 h2#Turkana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Flag_of_Turkana_County.gif/40px-Flag_of_Turkana_County.gif');} .ns-0 h2 #Turkish::before, .ns-0 h2#Turkish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Flag_of_Turkey.svg/40px-Flag_of_Turkey.svg.png');} .ns-0 h2 #Turkmen::before, .ns-0 h2#Turkmen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Flag_of_Turkmenistan.svg/40px-Flag_of_Turkmenistan.svg.png');} .ns-0 h2 #Tuvaluan::before, .ns-0 h2#Tuvaluan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/38/Flag_of_Tuvalu.svg/40px-Flag_of_Tuvalu.svg.png');} .ns-0 h2 #Tuvan::before, .ns-0 h2#Tuvan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Tuva.svg/40px-Flag_of_Tuva.svg.png');} .ns-0 h2 #Tzotzil::before, .ns-0 h2#Tzotzil::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_the_Mayan_People.svg/40px-Flag_of_the_Mayan_People.svg.png');} .ns-0 h2 #Tày::before, .ns-0 h2#Tày::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Flag_of_the_Tay_people_(1947-1954).svg/40px-Flag_of_the_Tay_people_(1947-1954).svg.png');} .ns-0 h2 #Tübatulabal::before, .ns-0 h2#Tübatulabal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Seal_of_Kern_County,_California.png/40px-Seal_of_Kern_County,_California.png');} .ns-0 h2 #Udmurt::before, .ns-0 h2#Udmurt::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Udmurtia.svg/40px-Flag_of_Udmurtia.svg.png');} .ns-0 h2 #Ukrainian::before, .ns-0 h2#Ukrainian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Ukraine.svg/40px-Flag_of_Ukraine.svg.png');} .ns-0 h2 #Umbrian::before, .ns-0 h2#Umbrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Flag_of_Umbria.svg/40px-Flag_of_Umbria.svg.png');} .ns-0 h2 #Unserdeutsch::before, .ns-0 h2#Unserdeutsch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_East_New_Britain.svg/40px-Flag_of_East_New_Britain.svg.png');} .ns-0 h2 #Urdu::before, .ns-0 h2#Urdu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/32/Flag_of_Pakistan.svg/40px-Flag_of_Pakistan.svg.png');} .ns-0 h2 #Uyghur::before, .ns-0 h2#Uyghur::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Kokbayraq_flag.svg/40px-Kokbayraq_flag.svg.png');} .ns-0 h2 #Uzbek::before, .ns-0 h2#Uzbek::before, .ns-0 h2 #Uzbeki_Arabic::before, .ns-0 h2#Uzbeki_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Uzbekistan.svg/40px-Flag_of_Uzbekistan.svg.png');} .ns-0 h2 #Vai::before, .ns-0 h2#Vai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Liberia.svg/40px-Flag_of_Liberia.svg.png');} .ns-0 h2 #Veddah::before, .ns-0 h2#Veddah::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_the_Uva_Province_(Sri_Lanka).svg/40px-Flag_of_the_Uva_Province_(Sri_Lanka).svg.png');} .ns-0 h2 #Venda::before, .ns-0 h2#Venda::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Venda_(1973–1994).svg/40px-Flag_of_Venda_(1973–1994).svg.png');} .ns-0 h2 #Venetan::before, .ns-0 h2#Venetan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d5/Flag_of_Veneto.svg/40px-Flag_of_Veneto.svg.png');} .ns-0 h2 #Veps::before, .ns-0 h2#Veps::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Vepsia.svg/40px-Flag_of_Vepsia.svg.png');} .ns-0 h2 #Vilamovian::before, .ns-0 h2#Vilamovian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/POL_Wilamowice_COA.svg/35px-POL_Wilamowice_COA.svg.png');} .ns-0 h2 #Vincentian_Creole_English::before, .ns-0 h2#Vincentian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Flag_of_Saint_Vincent_and_the_Grenadines.svg/40px-Flag_of_Saint_Vincent_and_the_Grenadines.svg.png');} .ns-0 h2 #Virgin_Islands_Creole::before, .ns-0 h2#Virgin_Islands_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Flag_of_the_United_States_Virgin_Islands.svg/40px-Flag_of_the_United_States_Virgin_Islands.svg.png');} .ns-0 h2 #Volapük::before, .ns-0 h2#Volapük::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Volapuk_symbol.svg/40px-Volapuk_symbol.svg.png');} .ns-0 h2 #Volga_German::before, .ns-0 h2#Volga_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Flag_of_Volga_Germans_(version).svg/40px-Flag_of_Volga_Germans_(version).svg.png');} .ns-0 h2 #Votic::before, .ns-0 h2#Votic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Votic_Flag.svg/40px-Votic_Flag.svg.png');} .ns-0 h2 #Võro::before, .ns-0 h2#Võro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Võrumaa_lipp.svg/40px-Võrumaa_lipp.svg.png');} .ns-0 h2 #Walloon::before, .ns-0 h2#Walloon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Flag_of_Wallonia.svg/40px-Flag_of_Wallonia.svg.png');} .ns-0 h2 #Wapishana::before, .ns-0 h2#Wapishana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/98/Bandeira_de_Roraima.svg/40px-Bandeira_de_Roraima.svg.png');} .ns-0 h2 #Waray-Waray::before, .ns-0 h2#Waray-Waray::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Biliran_Provincial_Flag.png/40px-Biliran_Provincial_Flag.png');} .ns-0 h2 #Wayuu::before, .ns-0 h2#Wayuu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Panteera_Wayuu_Aumentado.png/40px-Panteera_Wayuu_Aumentado.png');} .ns-0 h2 #Welsh::before, .ns-0 h2#Welsh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Flag_of_Wales.svg/40px-Flag_of_Wales.svg.png');} .ns-0 h2 #West_Circassian::before, .ns-0 h2#West_Circassian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Adygea.svg/40px-Flag_of_Adygea.svg.png');} .ns-0 h2 #West_Flemish::before, .ns-0 h2#West_Flemish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Flag_of_West_Flanders.svg/40px-Flag_of_West_Flanders.svg.png');} .ns-0 h2 #West_Frisian::before, .ns-0 h2#West_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Frisian_flag.svg/40px-Frisian_flag.svg.png');} .ns-0 h2 #West_Miraya_Bikol::before, .ns-0 h2#West_Miraya_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Albay_Flag.png/40px-Albay_Flag.png');} .ns-0 h2 #Western_Apache::before, .ns-0 h2#Western_Apache::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Coat_of_arms_of_Sonora.svg/35px-Coat_of_arms_of_Sonora.svg.png');} .ns-0 h2 #Western_Cham::before, .ns-0 h2#Western_Cham::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Bandera_Front_Alliberament_Cham.svg/40px-Bandera_Front_Alliberament_Cham.svg.png');} .ns-0 h2 #Western_Mari::before, .ns-0 h2#Western_Mari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/24/Flag_of_Gornomariysky_rayon.svg/40px-Flag_of_Gornomariysky_rayon.svg.png');} .ns-0 h2 #Wichí_Lhamtés_Güisnay::before, .ns-0 h2#Wichí_Lhamtés_Güisnay::before, .ns-0 h2 #Wichí_Lhamtés_Nocten::before, .ns-0 h2#Wichí_Lhamtés_Nocten::before, .ns-0 h2 #Wichí_Lhamtés_Vejoz::before, .ns-0 h2#Wichí_Lhamtés_Vejoz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Bandera_del_pueblo_Wichi.svg/40px-Bandera_del_pueblo_Wichi.svg.png');} .ns-0 h2 #Woiwurrung::before, .ns-0 h2#Woiwurrung::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_Victoria_(Australia).svg/40px-Flag_of_Victoria_(Australia).svg.png');} .ns-0 h2 #Wolio::before, .ns-0 h2#Wolio::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Lambang_Kota_Bau-Bau.png/35px-Lambang_Kota_Bau-Bau.png');} .ns-0 h2 #Xerénte::before, .ns-0 h2#Xerénte::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Bandeira_do_Tocantins.svg/40px-Bandeira_do_Tocantins.svg.png');} .ns-0 h2 #Xhosa::before, .ns-0 h2#Xhosa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Flag_of_Ciskei.svg/40px-Flag_of_Ciskei.svg.png');} .ns-0 h2 #Xokleng::before, .ns-0 h2#Xokleng::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Bandeira_de_Santa_Catarina.svg/40px-Bandeira_de_Santa_Catarina.svg.png');} .ns-0 h2 #Yakan::before, .ns-0 h2#Yakan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Flag_of_Basilan.svg/40px-Flag_of_Basilan.svg.png');} .ns-0 h2 #Yakut::before, .ns-0 h2#Yakut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Flag_of_Sakha.svg/40px-Flag_of_Sakha.svg.png');} .ns-0 h2 #Yapese::before, .ns-0 h2#Yapese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Yap.svg/40px-Flag_of_Yap.svg.png');} .ns-0 h2 #Yaqui::before, .ns-0 h2#Yaqui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_the_Pascua_Yaqui_Tribe_of_Arizona.svg/40px-Flag_of_the_Pascua_Yaqui_Tribe_of_Arizona.svg.png');} .ns-0 h2 #Ye\'kwana::before, .ns-0 h2#Ye\'kwana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_Venezuela.svg/40px-Flag_of_Venezuela.svg.png');} .ns-0 h2 #Yemeni_Arabic::before, .ns-0 h2#Yemeni_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Yemen.svg/40px-Flag_of_Yemen.svg.png');} .ns-0 h2 #Yiddish::before, .ns-0 h2#Yiddish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Proposed_Yiddish_flag.svg/40px-Proposed_Yiddish_flag.svg.png');} .ns-0 h2 #Yilan_Creole::before, .ns-0 h2#Yilan_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Flag_of_Yilan_County.svg/40px-Flag_of_Yilan_County.svg.png');} .ns-0 h2 #Yogad::before, .ns-0 h2#Yogad::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Flag_of_Echague,_Isabela_(2022-present).png/40px-Flag_of_Echague,_Isabela_(2022-present).png');} .ns-0 h2 #Yola::before, .ns-0 h2#Yola::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/40/Flag_of_Yola.svg/40px-Flag_of_Yola.svg.png');} .ns-0 h2 #Yonaguni::before, .ns-0 h2#Yonaguni::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Yonaguni,_Okinawa.svg/40px-Flag_of_Yonaguni,_Okinawa.svg.png');} .ns-0 h2 #Yucatec_Maya::before, .ns-0 h2#Yucatec_Maya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_the_Republic_of_Yucatan.svg/40px-Flag_of_the_Republic_of_Yucatan.svg.png');} .ns-0 h2 #Yuracare::before, .ns-0 h2#Yuracare::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Flag_of_Cochabamba.svg/40px-Flag_of_Cochabamba.svg.png');} .ns-0 h2 #Zaniza_Zapotec::before, .ns-0 h2#Zaniza_Zapotec::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Flag_of_Oaxaca.svg/40px-Flag_of_Oaxaca.svg.png');} .ns-0 h2 #Zarma::before, .ns-0 h2#Zarma::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Flag_of_Niger.svg/40px-Flag_of_Niger.svg.png');} .ns-0 h2 #Zazaki::before, .ns-0 h2#Zazaki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Zazaistan.svg/40px-Flag_of_Zazaistan.svg.png');} .ns-0 h2 #Zealandic::before, .ns-0 h2#Zealandic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Zeeland.svg/40px-Flag_of_Zeeland.svg.png');} .ns-0 h2 #Zhuang::before, .ns-0 h2#Zhuang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_the_Zhuang_people.svg/40px-Flag_of_the_Zhuang_people.svg.png');} .ns-0 h2 #Zulu::before, .ns-0 h2#Zulu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/60/Flag_of_the_KwaZulu-Natal_Province.png/40px-Flag_of_the_KwaZulu-Natal_Province.png');} jck1btrdumjdqvveo7urrvsepfplb4z 88881 88880 2026-08-06T23:09:06Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-WiktCountryFlags.css]] 88880 css text/css /* * flags.css - adds flags to language headers. * originally created by [[User:Prince Kassad]] * this version is auto-generated from the list at [[Wiktionary:Language flags list]] * ([[Special:Permalink/91668618]]) */ .ns-0 h2 #Translingual::before, .ns-0 h2#Translingual::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Earth_Day_Flag.png/40px-Earth_Day_Flag.png');} .ns-0 h2 #English::before, .ns-0 h2#English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/English_language.svg/40px-English_language.svg.png');} .ns-0 h2 #\'Are\'are::before, .ns-0 h2#\'Are\'are::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Flag_of_Guadalcanal.svg/40px-Flag_of_Guadalcanal.svg.png');} .ns-0 h2 #Aari::before, .ns-0 h2#Aari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Flag_of_Southern_Ethiopia.svg/40px-Flag_of_Southern_Ethiopia.svg.png');} .ns-0 h2 #Abau::before, .ns-0 h2#Abau::before, .ns-0 h2 #Krisa::before, .ns-0 h2#Krisa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_Sandaun.svg/40px-Flag_of_Sandaun.svg.png');} .ns-0 h2 #Abaza::before, .ns-0 h2#Abaza::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Abazinia.svg/40px-Flag_of_Abazinia.svg.png');} .ns-0 h2 #Abenaki::before, .ns-0 h2#Abenaki::before, .ns-0 h2 #Malecite-Passamaquoddy::before, .ns-0 h2#Malecite-Passamaquoddy::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Wabanaki_Seal.png/40px-Wabanaki_Seal.png');} .ns-0 h2 #Abkhaz::before, .ns-0 h2#Abkhaz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_the_Republic_of_Abkhazia.svg/40px-Flag_of_the_Republic_of_Abkhazia.svg.png');} .ns-0 h2 #Acehnese::before, .ns-0 h2#Acehnese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Aceh_Sultanate.svg/40px-Flag_of_Aceh_Sultanate.svg.png');} .ns-0 h2 #Acholi::before, .ns-0 h2#Acholi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Acholi.svg/40px-Flag_of_Acholi.svg.png');} .ns-0 h2 #Adzera::before, .ns-0 h2#Adzera::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Flag_of_Morobe.png/40px-Flag_of_Morobe.png');} .ns-0 h2 #Afar::before, .ns-0 h2#Afar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/34/Flag_of_Djibouti.svg/40px-Flag_of_Djibouti.svg.png');} .ns-0 h2 #Afrikaans::before, .ns-0 h2#Afrikaans::before, .ns-0 h2 #Fanagalo::before, .ns-0 h2#Fanagalo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/af/Flag_of_South_Africa.svg/40px-Flag_of_South_Africa.svg.png');} .ns-0 h2 #Agutaynen::before, .ns-0 h2#Agutaynen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_Agutaya,_Palawan.png/40px-Flag_of_Agutaya,_Palawan.png');} .ns-0 h2 #Ahom::before, .ns-0 h2#Ahom::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Ahom_insignia_plain.svg/40px-Ahom_insignia_plain.svg.png');} .ns-0 h2 #Ainu::before, .ns-0 h2#Ainu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Ainu.svg/40px-Flag_of_Ainu.svg.png');} .ns-0 h2 #Akan::before, .ns-0 h2#Akan::before, .ns-0 h2 #Dagbani::before, .ns-0 h2#Dagbani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Ghana.svg/40px-Flag_of_Ghana.svg.png');} .ns-0 h2 #Akha::before, .ns-0 h2#Akha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_the_Akha_National_Development_Party.svg/40px-Flag_of_the_Akha_National_Development_Party.svg.png');} .ns-0 h2 #Akkala_Sami::before, .ns-0 h2#Akkala_Sami::before, .ns-0 h2 #Inari_Sami::before, .ns-0 h2#Inari_Sami::before, .ns-0 h2 #Kemi_Sami::before, .ns-0 h2#Kemi_Sami::before, .ns-0 h2 #Kildin_Sami::before, .ns-0 h2#Kildin_Sami::before, .ns-0 h2 #Lule_Sami::before, .ns-0 h2#Lule_Sami::before, .ns-0 h2 #Northern_Sami::before, .ns-0 h2#Northern_Sami::before, .ns-0 h2 #Pite_Sami::before, .ns-0 h2#Pite_Sami::before, .ns-0 h2 #Skolt_Sami::before, .ns-0 h2#Skolt_Sami::before, .ns-0 h2 #Southern_Sami::before, .ns-0 h2#Southern_Sami::before, .ns-0 h2 #Ter_Sami::before, .ns-0 h2#Ter_Sami::before, .ns-0 h2 #Ume_Sami::before, .ns-0 h2#Ume_Sami::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Sami_flag.svg/40px-Sami_flag.svg.png');} .ns-0 h2 #Aklanon::before, .ns-0 h2#Aklanon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/90/PH-AKL_Flag.png/40px-PH-AKL_Flag.png');} .ns-0 h2 #Albanian::before, .ns-0 h2#Albanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_Albania.svg/40px-Flag_of_Albania.svg.png');} .ns-0 h2 #Alemannic_German::before, .ns-0 h2#Alemannic_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_Switzerland_(Pantone).svg/40px-Flag_of_Switzerland_(Pantone).svg.png');} .ns-0 h2 #Aleut::before, .ns-0 h2#Aleut::before, .ns-0 h2 #Inupiaq::before, .ns-0 h2#Inupiaq::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Alaska.svg/40px-Flag_of_Alaska.svg.png');} .ns-0 h2 #Algerian_Arabic::before, .ns-0 h2#Algerian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Algeria.svg/40px-Flag_of_Algeria.svg.png');} .ns-0 h2 #Ambonese_Malay::before, .ns-0 h2#Ambonese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Lambang_Ambon.png/28px-Lambang_Ambon.png');} .ns-0 h2 #American_Sign_Language::before, .ns-0 h2#American_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Flag_of_the_United_States.svg/40px-Flag_of_the_United_States.svg.png');} .ns-0 h2 #Amharic::before, .ns-0 h2#Amharic::before, .ns-0 h2 #Argobba::before, .ns-0 h2#Argobba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_Ethiopia.svg/40px-Flag_of_Ethiopia.svg.png');} .ns-0 h2 #Amis::before, .ns-0 h2#Amis::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Emblem_of_Hualien_County_2010.svg/37px-Emblem_of_Hualien_County_2010.svg.png');} .ns-0 h2 #Ancient_Greek::before, .ns-0 h2#Ancient_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/58/Byzantine_imperial_flag,_14th_century,_square.svg/37px-Byzantine_imperial_flag,_14th_century,_square.svg.png');} .ns-0 h2 #Andalusian_Arabic::before, .ns-0 h2#Andalusian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Green-White_Flag.svg/40px-Green-White_Flag.svg.png');} .ns-0 h2 #Angevin::before, .ns-0 h2#Angevin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ad/Flag_of_Anjou.svg/40px-Flag_of_Anjou.svg.png');} .ns-0 h2 #Angika::before, .ns-0 h2#Angika::before, .ns-0 h2 #Magahi::before, .ns-0 h2#Magahi::before, .ns-0 h2 #Maithili::before, .ns-0 h2#Maithili::before, .ns-0 h2 #Santali::before, .ns-0 h2#Santali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Jharkhand_Rajakiya_Chihna.svg/40px-Jharkhand_Rajakiya_Chihna.svg.png');} .ns-0 h2 #Angolar::before, .ns-0 h2#Angolar::before, .ns-0 h2 #Sãotomense::before, .ns-0 h2#Sãotomense::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_São_Tomé_and_Príncipe.svg/40px-Flag_of_São_Tomé_and_Príncipe.svg.png');} .ns-0 h2 #Anguthimri::before, .ns-0 h2#Anguthimri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/04/Flag_of_Queensland.svg/40px-Flag_of_Queensland.svg.png');} .ns-0 h2 #Annobonese::before, .ns-0 h2#Annobonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Bandera_Annobon.png/40px-Bandera_Annobon.png');} .ns-0 h2 #Antigua_and_Barbuda_Creole_English::before, .ns-0 h2#Antigua_and_Barbuda_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Antigua_and_Barbuda.svg/40px-Flag_of_Antigua_and_Barbuda.svg.png');} .ns-0 h2 #Antillean_Creole::before, .ns-0 h2#Antillean_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Saint_Lucia.svg/40px-Flag_of_Saint_Lucia.svg.png');} .ns-0 h2 #Ao::before, .ns-0 h2#Ao::before, .ns-0 h2 #Naga_Pidgin::before, .ns-0 h2#Naga_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Unofficial_flag_of_Nagaland.svg/40px-Unofficial_flag_of_Nagaland.svg.png');} .ns-0 h2 #Arabic::before, .ns-0 h2#Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Flag_of_the_Arab_League.svg/40px-Flag_of_the_Arab_League.svg.png');} .ns-0 h2 #Aragonese::before, .ns-0 h2#Aragonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/18/Flag_of_Aragon.svg/40px-Flag_of_Aragon.svg.png');} .ns-0 h2 #Arapaho::before, .ns-0 h2#Arapaho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/85/Flag_of_Arapaho_Nation.svg/40px-Flag_of_Arapaho_Nation.svg.png');} .ns-0 h2 #Armenian::before, .ns-0 h2#Armenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Armenia.svg/40px-Flag_of_Armenia.svg.png');} .ns-0 h2 #Aromanian::before, .ns-0 h2#Aromanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/97/Aromanian_flag.svg/40px-Aromanian_flag.svg.png');} .ns-0 h2 #Asi::before, .ns-0 h2#Asi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/39/Flag_of_Banton,_Romblon.png/40px-Flag_of_Banton,_Romblon.png');} .ns-0 h2 #Assamese::before, .ns-0 h2#Assamese::before, .ns-0 h2 #Bodo_\(India\)::before, .ns-0 h2#Bodo_\(India\)::before, .ns-0 h2 #Gujarati::before, .ns-0 h2#Gujarati::before, .ns-0 h2 #Hindi::before, .ns-0 h2#Hindi::before, .ns-0 h2 #Malayalam::before, .ns-0 h2#Malayalam::before, .ns-0 h2 #Marathi::before, .ns-0 h2#Marathi::before, .ns-0 h2 #Telugu::before, .ns-0 h2#Telugu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_India.svg/40px-Flag_of_India.svg.png');} .ns-0 h2 #Assyrian_Neo-Aramaic::before, .ns-0 h2#Assyrian_Neo-Aramaic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_the_Assyrians_(gold_and_blue_Assur).svg/40px-Flag_of_the_Assyrians_(gold_and_blue_Assur).svg.png');} .ns-0 h2 #Asturian::before, .ns-0 h2#Asturian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_Asturias.svg/40px-Flag_of_Asturias.svg.png');} .ns-0 h2 #Atayal::before, .ns-0 h2#Atayal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_New_Taipei_City.svg/40px-Flag_of_New_Taipei_City.svg.png');} .ns-0 h2 #Atikamekw::before, .ns-0 h2#Atikamekw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Flag_of_Quebec.svg/40px-Flag_of_Quebec.svg.png');} .ns-0 h2 #Aukan::before, .ns-0 h2#Aukan::before, .ns-0 h2 #Saramaccan::before, .ns-0 h2#Saramaccan::before, .ns-0 h2 #Sranan_Tongo::before, .ns-0 h2#Sranan_Tongo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/60/Flag_of_Suriname.svg/40px-Flag_of_Suriname.svg.png');} .ns-0 h2 #Australian_Kriol::before, .ns-0 h2#Australian_Kriol::before, .ns-0 h2 #Torres_Strait_Creole::before, .ns-0 h2#Torres_Strait_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Australian_Aboriginal_Flag.svg/40px-Australian_Aboriginal_Flag.svg.png');} .ns-0 h2 #Avar::before, .ns-0 h2#Avar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Flag_of_Avars.svg/40px-Flag_of_Avars.svg.png');} .ns-0 h2 #Avestan::before, .ns-0 h2#Avestan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Faravahar-Gold.svg/40px-Faravahar-Gold.svg.png');} .ns-0 h2 #Awadhi::before, .ns-0 h2#Awadhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Flag_of_Awadh.svg/40px-Flag_of_Awadh.svg.png');} .ns-0 h2 #Aymara::before, .ns-0 h2#Aymara::before, .ns-0 h2 #Bolivian_Sign_Language::before, .ns-0 h2#Bolivian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_Bolivia_(state).svg/40px-Flag_of_Bolivia_(state).svg.png');} .ns-0 h2 #Azerbaijani::before, .ns-0 h2#Azerbaijani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_Azerbaijan.svg/40px-Flag_of_Azerbaijan.svg.png');} .ns-0 h2 #Baba_Malay::before, .ns-0 h2#Baba_Malay::before, .ns-0 h2 #Singapore_Sign_Language::before, .ns-0 h2#Singapore_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Singapore.svg/40px-Flag_of_Singapore.svg.png');} .ns-0 h2 #Bacanese_Malay::before, .ns-0 h2#Bacanese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Bendera_Sultan_Bacan.svg/40px-Bendera_Sultan_Bacan.svg.png');} .ns-0 h2 #Badaga::before, .ns-0 h2#Badaga::before, .ns-0 h2 #Tamil::before, .ns-0 h2#Tamil::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Seal_of_Tamil_Nadu.svg/40px-Seal_of_Tamil_Nadu.svg.png');} .ns-0 h2 #Bagheli::before, .ns-0 h2#Bagheli::before, .ns-0 h2 #Bundeli::before, .ns-0 h2#Bundeli::before, .ns-0 h2 #Korku::before, .ns-0 h2#Korku::before, .ns-0 h2 #Malvi::before, .ns-0 h2#Malvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Emblem_of_Madhya_Pradesh.svg/40px-Emblem_of_Madhya_Pradesh.svg.png');} .ns-0 h2 #Baharna_Arabic::before, .ns-0 h2#Baharna_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Bahrain.svg/40px-Flag_of_Bahrain.svg.png');} .ns-0 h2 #Bahnar::before, .ns-0 h2#Bahnar::before, .ns-0 h2 #Hrê::before, .ns-0 h2#Hrê::before, .ns-0 h2 #Vietnamese::before, .ns-0 h2#Vietnamese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Vietnam.svg/40px-Flag_of_Vietnam.svg.png');} .ns-0 h2 #Bajan::before, .ns-0 h2#Bajan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Flag_of_Barbados.svg/40px-Flag_of_Barbados.svg.png');} .ns-0 h2 #Balinese::before, .ns-0 h2#Balinese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Historical_Flag_of_Bali.png/40px-Historical_Flag_of_Bali.png');} .ns-0 h2 #Balinese_Malay::before, .ns-0 h2#Balinese_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Coat_of_arms_of_Bali.svg/35px-Coat_of_arms_of_Bali.svg.png');} .ns-0 h2 #Balti::before, .ns-0 h2#Balti::before, .ns-0 h2 #Burushaski::before, .ns-0 h2#Burushaski::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Hunza.svg/40px-Flag_of_Hunza.svg.png');} .ns-0 h2 #Baluchi::before, .ns-0 h2#Baluchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Balochistan.svg/40px-Flag_of_Balochistan.svg.png');} .ns-0 h2 #Bambara::before, .ns-0 h2#Bambara::before, .ns-0 h2 #Soninke::before, .ns-0 h2#Soninke::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_Mali.svg/40px-Flag_of_Mali.svg.png');} .ns-0 h2 #Banjarese::before, .ns-0 h2#Banjarese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Banjar_Sultanate_Flag.svg/40px-Banjar_Sultanate_Flag.svg.png');} .ns-0 h2 #Baoule::before, .ns-0 h2#Baoule::before, .ns-0 h2 #Dyula::before, .ns-0 h2#Dyula::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Côte_d'Ivoire.svg/40px-Flag_of_Côte_d'Ivoire.svg.png");} .ns-0 h2 #Bari::before, .ns-0 h2#Bari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Flag_of_the_Bari_people.svg/40px-Flag_of_the_Bari_people.svg.png');} .ns-0 h2 #Barikanchi::before, .ns-0 h2#Barikanchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Flag_of_the_Nigerian_Armed_Forces.svg/40px-Flag_of_the_Nigerian_Armed_Forces.svg.png');} .ns-0 h2 #Bashkir::before, .ns-0 h2#Bashkir::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Flag_of_Bashkortostan.svg/40px-Flag_of_Bashkortostan.svg.png');} .ns-0 h2 #Basque::before, .ns-0 h2#Basque::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Flag_of_the_Basque_Country.svg/40px-Flag_of_the_Basque_Country.svg.png');} .ns-0 h2 #Bavarian::before, .ns-0 h2#Bavarian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_Bavaria_(lozengy).svg/40px-Flag_of_Bavaria_(lozengy).svg.png');} .ns-0 h2 #Beja::before, .ns-0 h2#Beja::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_the_Beja_Congress.svg/40px-Flag_of_the_Beja_Congress.svg.png');} .ns-0 h2 #Belarusian::before, .ns-0 h2#Belarusian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/85/Flag_of_Belarus.svg/40px-Flag_of_Belarus.svg.png');} .ns-0 h2 #Belizean_Creole::before, .ns-0 h2#Belizean_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Flag_of_Belize.svg/40px-Flag_of_Belize.svg.png');} .ns-0 h2 #Bella_Coola::before, .ns-0 h2#Bella_Coola::before, .ns-0 h2 #Halkomelem::before, .ns-0 h2#Halkomelem::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_British_Columbia.svg/40px-Flag_of_British_Columbia.svg.png');} .ns-0 h2 #Bemba::before, .ns-0 h2#Bemba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_Zambia.svg/40px-Flag_of_Zambia.svg.png');} .ns-0 h2 #Bengali::before, .ns-0 h2#Bengali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Bengali_language.svg/40px-Bengali_language.svg.png');} .ns-0 h2 #Berau_Malay::before, .ns-0 h2#Berau_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7f/East_Borneo_Sultanate_Flags.png/40px-East_Borneo_Sultanate_Flags.png');} .ns-0 h2 #Berbice_Creole_Dutch::before, .ns-0 h2#Berbice_Creole_Dutch::before, .ns-0 h2 #Skepi_Creole_Dutch::before, .ns-0 h2#Skepi_Creole_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_the_Dutch_West_India_Company.svg/40px-Flag_of_the_Dutch_West_India_Company.svg.png');} .ns-0 h2 #Betawi::before, .ns-0 h2#Betawi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Coat_of_arms_of_Jakarta.svg/30px-Coat_of_arms_of_Jakarta.svg.png');} .ns-0 h2 #Bhojpuri::before, .ns-0 h2#Bhojpuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Seal_of_Uttar_Pradesh.svg/40px-Seal_of_Uttar_Pradesh.svg.png');} .ns-0 h2 #Bihari::before, .ns-0 h2#Bihari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Seal_of_Bihar.svg/40px-Seal_of_Bihar.svg.png');} .ns-0 h2 #Bima::before, .ns-0 h2#Bima::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Bendera_Kesultanan_Bima.png/40px-Bendera_Kesultanan_Bima.png');} .ns-0 h2 #Binukid::before, .ns-0 h2#Binukid::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Flag_of_the_Province_of_Bukidnon.svg/40px-Flag_of_the_Province_of_Bukidnon.svg.png');} .ns-0 h2 #Bislama::before, .ns-0 h2#Bislama::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Vanuatu.svg/40px-Flag_of_Vanuatu.svg.png');} .ns-0 h2 #Blackfoot::before, .ns-0 h2#Blackfoot::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Flag_of_the_Blackfoot_Confederacy.jpg/40px-Flag_of_the_Blackfoot_Confederacy.jpg');} .ns-0 h2 #Boon::before, .ns-0 h2#Boon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Jubaland_(Somalia).svg/40px-Flag_of_Jubaland_(Somalia).svg.png');} .ns-0 h2 #Bourbonnais-Berrichon::before, .ns-0 h2#Bourbonnais-Berrichon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Flag_of_Bourbonnais.svg/40px-Flag_of_Bourbonnais.svg.png');} .ns-0 h2 #Bourguignon::before, .ns-0 h2#Bourguignon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Bourgogne.svg/40px-Flag_of_Bourgogne.svg.png');} .ns-0 h2 #Brahui::before, .ns-0 h2#Brahui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/FlagofKalat.svg/40px-FlagofKalat.svg.png');} .ns-0 h2 #Brazilian_Sign_Language::before, .ns-0 h2#Brazilian_Sign_Language::before, .ns-0 h2 #Old_Tupi::before, .ns-0 h2#Old_Tupi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/05/Flag_of_Brazil.svg/40px-Flag_of_Brazil.svg.png');} .ns-0 h2 #Breton::before, .ns-0 h2#Breton::before, .ns-0 h2 #Gallo::before, .ns-0 h2#Gallo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Flag_of_Brittany.svg/40px-Flag_of_Brittany.svg.png');} .ns-0 h2 #Brokkat::before, .ns-0 h2#Brokkat::before, .ns-0 h2 #Bumthangkha::before, .ns-0 h2#Bumthangkha::before, .ns-0 h2 #Chocangaca::before, .ns-0 h2#Chocangaca::before, .ns-0 h2 #Dzala::before, .ns-0 h2#Dzala::before, .ns-0 h2 #Dzongkha::before, .ns-0 h2#Dzongkha::before, .ns-0 h2 #Kurtöp::before, .ns-0 h2#Kurtöp::before, .ns-0 h2 #Tshangla::before, .ns-0 h2#Tshangla::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/91/Flag_of_Bhutan.svg/40px-Flag_of_Bhutan.svg.png');} .ns-0 h2 #Brooke\'s_Point_Palawano::before, .ns-0 h2#Brooke\'s_Point_Palawano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Flag_of_Palawan,_Philippines.svg/40px-Flag_of_Palawan,_Philippines.svg.png');} .ns-0 h2 #Brunei_Malay::before, .ns-0 h2#Brunei_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Flag_of_Brunei.svg/40px-Flag_of_Brunei.svg.png');} .ns-0 h2 #Bulgarian::before, .ns-0 h2#Bulgarian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Bulgaria.svg/40px-Flag_of_Bulgaria.svg.png');} .ns-0 h2 #Bunun::before, .ns-0 h2#Bunun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Nantou_County.svg/40px-Flag_of_Nantou_County.svg.png');} .ns-0 h2 #Burmese::before, .ns-0 h2#Burmese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Flag_of_Myanmar.svg/40px-Flag_of_Myanmar.svg.png');} .ns-0 h2 #Buryat::before, .ns-0 h2#Buryat::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/68/Flag_of_Buryatia.svg/40px-Flag_of_Buryatia.svg.png');} .ns-0 h2 #Butuanon::before, .ns-0 h2#Butuanon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Butuancityflag.jpg/40px-Butuancityflag.jpg');} .ns-0 h2 #Cahuilla::before, .ns-0 h2#Cahuilla::before, .ns-0 h2 #Northern_Valley_Yokuts::before, .ns-0 h2#Northern_Valley_Yokuts::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_California.svg/40px-Flag_of_California.svg.png');} .ns-0 h2 #Calabrian_Greek::before, .ns-0 h2#Calabrian_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Flag_of_Calabria.svg/40px-Flag_of_Calabria.svg.png');} .ns-0 h2 #Caluyanun::before, .ns-0 h2#Caluyanun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Caluya,_Antique.png/40px-Flag_of_Caluya,_Antique.png');} .ns-0 h2 #Caló::before, .ns-0 h2#Caló::before, .ns-0 h2 #Romani::before, .ns-0 h2#Romani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_the_Romani_people.svg/40px-Flag_of_the_Romani_people.svg.png');} .ns-0 h2 #Cameroon_Pidgin::before, .ns-0 h2#Cameroon_Pidgin::before, .ns-0 h2 #Ghomala\'::before, .ns-0 h2#Ghomala\'::before, .ns-0 h2 #Matal::before, .ns-0 h2#Matal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Flag_of_Cameroon.svg/40px-Flag_of_Cameroon.svg.png');} .ns-0 h2 #Cantonese::before, .ns-0 h2#Cantonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_Hong_Kong.svg/40px-Flag_of_Hong_Kong.svg.png');} .ns-0 h2 #Caribbean_Hindustani::before, .ns-0 h2#Caribbean_Hindustani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Suriname_and_Guyana.png/40px-Flag_of_Suriname_and_Guyana.png');} .ns-0 h2 #Carolinian::before, .ns-0 h2#Carolinian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_the_Northern_Mariana_Islands.svg/40px-Flag_of_the_Northern_Mariana_Islands.svg.png');} .ns-0 h2 #Carpathian_Rusyn::before, .ns-0 h2#Carpathian_Rusyn::before, .ns-0 h2 #Pannonian_Rusyn::before, .ns-0 h2#Pannonian_Rusyn::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Rusyns_2007.svg/40px-Flag_of_Rusyns_2007.svg.png');} .ns-0 h2 #Catalan::before, .ns-0 h2#Catalan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Catalonia.svg/40px-Flag_of_Catalonia.svg.png');} .ns-0 h2 #Cavineña::before, .ns-0 h2#Cavineña::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Beni.svg/40px-Flag_of_Beni.svg.png');} .ns-0 h2 #Cebuano::before, .ns-0 h2#Cebuano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Cebu_(province).svg/40px-Flag_of_Cebu_(province).svg.png');} .ns-0 h2 #Central_Atlas_Tamazight::before, .ns-0 h2#Central_Atlas_Tamazight::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Berber_flag.svg/40px-Berber_flag.svg.png');} .ns-0 h2 #Central_Bikol::before, .ns-0 h2#Central_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_the_Katipuneros_of_Bicol.svg/40px-Flag_of_the_Katipuneros_of_Bicol.svg.png');} .ns-0 h2 #Central_Dusun::before, .ns-0 h2#Central_Dusun::before, .ns-0 h2 #Sabah_Malay::before, .ns-0 h2#Sabah_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b5/Flag_of_Sabah.svg/40px-Flag_of_Sabah.svg.png');} .ns-0 h2 #Central_Kurdish::before, .ns-0 h2#Central_Kurdish::before, .ns-0 h2 #Northern_Kurdish::before, .ns-0 h2#Northern_Kurdish::before, .ns-0 h2 #Southern_Kurdish::before, .ns-0 h2#Southern_Kurdish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/35/Flag_of_Kurdistan.svg/40px-Flag_of_Kurdistan.svg.png');} .ns-0 h2 #Central_Mansi::before, .ns-0 h2#Central_Mansi::before, .ns-0 h2 #Eastern_Khanty::before, .ns-0 h2#Eastern_Khanty::before, .ns-0 h2 #Northern_Khanty::before, .ns-0 h2#Northern_Khanty::before, .ns-0 h2 #Northern_Mansi::before, .ns-0 h2#Northern_Mansi::before, .ns-0 h2 #Southern_Khanty::before, .ns-0 h2#Southern_Khanty::before, .ns-0 h2 #Southern_Mansi::before, .ns-0 h2#Southern_Mansi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Yugra.svg/40px-Flag_of_Yugra.svg.png');} .ns-0 h2 #Central_Nahuatl::before, .ns-0 h2#Central_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_Tlaxcala.svg/40px-Flag_of_Tlaxcala.svg.png');} .ns-0 h2 #Chadian_Arabic::before, .ns-0 h2#Chadian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Flag_of_Chad.svg/40px-Flag_of_Chad.svg.png');} .ns-0 h2 #Chakma::before, .ns-0 h2#Chakma::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Chakma_Flag.jpg/40px-Chakma_Flag.jpg');} .ns-0 h2 #Chaldean_Neo-Aramaic::before, .ns-0 h2#Chaldean_Neo-Aramaic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/95/Chaldean_flag.svg/40px-Chaldean_flag.svg.png');} .ns-0 h2 #Chamorro::before, .ns-0 h2#Chamorro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/07/Flag_of_Guam.svg/40px-Flag_of_Guam.svg.png');} .ns-0 h2 #Champenois::before, .ns-0 h2#Champenois::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Flag_of_Champagne-Ardenne.svg/40px-Flag_of_Champagne-Ardenne.svg.png');} .ns-0 h2 #Chavacano::before, .ns-0 h2#Chavacano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Zamboanga.jpg/40px-Flag_of_Zamboanga.jpg');} .ns-0 h2 #Chechen::before, .ns-0 h2#Chechen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Flag_of_the_Chechen_Republic.svg/40px-Flag_of_the_Chechen_Republic.svg.png');} .ns-0 h2 #Cherokee::before, .ns-0 h2#Cherokee::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_the_Cherokee_Nation.svg/40px-Flag_of_the_Cherokee_Nation.svg.png');} .ns-0 h2 #Cheyenne::before, .ns-0 h2#Cheyenne::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e7/Flag_of_Northern_Cheyenne.svg/40px-Flag_of_Northern_Cheyenne.svg.png');} .ns-0 h2 #Chhattisgarhi::before, .ns-0 h2#Chhattisgarhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Coat_of_arms_of_Chhattisgarh.svg/40px-Coat_of_arms_of_Chhattisgarh.svg.png');} .ns-0 h2 #Chibcha::before, .ns-0 h2#Chibcha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Bandera_de_la_confederacion_muisca.png/33px-Bandera_de_la_confederacion_muisca.png');} .ns-0 h2 #Chichewa::before, .ns-0 h2#Chichewa::before, .ns-0 h2 #Tumbuka::before, .ns-0 h2#Tumbuka::before, .ns-0 h2 #Yao_\(Africa\)::before, .ns-0 h2#Yao_\(Africa\)::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Flag_of_Malawi.svg/40px-Flag_of_Malawi.svg.png');} .ns-0 h2 #Chickasaw::before, .ns-0 h2#Chickasaw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/74/Flag_of_the_Chickasaw_Nation.svg/40px-Flag_of_the_Chickasaw_Nation.svg.png');} .ns-0 h2 #Chimwiini::before, .ns-0 h2#Chimwiini::before, .ns-0 h2 #Maay::before, .ns-0 h2#Maay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Flag_of_South_West_State_of_Somalia.svg/40px-Flag_of_South_West_State_of_Somalia.svg.png');} .ns-0 h2 #Chinese::before, .ns-0 h2#Chinese::before, .ns-0 h2 #Chinese_Pidgin_English::before, .ns-0 h2#Chinese_Pidgin_English::before, .ns-0 h2 #Mandarin::before, .ns-0 h2#Mandarin::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_the_People's_Republic_of_China.svg/40px-Flag_of_the_People's_Republic_of_China.svg.png");} .ns-0 h2 #Chittagonian::before, .ns-0 h2#Chittagonian::before, .ns-0 h2 #Sylheti::before, .ns-0 h2#Sylheti::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Flag_of_Bangladesh.svg/40px-Flag_of_Bangladesh.svg.png');} .ns-0 h2 #Choctaw::before, .ns-0 h2#Choctaw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Choctaw_flag.svg/40px-Choctaw_flag.svg.png');} .ns-0 h2 #Chukchi::before, .ns-0 h2#Chukchi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Flag_of_Chukotka.svg/40px-Flag_of_Chukotka.svg.png');} .ns-0 h2 #Church_Slavonic::before, .ns-0 h2#Church_Slavonic::before, .ns-0 h2 #Old_Church_Slavonic::before, .ns-0 h2#Old_Church_Slavonic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Bulgarian_Orthodox_Cross_6.svg/33px-Bulgarian_Orthodox_Cross_6.svg.png');} .ns-0 h2 #Chuukese::before, .ns-0 h2#Chuukese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Flag_of_Chuuk.svg/40px-Flag_of_Chuuk.svg.png');} .ns-0 h2 #Chuvash::before, .ns-0 h2#Chuvash::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Flag_of_Chuvashia.svg/40px-Flag_of_Chuvashia.svg.png');} .ns-0 h2 #Cimbrian::before, .ns-0 h2#Cimbrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_the_Province_of_Trento.svg/40px-Flag_of_the_Province_of_Trento.svg.png');} .ns-0 h2 #Classical_Nahuatl::before, .ns-0 h2#Classical_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Aztec_Triple_Alliance.png/40px-Aztec_Triple_Alliance.png');} .ns-0 h2 #Coptic::before, .ns-0 h2#Coptic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Coptic_cross.svg/35px-Coptic_cross.svg.png');} .ns-0 h2 #Cornish::before, .ns-0 h2#Cornish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Cornwall.svg/40px-Flag_of_Cornwall.svg.png');} .ns-0 h2 #Corsican::before, .ns-0 h2#Corsican::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Flag_of_Corsica.svg/40px-Flag_of_Corsica.svg.png');} .ns-0 h2 #Cree::before, .ns-0 h2#Cree::before, .ns-0 h2 #Dogrib::before, .ns-0 h2#Dogrib::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_the_Northwest_Territories.svg/40px-Flag_of_the_Northwest_Territories.svg.png');} .ns-0 h2 #Creek::before, .ns-0 h2#Creek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/State_of_Muskogee_(Florida,_1799-1803).svg/40px-State_of_Muskogee_(Florida,_1799-1803).svg.png');} .ns-0 h2 #Crimean_Tatar::before, .ns-0 h2#Crimean_Tatar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_the_Crimean_Tatar_people.svg/40px-Flag_of_the_Crimean_Tatar_people.svg.png');} .ns-0 h2 #Croatian_Sign_Language::before, .ns-0 h2#Croatian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Flag_of_Croatia.svg/40px-Flag_of_Croatia.svg.png');} .ns-0 h2 #Cuban_Sign_Language::before, .ns-0 h2#Cuban_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Flag_of_Cuba.svg/40px-Flag_of_Cuba.svg.png');} .ns-0 h2 #Cubeo::before, .ns-0 h2#Cubeo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Flag_of_Vaupés.svg/40px-Flag_of_Vaupés.svg.png');} .ns-0 h2 #Cuyunon::before, .ns-0 h2#Cuyunon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Cuyo,_Palawan.png/40px-Flag_of_Cuyo,_Palawan.png');} .ns-0 h2 #Cypriot_Arabic::before, .ns-0 h2#Cypriot_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_Cyprus.svg/40px-Flag_of_Cyprus.svg.png');} .ns-0 h2 #Czech::before, .ns-0 h2#Czech::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_Czech_Republic.svg/40px-Flag_of_the_Czech_Republic.svg.png');} .ns-0 h2 #Dahalik::before, .ns-0 h2#Dahalik::before, .ns-0 h2 #Tigre::before, .ns-0 h2#Tigre::before, .ns-0 h2 #Tigrinya::before, .ns-0 h2#Tigrinya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/29/Flag_of_Eritrea.svg/40px-Flag_of_Eritrea.svg.png');} .ns-0 h2 #Dakota::before, .ns-0 h2#Dakota::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ee/Flag_of_North_Dakota.svg/40px-Flag_of_North_Dakota.svg.png');} .ns-0 h2 #Dalmatian::before, .ns-0 h2#Dalmatian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Kingdom_of_Dalmatia_(1852-1860).svg/40px-Flag_of_Kingdom_of_Dalmatia_(1852-1860).svg.png');} .ns-0 h2 #Danish::before, .ns-0 h2#Danish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Flag_of_Denmark.svg/40px-Flag_of_Denmark.svg.png');} .ns-0 h2 #Dhivehi::before, .ns-0 h2#Dhivehi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Maldives.svg/40px-Flag_of_Maldives.svg.png');} .ns-0 h2 #Dhofari_Arabic::before, .ns-0 h2#Dhofari_Arabic::before, .ns-0 h2 #Omani_Arabic::before, .ns-0 h2#Omani_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_Oman.svg/40px-Flag_of_Oman.svg.png');} .ns-0 h2 #Dinka::before, .ns-0 h2#Dinka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Flag_of_Dinka_people.svg/40px-Flag_of_Dinka_people.svg.png');} .ns-0 h2 #Dutch::before, .ns-0 h2#Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_the_Netherlands.svg/40px-Flag_of_the_Netherlands.svg.png');} .ns-0 h2 #East_Circassian::before, .ns-0 h2#East_Circassian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Kabardino-Balkaria.svg/40px-Flag_of_Kabardino-Balkaria.svg.png');} .ns-0 h2 #East_Futuna::before, .ns-0 h2#East_Futuna::before, .ns-0 h2 #Wallisian::before, .ns-0 h2#Wallisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Flag_of_Wallis_and_Futuna.svg/40px-Flag_of_Wallis_and_Futuna.svg.png');} .ns-0 h2 #Eastern_Durango_Nahuatl::before, .ns-0 h2#Eastern_Durango_Nahuatl::before, .ns-0 h2 #Western_Durango_Nahuatl::before, .ns-0 h2#Western_Durango_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Coat_of_arms_of_Durango.svg/35px-Coat_of_arms_of_Durango.svg.png');} .ns-0 h2 #Eastern_Maninkakan::before, .ns-0 h2#Eastern_Maninkakan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Flag_of_Guinea.svg/40px-Flag_of_Guinea.svg.png');} .ns-0 h2 #Eastern_Mari::before, .ns-0 h2#Eastern_Mari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Flag_of_Mari_El.svg/40px-Flag_of_Mari_El.svg.png');} .ns-0 h2 #Edo::before, .ns-0 h2#Edo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Edo_State_Flag.png/40px-Edo_State_Flag.png');} .ns-0 h2 #Egyptian::before, .ns-0 h2#Egyptian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Ancient_Egyptian_Culture_Flag.webp/40px-Ancient_Egyptian_Culture_Flag.webp');} .ns-0 h2 #Egyptian_Arabic::before, .ns-0 h2#Egyptian_Arabic::before, .ns-0 h2 #Nobiin::before, .ns-0 h2#Nobiin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Egypt.svg/40px-Flag_of_Egypt.svg.png');} .ns-0 h2 #Elfdalian::before, .ns-0 h2#Elfdalian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Älvdalen_vapen.svg/33px-Älvdalen_vapen.svg.png');} .ns-0 h2 #Emilian::before, .ns-0 h2#Emilian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Flag_of_Bologna_2.png/40px-Flag_of_Bologna_2.png');} .ns-0 h2 #Erzya::before, .ns-0 h2#Erzya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Erzya_Flag.svg/40px-Erzya_Flag.svg.png');} .ns-0 h2 #Ese::before, .ns-0 h2#Ese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Flag_Oro_new.png/40px-Flag_of_Flag_Oro_new.png');} .ns-0 h2 #Esperanto::before, .ns-0 h2#Esperanto::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f5/Flag_of_Esperanto.svg/40px-Flag_of_Esperanto.svg.png');} .ns-0 h2 #Estonian::before, .ns-0 h2#Estonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Flag_of_Estonia.svg/40px-Flag_of_Estonia.svg.png');} .ns-0 h2 #Evenki::before, .ns-0 h2#Evenki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_Evenks.svg/40px-Flag_of_Evenks.svg.png');} .ns-0 h2 #Ewe::before, .ns-0 h2#Ewe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_the_Ewe_people.svg/40px-Flag_of_the_Ewe_people.svg.png');} .ns-0 h2 #Extremaduran::before, .ns-0 h2#Extremaduran::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Flag_of_Extremadura,_Spain_(with_coat_of_arms).svg/40px-Flag_of_Extremadura,_Spain_(with_coat_of_arms).svg.png');} .ns-0 h2 #Fala::before, .ns-0 h2#Fala::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Bandera_de_Valverde_del_Fresno_(Cáceres).svg/40px-Bandera_de_Valverde_del_Fresno_(Cáceres).svg.png');} .ns-0 h2 #Fang_\(Bantu\)::before, .ns-0 h2#Fang_\(Bantu\)::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/04/Flag_of_Gabon.svg/40px-Flag_of_Gabon.svg.png');} .ns-0 h2 #Faroese::before, .ns-0 h2#Faroese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_Faroe_Islands.svg/40px-Flag_of_the_Faroe_Islands.svg.png');} .ns-0 h2 #Fiji_Hindi::before, .ns-0 h2#Fiji_Hindi::before, .ns-0 h2 #Fijian::before, .ns-0 h2#Fijian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Fiji.svg/40px-Flag_of_Fiji.svg.png');} .ns-0 h2 #Fingallian::before, .ns-0 h2#Fingallian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/22/Flag_of_County_Limerick.svg/40px-Flag_of_County_Limerick.svg.png');} .ns-0 h2 #Finnish::before, .ns-0 h2#Finnish::before, .ns-0 h2 #Finnish_Sign_Language::before, .ns-0 h2#Finnish_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Finland.svg/40px-Flag_of_Finland.svg.png');} .ns-0 h2 #Fon::before, .ns-0 h2#Fon::before, .ns-0 h2 #Gun::before, .ns-0 h2#Gun::before, .ns-0 h2 #Ifè::before, .ns-0 h2#Ifè::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_Benin.svg/40px-Flag_of_Benin.svg.png');} .ns-0 h2 #Forest_Nenets::before, .ns-0 h2#Forest_Nenets::before, .ns-0 h2 #Tundra_Nenets::before, .ns-0 h2#Tundra_Nenets::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/15/Flag_of_Nenets_Autonomous_District.svg/40px-Flag_of_Nenets_Autonomous_District.svg.png');} .ns-0 h2 #Franc-Comtois::before, .ns-0 h2#Franc-Comtois::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/96/Flag_of_Franche-Comté.svg/40px-Flag_of_Franche-Comté.svg.png');} .ns-0 h2 #Franco-Provençal::before, .ns-0 h2#Franco-Provençal::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/9/90/Flag_of_Valle_d'Aosta.svg/40px-Flag_of_Valle_d'Aosta.svg.png");} .ns-0 h2 #French::before, .ns-0 h2#French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_France.svg/40px-Flag_of_France.svg.png');} .ns-0 h2 #Friulian::before, .ns-0 h2#Friulian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Bandiere_dal_Friûl.svg/40px-Bandiere_dal_Friûl.svg.png');} .ns-0 h2 #Fula::before, .ns-0 h2#Fula::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/NE-CM-BF-GM_flag.svg/40px-NE-CM-BF-GM_flag.svg.png');} .ns-0 h2 #Fur::before, .ns-0 h2#Fur::before, .ns-0 h2 #Sudanese_Arabic::before, .ns-0 h2#Sudanese_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Sudan.svg/40px-Flag_of_Sudan.svg.png');} .ns-0 h2 #Futuna-Aniwa::before, .ns-0 h2#Futuna-Aniwa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Tafea_Province_Flag.svg/40px-Tafea_Province_Flag.svg.png');} .ns-0 h2 #Fyam::before, .ns-0 h2#Fyam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Plateau_State_Flag.jpg/40px-Plateau_State_Flag.jpg');} .ns-0 h2 #Ga::before, .ns-0 h2#Ga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Flag_of_Accra.svg/40px-Flag_of_Accra.svg.png');} .ns-0 h2 #Gabadi::before, .ns-0 h2#Gabadi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Central_Province,_Papua_New_Guinea.svg/40px-Flag_of_Central_Province,_Papua_New_Guinea.svg.png');} .ns-0 h2 #Gagauz::before, .ns-0 h2#Gagauz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/69/Flag_of_Gagauzia.svg/40px-Flag_of_Gagauzia.svg.png');} .ns-0 h2 #Galician::before, .ns-0 h2#Galician::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_Galicia.svg/40px-Flag_of_Galicia.svg.png');} .ns-0 h2 #Gallo-Italic_of_Basilicata::before, .ns-0 h2#Gallo-Italic_of_Basilicata::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_for_the_Lombards_of_Basilicata.png/40px-Flag_for_the_Lombards_of_Basilicata.png');} .ns-0 h2 #Gallo-Italic_of_Sicily::before, .ns-0 h2#Gallo-Italic_of_Sicily::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/30/Flag_for_the_Lombards_of_Sicily.png/40px-Flag_for_the_Lombards_of_Sicily.png');} .ns-0 h2 #Gamilaraay::before, .ns-0 h2#Gamilaraay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_New_South_Wales.svg/40px-Flag_of_New_South_Wales.svg.png');} .ns-0 h2 #Garhwali::before, .ns-0 h2#Garhwali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Flag_of_the_Princely_State_of_Tehri_Garhwal.svg/40px-Flag_of_the_Princely_State_of_Tehri_Garhwal.svg.png');} .ns-0 h2 #Garifuna::before, .ns-0 h2#Garifuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_Garifuna.svg/40px-Flag_of_Garifuna.svg.png');} .ns-0 h2 #Garo::before, .ns-0 h2#Garo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Garo_hills.png/40px-Garo_hills.png');} .ns-0 h2 #Ge\'ez::before, .ns-0 h2#Ge\'ez::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Lion_of_Judah_emblem_of_the_Ethiopian_Empire.svg/40px-Lion_of_Judah_emblem_of_the_Ethiopian_Empire.svg.png');} .ns-0 h2 #Georgian::before, .ns-0 h2#Georgian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Georgia.svg/40px-Flag_of_Georgia.svg.png');} .ns-0 h2 #German::before, .ns-0 h2#German::before, .ns-0 h2 #German_Sign_Language::before, .ns-0 h2#German_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/40px-Flag_of_Germany.svg.png');} .ns-0 h2 #Ghadames::before, .ns-0 h2#Ghadames::before, .ns-0 h2 #Libyan_Arabic::before, .ns-0 h2#Libyan_Arabic::before, .ns-0 h2 #Nefusa::before, .ns-0 h2#Nefusa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/05/Flag_of_Libya.svg/40px-Flag_of_Libya.svg.png');} .ns-0 h2 #Gilbertese::before, .ns-0 h2#Gilbertese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Flag_of_Kiribati.svg/40px-Flag_of_Kiribati.svg.png');} .ns-0 h2 #Gorontalo::before, .ns-0 h2#Gorontalo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Coat_of_arms_of_Gorontalo.svg/35px-Coat_of_arms_of_Gorontalo.svg.png');} .ns-0 h2 #Greek::before, .ns-0 h2#Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Greece.svg/40px-Flag_of_Greece.svg.png');} .ns-0 h2 #Green_Hmong::before, .ns-0 h2#Green_Hmong::before, .ns-0 h2 #White_Hmong::before, .ns-0 h2#White_Hmong::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Hmong_Flag_(UNPO).svg/40px-Hmong_Flag_(UNPO).svg.png');} .ns-0 h2 #Greenlandic::before, .ns-0 h2#Greenlandic::before, .ns-0 h2 #West_Greenlandic_Pidgin::before, .ns-0 h2#West_Greenlandic_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Greenland.svg/40px-Flag_of_Greenland.svg.png');} .ns-0 h2 #Grenadian_Creole_English::before, .ns-0 h2#Grenadian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Grenada.svg/40px-Flag_of_Grenada.svg.png');} .ns-0 h2 #Guajajára::before, .ns-0 h2#Guajajára::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Bandeira_do_Maranhão.svg/40px-Bandeira_do_Maranhão.svg.png');} .ns-0 h2 #Guanche::before, .ns-0 h2#Guanche::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Flag_of_the_Canary_Islands.svg/40px-Flag_of_the_Canary_Islands.svg.png');} .ns-0 h2 #Guerrero_Amuzgo::before, .ns-0 h2#Guerrero_Amuzgo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Guerrero.svg/40px-Flag_of_Guerrero.svg.png');} .ns-0 h2 #Guianese_Creole::before, .ns-0 h2#Guianese_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/29/Flag_of_French_Guiana.svg/40px-Flag_of_French_Guiana.svg.png');} .ns-0 h2 #Guinea-Bissau_Creole::before, .ns-0 h2#Guinea-Bissau_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Guinea-Bissau.svg/40px-Flag_of_Guinea-Bissau.svg.png');} .ns-0 h2 #Gulf_Arabic::before, .ns-0 h2#Gulf_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_United_Arab_Emirates.svg/40px-Flag_of_the_United_Arab_Emirates.svg.png');} .ns-0 h2 #Gullah::before, .ns-0 h2#Gullah::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Black_American_Heritage_flag.svg/40px-Black_American_Heritage_flag.svg.png');} .ns-0 h2 #Gurindji::before, .ns-0 h2#Gurindji::before, .ns-0 h2 #Warlpiri::before, .ns-0 h2#Warlpiri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Flag_of_the_Northern_Territory.svg/40px-Flag_of_the_Northern_Territory.svg.png');} .ns-0 h2 #Gutnish::before, .ns-0 h2#Gutnish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Gotlands_län_vapenflagga.svg/37px-Gotlands_län_vapenflagga.svg.png');} .ns-0 h2 #Guyanese_Creole_English::before, .ns-0 h2#Guyanese_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Flag_of_Guyana.svg/40px-Flag_of_Guyana.svg.png');} .ns-0 h2 #Hadza::before, .ns-0 h2#Hadza::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/38/Flag_of_Tanzania.svg/40px-Flag_of_Tanzania.svg.png');} .ns-0 h2 #Haida::before, .ns-0 h2#Haida::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/CHN_Crest.png/33px-CHN_Crest.png');} .ns-0 h2 #Haitian_Creole::before, .ns-0 h2#Haitian_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/56/Flag_of_Haiti.svg/40px-Flag_of_Haiti.svg.png');} .ns-0 h2 #Hakka::before, .ns-0 h2#Hakka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Hakka_Party.svg/40px-Flag_of_Hakka_Party.svg.png');} .ns-0 h2 #Halia::before, .ns-0 h2#Halia::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e4/Flag_of_Bougainville.svg/40px-Flag_of_Bougainville.svg.png');} .ns-0 h2 #Harari::before, .ns-0 h2#Harari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Harari_Flag.svg/40px-Harari_Flag.svg.png');} .ns-0 h2 #Haryanvi::before, .ns-0 h2#Haryanvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Haryana.svg/40px-Flag_of_Haryana.svg.png');} .ns-0 h2 #Hassaniya_Arabic::before, .ns-0 h2#Hassaniya_Arabic::before, .ns-0 h2 #Zenaga::before, .ns-0 h2#Zenaga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/43/Flag_of_Mauritania.svg/40px-Flag_of_Mauritania.svg.png');} .ns-0 h2 #Hausa::before, .ns-0 h2#Hausa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_the_Hausa_people.svg/40px-Flag_of_the_Hausa_people.svg.png');} .ns-0 h2 #Hawaiian::before, .ns-0 h2#Hawaiian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Flag_of_Hawaii.svg/40px-Flag_of_Hawaii.svg.png');} .ns-0 h2 #Hebrew::before, .ns-0 h2#Hebrew::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Flag_of_Israel.svg/40px-Flag_of_Israel.svg.png');} .ns-0 h2 #Herero::before, .ns-0 h2#Herero::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Namibia,_Botswana_and_Angola.gif/40px-Namibia,_Botswana_and_Angola.gif');} .ns-0 h2 #Higaonon::before, .ns-0 h2#Higaonon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Ph_seal_misamis_oriental.2.png/40px-Ph_seal_misamis_oriental.2.png');} .ns-0 h2 #Hijazi_Arabic::before, .ns-0 h2#Hijazi_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Flag_of_Hejaz_(1920).svg/40px-Flag_of_Hejaz_(1920).svg.png');} .ns-0 h2 #Hiligaynon::before, .ns-0 h2#Hiligaynon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Flag_of_the_Province_of_Iloilo.svg/40px-Flag_of_the_Province_of_Iloilo.svg.png');} .ns-0 h2 #Hiri_Motu::before, .ns-0 h2#Hiri_Motu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_Port_Moresby.png/40px-Flag_of_Port_Moresby.png');} .ns-0 h2 #Hokkien::before, .ns-0 h2#Hokkien::before, .ns-0 h2 #Min_Nan::before, .ns-0 h2#Min_Nan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_the_Republic_of_China.svg/40px-Flag_of_the_Republic_of_China.svg.png');} .ns-0 h2 #Hungarian::before, .ns-0 h2#Hungarian::before, .ns-0 h2 #Hungarian_Sign_Language::before, .ns-0 h2#Hungarian_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_Hungary.svg/40px-Flag_of_Hungary.svg.png');} .ns-0 h2 #Hunsrik::before, .ns-0 h2#Hunsrik::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/63/Bandeira_do_Rio_Grande_do_Sul.svg/40px-Bandeira_do_Rio_Grande_do_Sul.svg.png');} .ns-0 h2 #Iban::before, .ns-0 h2#Iban::before, .ns-0 h2 #Sarawak_Malay::before, .ns-0 h2#Sarawak_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Flag_of_Sarawak.svg/40px-Flag_of_Sarawak.svg.png');} .ns-0 h2 #Ibanag::before, .ns-0 h2#Ibanag::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Cagayan.svg/40px-Flag_of_Cagayan.svg.png');} .ns-0 h2 #Icelandic::before, .ns-0 h2#Icelandic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Iceland.svg/40px-Flag_of_Iceland.svg.png');} .ns-0 h2 #Ido::before, .ns-0 h2#Ido::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Flag_of_Ido.svg/40px-Flag_of_Ido.svg.png');} .ns-0 h2 #Igala::before, .ns-0 h2#Igala::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Kogi_State_Flag.svg/40px-Kogi_State_Flag.svg.png');} .ns-0 h2 #Igbo::before, .ns-0 h2#Igbo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/82/Flag_of_Biafra.svg/40px-Flag_of_Biafra.svg.png');} .ns-0 h2 #Ilocano::before, .ns-0 h2#Ilocano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/PH-ILS_Flag.png/40px-PH-ILS_Flag.png');} .ns-0 h2 #Indo-Portuguese::before, .ns-0 h2#Indo-Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/72/Flag_of_Portugal_(1640).svg/40px-Flag_of_Portugal_(1640).svg.png');} .ns-0 h2 #Indonesian::before, .ns-0 h2#Indonesian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Indonesia.svg/40px-Flag_of_Indonesia.svg.png');} .ns-0 h2 #Ingrian::before, .ns-0 h2#Ingrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_igora.svg/40px-Flag_igora.svg.png');} .ns-0 h2 #Ingush::before, .ns-0 h2#Ingush::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Ingushetia.svg/40px-Flag_of_Ingushetia.svg.png');} .ns-0 h2 #Interlingua::before, .ns-0 h2#Interlingua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Bandiera_de_Interlingua.svg/40px-Bandiera_de_Interlingua.svg.png');} .ns-0 h2 #Interlingue::before, .ns-0 h2#Interlingue::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5b/Flag_of_Interlingue.svg/40px-Flag_of_Interlingue.svg.png');} .ns-0 h2 #Inuktitut::before, .ns-0 h2#Inuktitut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/90/Flag_of_Nunavut.svg/40px-Flag_of_Nunavut.svg.png');} .ns-0 h2 #Iranun::before, .ns-0 h2#Iranun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Seal_of_Maguindanao_del_Norte.png/40px-Seal_of_Maguindanao_del_Norte.png');} .ns-0 h2 #Iraqi_Arabic::before, .ns-0 h2#Iraqi_Arabic::before, .ns-0 h2 #North_Mesopotamian_Arabic::before, .ns-0 h2#North_Mesopotamian_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Flag_of_Iraq.svg/40px-Flag_of_Iraq.svg.png');} .ns-0 h2 #Iraqw::before, .ns-0 h2#Iraqw::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Iraqw_Flag.png/40px-Iraqw_Flag.png');} .ns-0 h2 #Irish::before, .ns-0 h2#Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Ireland.svg/40px-Flag_of_Ireland.svg.png');} .ns-0 h2 #Islander_Creole_English::before, .ns-0 h2#Islander_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_San_Andrés_y_Providencia.svg/40px-Flag_of_San_Andrés_y_Providencia.svg.png');} .ns-0 h2 #Istriot::before, .ns-0 h2#Istriot::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/HRV_Rovinj_flag.svg/40px-HRV_Rovinj_flag.svg.png');} .ns-0 h2 #Italian::before, .ns-0 h2#Italian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/03/Flag_of_Italy.svg/40px-Flag_of_Italy.svg.png');} .ns-0 h2 #Italiot_Greek::before, .ns-0 h2#Italiot_Greek::before, .ns-0 h2 #Tarantino::before, .ns-0 h2#Tarantino::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Apulia.svg/40px-Flag_of_Apulia.svg.png');} .ns-0 h2 #Itsekiri::before, .ns-0 h2#Itsekiri::before, .ns-0 h2 #Olukumi::before, .ns-0 h2#Olukumi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Flag_of_Delta_State.gif/40px-Flag_of_Delta_State.gif');} .ns-0 h2 #Jah_Hut::before, .ns-0 h2#Jah_Hut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Flag_of_Pahang.svg/40px-Flag_of_Pahang.svg.png');} .ns-0 h2 #Jamaican_Creole::before, .ns-0 h2#Jamaican_Creole::before, .ns-0 h2 #Maroon_Spirit_Language::before, .ns-0 h2#Maroon_Spirit_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Flag_of_Jamaica.svg/40px-Flag_of_Jamaica.svg.png');} .ns-0 h2 #Jamtish::before, .ns-0 h2#Jamtish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Jämtlands_vapen.svg/35px-Jämtlands_vapen.svg.png');} .ns-0 h2 #Japanese::before, .ns-0 h2#Japanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Flag_of_Japan.svg/40px-Flag_of_Japan.svg.png');} .ns-0 h2 #Jaqaru::before, .ns-0 h2#Jaqaru::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Bandera_Provincia_Yauyos.jpg/40px-Bandera_Provincia_Yauyos.jpg');} .ns-0 h2 #Jaunsari::before, .ns-0 h2#Jaunsari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Seal_of_Uttarakhand.svg/35px-Seal_of_Uttarakhand.svg.png');} .ns-0 h2 #Javanese::before, .ns-0 h2#Javanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_the_Mataram_Sultanate.svg/40px-Flag_of_the_Mataram_Sultanate.svg.png');} .ns-0 h2 #Jeju::before, .ns-0 h2#Jeju::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b9/Flag_of_Jeju_Province.svg/40px-Flag_of_Jeju_Province.svg.png');} .ns-0 h2 #Jersey_Dutch::before, .ns-0 h2#Jersey_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_New_Jersey.svg/40px-Flag_of_New_Jersey.svg.png');} .ns-0 h2 #Jingpho::before, .ns-0 h2#Jingpho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/47/Kachin_People_Flag.svg/40px-Kachin_People_Flag.svg.png');} .ns-0 h2 #Juba_Arabic::before, .ns-0 h2#Juba_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_South_Sudan.svg/40px-Flag_of_South_Sudan.svg.png');} .ns-0 h2 #Judeo-Italian::before, .ns-0 h2#Judeo-Italian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_Italian_Jews.svg/40px-Flag_of_Italian_Jews.svg.png');} .ns-0 h2 #K\'iche\'::before, .ns-0 h2#K\'iche\'::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/El_Quiché_Flag_(GUATEMALA).png/40px-El_Quiché_Flag_(GUATEMALA).png');} .ns-0 h2 #Kabiye::before, .ns-0 h2#Kabiye::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_Togo_(3-2).svg/40px-Flag_of_Togo_(3-2).svg.png');} .ns-0 h2 #Kabuverdianu::before, .ns-0 h2#Kabuverdianu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/65/Flag_of_Cape_Verde_(10-17).svg/40px-Flag_of_Cape_Verde_(10-17).svg.png');} .ns-0 h2 #Kabyle::before, .ns-0 h2#Kabyle::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_the_Republic_of_Kabylia.svg/40px-Flag_of_the_Republic_of_Kabylia.svg.png');} .ns-0 h2 #Kaingang::before, .ns-0 h2#Kaingang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Bandeira_do_Paraná.svg/40px-Bandeira_do_Paraná.svg.png');} .ns-0 h2 #Kaitag::before, .ns-0 h2#Kaitag::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_Dagestan.svg/40px-Flag_of_Dagestan.svg.png');} .ns-0 h2 #Kalasha::before, .ns-0 h2#Kalasha::before, .ns-0 h2 #Khowar::before, .ns-0 h2#Khowar::before, .ns-0 h2 #Palula::before, .ns-0 h2#Palula::before, .ns-0 h2 #Ushojo::before, .ns-0 h2#Ushojo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Khyber_Pakhtunkhwa.svg/40px-Flag_of_Khyber_Pakhtunkhwa.svg.png');} .ns-0 h2 #Kalmyk::before, .ns-0 h2#Kalmyk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Flag_of_Kalmykia.svg/40px-Flag_of_Kalmykia.svg.png');} .ns-0 h2 #Kamayurá::before, .ns-0 h2#Kamayurá::before, .ns-0 h2 #Xavante::before, .ns-0 h2#Xavante::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Bandeira_de_Mato_Grosso.svg/40px-Bandeira_de_Mato_Grosso.svg.png');} .ns-0 h2 #Kankanaey::before, .ns-0 h2#Kankanaey::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Flag_of_Mountain_Province.png/40px-Flag_of_Mountain_Province.png');} .ns-0 h2 #Kannada::before, .ns-0 h2#Kannada::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Flag_of_Karnataka,_India.svg/40px-Flag_of_Karnataka,_India.svg.png');} .ns-0 h2 #Kanuri::before, .ns-0 h2#Kanuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/95/Flag_of_the_Kanuri_people.svg/40px-Flag_of_the_Kanuri_people.svg.png');} .ns-0 h2 #Kapampangan::before, .ns-0 h2#Kapampangan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Pampanga_Flag.png/40px-Pampanga_Flag.png');} .ns-0 h2 #Karachay-Balkar::before, .ns-0 h2#Karachay-Balkar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/Flag_of_Karachay-Cherkessia.svg/40px-Flag_of_Karachay-Cherkessia.svg.png');} .ns-0 h2 #Karakalpak::before, .ns-0 h2#Karakalpak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Karakalpakstan.svg/40px-Flag_of_Karakalpakstan.svg.png');} .ns-0 h2 #Karakhanid::before, .ns-0 h2#Karakhanid::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Flag_of_the_Kara-Khanids.svg/40px-Flag_of_the_Kara-Khanids.svg.png');} .ns-0 h2 #Karelian::before, .ns-0 h2#Karelian::before, .ns-0 h2 #Livvi::before, .ns-0 h2#Livvi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/78/Itäkarjalaisten_lippu.svg/40px-Itäkarjalaisten_lippu.svg.png');} .ns-0 h2 #Karipúna_Creole_French::before, .ns-0 h2#Karipúna_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Bandeira_do_Amapá.svg/40px-Bandeira_do_Amapá.svg.png');} .ns-0 h2 #Kashmiri::before, .ns-0 h2#Kashmiri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/32/Flag_of_Jammu_and_Kashmir_(1936-1953).svg/40px-Flag_of_Jammu_and_Kashmir_(1936-1953).svg.png');} .ns-0 h2 #Kashubian::before, .ns-0 h2#Kashubian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/POL_Kaszuby_flag.svg/40px-POL_Kaszuby_flag.svg.png');} .ns-0 h2 #Kazakh::before, .ns-0 h2#Kazakh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Flag_of_Kazakhstan.svg/40px-Flag_of_Kazakhstan.svg.png');} .ns-0 h2 #Kedah_Malay::before, .ns-0 h2#Kedah_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/67/Flag_of_Kedah_(18th_century_-_1821).svg/40px-Flag_of_Kedah_(18th_century_-_1821).svg.png');} .ns-0 h2 #Kelantan_Peranakan_Hokkien::before, .ns-0 h2#Kelantan_Peranakan_Hokkien::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Flag_of_Kelantan.svg/40px-Flag_of_Kelantan.svg.png');} .ns-0 h2 #Ket::before, .ns-0 h2#Ket::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2d/Flag_of_Krasnoyarsk_Krai.svg/40px-Flag_of_Krasnoyarsk_Krai.svg.png');} .ns-0 h2 #Khakas::before, .ns-0 h2#Khakas::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Flag_of_Khakassia.svg/40px-Flag_of_Khakassia.svg.png');} .ns-0 h2 #Khasi::before, .ns-0 h2#Khasi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Seng-Khasi.png/40px-Seng-Khasi.png');} .ns-0 h2 #Khmer::before, .ns-0 h2#Khmer::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Flag_of_Cambodia.svg/40px-Flag_of_Cambodia.svg.png');} .ns-0 h2 #Khoekhoe::before, .ns-0 h2#Khoekhoe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Namibia.svg/40px-Flag_of_Namibia.svg.png');} .ns-0 h2 #Kikuyu::before, .ns-0 h2#Kikuyu::before, .ns-0 h2 #Maasai::before, .ns-0 h2#Maasai::before, .ns-0 h2 #Swahili::before, .ns-0 h2#Swahili::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Kenya.svg/40px-Flag_of_Kenya.svg.png');} .ns-0 h2 #Kimbundu::before, .ns-0 h2#Kimbundu::before, .ns-0 h2 #Umbundu::before, .ns-0 h2#Umbundu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Flag_of_Angola.svg/40px-Flag_of_Angola.svg.png');} .ns-0 h2 #Kiowa::before, .ns-0 h2#Kiowa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Flag_of_Oklahoma.svg/40px-Flag_of_Oklahoma.svg.png');} .ns-0 h2 #Kituba::before, .ns-0 h2#Kituba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/92/Flag_of_the_Republic_of_the_Congo.svg/40px-Flag_of_the_Republic_of_the_Congo.svg.png');} .ns-0 h2 #Klingon::before, .ns-0 h2#Klingon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Klingon_Empire_Flag.svg/40px-Klingon_Empire_Flag.svg.png');} .ns-0 h2 #Kokborok::before, .ns-0 h2#Kokborok::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_the_National_Liberation_Front_of_Tripura.svg/40px-Flag_of_the_National_Liberation_Front_of_Tripura.svg.png');} .ns-0 h2 #Komi-Permyak::before, .ns-0 h2#Komi-Permyak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Flag_of_Permyakia.svg/40px-Flag_of_Permyakia.svg.png');} .ns-0 h2 #Komi-Zyrian::before, .ns-0 h2#Komi-Zyrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Komi.svg/40px-Flag_of_Komi.svg.png');} .ns-0 h2 #Kongo::before, .ns-0 h2#Kongo::before, .ns-0 h2 #Lingala::before, .ns-0 h2#Lingala::before, .ns-0 h2 #Luba-Kasai::before, .ns-0 h2#Luba-Kasai::before, .ns-0 h2 #Luba-Katanga::before, .ns-0 h2#Luba-Katanga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_the_Democratic_Republic_of_the_Congo.svg/40px-Flag_of_the_Democratic_Republic_of_the_Congo.svg.png');} .ns-0 h2 #Konzo::before, .ns-0 h2#Konzo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Rwenzururu.svg/40px-Flag_of_Rwenzururu.svg.png');} .ns-0 h2 #Korean::before, .ns-0 h2#Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Unification_flag_of_Korea.svg/40px-Unification_flag_of_Korea.svg.png');} .ns-0 h2 #Korlai_Creole_Portuguese::before, .ns-0 h2#Korlai_Creole_Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Seal_of_Maharashtra.svg/35px-Seal_of_Maharashtra.svg.png');} .ns-0 h2 #Koryak::before, .ns-0 h2#Koryak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Flag_of_Koryakia.svg/40px-Flag_of_Koryakia.svg.png');} .ns-0 h2 #Kosraean::before, .ns-0 h2#Kosraean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/23/Flag_of_Kosrae.svg/40px-Flag_of_Kosrae.svg.png');} .ns-0 h2 #Krio::before, .ns-0 h2#Krio::before, .ns-0 h2 #Mende_\(Sierra_Leone\)::before, .ns-0 h2#Mende_\(Sierra_Leone\)::before, .ns-0 h2 #Temne::before, .ns-0 h2#Temne::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Flag_of_Sierra_Leone.svg/40px-Flag_of_Sierra_Leone.svg.png');} .ns-0 h2 #Kristang::before, .ns-0 h2#Kristang::before, .ns-0 h2 #Malaccan_Creole_Malay::before, .ns-0 h2#Malaccan_Creole_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/09/Flag_of_Malacca.svg/40px-Flag_of_Malacca.svg.png');} .ns-0 h2 #Kumaoni::before, .ns-0 h2#Kumaoni::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Flag_of_the_Kumaon_Kingdom.svg/40px-Flag_of_the_Kumaon_Kingdom.svg.png');} .ns-0 h2 #Kumyk::before, .ns-0 h2#Kumyk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_Kumyks.svg/40px-Flag_of_Kumyks.svg.png');} .ns-0 h2 #Kuna::before, .ns-0 h2#Kuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Bandera_de_la_Comarca_Guna_Yala.svg/40px-Bandera_de_la_Comarca_Guna_Yala.svg.png');} .ns-0 h2 #Kunigami::before, .ns-0 h2#Kunigami::before, .ns-0 h2 #Miyako::before, .ns-0 h2#Miyako::before, .ns-0 h2 #Okinawan::before, .ns-0 h2#Okinawan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_Okinawa_Prefecture.svg/40px-Flag_of_Okinawa_Prefecture.svg.png');} .ns-0 h2 #Kupang_Malay::before, .ns-0 h2#Kupang_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c6/Flag_of_Kupang_City.png/40px-Flag_of_Kupang_City.png');} .ns-0 h2 #Kven::before, .ns-0 h2#Kven::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_the_Kven_people.svg/40px-Flag_of_the_Kven_people.svg.png');} .ns-0 h2 #Kwanyama::before, .ns-0 h2#Kwanyama::before, .ns-0 h2 #Ndonga::before, .ns-0 h2#Ndonga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Flag_of_Ovamboland.svg/40px-Flag_of_Ovamboland.svg.png');} .ns-0 h2 #Kyrgyz::before, .ns-0 h2#Kyrgyz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Kyrgyzstan.svg/40px-Flag_of_Kyrgyzstan.svg.png');} .ns-0 h2 #Laboya::before, .ns-0 h2#Laboya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Coat_of_Arms_of_East_Nusa_Tenggara_NEW.png/35px-Coat_of_Arms_of_East_Nusa_Tenggara_NEW.png');} .ns-0 h2 #Ladakhi::before, .ns-0 h2#Ladakhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Flag_of_the_Ladakh_Nationalist_Movement.svg/40px-Flag_of_the_Ladakh_Nationalist_Movement.svg.png');} .ns-0 h2 #Ladin::before, .ns-0 h2#Ladin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Ladinia.svg/40px-Flag_of_Ladinia.svg.png');} .ns-0 h2 #Ladino::before, .ns-0 h2#Ladino::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Spanish_Jewish_flag.png/40px-Spanish_Jewish_flag.png');} .ns-0 h2 #Lahu::before, .ns-0 h2#Lahu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Lahu_flag.svg/40px-Lahu_flag.svg.png');} .ns-0 h2 #Lai::before, .ns-0 h2#Lai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/af/Emblem_of_Lai_Autonomous_Council.png/40px-Emblem_of_Lai_Autonomous_Council.png');} .ns-0 h2 #Lakota::before, .ns-0 h2#Lakota::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Pine_Ridge_Flag.svg/40px-Pine_Ridge_Flag.svg.png');} .ns-0 h2 #Lao::before, .ns-0 h2#Lao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/56/Flag_of_Laos.svg/40px-Flag_of_Laos.svg.png');} .ns-0 h2 #Latgalian::before, .ns-0 h2#Latgalian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7d/Official_flag_of_Latgale.svg/40px-Official_flag_of_Latgale.svg.png');} .ns-0 h2 #Latin::before, .ns-0 h2#Latin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Rome.svg/40px-Flag_of_Rome.svg.png');} .ns-0 h2 #Latvian::before, .ns-0 h2#Latvian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Latvia.svg/40px-Flag_of_Latvia.svg.png');} .ns-0 h2 #Leonese::before, .ns-0 h2#Leonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/75/Bandera_del_País_Leonés.svg/40px-Bandera_del_País_Leonés.svg.png');} .ns-0 h2 #Lepcha::before, .ns-0 h2#Lepcha::before, .ns-0 h2 #Sherpa::before, .ns-0 h2#Sherpa::before, .ns-0 h2 #Thulung::before, .ns-0 h2#Thulung::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Seal_of_Sikkim.svg/40px-Seal_of_Sikkim.svg.png');} .ns-0 h2 #Lezgi::before, .ns-0 h2#Lezgi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Lezgian_flag.svg/40px-Lezgian_flag.svg.png');} .ns-0 h2 #Ligurian::before, .ns-0 h2#Ligurian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/88/Flag_of_Liguria.svg/40px-Flag_of_Liguria.svg.png');} .ns-0 h2 #Limbu::before, .ns-0 h2#Limbu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Flag_of_Limbuwan.svg/40px-Flag_of_Limbuwan.svg.png');} .ns-0 h2 #Limburgish::before, .ns-0 h2#Limburgish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Flag_of_Limburg_(Netherlands).svg/40px-Flag_of_Limburg_(Netherlands).svg.png');} .ns-0 h2 #Limos_Kalinga::before, .ns-0 h2#Limos_Kalinga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Ph_seal_kalinga.png/40px-Ph_seal_kalinga.png');} .ns-0 h2 #Lindu::before, .ns-0 h2#Lindu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/46/Coat_of_arms_of_Central_Sulawesi.svg/30px-Coat_of_arms_of_Central_Sulawesi.svg.png');} .ns-0 h2 #Lithuanian::before, .ns-0 h2#Lithuanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Lithuania.svg/40px-Flag_of_Lithuania.svg.png');} .ns-0 h2 #Livonian::before, .ns-0 h2#Livonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Flag_of_the_Livonians.svg/40px-Flag_of_the_Livonians.svg.png');} .ns-0 h2 #Lojban::before, .ns-0 h2#Lojban::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Lojban_logo.svg/40px-Lojban_logo.svg.png');} .ns-0 h2 #Lombard::before, .ns-0 h2#Lombard::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_Lombardy.svg/40px-Flag_of_Lombardy.svg.png');} .ns-0 h2 #Louisiana_Creole::before, .ns-0 h2#Louisiana_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_Louisiana.svg/40px-Flag_of_Louisiana.svg.png');} .ns-0 h2 #Lovono::before, .ns-0 h2#Lovono::before, .ns-0 h2 #Äiwoo::before, .ns-0 h2#Äiwoo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Temotu_province_flag.svg/40px-Temotu_province_flag.svg.png');} .ns-0 h2 #Lower_Sorbian::before, .ns-0 h2#Lower_Sorbian::before, .ns-0 h2 #Upper_Sorbian::before, .ns-0 h2#Upper_Sorbian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c0/Flag_of_Sorbs.svg/40px-Flag_of_Sorbs.svg.png');} .ns-0 h2 #Lozi::before, .ns-0 h2#Lozi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/62/Flag_of_Barotseland.svg/40px-Flag_of_Barotseland.svg.png');} .ns-0 h2 #Ludian::before, .ns-0 h2#Ludian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Ludic_flag.svg/40px-Ludic_flag.svg.png');} .ns-0 h2 #Luganda::before, .ns-0 h2#Luganda::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Uganda.svg/40px-Flag_of_Uganda.svg.png');} .ns-0 h2 #Lushootseed::before, .ns-0 h2#Lushootseed::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Washington.svg/40px-Flag_of_Washington.svg.png');} .ns-0 h2 #Lutuv::before, .ns-0 h2#Lutuv::before, .ns-0 h2 #Zou::before, .ns-0 h2#Zou::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Chin_State.svg/40px-Flag_of_Chin_State.svg.png');} .ns-0 h2 #Luxembourgish::before, .ns-0 h2#Luxembourgish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Flag_of_Luxembourg.svg/40px-Flag_of_Luxembourg.svg.png');} .ns-0 h2 #Macanese::before, .ns-0 h2#Macanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/63/Flag_of_Macau.svg/40px-Flag_of_Macau.svg.png');} .ns-0 h2 #Macedonian::before, .ns-0 h2#Macedonian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_North_Macedonia.svg/40px-Flag_of_North_Macedonia.svg.png');} .ns-0 h2 #Maguindanao::before, .ns-0 h2#Maguindanao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Flag_of_Maguindanao.svg/40px-Flag_of_Maguindanao.svg.png');} .ns-0 h2 #Makasar::before, .ns-0 h2#Makasar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_the_Sultanate_of_Gowa.svg/40px-Flag_of_the_Sultanate_of_Gowa.svg.png');} .ns-0 h2 #Malagasy::before, .ns-0 h2#Malagasy::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_Madagascar.svg/40px-Flag_of_Madagascar.svg.png');} .ns-0 h2 #Malay::before, .ns-0 h2#Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Malaysia_and_Indonesia.svg/40px-Flag_of_Malaysia_and_Indonesia.svg.png');} .ns-0 h2 #Maltese::before, .ns-0 h2#Maltese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Malta.svg/40px-Flag_of_Malta.svg.png');} .ns-0 h2 #Manado_Malay::before, .ns-0 h2#Manado_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Lambang_Kota_Manado.png/30px-Lambang_Kota_Manado.png');} .ns-0 h2 #Manchu::before, .ns-0 h2#Manchu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/86/Flag_of_China_(1862–1889).svg/40px-Flag_of_China_(1862–1889).svg.png');} .ns-0 h2 #Mandinka::before, .ns-0 h2#Mandinka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_The_Gambia.svg/40px-Flag_of_The_Gambia.svg.png');} .ns-0 h2 #Manipuri::before, .ns-0 h2#Manipuri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Manipur.svg/40px-Flag_of_Manipur.svg.png');} .ns-0 h2 #Mansaka::before, .ns-0 h2#Mansaka::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Davao_De_Oro_Flag.jpg/40px-Davao_De_Oro_Flag.jpg');} .ns-0 h2 #Manx::before, .ns-0 h2#Manx::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_the_Isle_of_Man.svg/40px-Flag_of_the_Isle_of_Man.svg.png');} .ns-0 h2 #Maore_Comorian::before, .ns-0 h2#Maore_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Coat_of_Arms_of_Mayotte.svg/40px-Coat_of_Arms_of_Mayotte.svg.png');} .ns-0 h2 #Mapudungun::before, .ns-0 h2#Mapudungun::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Flag_of_the_Mapuches_(1992).svg/40px-Flag_of_the_Mapuches_(1992).svg.png');} .ns-0 h2 #Maranao::before, .ns-0 h2#Maranao::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/PH-LAS_Flag.png/40px-PH-LAS_Flag.png');} .ns-0 h2 #Margi::before, .ns-0 h2#Margi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1d/Borno_State_Flag.gif/40px-Borno_State_Flag.gif');} .ns-0 h2 #Marshallese::before, .ns-0 h2#Marshallese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2e/Flag_of_the_Marshall_Islands.svg/40px-Flag_of_the_Marshall_Islands.svg.png');} .ns-0 h2 #Masalit::before, .ns-0 h2#Masalit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Flag_of_the_Masalit.svg/40px-Flag_of_the_Masalit.svg.png');} .ns-0 h2 #Masbatenyo::before, .ns-0 h2#Masbatenyo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/PH-MAS_Flag.png/40px-PH-MAS_Flag.png');} .ns-0 h2 #Mauritian_Creole::before, .ns-0 h2#Mauritian_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Mauritius.svg/40px-Flag_of_Mauritius.svg.png');} .ns-0 h2 #Maybrat::before, .ns-0 h2#Maybrat::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/43/Flag_of_Southwest_Papua.svg/40px-Flag_of_Southwest_Papua.svg.png');} .ns-0 h2 #Mbya_Guarani::before, .ns-0 h2#Mbya_Guarani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/24/Flag_of_Uruguay,_Brazil_and_Argentina.png/40px-Flag_of_Uruguay,_Brazil_and_Argentina.png');} .ns-0 h2 #Media_Lengua::before, .ns-0 h2#Media_Lengua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Bandera_Provincia_Imbabura.svg/40px-Bandera_Provincia_Imbabura.svg.png');} .ns-0 h2 #Megleno-Romanian::before, .ns-0 h2#Megleno-Romanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Flag_of_Greek_Macedonia.svg/40px-Flag_of_Greek_Macedonia.svg.png');} .ns-0 h2 #Mehri::before, .ns-0 h2#Mehri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_the_Mahra_Sultanate.svg/40px-Flag_of_the_Mahra_Sultanate.svg.png');} .ns-0 h2 #Meriam::before, .ns-0 h2#Meriam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/37/Flag_of_Murray_Island_(Mer).svg/40px-Flag_of_Murray_Island_(Mer).svg.png');} .ns-0 h2 #Meru::before, .ns-0 h2#Meru::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_Meru_County.png/40px-Flag_of_Meru_County.png');} .ns-0 h2 #Meänkieli::before, .ns-0 h2#Meänkieli::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_Tornedalians_(2007).svg/40px-Flag_of_Tornedalians_(2007).svg.png');} .ns-0 h2 #Mi\'kmaq::before, .ns-0 h2#Mi\'kmaq::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Mikmaq_State_Flag.svg/40px-Mikmaq_State_Flag.svg.png');} .ns-0 h2 #Michif::before, .ns-0 h2#Michif::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Metis_Blue.svg/40px-Metis_Blue.svg.png');} .ns-0 h2 #Michoacán_Nahuatl::before, .ns-0 h2#Michoacán_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Coat_of_arms_of_Michoacan.svg/32px-Coat_of_arms_of_Michoacan.svg.png');} .ns-0 h2 #Middle_Dutch::before, .ns-0 h2#Middle_Dutch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_prince-bishopric_of_Utrecht.svg/36px-Flag_of_the_prince-bishopric_of_Utrecht.svg.png');} .ns-0 h2 #Middle_English::before, .ns-0 h2#Middle_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/be/Flag_of_England.svg/40px-Flag_of_England.svg.png');} .ns-0 h2 #Middle_French::before, .ns-0 h2#Middle_French::before, .ns-0 h2 #Old_French::before, .ns-0 h2#Old_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/82/Royal_flag_of_France.svg/40px-Royal_flag_of_France.svg.png');} .ns-0 h2 #Middle_Irish::before, .ns-0 h2#Middle_Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Flag_of_Leinster.svg/40px-Flag_of_Leinster.svg.png');} .ns-0 h2 #Middle_Korean::before, .ns-0 h2#Middle_Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Royal_flag_of_Goryeo_(Bong-gi).svg/40px-Royal_flag_of_Goryeo_(Bong-gi).svg.png');} .ns-0 h2 #Middle_Mongol::before, .ns-0 h2#Middle_Mongol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Flag_of_the_Mongol_Empire_3.svg/40px-Flag_of_the_Mongol_Empire_3.svg.png');} .ns-0 h2 #Middle_Norwegian::before, .ns-0 h2#Middle_Norwegian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Royal_Banner_of_Norway_(14th_Century).svg/34px-Royal_Banner_of_Norway_(14th_Century).svg.png');} .ns-0 h2 #Middle_Persian::before, .ns-0 h2#Middle_Persian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Derafsh_kaviani.svg/38px-Derafsh_kaviani.svg.png');} .ns-0 h2 #Middle_Scots::before, .ns-0 h2#Middle_Scots::before, .ns-0 h2 #Scottish_Gaelic::before, .ns-0 h2#Scottish_Gaelic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Royal_Banner_of_Scotland.svg/40px-Royal_Banner_of_Scotland.svg.png');} .ns-0 h2 #Mikasuki::before, .ns-0 h2#Mikasuki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/34/Flag_of_the_Miccosukee_Tribe_of_Indians_of_Florida.svg/40px-Flag_of_the_Miccosukee_Tribe_of_Indians_of_Florida.svg.png');} .ns-0 h2 #Minangkabau::before, .ns-0 h2#Minangkabau::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Flag_of_Minang.svg/40px-Flag_of_Minang.svg.png');} .ns-0 h2 #Mingrelian::before, .ns-0 h2#Mingrelian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Flag_of_The_Principality_of_Mingrelia_(Portolan_1560).svg/40px-Flag_of_The_Principality_of_Mingrelia_(Portolan_1560).svg.png');} .ns-0 h2 #Mirandese::before, .ns-0 h2#Mirandese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Bandeira-de-Miranda-do-Douro.png/36px-Bandeira-de-Miranda-do-Douro.png');} .ns-0 h2 #Miskito::before, .ns-0 h2#Miskito::before, .ns-0 h2 #Nicaraguan_Creole::before, .ns-0 h2#Nicaraguan_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Nicaragua.svg/40px-Flag_of_Nicaragua.svg.png');} .ns-0 h2 #Mohawk::before, .ns-0 h2#Mohawk::before, .ns-0 h2 #Oneida::before, .ns-0 h2#Oneida::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_the_Iroquois_Confederacy.svg/40px-Flag_of_the_Iroquois_Confederacy.svg.png');} .ns-0 h2 #Mokilese::before, .ns-0 h2#Mokilese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Mwoakilloa.svg/40px-Flag_of_Mwoakilloa.svg.png');} .ns-0 h2 #Moksha::before, .ns-0 h2#Moksha::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Flag_of_the_Moksha_people.svg/40px-Flag_of_the_Moksha_people.svg.png');} .ns-0 h2 #Mon::before, .ns-0 h2#Mon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/03/Flag_of_Mon_State_(2018).svg/40px-Flag_of_Mon_State_(2018).svg.png');} .ns-0 h2 #Mongolian::before, .ns-0 h2#Mongolian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Flag_of_Mongolia.svg/40px-Flag_of_Mongolia.svg.png');} .ns-0 h2 #Mongondow::before, .ns-0 h2#Mongondow::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Lambang_Kabupaten_Bolaang_Mongondow.png/35px-Lambang_Kabupaten_Bolaang_Mongondow.png');} .ns-0 h2 #Moore::before, .ns-0 h2#Moore::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Burkina_Faso.svg/40px-Flag_of_Burkina_Faso.svg.png');} .ns-0 h2 #Morelos_Nahuatl::before, .ns-0 h2#Morelos_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Coat_of_arms_of_Morelos.svg/32px-Coat_of_arms_of_Morelos.svg.png');} .ns-0 h2 #Moroccan_Amazigh::before, .ns-0 h2#Moroccan_Amazigh::before, .ns-0 h2 #Moroccan_Arabic::before, .ns-0 h2#Moroccan_Arabic::before, .ns-0 h2 #Tashelhit::before, .ns-0 h2#Tashelhit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Morocco.svg/40px-Flag_of_Morocco.svg.png');} .ns-0 h2 #Muong::before, .ns-0 h2#Muong::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/14/Flag_of_Muong_Autonomous_Region.svg/40px-Flag_of_Muong_Autonomous_Region.svg.png');} .ns-0 h2 #Mwali_Comorian::before, .ns-0 h2#Mwali_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Flag_of_Mohéli_(official).svg/40px-Flag_of_Mohéli_(official).svg.png');} .ns-0 h2 #Mwani::before, .ns-0 h2#Mwani::before, .ns-0 h2 #Ronga::before, .ns-0 h2#Ronga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_Mozambique.svg/40px-Flag_of_Mozambique.svg.png');} .ns-0 h2 #Mòcheno::before, .ns-0 h2#Mòcheno::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/51/Flag_of_Comunità_Alta_Valsugana_e_Bersntol.png/40px-Flag_of_Comunità_Alta_Valsugana_e_Bersntol.png');} .ns-0 h2 #Māori::before, .ns-0 h2#Māori::before, .ns-0 h2 #New_Zealand_Sign_Language::before, .ns-0 h2#New_Zealand_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_New_Zealand.svg/40px-Flag_of_New_Zealand.svg.png');} .ns-0 h2 #Najdi_Arabic::before, .ns-0 h2#Najdi_Arabic::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/1/17/Flag_of_the_Emirate_of_Ha'il.svg/40px-Flag_of_the_Emirate_of_Ha'il.svg.png");} .ns-0 h2 #Nauruan::before, .ns-0 h2#Nauruan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/30/Flag_of_Nauru.svg/40px-Flag_of_Nauru.svg.png');} .ns-0 h2 #Navajo::before, .ns-0 h2#Navajo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Official_design_of_the_Navajo_Nation_flag_as_it_was_adopted_on_May_21,_1968.svg/40px-Official_design_of_the_Navajo_Nation_flag_as_it_was_adopted_on_May_21,_1968.svg.png');} .ns-0 h2 #Ndzwani_Comorian::before, .ns-0 h2#Ndzwani_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Flag_of_Anjouan_(official).svg/40px-Flag_of_Anjouan_(official).svg.png');} .ns-0 h2 #Neapolitan::before, .ns-0 h2#Neapolitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Flag_of_Campania.svg/40px-Flag_of_Campania.svg.png');} .ns-0 h2 #Negeri_Sembilan_Malay::before, .ns-0 h2#Negeri_Sembilan_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/db/Flag_of_Negeri_Sembilan.svg/40px-Flag_of_Negeri_Sembilan.svg.png');} .ns-0 h2 #Nepali::before, .ns-0 h2#Nepali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Flag_of_Nepal.svg/20px-Flag_of_Nepal.svg.png');} .ns-0 h2 #Newar::before, .ns-0 h2#Newar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Flag_of_Kathmandu,_Nepal.svg/40px-Flag_of_Kathmandu,_Nepal.svg.png');} .ns-0 h2 #Ngazidja_Comorian::before, .ns-0 h2#Ngazidja_Comorian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Comoros.svg/40px-Flag_of_the_Comoros.svg.png');} .ns-0 h2 #Nheengatu::before, .ns-0 h2#Nheengatu::before, .ns-0 h2 #Trió::before, .ns-0 h2#Trió::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/02/Bandeira_do_Pará.svg/40px-Bandeira_do_Pará.svg.png');} .ns-0 h2 #Nias::before, .ns-0 h2#Nias::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Coat_of_arms_of_North_Sumatra.svg/30px-Coat_of_arms_of_North_Sumatra.svg.png');} .ns-0 h2 #Nigerian_Pidgin::before, .ns-0 h2#Nigerian_Pidgin::before, .ns-0 h2 #Nigerian_Sign_Language::before, .ns-0 h2#Nigerian_Sign_Language::before, .ns-0 h2 #Yoruba::before, .ns-0 h2#Yoruba::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/79/Flag_of_Nigeria.svg/40px-Flag_of_Nigeria.svg.png');} .ns-0 h2 #Niuean::before, .ns-0 h2#Niuean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/01/Flag_of_Niue.svg/40px-Flag_of_Niue.svg.png');} .ns-0 h2 #Nivkh::before, .ns-0 h2#Nivkh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Flag_of_Sakhalin_Oblast.svg/40px-Flag_of_Sakhalin_Oblast.svg.png');} .ns-0 h2 #Norman::before, .ns-0 h2#Norman::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_Normandie.svg/40px-Flag_of_Normandie.svg.png');} .ns-0 h2 #North_Frisian::before, .ns-0 h2#North_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Nordfriesischeflagge.svg/40px-Nordfriesischeflagge.svg.png');} .ns-0 h2 #North_Moluccan_Malay::before, .ns-0 h2#North_Moluccan_Malay::before, .ns-0 h2 #West_Makian::before, .ns-0 h2#West_Makian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Coat_of_arms_of_North_Maluku.svg/35px-Coat_of_arms_of_North_Maluku.svg.png');} .ns-0 h2 #Northern_Altai::before, .ns-0 h2#Northern_Altai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Flag_of_Altai_Krai.svg/40px-Flag_of_Altai_Krai.svg.png');} .ns-0 h2 #Northern_Catanduanes_Bikol::before, .ns-0 h2#Northern_Catanduanes_Bikol::before, .ns-0 h2 #Southern_Catanduanes_Bikol::before, .ns-0 h2#Southern_Catanduanes_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/PH-CAT_Flag.png/40px-PH-CAT_Flag.png');} .ns-0 h2 #Northern_Ndebele::before, .ns-0 h2#Northern_Ndebele::before, .ns-0 h2 #Shona::before, .ns-0 h2#Shona::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Flag_of_Zimbabwe.svg/40px-Flag_of_Zimbabwe.svg.png');} .ns-0 h2 #Northern_Sotho::before, .ns-0 h2#Northern_Sotho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/52/Flag_of_Lebowa.svg/40px-Flag_of_Lebowa.svg.png');} .ns-0 h2 #Northern_Thai::before, .ns-0 h2#Northern_Thai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Seal_of_Lanna_Kingdom.png/40px-Seal_of_Lanna_Kingdom.png');} .ns-0 h2 #Norwegian::before, .ns-0 h2#Norwegian::before, .ns-0 h2 #Norwegian_Bokmål::before, .ns-0 h2#Norwegian_Bokmål::before, .ns-0 h2 #Norwegian_Nynorsk::before, .ns-0 h2#Norwegian_Nynorsk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Flag_of_Norway.svg/40px-Flag_of_Norway.svg.png');} .ns-0 h2 #Novial::before, .ns-0 h2#Novial::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Flag_of_Novial.svg/40px-Flag_of_Novial.svg.png');} .ns-0 h2 #Nubi::before, .ns-0 h2#Nubi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Kenia-Uganda-Flagge.png/40px-Kenia-Uganda-Flagge.png');} .ns-0 h2 #Nuosu::before, .ns-0 h2#Nuosu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Proposed_Yi_flag.svg/40px-Proposed_Yi_flag.svg.png');} .ns-0 h2 #Nupe::before, .ns-0 h2#Nupe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Niger_state_flag.png/40px-Niger_state_flag.png');} .ns-0 h2 #Nyankole::before, .ns-0 h2#Nyankole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Ankole.svg/40px-Flag_of_Ankole.svg.png');} .ns-0 h2 #Nyoro::before, .ns-0 h2#Nyoro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Bunyoro-Kitara_Kingdom_Flag.png/40px-Bunyoro-Kitara_Kingdom_Flag.png');} .ns-0 h2 #Nùng::before, .ns-0 h2#Nùng::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/75/Flag_of_the_Nùng_Autonomous_Territory.svg/40px-Flag_of_the_Nùng_Autonomous_Territory.svg.png');} .ns-0 h2 #O\'odham::before, .ns-0 h2#O\'odham::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/0/05/O'odham_unofficial_flag.svg/40px-O'odham_unofficial_flag.svg.png");} .ns-0 h2 #Occitan::before, .ns-0 h2#Occitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Flag_of_Occitania_(with_star).svg/40px-Flag_of_Occitania_(with_star).svg.png');} .ns-0 h2 #Odia::before, .ns-0 h2#Odia::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Mayurbhanj.png/40px-Flag_of_Mayurbhanj.png');} .ns-0 h2 #Ojibwe::before, .ns-0 h2#Ojibwe::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Peguis_First_Nation.svg/40px-Flag_of_the_Peguis_First_Nation.svg.png');} .ns-0 h2 #Old_Armenian::before, .ns-0 h2#Old_Armenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Standard_of_the_Artaxiad_dynasty.svg/40px-Standard_of_the_Artaxiad_dynasty.svg.png');} .ns-0 h2 #Old_Catalan::before, .ns-0 h2#Old_Catalan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/58/Bandera_del_Principat_de_Catalunya_(1200_dC).svg/40px-Bandera_del_Principat_de_Catalunya_(1200_dC).svg.png');} .ns-0 h2 #Old_Czech::before, .ns-0 h2#Old_Czech::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Banner_of_Přemyslid_family.svg/40px-Banner_of_Přemyslid_family.svg.png');} .ns-0 h2 #Old_English::before, .ns-0 h2#Old_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Flag_of_Wessex.svg/40px-Flag_of_Wessex.svg.png');} .ns-0 h2 #Old_Galician-Portuguese::before, .ns-0 h2#Old_Galician-Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/25/PortugueseFlag1143.svg/40px-PortugueseFlag1143.svg.png');} .ns-0 h2 #Old_Georgian::before, .ns-0 h2#Old_Georgian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Kartli_-_drosha_jvari.svg/40px-Kartli_-_drosha_jvari.svg.png');} .ns-0 h2 #Old_High_German::before, .ns-0 h2#Old_High_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_East_Francia_(843–962).png/40px-Flag_of_East_Francia_(843–962).png');} .ns-0 h2 #Old_Irish::before, .ns-0 h2#Old_Irish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Triskele-Symbol1.svg/40px-Triskele-Symbol1.svg.png');} .ns-0 h2 #Old_Javanese::before, .ns-0 h2#Old_Javanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Naval_flag_of_Majapahit_Kingdom.svg/40px-Naval_flag_of_Majapahit_Kingdom.svg.png');} .ns-0 h2 #Old_Korean::before, .ns-0 h2#Old_Korean::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/80/Military_Banner_of_Silla.svg/40px-Military_Banner_of_Silla.svg.png');} .ns-0 h2 #Old_Leonese::before, .ns-0 h2#Old_Leonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Royal_Banner_of_Leon_(Variant).svg/40px-Royal_Banner_of_Leon_(Variant).svg.png');} .ns-0 h2 #Old_Navarro-Aragonese::before, .ns-0 h2#Old_Navarro-Aragonese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Navarro-Aragonese_flag.png/40px-Navarro-Aragonese_flag.png');} .ns-0 h2 #Old_Norse::before, .ns-0 h2#Old_Norse::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Raven_Banner.svg/40px-Raven_Banner.svg.png');} .ns-0 h2 #Old_Novgorodian::before, .ns-0 h2#Old_Novgorodian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Banner_of_the_Novgorod_Republic_(c._1385).svg/40px-Banner_of_the_Novgorod_Republic_(c._1385).svg.png');} .ns-0 h2 #Old_Nubian::before, .ns-0 h2#Old_Nubian::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/4/47/The_flag_of_the_'Kingdom_of_Dongola'_(Makuria)_in_the_%22Book_of_all_kingdoms%22_(C._1350).svg/40px-The_flag_of_the_'Kingdom_of_Dongola'_(Makuria)_in_the_%22Book_of_all_kingdoms%22_(C._1350).svg.png");} .ns-0 h2 #Old_Occitan::before, .ns-0 h2#Old_Occitan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_Provence.svg/40px-Flag_of_Provence.svg.png');} .ns-0 h2 #Old_Polish::before, .ns-0 h2#Old_Polish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/12/Flag_of_the_Kingdom_of_Poland.svg/40px-Flag_of_the_Kingdom_of_Poland.svg.png');} .ns-0 h2 #Old_Ruthenian::before, .ns-0 h2#Old_Ruthenian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Royal_banner_of_the_Grand_Duchy_of_Lithuania.svg/40px-Royal_banner_of_the_Grand_Duchy_of_Lithuania.svg.png');} .ns-0 h2 #Old_Saxon::before, .ns-0 h2#Old_Saxon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Flag_of_Old_Saxony.svg/40px-Flag_of_Old_Saxony.svg.png');} .ns-0 h2 #Old_Spanish::before, .ns-0 h2#Old_Spanish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/71/Flag_of_Castile.svg/40px-Flag_of_Castile.svg.png');} .ns-0 h2 #Old_Swedish::before, .ns-0 h2#Old_Swedish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/25/Royal_Banner_of_Sweden_(14th_Century).svg/30px-Royal_Banner_of_Sweden_(14th_Century).svg.png');} .ns-0 h2 #Old_Welsh::before, .ns-0 h2#Old_Welsh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_Gwynedd_(3-2).svg/40px-Flag_of_Gwynedd_(3-2).svg.png');} .ns-0 h2 #Orizaba_Nahuatl::before, .ns-0 h2#Orizaba_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Escudo_de_Armas_de_la_Ciudad_de_Orizaba.svg/35px-Escudo_de_Armas_de_la_Ciudad_de_Orizaba.svg.png');} .ns-0 h2 #Oromo::before, .ns-0 h2#Oromo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_the_Oromia_Region.svg/40px-Flag_of_the_Oromia_Region.svg.png');} .ns-0 h2 #Osage::before, .ns-0 h2#Osage::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_the_Osage_Nation.svg/40px-Flag_of_the_Osage_Nation.svg.png');} .ns-0 h2 #Ossetian::before, .ns-0 h2#Ossetian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_North_Ossetia.svg/40px-Flag_of_North_Ossetia.svg.png');} .ns-0 h2 #Ottoman_Turkish::before, .ns-0 h2#Ottoman_Turkish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_the_Ottoman_Empire_(Thicker_Crescent).svg/40px-Flag_of_the_Ottoman_Empire_(Thicker_Crescent).svg.png');} .ns-0 h2 #Pa\'o_Karen::before, .ns-0 h2#Pa\'o_Karen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_the_Pa-O_National_Organisation.svg/40px-Flag_of_the_Pa-O_National_Organisation.svg.png');} .ns-0 h2 #Pahari-Potwari::before, .ns-0 h2#Pahari-Potwari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_Azad_Kashmir.svg/40px-Flag_of_Azad_Kashmir.svg.png');} .ns-0 h2 #Palauan::before, .ns-0 h2#Palauan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Palau.svg/40px-Flag_of_Palau.svg.png');} .ns-0 h2 #Palenquero::before, .ns-0 h2#Palenquero::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Colombia.svg/40px-Flag_of_Colombia.svg.png');} .ns-0 h2 #Pali::before, .ns-0 h2#Pali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Buddhism_dham_jak.svg/35px-Buddhism_dham_jak.svg.png');} .ns-0 h2 #Panamanian_Sign_Language::before, .ns-0 h2#Panamanian_Sign_Language::before, .ns-0 h2 #San_Miguel_Creole_French::before, .ns-0 h2#San_Miguel_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ab/Flag_of_Panama.svg/40px-Flag_of_Panama.svg.png');} .ns-0 h2 #Pangasinan::before, .ns-0 h2#Pangasinan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Flag_of_Pangasinan.svg/40px-Flag_of_Pangasinan.svg.png');} .ns-0 h2 #Papiamentu::before, .ns-0 h2#Papiamentu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Flag_of_the_Netherlands_Antilles_(1986–2010).svg/40px-Flag_of_the_Netherlands_Antilles_(1986–2010).svg.png');} .ns-0 h2 #Papuan_Malay::before, .ns-0 h2#Papuan_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Kerajaan_Kaimana_Papua.gif/40px-Kerajaan_Kaimana_Papua.gif');} .ns-0 h2 #Paraguayan_Guarani::before, .ns-0 h2#Paraguayan_Guarani::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/27/Flag_of_Paraguay.svg/40px-Flag_of_Paraguay.svg.png');} .ns-0 h2 #Parauk::before, .ns-0 h2#Parauk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Wa_State.svg/40px-Flag_of_Wa_State.svg.png');} .ns-0 h2 #Pashto::before, .ns-0 h2#Pashto::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Pashto_Banner_flag_(Neutral).png/40px-Pashto_Banner_flag_(Neutral).png');} .ns-0 h2 #Pennsylvania_German::before, .ns-0 h2#Pennsylvania_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Flag_of_Pennsylvania.svg/40px-Flag_of_Pennsylvania.svg.png');} .ns-0 h2 #Penrhyn::before, .ns-0 h2#Penrhyn::before, .ns-0 h2 #Pukapukan::before, .ns-0 h2#Pukapukan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/35/Flag_of_the_Cook_Islands.svg/40px-Flag_of_the_Cook_Islands.svg.png');} .ns-0 h2 #Persian::before, .ns-0 h2#Persian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Flag_of_Iran.svg/40px-Flag_of_Iran.svg.png');} .ns-0 h2 #Phuthi::before, .ns-0 h2#Phuthi::before, .ns-0 h2 #Sotho::before, .ns-0 h2#Sotho::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4a/Flag_of_Lesotho.svg/40px-Flag_of_Lesotho.svg.png');} .ns-0 h2 #Picard::before, .ns-0 h2#Picard::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/50/Picardy_flag.png/40px-Picardy_flag.png');} .ns-0 h2 #Pichinglis::before, .ns-0 h2#Pichinglis::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Equatorial_Guinea.svg/40px-Flag_of_Equatorial_Guinea.svg.png');} .ns-0 h2 #Piedmontese::before, .ns-0 h2#Piedmontese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b9/Flag_of_Piedmont.svg/40px-Flag_of_Piedmont.svg.png');} .ns-0 h2 #Pijin::before, .ns-0 h2#Pijin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/74/Flag_of_the_Solomon_Islands.svg/40px-Flag_of_the_Solomon_Islands.svg.png');} .ns-0 h2 #Pitcairn-Norfolk::before, .ns-0 h2#Pitcairn-Norfolk::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/48/Flag_of_Norfolk_Island.svg/40px-Flag_of_Norfolk_Island.svg.png');} .ns-0 h2 #Pitjantjatjara::before, .ns-0 h2#Pitjantjatjara::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_South_Australia.svg/40px-Flag_of_South_Australia.svg.png');} .ns-0 h2 #Pnar::before, .ns-0 h2#Pnar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Emblem_of_Jaintia_Hills_Autonomous_District_Council.png/40px-Emblem_of_Jaintia_Hills_Autonomous_District_Council.png');} .ns-0 h2 #Pohnpeian::before, .ns-0 h2#Pohnpeian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Flag_of_Pohnpei_(1977-1992).svg/40px-Flag_of_Pohnpei_(1977-1992).svg.png');} .ns-0 h2 #Polabian::before, .ns-0 h2#Polabian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Banner_of_Wends.png/40px-Banner_of_Wends.png');} .ns-0 h2 #Polish::before, .ns-0 h2#Polish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/12/Flag_of_Poland.svg/40px-Flag_of_Poland.svg.png');} .ns-0 h2 #Pontic_Greek::before, .ns-0 h2#Pontic_Greek::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Flag_of_Pontus.svg/40px-Flag_of_Pontus.svg.png');} .ns-0 h2 #Portuguese::before, .ns-0 h2#Portuguese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Portuguese_language_(PT-BR).svg/40px-Flag_of_Portuguese_language_(PT-BR).svg.png');} .ns-0 h2 #Principense::before, .ns-0 h2#Principense::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Príncipe_Autonomous_Region.svg/40px-Flag_of_Príncipe_Autonomous_Region.svg.png');} .ns-0 h2 #Puerto_Rican_Sign_Language::before, .ns-0 h2#Puerto_Rican_Sign_Language::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Puerto_Rico.svg/40px-Flag_of_Puerto_Rico.svg.png');} .ns-0 h2 #Punjabi::before, .ns-0 h2#Punjabi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Flag_of_Punjab_(Paired).png/40px-Flag_of_Punjab_(Paired).png');} .ns-0 h2 #Quechua::before, .ns-0 h2#Quechua::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8f/Quechuas_flag.svg/40px-Quechuas_flag.svg.png');} .ns-0 h2 #Rakhine::before, .ns-0 h2#Rakhine::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_Rakhine.svg/40px-Flag_of_Rakhine.svg.png');} .ns-0 h2 #Rapa_Nui::before, .ns-0 h2#Rapa_Nui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Rapa_Nui,_Chile.svg/40px-Flag_of_Rapa_Nui,_Chile.svg.png');} .ns-0 h2 #Ratagnon::before, .ns-0 h2#Ratagnon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Province_of_Occidental_Mindoro_seal.svg/40px-Province_of_Occidental_Mindoro_seal.svg.png');} .ns-0 h2 #Rennellese::before, .ns-0 h2#Rennellese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Flag_of_Rennell_and_Bellona_Province.svg/40px-Flag_of_Rennell_and_Bellona_Province.svg.png');} .ns-0 h2 #Rohingya::before, .ns-0 h2#Rohingya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/83/Rohingya_flag.svg/40px-Rohingya_flag.svg.png');} .ns-0 h2 #Romagnol::before, .ns-0 h2#Romagnol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Flag_of_San_Marino.svg/40px-Flag_of_San_Marino.svg.png');} .ns-0 h2 #Romanian::before, .ns-0 h2#Romanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Romania.svg/40px-Flag_of_Romania.svg.png');} .ns-0 h2 #Romansh::before, .ns-0 h2#Romansh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Flag_of_Canton_of_Graubünden.svg/40px-Flag_of_Canton_of_Graubünden.svg.png');} .ns-0 h2 #Rotuman::before, .ns-0 h2#Rotuman::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bb/Flag_of_Rotuma_(1987-1988).svg/40px-Flag_of_Rotuma_(1987-1988).svg.png');} .ns-0 h2 #Russian::before, .ns-0 h2#Russian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Flag_of_Russia.svg/40px-Flag_of_Russia.svg.png');} .ns-0 h2 #Rutul::before, .ns-0 h2#Rutul::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Flag_of_the_Rutul_People.svg/40px-Flag_of_the_Rutul_People.svg.png');} .ns-0 h2 #Rwanda-Rundi::before, .ns-0 h2#Rwanda-Rundi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Flag_of_Rwanda_and_Burundi.svg/40px-Flag_of_Rwanda_and_Burundi.svg.png');} .ns-0 h2 #Réunion_Creole_French::before, .ns-0 h2#Réunion_Creole_French::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Proposed_flag_of_Réunion_(VAR).svg/40px-Proposed_flag_of_Réunion_(VAR).svg.png');} .ns-0 h2 #S\'gaw_Karen::before, .ns-0 h2#S\'gaw_Karen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Flag_of_the_Karen_National_Union.svg/40px-Flag_of_the_Karen_National_Union.svg.png');} .ns-0 h2 #Saho::before, .ns-0 h2#Saho::before{padding-right:5px; content:url("//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Flag_of_the_Saho_People's_Democratic_Movement.svg/40px-Flag_of_the_Saho_People's_Democratic_Movement.svg.png");} .ns-0 h2 #Sambali::before, .ns-0 h2#Sambali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/81/Seal_of_Zambales.svg/40px-Seal_of_Zambales.svg.png');} .ns-0 h2 #Samoan::before, .ns-0 h2#Samoan::before, .ns-0 h2 #Samoan_Plantation_Pidgin::before, .ns-0 h2#Samoan_Plantation_Pidgin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/31/Flag_of_Samoa.svg/40px-Flag_of_Samoa.svg.png');} .ns-0 h2 #Samogitian::before, .ns-0 h2#Samogitian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Flag_of_Žemaitija.svg/40px-Flag_of_Žemaitija.svg.png');} .ns-0 h2 #Sanaviron::before, .ns-0 h2#Sanaviron::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Bandera_de_la_Ciudad_de_Córdoba.svg/40px-Bandera_de_la_Ciudad_de_Córdoba.svg.png');} .ns-0 h2 #Sango::before, .ns-0 h2#Sango::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_the_Central_African_Republic.svg/40px-Flag_of_the_Central_African_Republic.svg.png');} .ns-0 h2 #Sanskrit::before, .ns-0 h2#Sanskrit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Red_om_symbol.png/35px-Red_om_symbol.png');} .ns-0 h2 #Sardinian::before, .ns-0 h2#Sardinian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Flag_of_Sardinia,_Italy.svg/40px-Flag_of_Sardinia,_Italy.svg.png');} .ns-0 h2 #Sassarese::before, .ns-0 h2#Sassarese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Flag_of_Sassari.svg/40px-Flag_of_Sassari.svg.png');} .ns-0 h2 #Saterland_Frisian::before, .ns-0 h2#Saterland_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2f/DEU_Saterland_Flag.svg/40px-DEU_Saterland_Flag.svg.png');} .ns-0 h2 #Scanian::before, .ns-0 h2#Scanian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Banner_of_Arms_of_Scania.svg/35px-Banner_of_Arms_of_Scania.svg.png');} .ns-0 h2 #Scots::before, .ns-0 h2#Scots::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_Scotland.svg/40px-Flag_of_Scotland.svg.png');} .ns-0 h2 #Sedang::before, .ns-0 h2#Sedang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/19/Flag_of_Sedang.svg/36px-Flag_of_Sedang.svg.png');} .ns-0 h2 #Selk\'nam::before, .ns-0 h2#Selk\'nam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Bandera_de_la_Provincia_de_Tierra_del_Fuego.svg/40px-Bandera_de_la_Provincia_de_Tierra_del_Fuego.svg.png');} .ns-0 h2 #Serbo-Croatian::before, .ns-0 h2#Serbo-Croatian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/HR-BA-ME-RS_flag.svg/40px-HR-BA-ME-RS_flag.svg.png');} .ns-0 h2 #Serer::before, .ns-0 h2#Serer::before, .ns-0 h2 #Wolof::before, .ns-0 h2#Wolof::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Flag_of_Senegal.svg/40px-Flag_of_Senegal.svg.png');} .ns-0 h2 #Seri::before, .ns-0 h2#Seri::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Bandera_de_la_Nacion_Comcaac.svg/40px-Bandera_de_la_Nacion_Comcaac.svg.png');} .ns-0 h2 #Seychellois_Creole::before, .ns-0 h2#Seychellois_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Flag_of_Seychelles.svg/40px-Flag_of_Seychelles.svg.png');} .ns-0 h2 #Shan::before, .ns-0 h2#Shan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/68/Flag_of_Shan_State.svg/40px-Flag_of_Shan_State.svg.png');} .ns-0 h2 #Shihhi_Arabic::before, .ns-0 h2#Shihhi_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Flag_of_Sharjah_and_Ras_Al_Khaimah.svg/40px-Flag_of_Sharjah_and_Ras_Al_Khaimah.svg.png');} .ns-0 h2 #Sicilian::before, .ns-0 h2#Sicilian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Flag_of_Sicily.svg/40px-Flag_of_Sicily.svg.png');} .ns-0 h2 #Sidamo::before, .ns-0 h2#Sidamo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/59/Flag_of_Sidama.svg/40px-Flag_of_Sidama.svg.png');} .ns-0 h2 #Sikkimese::before, .ns-0 h2#Sikkimese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Flag_of_Sikkim_(1967-1975).svg/40px-Flag_of_Sikkim_(1967-1975).svg.png');} .ns-0 h2 #Silesian::before, .ns-0 h2#Silesian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Flag_of_Upper_Silesia.svg/40px-Flag_of_Upper_Silesia.svg.png');} .ns-0 h2 #Sindhi::before, .ns-0 h2#Sindhi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c3/Flag_of_Sindh.svg/40px-Flag_of_Sindh.svg.png');} .ns-0 h2 #Sinhalese::before, .ns-0 h2#Sinhalese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/11/Flag_of_Sri_Lanka.svg/40px-Flag_of_Sri_Lanka.svg.png');} .ns-0 h2 #Slavomolisano::before, .ns-0 h2#Slavomolisano::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Molise.svg/40px-Flag_of_Molise.svg.png');} .ns-0 h2 #Slovak::before, .ns-0 h2#Slovak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e6/Flag_of_Slovakia.svg/40px-Flag_of_Slovakia.svg.png');} .ns-0 h2 #Slovene::before, .ns-0 h2#Slovene::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Flag_of_Slovenia.svg/40px-Flag_of_Slovenia.svg.png');} .ns-0 h2 #Slovincian::before, .ns-0 h2#Slovincian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Wappen_Pommern.svg/35px-Wappen_Pommern.svg.png');} .ns-0 h2 #Soga::before, .ns-0 h2#Soga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d8/Flag_of_Busoga_(royal_standard).png/40px-Flag_of_Busoga_(royal_standard).png');} .ns-0 h2 #Solombala_English::before, .ns-0 h2#Solombala_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/20/Coat_of_Arms_of_Arkhangelsk.svg/32px-Coat_of_Arms_of_Arkhangelsk.svg.png');} .ns-0 h2 #Somali::before, .ns-0 h2#Somali::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Flag_of_Somalia.svg/40px-Flag_of_Somalia.svg.png');} .ns-0 h2 #South_Levantine_Arabic::before, .ns-0 h2#South_Levantine_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/00/Flag_of_Palestine.svg/40px-Flag_of_Palestine.svg.png');} .ns-0 h2 #Southern_Altai::before, .ns-0 h2#Southern_Altai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Flag_of_Altai_Republic.svg/40px-Flag_of_Altai_Republic.svg.png');} .ns-0 h2 #Southern_Ndebele::before, .ns-0 h2#Southern_Ndebele::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Flag_of_Mpumalanga_Province.svg/40px-Flag_of_Mpumalanga_Province.svg.png');} .ns-0 h2 #Spanish::before, .ns-0 h2#Spanish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Spanish_language_(ES-MX).svg/40px-Flag_of_Spanish_language_(ES-MX).svg.png');} .ns-0 h2 #Sri_Lankan_Creole_Malay::before, .ns-0 h2#Sri_Lankan_Creole_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Flag_of_the_Southern_Province_(Sri_Lanka).PNG/40px-Flag_of_the_Southern_Province_(Sri_Lanka).PNG');} .ns-0 h2 #Sudovian::before, .ns-0 h2#Sudovian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Suvalkija.svg/40px-Flag_of_Suvalkija.svg.png');} .ns-0 h2 #Sumerian::before, .ns-0 h2#Sumerian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Cuneiform_sumer_dingir.svg/28px-Cuneiform_sumer_dingir.svg.png');} .ns-0 h2 #Sundanese::before, .ns-0 h2#Sundanese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_West_Java_(vectorised).svg/40px-Flag_of_West_Java_(vectorised).svg.png');} .ns-0 h2 #Surigaonon::before, .ns-0 h2#Surigaonon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Flag_of_Surigao_del_Norte.svg/40px-Flag_of_Surigao_del_Norte.svg.png');} .ns-0 h2 #Swabian::before, .ns-0 h2#Swabian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/14/Flagge_Königreich_Württemberg.svg/40px-Flagge_Königreich_Württemberg.svg.png');} .ns-0 h2 #Swazi::before, .ns-0 h2#Swazi::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fb/Flag_of_Eswatini.svg/40px-Flag_of_Eswatini.svg.png');} .ns-0 h2 #Swedish::before, .ns-0 h2#Swedish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Flag_of_Sweden.svg/40px-Flag_of_Sweden.svg.png');} .ns-0 h2 #Tabasaran::before, .ns-0 h2#Tabasaran::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Ethnic_flag_of_Tabasarans.svg/40px-Ethnic_flag_of_Tabasarans.svg.png');} .ns-0 h2 #Tabasco_Nahuatl::before, .ns-0 h2#Tabasco_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Coat_of_arms_of_Tabasco_(México).svg/32px-Coat_of_arms_of_Tabasco_(México).svg.png');} .ns-0 h2 #Tachawit::before, .ns-0 h2#Tachawit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Flag_of_Chaouia.svg/40px-Flag_of_Chaouia.svg.png');} .ns-0 h2 #Tagalog::before, .ns-0 h2#Tagalog::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/99/Flag_of_the_Philippines.svg/40px-Flag_of_the_Philippines.svg.png');} .ns-0 h2 #Tahitian::before, .ns-0 h2#Tahitian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/db/Flag_of_French_Polynesia.svg/40px-Flag_of_French_Polynesia.svg.png');} .ns-0 h2 #Tai_Dam::before, .ns-0 h2#Tai_Dam::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/93/Flag_of_the_Tai_Dam_People.svg/40px-Flag_of_the_Tai_Dam_People.svg.png');} .ns-0 h2 #Tai_Dón::before, .ns-0 h2#Tai_Dón::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/86/Flag_of_Tay_Khao.png/40px-Flag_of_Tay_Khao.png');} .ns-0 h2 #Taimyr_Pidgin_Russian::before, .ns-0 h2#Taimyr_Pidgin_Russian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Flag_of_the_Siberian_Federal_District.png/40px-Flag_of_the_Siberian_Federal_District.png');} .ns-0 h2 #Tajik::before, .ns-0 h2#Tajik::before, .ns-0 h2 #Tajiki_Arabic::before, .ns-0 h2#Tajiki_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Flag_of_Tajikistan.svg/40px-Flag_of_Tajikistan.svg.png');} .ns-0 h2 #Talysh::before, .ns-0 h2#Talysh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/de/Flag_of_the_Talysh_National_Movement.svg/40px-Flag_of_the_Talysh_National_Movement.svg.png');} .ns-0 h2 #Tarifit::before, .ns-0 h2#Tarifit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Flag_of_the_Republic_of_the_Rif.svg/40px-Flag_of_the_Republic_of_the_Rif.svg.png');} .ns-0 h2 #Tarjumo::before, .ns-0 h2#Tarjumo::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Kanem_flag_from_dulcerta_1339-pt.svg/40px-Kanem_flag_from_dulcerta_1339-pt.svg.png');} .ns-0 h2 #Tatar::before, .ns-0 h2#Tatar::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/28/Flag_of_Tatarstan.svg/40px-Flag_of_Tatarstan.svg.png');} .ns-0 h2 #Tausug::before, .ns-0 h2#Tausug::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/da/Late_19th_Century_Flag_of_Sulu.svg/40px-Late_19th_Century_Flag_of_Sulu.svg.png');} .ns-0 h2 #Tayo::before, .ns-0 h2#Tayo::before, .ns-0 h2 #Xârâcùù::before, .ns-0 h2#Xârâcùù::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Flag_of_FLNKS.svg/40px-Flag_of_FLNKS.svg.png');} .ns-0 h2 #Tboli::before, .ns-0 h2#Tboli::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/7f/South_Cotabato_Flag.png/40px-South_Cotabato_Flag.png');} .ns-0 h2 #Temascaltepec_Nahuatl::before, .ns-0 h2#Temascaltepec_Nahuatl::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/4b/TEMASCALTEPEC.svg/35px-TEMASCALTEPEC.svg.png');} .ns-0 h2 #Terengganu_Malay::before, .ns-0 h2#Terengganu_Malay::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Flag_of_Terengganu.svg/40px-Flag_of_Terengganu.svg.png');} .ns-0 h2 #Ternate::before, .ns-0 h2#Ternate::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/61/Bendera_Ternate_-_Almulk_Buldan_Ternate.svg/40px-Bendera_Ternate_-_Almulk_Buldan_Ternate.svg.png');} .ns-0 h2 #Tetum::before, .ns-0 h2#Tetum::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_East_Timor.svg/40px-Flag_of_East_Timor.svg.png');} .ns-0 h2 #Thai::before, .ns-0 h2#Thai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Flag_of_Thailand.svg/40px-Flag_of_Thailand.svg.png');} .ns-0 h2 #Tibetan::before, .ns-0 h2#Tibetan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Flag_of_Tibet.svg/40px-Flag_of_Tibet.svg.png');} .ns-0 h2 #Ticuna::before, .ns-0 h2#Ticuna::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6b/Bandeira_do_Amazonas.svg/40px-Bandeira_do_Amazonas.svg.png');} .ns-0 h2 #Tlingit::before, .ns-0 h2#Tlingit::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/94/Flag_of_the_Organized_Village_of_Kake.svg/40px-Flag_of_the_Organized_Village_of_Kake.svg.png');} .ns-0 h2 #Toba_Batak::before, .ns-0 h2#Toba_Batak::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Flag_of_Batak_WRB.svg/40px-Flag_of_Batak_WRB.svg.png');} .ns-0 h2 #Tobagonian_Creole_English::before, .ns-0 h2#Tobagonian_Creole_English::before, .ns-0 h2 #Trinidadian_Creole_English::before, .ns-0 h2#Trinidadian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_Trinidad_and_Tobago.svg/40px-Flag_of_Trinidad_and_Tobago.svg.png');} .ns-0 h2 #Tok_Pisin::before, .ns-0 h2#Tok_Pisin::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Flag_of_Papua_New_Guinea.svg/40px-Flag_of_Papua_New_Guinea.svg.png');} .ns-0 h2 #Tokelauan::before, .ns-0 h2#Tokelauan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8e/Flag_of_Tokelau.svg/40px-Flag_of_Tokelau.svg.png');} .ns-0 h2 #Tongan::before, .ns-0 h2#Tongan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Flag_of_Tonga.svg/40px-Flag_of_Tonga.svg.png');} .ns-0 h2 #Tooro::before, .ns-0 h2#Tooro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Toro.gif/40px-Flag_of_Toro.gif');} .ns-0 h2 #Transylvanian_Saxon::before, .ns-0 h2#Transylvanian_Saxon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Flag_of_Transylvania_Saxons.svg/40px-Flag_of_Transylvania_Saxons.svg.png');} .ns-0 h2 #Tsonga::before, .ns-0 h2#Tsonga::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/70/Flag_of_Tsonga_language.svg/40px-Flag_of_Tsonga_language.svg.png');} .ns-0 h2 #Tsou::before, .ns-0 h2#Tsou::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_Chiayi_County.svg/40px-Flag_of_Chiayi_County.svg.png');} .ns-0 h2 #Tswana::before, .ns-0 h2#Tswana::before, .ns-0 h2 #ǃXóõ::before, .ns-0 h2#ǃXóõ::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Flag_of_Botswana.svg/40px-Flag_of_Botswana.svg.png');} .ns-0 h2 #Tuareg::before, .ns-0 h2#Tuareg::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Touareg_People_Flag.svg/40px-Touareg_People_Flag.svg.png');} .ns-0 h2 #Tunisian_Arabic::before, .ns-0 h2#Tunisian_Arabic::before, .ns-0 h2 #Tunisian_Berber::before, .ns-0 h2#Tunisian_Berber::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Flag_of_Tunisia.svg/40px-Flag_of_Tunisia.svg.png');} .ns-0 h2 #Turkana::before, .ns-0 h2#Turkana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Flag_of_Turkana_County.gif/40px-Flag_of_Turkana_County.gif');} .ns-0 h2 #Turkish::before, .ns-0 h2#Turkish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Flag_of_Turkey.svg/40px-Flag_of_Turkey.svg.png');} .ns-0 h2 #Turkmen::before, .ns-0 h2#Turkmen::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Flag_of_Turkmenistan.svg/40px-Flag_of_Turkmenistan.svg.png');} .ns-0 h2 #Tuvaluan::before, .ns-0 h2#Tuvaluan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/38/Flag_of_Tuvalu.svg/40px-Flag_of_Tuvalu.svg.png');} .ns-0 h2 #Tuvan::before, .ns-0 h2#Tuvan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Tuva.svg/40px-Flag_of_Tuva.svg.png');} .ns-0 h2 #Tzotzil::before, .ns-0 h2#Tzotzil::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Flag_of_the_Mayan_People.svg/40px-Flag_of_the_Mayan_People.svg.png');} .ns-0 h2 #Tày::before, .ns-0 h2#Tày::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Flag_of_the_Tay_people_(1947-1954).svg/40px-Flag_of_the_Tay_people_(1947-1954).svg.png');} .ns-0 h2 #Tübatulabal::before, .ns-0 h2#Tübatulabal::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Seal_of_Kern_County,_California.png/40px-Seal_of_Kern_County,_California.png');} .ns-0 h2 #Udmurt::before, .ns-0 h2#Udmurt::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Flag_of_Udmurtia.svg/40px-Flag_of_Udmurtia.svg.png');} .ns-0 h2 #Ukrainian::before, .ns-0 h2#Ukrainian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/49/Flag_of_Ukraine.svg/40px-Flag_of_Ukraine.svg.png');} .ns-0 h2 #Umbrian::before, .ns-0 h2#Umbrian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Flag_of_Umbria.svg/40px-Flag_of_Umbria.svg.png');} .ns-0 h2 #Unserdeutsch::before, .ns-0 h2#Unserdeutsch::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Flag_of_East_New_Britain.svg/40px-Flag_of_East_New_Britain.svg.png');} .ns-0 h2 #Urdu::before, .ns-0 h2#Urdu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/32/Flag_of_Pakistan.svg/40px-Flag_of_Pakistan.svg.png');} .ns-0 h2 #Uyghur::before, .ns-0 h2#Uyghur::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Kokbayraq_flag.svg/40px-Kokbayraq_flag.svg.png');} .ns-0 h2 #Uzbek::before, .ns-0 h2#Uzbek::before, .ns-0 h2 #Uzbeki_Arabic::before, .ns-0 h2#Uzbeki_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/84/Flag_of_Uzbekistan.svg/40px-Flag_of_Uzbekistan.svg.png');} .ns-0 h2 #Vai::before, .ns-0 h2#Vai::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Flag_of_Liberia.svg/40px-Flag_of_Liberia.svg.png');} .ns-0 h2 #Veddah::before, .ns-0 h2#Veddah::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Flag_of_the_Uva_Province_(Sri_Lanka).svg/40px-Flag_of_the_Uva_Province_(Sri_Lanka).svg.png');} .ns-0 h2 #Venda::before, .ns-0 h2#Venda::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/21/Flag_of_Venda_(1973–1994).svg/40px-Flag_of_Venda_(1973–1994).svg.png');} .ns-0 h2 #Venetan::before, .ns-0 h2#Venetan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d5/Flag_of_Veneto.svg/40px-Flag_of_Veneto.svg.png');} .ns-0 h2 #Veps::before, .ns-0 h2#Veps::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Vepsia.svg/40px-Flag_of_Vepsia.svg.png');} .ns-0 h2 #Vilamovian::before, .ns-0 h2#Vilamovian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/3/3d/POL_Wilamowice_COA.svg/35px-POL_Wilamowice_COA.svg.png');} .ns-0 h2 #Vincentian_Creole_English::before, .ns-0 h2#Vincentian_Creole_English::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Flag_of_Saint_Vincent_and_the_Grenadines.svg/40px-Flag_of_Saint_Vincent_and_the_Grenadines.svg.png');} .ns-0 h2 #Virgin_Islands_Creole::before, .ns-0 h2#Virgin_Islands_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Flag_of_the_United_States_Virgin_Islands.svg/40px-Flag_of_the_United_States_Virgin_Islands.svg.png');} .ns-0 h2 #Volapük::before, .ns-0 h2#Volapük::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Volapuk_symbol.svg/40px-Volapuk_symbol.svg.png');} .ns-0 h2 #Volga_German::before, .ns-0 h2#Volga_German::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Flag_of_Volga_Germans_(version).svg/40px-Flag_of_Volga_Germans_(version).svg.png');} .ns-0 h2 #Votic::before, .ns-0 h2#Votic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Votic_Flag.svg/40px-Votic_Flag.svg.png');} .ns-0 h2 #Võro::before, .ns-0 h2#Võro::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Võrumaa_lipp.svg/40px-Võrumaa_lipp.svg.png');} .ns-0 h2 #Walloon::before, .ns-0 h2#Walloon::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/42/Flag_of_Wallonia.svg/40px-Flag_of_Wallonia.svg.png');} .ns-0 h2 #Wapishana::before, .ns-0 h2#Wapishana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/9/98/Bandeira_de_Roraima.svg/40px-Bandeira_de_Roraima.svg.png');} .ns-0 h2 #Waray-Waray::before, .ns-0 h2#Waray-Waray::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Biliran_Provincial_Flag.png/40px-Biliran_Provincial_Flag.png');} .ns-0 h2 #Wayuu::before, .ns-0 h2#Wayuu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/13/Panteera_Wayuu_Aumentado.png/40px-Panteera_Wayuu_Aumentado.png');} .ns-0 h2 #Welsh::before, .ns-0 h2#Welsh::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/dc/Flag_of_Wales.svg/40px-Flag_of_Wales.svg.png');} .ns-0 h2 #West_Circassian::before, .ns-0 h2#West_Circassian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/16/Flag_of_Adygea.svg/40px-Flag_of_Adygea.svg.png');} .ns-0 h2 #West_Flemish::before, .ns-0 h2#West_Flemish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Flag_of_West_Flanders.svg/40px-Flag_of_West_Flanders.svg.png');} .ns-0 h2 #West_Frisian::before, .ns-0 h2#West_Frisian::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Frisian_flag.svg/40px-Frisian_flag.svg.png');} .ns-0 h2 #West_Miraya_Bikol::before, .ns-0 h2#West_Miraya_Bikol::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Albay_Flag.png/40px-Albay_Flag.png');} .ns-0 h2 #Western_Apache::before, .ns-0 h2#Western_Apache::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Coat_of_arms_of_Sonora.svg/35px-Coat_of_arms_of_Sonora.svg.png');} .ns-0 h2 #Western_Cham::before, .ns-0 h2#Western_Cham::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Bandera_Front_Alliberament_Cham.svg/40px-Bandera_Front_Alliberament_Cham.svg.png');} .ns-0 h2 #Western_Mari::before, .ns-0 h2#Western_Mari::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/24/Flag_of_Gornomariysky_rayon.svg/40px-Flag_of_Gornomariysky_rayon.svg.png');} .ns-0 h2 #Wichí_Lhamtés_Güisnay::before, .ns-0 h2#Wichí_Lhamtés_Güisnay::before, .ns-0 h2 #Wichí_Lhamtés_Nocten::before, .ns-0 h2#Wichí_Lhamtés_Nocten::before, .ns-0 h2 #Wichí_Lhamtés_Vejoz::before, .ns-0 h2#Wichí_Lhamtés_Vejoz::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/66/Bandera_del_pueblo_Wichi.svg/40px-Bandera_del_pueblo_Wichi.svg.png');} .ns-0 h2 #Woiwurrung::before, .ns-0 h2#Woiwurrung::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/08/Flag_of_Victoria_(Australia).svg/40px-Flag_of_Victoria_(Australia).svg.png');} .ns-0 h2 #Wolio::before, .ns-0 h2#Wolio::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/55/Lambang_Kota_Bau-Bau.png/35px-Lambang_Kota_Bau-Bau.png');} .ns-0 h2 #Xerénte::before, .ns-0 h2#Xerénte::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Bandeira_do_Tocantins.svg/40px-Bandeira_do_Tocantins.svg.png');} .ns-0 h2 #Xhosa::before, .ns-0 h2#Xhosa::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Flag_of_Ciskei.svg/40px-Flag_of_Ciskei.svg.png');} .ns-0 h2 #Xokleng::before, .ns-0 h2#Xokleng::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Bandeira_de_Santa_Catarina.svg/40px-Bandeira_de_Santa_Catarina.svg.png');} .ns-0 h2 #Yakan::before, .ns-0 h2#Yakan::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/87/Flag_of_Basilan.svg/40px-Flag_of_Basilan.svg.png');} .ns-0 h2 #Yakut::before, .ns-0 h2#Yakut::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/e/eb/Flag_of_Sakha.svg/40px-Flag_of_Sakha.svg.png');} .ns-0 h2 #Yapese::before, .ns-0 h2#Yapese::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Flag_of_Yap.svg/40px-Flag_of_Yap.svg.png');} .ns-0 h2 #Yaqui::before, .ns-0 h2#Yaqui::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/41/Flag_of_the_Pascua_Yaqui_Tribe_of_Arizona.svg/40px-Flag_of_the_Pascua_Yaqui_Tribe_of_Arizona.svg.png');} .ns-0 h2 #Ye\'kwana::before, .ns-0 h2#Ye\'kwana::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/0/06/Flag_of_Venezuela.svg/40px-Flag_of_Venezuela.svg.png');} .ns-0 h2 #Yemeni_Arabic::before, .ns-0 h2#Yemeni_Arabic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Yemen.svg/40px-Flag_of_Yemen.svg.png');} .ns-0 h2 #Yiddish::before, .ns-0 h2#Yiddish::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Proposed_Yiddish_flag.svg/40px-Proposed_Yiddish_flag.svg.png');} .ns-0 h2 #Yilan_Creole::before, .ns-0 h2#Yilan_Creole::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b4/Flag_of_Yilan_County.svg/40px-Flag_of_Yilan_County.svg.png');} .ns-0 h2 #Yogad::before, .ns-0 h2#Yogad::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Flag_of_Echague,_Isabela_(2022-present).png/40px-Flag_of_Echague,_Isabela_(2022-present).png');} .ns-0 h2 #Yola::before, .ns-0 h2#Yola::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/40/Flag_of_Yola.svg/40px-Flag_of_Yola.svg.png');} .ns-0 h2 #Yonaguni::before, .ns-0 h2#Yonaguni::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/4/45/Flag_of_Yonaguni,_Okinawa.svg/40px-Flag_of_Yonaguni,_Okinawa.svg.png');} .ns-0 h2 #Yucatec_Maya::before, .ns-0 h2#Yucatec_Maya::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/2/26/Flag_of_the_Republic_of_Yucatan.svg/40px-Flag_of_the_Republic_of_Yucatan.svg.png');} .ns-0 h2 #Yuracare::before, .ns-0 h2#Yuracare::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Flag_of_Cochabamba.svg/40px-Flag_of_Cochabamba.svg.png');} .ns-0 h2 #Zaniza_Zapotec::before, .ns-0 h2#Zaniza_Zapotec::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Flag_of_Oaxaca.svg/40px-Flag_of_Oaxaca.svg.png');} .ns-0 h2 #Zarma::before, .ns-0 h2#Zarma::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Flag_of_Niger.svg/40px-Flag_of_Niger.svg.png');} .ns-0 h2 #Zazaki::before, .ns-0 h2#Zazaki::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/8/89/Flag_of_Zazaistan.svg/40px-Flag_of_Zazaistan.svg.png');} .ns-0 h2 #Zealandic::before, .ns-0 h2#Zealandic::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/5/54/Flag_of_Zeeland.svg/40px-Flag_of_Zeeland.svg.png');} .ns-0 h2 #Zhuang::before, .ns-0 h2#Zhuang::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Flag_of_the_Zhuang_people.svg/40px-Flag_of_the_Zhuang_people.svg.png');} .ns-0 h2 #Zulu::before, .ns-0 h2#Zulu::before{padding-right:5px; content:url('//upload.wikimedia.org/wikipedia/commons/thumb/6/60/Flag_of_the_KwaZulu-Natal_Province.png/40px-Flag_of_the_KwaZulu-Natal_Province.png');} jck1btrdumjdqvveo7urrvsepfplb4z MediaWiki:Gadget-WiktPreviewRightTOCs.css 8 17940 88882 2017-09-03T07:27:11Z en>Dixtosa 0 88882 css text/css html:not([dummyparam]) .ns-0 #toc { float: right; clear: right; margin-left: 7px; margin-bottom: 6px; } 97xoqtgvaxinybefujx240ftm0v7mhb 88883 88882 2026-08-06T23:09:19Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-WiktPreviewRightTOCs.css]] 88882 css text/css html:not([dummyparam]) .ns-0 #toc { float: right; clear: right; margin-left: 7px; margin-bottom: 6px; } 97xoqtgvaxinybefujx240ftm0v7mhb MediaWiki:Gadget-LogoTiles.css 8 17941 88884 2026-04-28T13:04:23Z en>Catonif 0 lower logo a bit, see [[Wiktionary:Grease_pit/2026/April#Setting_to_enable_the_"tiles"_logo_is_suddenly_broken|discussion]] 88884 css text/css #p-logo a { background-image: url(//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/WiktionaryEn.svg/250px-WiktionaryEn.svg.png); background-size: 136px; background-repeat: no-repeat; background-position-y: 0; } mpf24gdbw8xbu4dt5n7w716rkty4axh 88885 88884 2026-08-06T23:09:27Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-LogoTiles.css]] 88884 css text/css #p-logo a { background-image: url(//upload.wikimedia.org/wikipedia/commons/thumb/f/ff/WiktionaryEn.svg/250px-WiktionaryEn.svg.png); background-size: 136px; background-repeat: no-repeat; background-position-y: 0; } mpf24gdbw8xbu4dt5n7w716rkty4axh MediaWiki:Gadget-RoundBullets4Lists.css 8 17942 88886 2014-07-31T06:05:56Z en>Kephir 0 Migrating pure-CSS gadgets from [[WT:PREFS]] 88886 css text/css ul { list-style-image:none; list-style-type:disc;} d4wgez9ezgmv0qm269tbobokv69mkgh 88887 88886 2026-08-06T23:09:38Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-RoundBullets4Lists.css]] 88886 css text/css ul { list-style-image:none; list-style-type:disc;} d4wgez9ezgmv0qm269tbobokv69mkgh MediaWiki:Gadget-BC-AD.js 8 17943 88888 2019-11-15T19:29:56Z en>Erutuon 0 fix handling of CE ranges such as "46 CE – 120 CE" 88888 javascript text/javascript // <nowiki> // Switches the year-numbering system from BCE/CE to BC/AD /* jshint undef: true */ /* globals $, mw */ "use strict"; function yearFormatSwitch() { /* * This code supports date labels formatted using the following wikitext. * (See {{B.C.E}} and {{C.E.}}.) BCE can be replaced by CE: <small class="ce-date">[[Appendix:Glossary#BCE|<span title="Glossary and display preference">BCE</span>]]</small> */ var convert = { "BCE": "BC", "B.C.E.": "B.C.", "CE": "AD", "C.E.": "A.D." }; var datetags = document.getElementsByClassName("ce-date"); var articlePath = mw.config.get("wgArticlePath"); var links = { BC: articlePath.replace("$1", "Appendix:Glossary#BC"), AD: articlePath.replace("$1", "Appendix:Glossary#AD") }; for (var i = 0; i < datetags.length; i++) { var datetag = datetags[i], link = datetag && datetag.firstChild, innerSpan = link && link.firstChild, abbreviation = innerSpan && innerSpan.firstChild && innerSpan.firstChild.nodeValue; if (!(link && innerSpan && abbreviation)) continue; if (abbreviation === "CE" || abbreviation === "C.E.") { link.href = links.AD; innerSpan.textContent = convert[abbreviation]; // Change position of year number: 10 CE → AD 10. var beforeDatetag = datetag.previousSibling; if (!beforeDatetag) continue; var patt = /((?:\d{1,4}\s*(?:-|–|to)\s*)?\d{1,4})\s*$/; // first if hyphen-minus, then en-dash var matches = beforeDatetag.nodeValue.match(patt); if (matches === null) continue; var yearNumber = matches[matches.length - 1]; beforeDatetag.nodeValue = beforeDatetag.nodeValue.substring(0, beforeDatetag.nodeValue.length - matches[0].length); datetag.parentElement.insertBefore(document.createTextNode(" " + yearNumber), datetag.nextSibling); } else if (abbreviation === "BCE" || abbreviation === "B.C.E.") { datetag.firstChild.href = links.BC; innerSpan.textContent = convert[abbreviation]; } } /* * This code handles dates with the class ce-date2: * <small class="ce-date2">CE</small> */ var datetags2 = document.getElementsByClassName("ce-date2"); for (i = 0; i < datetags2.length; ++i ) { var datetag2 = datetags2[i]; datetag2.textContent = convert[datetag2.textContent]; } } $(yearFormatSwitch); // </nowiki> cb3cj9vs7sca9owe00ofpdhot9lavv0 88889 88888 2026-08-06T23:09:47Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-BC-AD.js]] 88888 javascript text/javascript // <nowiki> // Switches the year-numbering system from BCE/CE to BC/AD /* jshint undef: true */ /* globals $, mw */ "use strict"; function yearFormatSwitch() { /* * This code supports date labels formatted using the following wikitext. * (See {{B.C.E}} and {{C.E.}}.) BCE can be replaced by CE: <small class="ce-date">[[Appendix:Glossary#BCE|<span title="Glossary and display preference">BCE</span>]]</small> */ var convert = { "BCE": "BC", "B.C.E.": "B.C.", "CE": "AD", "C.E.": "A.D." }; var datetags = document.getElementsByClassName("ce-date"); var articlePath = mw.config.get("wgArticlePath"); var links = { BC: articlePath.replace("$1", "Appendix:Glossary#BC"), AD: articlePath.replace("$1", "Appendix:Glossary#AD") }; for (var i = 0; i < datetags.length; i++) { var datetag = datetags[i], link = datetag && datetag.firstChild, innerSpan = link && link.firstChild, abbreviation = innerSpan && innerSpan.firstChild && innerSpan.firstChild.nodeValue; if (!(link && innerSpan && abbreviation)) continue; if (abbreviation === "CE" || abbreviation === "C.E.") { link.href = links.AD; innerSpan.textContent = convert[abbreviation]; // Change position of year number: 10 CE → AD 10. var beforeDatetag = datetag.previousSibling; if (!beforeDatetag) continue; var patt = /((?:\d{1,4}\s*(?:-|–|to)\s*)?\d{1,4})\s*$/; // first if hyphen-minus, then en-dash var matches = beforeDatetag.nodeValue.match(patt); if (matches === null) continue; var yearNumber = matches[matches.length - 1]; beforeDatetag.nodeValue = beforeDatetag.nodeValue.substring(0, beforeDatetag.nodeValue.length - matches[0].length); datetag.parentElement.insertBefore(document.createTextNode(" " + yearNumber), datetag.nextSibling); } else if (abbreviation === "BCE" || abbreviation === "B.C.E.") { datetag.firstChild.href = links.BC; innerSpan.textContent = convert[abbreviation]; } } /* * This code handles dates with the class ce-date2: * <small class="ce-date2">CE</small> */ var datetags2 = document.getElementsByClassName("ce-date2"); for (i = 0; i < datetags2.length; ++i ) { var datetag2 = datetags2[i]; datetag2.textContent = convert[datetag2.textContent]; } } $(yearFormatSwitch); // </nowiki> cb3cj9vs7sca9owe00ofpdhot9lavv0 MediaWiki:Gadget-AutoContrastFixer.js 8 17944 88890 2025-10-08T16:06:59Z en>Surjection 0 88890 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ /** * Automatically adjusts contrast of templates in night mode. * * Author(s): Surjection * Last updated: 2025-10-08 */ // [[MediaWiki:Gadget-WiktGadgetPrefs.js]] const preferences = mw.wiktGadgetPrefs.get( "autoContrastFixer", { label: { en: "Automatically fix custom template colors in night mode", }, }, { darkTextColorOverride: { type: "boolean", default: false, label: { en: "Apply also to templates with explicit dark text colors", }, }, } ); const darkTextColorOverride = preferences.darkTextColorOverride; /* Color conversion code. */ /**************************/ function parseCssValue(cssAlpha, divisor) { /** * Parses a numeric value in CSS syntax, either given directly or * as a percentage. * * If a divisor is given, it is used to scale the value, unless it is * a percentage. */ if (cssAlpha.endsWith("%")) { return parseCssValue(cssAlpha.slice(0, -1).trim(), 100.0); } return Number(cssAlpha) / (divisor || 1.0); } // RegEx used by parseCssColor const RE_CSS_HEX_COLOR_3 = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/; const RE_CSS_HEX_COLOR_6 = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/; const RE_CSS_RGB_COLOR = /^rgb\(\s*([0-9.]+\s*%?)(?:\s+|\s*,\s*)([0-9.]+\s*%?)(?:\s+|\s*,\s*)([0-9.]+\s*%?)\s*\)$/; const RE_CSS_RGBA_COLOR = /^rgba?\(\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*\)$/; const RE_CSS_RGBA_SLASH_COLOR = /^rgba?\(\s*([0-9.]+\s*%?)\s+([0-9.]+\s*%?)\s+([0-9.]+\s*%?)\s*\/\s*([0-9.]+\s*%?)\s*\)$/; function parseCssColor(cssColor) { /** * Parses a color in CSS syntax and returns it in RGBA format: * * [r, g, b, a] * with each value within [0, 1]. * * Returns undefined if the color could not be parsed. */ let m; if ((m = cssColor.match(RE_CSS_RGB_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), 1.0, ]; } if ((m = cssColor.match(RE_CSS_RGBA_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), parseCssValue(m[4]), ]; } if ((m = cssColor.match(RE_CSS_RGBA_SLASH_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), parseCssValue(m[4]), ]; } if ((m = cssColor.match(RE_CSS_HEX_COLOR_6))) { return [ parseInt(m[1], 16) / 255.0, parseInt(m[2], 16) / 255.0, parseInt(m[3], 16) / 255.0, 1.0, ]; } if ((m = cssColor.match(RE_CSS_HEX_COLOR_3))) { return [ parseInt(m[1], 16) / 15.0, parseInt(m[2], 16) / 15.0, parseInt(m[3], 16) / 15.0, 1.0, ]; } if (cssColor === "transparent") return [0, 0, 0, 0]; return undefined; } function makeCssColor(rgbaColor) { /** * Converts the given RGBA color into CSS format. */ const [r, g, b, a] = rgbaColor; const normR = Math.round(r * 255.0); const normG = Math.round(g * 255.0); const normB = Math.round(b * 255.0); if (a >= 1.0) { return `rgb(${normR}, ${normG}, ${normB})`; } else { return `rgba(${normR}, ${normG}, ${normB}, ${a})`; } } function rgbToHsl(r, g, b) { /** * Converts colors from RGB to HSL (hue, saturation, lightness). * * The RGB inputs should all lie within [0, 1]. * * With valid inputs, the hue value will lie within [0, 6], * while the saturation and lightness values will lie within [0, 1]. */ const min = Math.min(r, g, b); const max = Math.max(r, g, b); const delta = max - min; const l = (max + min) / 2; if (delta === 0) { return [0, 0, l]; } const s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min); let h; if (max === r) h = (g - b) / delta + (g < b ? 6 : 0); else if (max === g) h = (b - r) / delta + 2; else if (max === b) h = (r - g) / delta + 4; return [h, s, l]; } function hslToRgb(h, s, l) { /** * Converts colors from HSL (hue, saturation, lightness) to RGB. * * The hue value should lie within [0, 6], and the saturation and * lightness values within [0, 1]. * * With valid inputs, the RGB outputs will all lie within [0, 1]. */ if (s === 0) { return [l, l, l]; } const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; h /= 6; if (h < 0) h = 1 - h; h %= 1; function hueToRgb(p, q, t) { if (t < 0) t += 1; else if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t); return p; } const r = hueToRgb(p, q, h + 1 / 3); const g = hueToRgb(p, q, h); const b = hueToRgb(p, q, h - 1 / 3); return [r, g, b]; } /* Color processing code. */ /**************************/ function colorLuminance(rgbaColor) { /** * Returns the luminance of the RGB color (alpha is ignored) using the * sRGB/BT.709 luminance formula. */ const [r, g, b] = rgbaColor; const convertSrgbChannel = (x) => x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); return 0.2126 * convertSrgbChannel(r) + 0.7152 * convertSrgbChannel(g) + 0.0722 * convertSrgbChannel(b); } function colorContrast(fgRgbaColor, bgRgbaColor) { /** * Returns the WCAG contrast ratio (>= 1) for the given two colors. */ const q = (colorLuminance(fgRgbaColor) + 0.05) / (colorLuminance(bgRgbaColor) + 0.05); return q < 1 ? 1 / q : q; } function darkenBackgroundColor(rgbaColor) { /** * Darkens the given RGBA color for it to make it a suitable * background color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); let lAdj = 1 - colorLuminance(rgbaColor); lAdj = 0.02 + 0.98 * Math.pow(lAdj, 0.95); const lScale = Math.min(Math.max(lAdj, 0.01) / Math.max(l, 0.01), 1); const [rr, gg, bb] = hslToRgb(h, (s + s * lScale) / 2, lAdj); return [rr, gg, bb, a]; } function darkenBorderColor(rgbaColor) { /** * Darkens the given RGBA color for it to make it a suitable * border color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); const [rr, gg, bb] = hslToRgb(h, s * 0.5, l * 0.5); return [rr, gg, bb, a]; } function lightenForegroundColor(rgbaColor) { /** * Lightens the given RGBA color for it to make it a suitable * text color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); const [rr, gg, bb] = hslToRgb(h, s * 0.5, 0.5 + (1 - l) * 0.5); return [rr, gg, bb, a]; } /* Auto-fixer parameters. */ /**************************/ /* Whether to adjust border colors. */ const PARAMETER_ADJUST_BORDER_COLORS = false; /** Any background-foreground combo with the contrast ratio exceeding * this value are ignored by the fixer. */ const PARAMETER_MAXIMUM_CONTRAST_TO_FIX = 3; /** The background color must have at least this much alpha, * or the element is ignored by the fixer. */ const PARAMETER_MINIMUM_BG_ALPHA = 0.5; /** The foreground color must have at least this much luminance, * or the element is ignored by the fixer. */ const PARAMETER_MINIMUM_FG_LUMA = 0.5; /** The border color must have at least this much luminance, * or it is ignored by the fixer. */ const PARAMETER_MINIMUM_BORDER_LUMA = 0.7; /* Auto-fixer framework. */ /*************************/ function isSkinNightMode() { /** * Returns true if the user has requested night mode. */ if (!window.matchMedia) return; const htmlRoot = document.documentElement; const nightPref = htmlRoot.classList.contains( "skin-theme-clientpref-night" ); const osPref = htmlRoot.classList.contains("skin-theme-clientpref-os"); const isScreen = window.matchMedia("screen").matches; const prefersDark = window.matchMedia( "(prefers-color-scheme: dark)" ).matches; return isScreen && (nightPref || (osPref && prefersDark)); } function doAutoContrastFix() { /** * Applies the auto-contrast fix to all elements in the * wikipage body. */ // see if the user has requested night mode. if (!isSkinNightMode()) return; const view = document.defaultView; const ELEMENTS_PER_FRAME = 50; function isCandidate(el) { const style = view.getComputedStyle(el); return style.background !== "none" || style.borderStyle !== "none"; } // TODO optimize; can we skip searching candidates or split it up // into multiple frames to avoid blocking the page for some time? const candidates = Array.prototype.filter.call( document.querySelectorAll("#mw-content-text *"), isCandidate ); let autoContrastReport = []; function autoContrastReportElement(el) { // find top level element within mw-content-text let top = el; while ( top.parentElement && !top.parentElement.classList.contains("mw-parser-output") ) { top = top.parentElement; } let nextHeadingLevel = 6; const foundHeadings = Array(nextHeadingLevel + 1); let sectionId, sectionNumber; if (top) { // find elements let previous = top; const recordHeading = function (headingElement, headingLevel) { foundHeadings[headingLevel] = headingElement.textContent; if (sectionId == null) sectionId = headingElement.id; if (sectionNumber == null) { const editLink = headingElement.parentElement.querySelector( ".mw-editsection a" ); const editUrl = !editLink ? null : new URL(editLink.href); if ( editUrl && editUrl.searchParams && editUrl.searchParams.has("section") ) sectionNumber = Number( editUrl.searchParams.get("section") ); } }; while ((previous = previous.previousElementSibling)) { if (previous.classList.contains("mw-heading")) { // get heading level const headingElement = previous.querySelector("h1,h2,h3,h4,h5,h6"); if (headingElement) { const headingLevel = Number( headingElement.tagName.replace(/h/i, "") ); if (headingLevel && headingLevel <= nextHeadingLevel) { recordHeading(headingElement, headingLevel); nextHeadingLevel = headingLevel - 1; } } } } } autoContrastReport.push({ headings: foundHeadings .filter(function (v) { return v != null; }) .join(" > "), sectionId: sectionId, sectionNumber: sectionNumber, topClasses: top ? top.className : undefined, classes: el.className, element: el, }); el.classList.add("wikt-auto-contrast-fixed"); } function autoContrastFixDone() { /** * Executed when the auto-contrast fix has been applied * to all elements. */ if (autoContrastReport.length > 0) { console.log( `Applied auto-contrast fix to ${autoContrastReport.length} elements` ); console.log("Full auto-contrast report", autoContrastReport); } } function doAutoContrastFixOne(el) { /** * Applies the auto-contrast fix to the specified element. */ // exemptions if (el.closest(".wikt-auto-contrast-exempt")) return; if (el.closest(".mw-no-invert")) return; const computedStyle = view.getComputedStyle(el); // get background and foreground colors. const cssBackgroundColor = computedStyle.backgroundColor; const parsedBackgroundColor = parseCssColor(cssBackgroundColor); if (parsedBackgroundColor == null) return; const cssForegroundColor = computedStyle.color; const parsedForegroundColor = parseCssColor(cssForegroundColor); if (parsedForegroundColor == null) return; let fixedElement = false; const hasDarkTextColor = colorLuminance(parsedForegroundColor) < PARAMETER_MINIMUM_FG_LUMA; // check that: // * the background color has enough alpha // * the text color is actually light (or overridden) // * the contrast is bad enough to consider fixing (or dark text color and overridden) // * this isn't something like an image tag if ( parsedBackgroundColor[3] >= PARAMETER_MINIMUM_BG_ALPHA && (darkTextColorOverride || !hasDarkTextColor) && (colorContrast(parsedForegroundColor, parsedBackgroundColor) <= PARAMETER_MAXIMUM_CONTRAST_TO_FIX || (hasDarkTextColor && darkTextColorOverride)) && el.tagName !== "IMG" ) { if ( colorLuminance(parsedForegroundColor) < PARAMETER_MINIMUM_FG_LUMA ) { // generate a new foreground color and apply it const newForegroundColor = lightenForegroundColor( parsedForegroundColor ); if ( colorLuminance(newForegroundColor) > colorLuminance(parsedForegroundColor) ) { fixedElement = true; el.style.color = makeCssColor(newForegroundColor); } } // generate a background color and apply it, but only if it is darker. const newBackgroundColor = darkenBackgroundColor( parsedBackgroundColor ); if ( colorLuminance(newBackgroundColor) < colorLuminance(parsedBackgroundColor) ) { fixedElement = true; el.style.backgroundColor = makeCssColor(newBackgroundColor); } } if (computedStyle.borderStyle !== "none" && PARAMETER_ADJUST_BORDER_COLORS) { // odds are the border color needs the same treatment. const cssBorderColor = view.getComputedStyle(el).borderColor; const parsedBorderColor = parseCssColor(cssBorderColor); if ( parsedBorderColor != null && colorLuminance(parsedBorderColor) >= PARAMETER_MINIMUM_BORDER_LUMA ) { // generate a border color and apply it, but only if it is darker. const newBorderColor = darkenBorderColor(parsedBorderColor); if ( colorLuminance(newBorderColor) < colorLuminance(parsedBorderColor) ) { fixedElement = true; el.style.borderColor = makeCssColor(newBorderColor); } } } if (fixedElement) { // report that we found an element to fix. autoContrastReportElement(el); } } function doAutoContrastFixBatch(base) { /** * Applies the auto-contrast fix to the next batch * of elements. */ for (let offset = 0; offset < ELEMENTS_PER_FRAME; ++offset) { const index = base + offset; if (index >= candidates.length) { autoContrastFixDone(); return; } doAutoContrastFixOne(candidates[index]); } window.requestAnimationFrame(function () { doAutoContrastFixBatch(base + ELEMENTS_PER_FRAME); }); } doAutoContrastFixBatch(0); } $(document).ready(function () { doAutoContrastFix(); }); // </nowiki> de6lc9zew25kkllal43ljzyhnkyh6h9 88891 88890 2026-08-06T23:09:56Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AutoContrastFixer.js]] 88890 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ /** * Automatically adjusts contrast of templates in night mode. * * Author(s): Surjection * Last updated: 2025-10-08 */ // [[MediaWiki:Gadget-WiktGadgetPrefs.js]] const preferences = mw.wiktGadgetPrefs.get( "autoContrastFixer", { label: { en: "Automatically fix custom template colors in night mode", }, }, { darkTextColorOverride: { type: "boolean", default: false, label: { en: "Apply also to templates with explicit dark text colors", }, }, } ); const darkTextColorOverride = preferences.darkTextColorOverride; /* Color conversion code. */ /**************************/ function parseCssValue(cssAlpha, divisor) { /** * Parses a numeric value in CSS syntax, either given directly or * as a percentage. * * If a divisor is given, it is used to scale the value, unless it is * a percentage. */ if (cssAlpha.endsWith("%")) { return parseCssValue(cssAlpha.slice(0, -1).trim(), 100.0); } return Number(cssAlpha) / (divisor || 1.0); } // RegEx used by parseCssColor const RE_CSS_HEX_COLOR_3 = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/; const RE_CSS_HEX_COLOR_6 = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/; const RE_CSS_RGB_COLOR = /^rgb\(\s*([0-9.]+\s*%?)(?:\s+|\s*,\s*)([0-9.]+\s*%?)(?:\s+|\s*,\s*)([0-9.]+\s*%?)\s*\)$/; const RE_CSS_RGBA_COLOR = /^rgba?\(\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*,\s*([0-9.]+\s*%?)\s*\)$/; const RE_CSS_RGBA_SLASH_COLOR = /^rgba?\(\s*([0-9.]+\s*%?)\s+([0-9.]+\s*%?)\s+([0-9.]+\s*%?)\s*\/\s*([0-9.]+\s*%?)\s*\)$/; function parseCssColor(cssColor) { /** * Parses a color in CSS syntax and returns it in RGBA format: * * [r, g, b, a] * with each value within [0, 1]. * * Returns undefined if the color could not be parsed. */ let m; if ((m = cssColor.match(RE_CSS_RGB_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), 1.0, ]; } if ((m = cssColor.match(RE_CSS_RGBA_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), parseCssValue(m[4]), ]; } if ((m = cssColor.match(RE_CSS_RGBA_SLASH_COLOR))) { return [ parseCssValue(m[1], 255.0), parseCssValue(m[2], 255.0), parseCssValue(m[3], 255.0), parseCssValue(m[4]), ]; } if ((m = cssColor.match(RE_CSS_HEX_COLOR_6))) { return [ parseInt(m[1], 16) / 255.0, parseInt(m[2], 16) / 255.0, parseInt(m[3], 16) / 255.0, 1.0, ]; } if ((m = cssColor.match(RE_CSS_HEX_COLOR_3))) { return [ parseInt(m[1], 16) / 15.0, parseInt(m[2], 16) / 15.0, parseInt(m[3], 16) / 15.0, 1.0, ]; } if (cssColor === "transparent") return [0, 0, 0, 0]; return undefined; } function makeCssColor(rgbaColor) { /** * Converts the given RGBA color into CSS format. */ const [r, g, b, a] = rgbaColor; const normR = Math.round(r * 255.0); const normG = Math.round(g * 255.0); const normB = Math.round(b * 255.0); if (a >= 1.0) { return `rgb(${normR}, ${normG}, ${normB})`; } else { return `rgba(${normR}, ${normG}, ${normB}, ${a})`; } } function rgbToHsl(r, g, b) { /** * Converts colors from RGB to HSL (hue, saturation, lightness). * * The RGB inputs should all lie within [0, 1]. * * With valid inputs, the hue value will lie within [0, 6], * while the saturation and lightness values will lie within [0, 1]. */ const min = Math.min(r, g, b); const max = Math.max(r, g, b); const delta = max - min; const l = (max + min) / 2; if (delta === 0) { return [0, 0, l]; } const s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min); let h; if (max === r) h = (g - b) / delta + (g < b ? 6 : 0); else if (max === g) h = (b - r) / delta + 2; else if (max === b) h = (r - g) / delta + 4; return [h, s, l]; } function hslToRgb(h, s, l) { /** * Converts colors from HSL (hue, saturation, lightness) to RGB. * * The hue value should lie within [0, 6], and the saturation and * lightness values within [0, 1]. * * With valid inputs, the RGB outputs will all lie within [0, 1]. */ if (s === 0) { return [l, l, l]; } const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; h /= 6; if (h < 0) h = 1 - h; h %= 1; function hueToRgb(p, q, t) { if (t < 0) t += 1; else if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t); return p; } const r = hueToRgb(p, q, h + 1 / 3); const g = hueToRgb(p, q, h); const b = hueToRgb(p, q, h - 1 / 3); return [r, g, b]; } /* Color processing code. */ /**************************/ function colorLuminance(rgbaColor) { /** * Returns the luminance of the RGB color (alpha is ignored) using the * sRGB/BT.709 luminance formula. */ const [r, g, b] = rgbaColor; const convertSrgbChannel = (x) => x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); return 0.2126 * convertSrgbChannel(r) + 0.7152 * convertSrgbChannel(g) + 0.0722 * convertSrgbChannel(b); } function colorContrast(fgRgbaColor, bgRgbaColor) { /** * Returns the WCAG contrast ratio (>= 1) for the given two colors. */ const q = (colorLuminance(fgRgbaColor) + 0.05) / (colorLuminance(bgRgbaColor) + 0.05); return q < 1 ? 1 / q : q; } function darkenBackgroundColor(rgbaColor) { /** * Darkens the given RGBA color for it to make it a suitable * background color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); let lAdj = 1 - colorLuminance(rgbaColor); lAdj = 0.02 + 0.98 * Math.pow(lAdj, 0.95); const lScale = Math.min(Math.max(lAdj, 0.01) / Math.max(l, 0.01), 1); const [rr, gg, bb] = hslToRgb(h, (s + s * lScale) / 2, lAdj); return [rr, gg, bb, a]; } function darkenBorderColor(rgbaColor) { /** * Darkens the given RGBA color for it to make it a suitable * border color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); const [rr, gg, bb] = hslToRgb(h, s * 0.5, l * 0.5); return [rr, gg, bb, a]; } function lightenForegroundColor(rgbaColor) { /** * Lightens the given RGBA color for it to make it a suitable * text color in night mode. */ const [r, g, b, a] = rgbaColor; const [h, s, l] = rgbToHsl(r, g, b); const [rr, gg, bb] = hslToRgb(h, s * 0.5, 0.5 + (1 - l) * 0.5); return [rr, gg, bb, a]; } /* Auto-fixer parameters. */ /**************************/ /* Whether to adjust border colors. */ const PARAMETER_ADJUST_BORDER_COLORS = false; /** Any background-foreground combo with the contrast ratio exceeding * this value are ignored by the fixer. */ const PARAMETER_MAXIMUM_CONTRAST_TO_FIX = 3; /** The background color must have at least this much alpha, * or the element is ignored by the fixer. */ const PARAMETER_MINIMUM_BG_ALPHA = 0.5; /** The foreground color must have at least this much luminance, * or the element is ignored by the fixer. */ const PARAMETER_MINIMUM_FG_LUMA = 0.5; /** The border color must have at least this much luminance, * or it is ignored by the fixer. */ const PARAMETER_MINIMUM_BORDER_LUMA = 0.7; /* Auto-fixer framework. */ /*************************/ function isSkinNightMode() { /** * Returns true if the user has requested night mode. */ if (!window.matchMedia) return; const htmlRoot = document.documentElement; const nightPref = htmlRoot.classList.contains( "skin-theme-clientpref-night" ); const osPref = htmlRoot.classList.contains("skin-theme-clientpref-os"); const isScreen = window.matchMedia("screen").matches; const prefersDark = window.matchMedia( "(prefers-color-scheme: dark)" ).matches; return isScreen && (nightPref || (osPref && prefersDark)); } function doAutoContrastFix() { /** * Applies the auto-contrast fix to all elements in the * wikipage body. */ // see if the user has requested night mode. if (!isSkinNightMode()) return; const view = document.defaultView; const ELEMENTS_PER_FRAME = 50; function isCandidate(el) { const style = view.getComputedStyle(el); return style.background !== "none" || style.borderStyle !== "none"; } // TODO optimize; can we skip searching candidates or split it up // into multiple frames to avoid blocking the page for some time? const candidates = Array.prototype.filter.call( document.querySelectorAll("#mw-content-text *"), isCandidate ); let autoContrastReport = []; function autoContrastReportElement(el) { // find top level element within mw-content-text let top = el; while ( top.parentElement && !top.parentElement.classList.contains("mw-parser-output") ) { top = top.parentElement; } let nextHeadingLevel = 6; const foundHeadings = Array(nextHeadingLevel + 1); let sectionId, sectionNumber; if (top) { // find elements let previous = top; const recordHeading = function (headingElement, headingLevel) { foundHeadings[headingLevel] = headingElement.textContent; if (sectionId == null) sectionId = headingElement.id; if (sectionNumber == null) { const editLink = headingElement.parentElement.querySelector( ".mw-editsection a" ); const editUrl = !editLink ? null : new URL(editLink.href); if ( editUrl && editUrl.searchParams && editUrl.searchParams.has("section") ) sectionNumber = Number( editUrl.searchParams.get("section") ); } }; while ((previous = previous.previousElementSibling)) { if (previous.classList.contains("mw-heading")) { // get heading level const headingElement = previous.querySelector("h1,h2,h3,h4,h5,h6"); if (headingElement) { const headingLevel = Number( headingElement.tagName.replace(/h/i, "") ); if (headingLevel && headingLevel <= nextHeadingLevel) { recordHeading(headingElement, headingLevel); nextHeadingLevel = headingLevel - 1; } } } } } autoContrastReport.push({ headings: foundHeadings .filter(function (v) { return v != null; }) .join(" > "), sectionId: sectionId, sectionNumber: sectionNumber, topClasses: top ? top.className : undefined, classes: el.className, element: el, }); el.classList.add("wikt-auto-contrast-fixed"); } function autoContrastFixDone() { /** * Executed when the auto-contrast fix has been applied * to all elements. */ if (autoContrastReport.length > 0) { console.log( `Applied auto-contrast fix to ${autoContrastReport.length} elements` ); console.log("Full auto-contrast report", autoContrastReport); } } function doAutoContrastFixOne(el) { /** * Applies the auto-contrast fix to the specified element. */ // exemptions if (el.closest(".wikt-auto-contrast-exempt")) return; if (el.closest(".mw-no-invert")) return; const computedStyle = view.getComputedStyle(el); // get background and foreground colors. const cssBackgroundColor = computedStyle.backgroundColor; const parsedBackgroundColor = parseCssColor(cssBackgroundColor); if (parsedBackgroundColor == null) return; const cssForegroundColor = computedStyle.color; const parsedForegroundColor = parseCssColor(cssForegroundColor); if (parsedForegroundColor == null) return; let fixedElement = false; const hasDarkTextColor = colorLuminance(parsedForegroundColor) < PARAMETER_MINIMUM_FG_LUMA; // check that: // * the background color has enough alpha // * the text color is actually light (or overridden) // * the contrast is bad enough to consider fixing (or dark text color and overridden) // * this isn't something like an image tag if ( parsedBackgroundColor[3] >= PARAMETER_MINIMUM_BG_ALPHA && (darkTextColorOverride || !hasDarkTextColor) && (colorContrast(parsedForegroundColor, parsedBackgroundColor) <= PARAMETER_MAXIMUM_CONTRAST_TO_FIX || (hasDarkTextColor && darkTextColorOverride)) && el.tagName !== "IMG" ) { if ( colorLuminance(parsedForegroundColor) < PARAMETER_MINIMUM_FG_LUMA ) { // generate a new foreground color and apply it const newForegroundColor = lightenForegroundColor( parsedForegroundColor ); if ( colorLuminance(newForegroundColor) > colorLuminance(parsedForegroundColor) ) { fixedElement = true; el.style.color = makeCssColor(newForegroundColor); } } // generate a background color and apply it, but only if it is darker. const newBackgroundColor = darkenBackgroundColor( parsedBackgroundColor ); if ( colorLuminance(newBackgroundColor) < colorLuminance(parsedBackgroundColor) ) { fixedElement = true; el.style.backgroundColor = makeCssColor(newBackgroundColor); } } if (computedStyle.borderStyle !== "none" && PARAMETER_ADJUST_BORDER_COLORS) { // odds are the border color needs the same treatment. const cssBorderColor = view.getComputedStyle(el).borderColor; const parsedBorderColor = parseCssColor(cssBorderColor); if ( parsedBorderColor != null && colorLuminance(parsedBorderColor) >= PARAMETER_MINIMUM_BORDER_LUMA ) { // generate a border color and apply it, but only if it is darker. const newBorderColor = darkenBorderColor(parsedBorderColor); if ( colorLuminance(newBorderColor) < colorLuminance(parsedBorderColor) ) { fixedElement = true; el.style.borderColor = makeCssColor(newBorderColor); } } } if (fixedElement) { // report that we found an element to fix. autoContrastReportElement(el); } } function doAutoContrastFixBatch(base) { /** * Applies the auto-contrast fix to the next batch * of elements. */ for (let offset = 0; offset < ELEMENTS_PER_FRAME; ++offset) { const index = base + offset; if (index >= candidates.length) { autoContrastFixDone(); return; } doAutoContrastFixOne(candidates[index]); } window.requestAnimationFrame(function () { doAutoContrastFixBatch(base + ELEMENTS_PER_FRAME); }); } doAutoContrastFixBatch(0); } $(document).ready(function () { doAutoContrastFix(); }); // </nowiki> de6lc9zew25kkllal43ljzyhnkyh6h9 MediaWiki:Gadget-ShowIDs.js 8 17945 88892 2026-05-29T20:09:29Z en>Fenakhay 0 88892 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ /** * Display sense and etym IDs (including Wikidata item/lexeme links). * * Note: this gadget also loads ShowIDs-pagestyles, which offers a * CSS-only fallback to this gadget that does not require JavaScript. * The CSS is nevertheless required for this JavaScript gadget * to display correctly. * CSS: [[MediaWiki:Gadget-ShowIDs-pagestyles.css]] * * Author(s): Surjection, Fenakhay * Last updated: 2026-05-29 */ $(document).ready(() => { 'use strict'; const ID_CLASSES = [ { name: 'senseid', showTooltip: true }, { name: 'etymid', showTooltip: true }, { name: 'etymonid', showTooltip: false } ]; const WIKIDATA_ITEM_PATTERN = /^Q\d+$/; const WIKIDATA_LEXEME_PATTERN = /^L(\d+)(?:-S(\d+))?$/; function getWikidataUrl(idStr) { if (WIKIDATA_ITEM_PATTERN.test(idStr)) { return `https://www.wikidata.org/wiki/${idStr}`; } const lexemeMatch = idStr.match(WIKIDATA_LEXEME_PATTERN); if (lexemeMatch) { const lexemeId = `L${lexemeMatch[1]}`; const baseUrl = `https://www.wikidata.org/wiki/Lexeme:${lexemeId}`; const senseId = lexemeMatch[2]; return senseId ? `${baseUrl}#S${senseId}` : baseUrl; } return null; } /** * Generate CSS selectors for all ID classes */ function generateSelectors(suffix = '') { return ID_CLASSES.map(cls => `.${cls.name}${suffix}`).join(', '); } /** * Returns the text content of element, excluding children (unlike .text()). */ function getTextOnlyRoot($elem) { return $elem.clone().children().remove().end().text(); } /** * Move element (sole child span) into the next visible, non-floated paragraph. */ function moveIntoNextParagraph($elem) { const $parentP = $elem.parent('p'); // Only proceed if parent is a p with single child and no text content if (!$parentP.length || $parentP.children().length !== 1 || getTextOnlyRoot($parentP).trim()) { return; } let $next = $parentP.next(); while ($next.length) { // Skip floated or hidden elements if ($next.css('float') !== 'none' || !$next.is(':visible')) { $next = $next.next(); continue; } // Move content to next paragraph if found if ($next.is('p')) { $next.prepend('\n'); $parentP.children().prependTo($next); $parentP.remove(); } break; } } /** * Create display element for ID (link for Wikidata, span for others). */ function createDisplayElement(idStr, tooltip) { const wikidataUrl = getWikidataUrl(idStr); return wikidataUrl ? $('<a/>', { href: wikidataUrl, text: idStr, title: tooltip || undefined, target: '_blank', rel: 'noopener noreferrer' }) : $('<span/>', { text: idStr, title: tooltip || undefined }); } /** * Generate tooltip text for template. */ function generateTooltip(classConfig, lang, idStr) { return (classConfig.showTooltip && lang && idStr) ? `{{${classConfig.name}|${lang}|${idStr}}}` : ''; } // Process each ID element $(generateSelectors()).each(function () { const $elem = $(this); // Find the matching class configuration const classConfig = ID_CLASSES.find(cls => $elem.hasClass(cls.name)); if (!classConfig) return; const displayedClass = `${classConfig.name}-displayed`; // Skip if already processed if ($elem.hasClass(displayedClass)) return; // Extract data const lang = $elem.attr('data-lang'); const rawId = $elem.data('id'); // Skip if no ID (e.g., etymonid without id=) if (rawId === undefined || rawId === null || rawId === '') { return; } const idStr = String(rawId); const tooltip = generateTooltip(classConfig, lang, idStr); const hasText = !!$elem.text().trim(); // Create display element const $content = createDisplayElement(idStr, tooltip); if ($elem.is('li') || hasText) { // Wrap in new span to preserve existing content const $wrapper = $('<span/>', { class: displayedClass }).append($content); // Add space if needed if (!hasText || !$elem.text().match(/^\s/)) { $elem.prepend(' '); } $elem.prepend($wrapper); } else { // Replace element content entirely $elem.addClass(displayedClass).empty().append($content); moveIntoNextParagraph($elem); } }); // Prevent CSS-only pseudo-elements from duplicating the display mw.util.addCSS( `${generateSelectors('::before')} { content: none !important; display: none !important; }` ); }); // Ensure CSS fallback is loaded mw.loader.load('ext.gadget.ShowIDs-pagestyles'); // </nowiki> 6olupmbgmixgloydhtnn7oudokddd9c 88893 88892 2026-08-06T23:10:06Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-ShowIDs.js]] 88892 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ /** * Display sense and etym IDs (including Wikidata item/lexeme links). * * Note: this gadget also loads ShowIDs-pagestyles, which offers a * CSS-only fallback to this gadget that does not require JavaScript. * The CSS is nevertheless required for this JavaScript gadget * to display correctly. * CSS: [[MediaWiki:Gadget-ShowIDs-pagestyles.css]] * * Author(s): Surjection, Fenakhay * Last updated: 2026-05-29 */ $(document).ready(() => { 'use strict'; const ID_CLASSES = [ { name: 'senseid', showTooltip: true }, { name: 'etymid', showTooltip: true }, { name: 'etymonid', showTooltip: false } ]; const WIKIDATA_ITEM_PATTERN = /^Q\d+$/; const WIKIDATA_LEXEME_PATTERN = /^L(\d+)(?:-S(\d+))?$/; function getWikidataUrl(idStr) { if (WIKIDATA_ITEM_PATTERN.test(idStr)) { return `https://www.wikidata.org/wiki/${idStr}`; } const lexemeMatch = idStr.match(WIKIDATA_LEXEME_PATTERN); if (lexemeMatch) { const lexemeId = `L${lexemeMatch[1]}`; const baseUrl = `https://www.wikidata.org/wiki/Lexeme:${lexemeId}`; const senseId = lexemeMatch[2]; return senseId ? `${baseUrl}#S${senseId}` : baseUrl; } return null; } /** * Generate CSS selectors for all ID classes */ function generateSelectors(suffix = '') { return ID_CLASSES.map(cls => `.${cls.name}${suffix}`).join(', '); } /** * Returns the text content of element, excluding children (unlike .text()). */ function getTextOnlyRoot($elem) { return $elem.clone().children().remove().end().text(); } /** * Move element (sole child span) into the next visible, non-floated paragraph. */ function moveIntoNextParagraph($elem) { const $parentP = $elem.parent('p'); // Only proceed if parent is a p with single child and no text content if (!$parentP.length || $parentP.children().length !== 1 || getTextOnlyRoot($parentP).trim()) { return; } let $next = $parentP.next(); while ($next.length) { // Skip floated or hidden elements if ($next.css('float') !== 'none' || !$next.is(':visible')) { $next = $next.next(); continue; } // Move content to next paragraph if found if ($next.is('p')) { $next.prepend('\n'); $parentP.children().prependTo($next); $parentP.remove(); } break; } } /** * Create display element for ID (link for Wikidata, span for others). */ function createDisplayElement(idStr, tooltip) { const wikidataUrl = getWikidataUrl(idStr); return wikidataUrl ? $('<a/>', { href: wikidataUrl, text: idStr, title: tooltip || undefined, target: '_blank', rel: 'noopener noreferrer' }) : $('<span/>', { text: idStr, title: tooltip || undefined }); } /** * Generate tooltip text for template. */ function generateTooltip(classConfig, lang, idStr) { return (classConfig.showTooltip && lang && idStr) ? `{{${classConfig.name}|${lang}|${idStr}}}` : ''; } // Process each ID element $(generateSelectors()).each(function () { const $elem = $(this); // Find the matching class configuration const classConfig = ID_CLASSES.find(cls => $elem.hasClass(cls.name)); if (!classConfig) return; const displayedClass = `${classConfig.name}-displayed`; // Skip if already processed if ($elem.hasClass(displayedClass)) return; // Extract data const lang = $elem.attr('data-lang'); const rawId = $elem.data('id'); // Skip if no ID (e.g., etymonid without id=) if (rawId === undefined || rawId === null || rawId === '') { return; } const idStr = String(rawId); const tooltip = generateTooltip(classConfig, lang, idStr); const hasText = !!$elem.text().trim(); // Create display element const $content = createDisplayElement(idStr, tooltip); if ($elem.is('li') || hasText) { // Wrap in new span to preserve existing content const $wrapper = $('<span/>', { class: displayedClass }).append($content); // Add space if needed if (!hasText || !$elem.text().match(/^\s/)) { $elem.prepend(' '); } $elem.prepend($wrapper); } else { // Replace element content entirely $elem.addClass(displayedClass).empty().append($content); moveIntoNextParagraph($elem); } }); // Prevent CSS-only pseudo-elements from duplicating the display mw.util.addCSS( `${generateSelectors('::before')} { content: none !important; display: none !important; }` ); }); // Ensure CSS fallback is loaded mw.loader.load('ext.gadget.ShowIDs-pagestyles'); // </nowiki> 6olupmbgmixgloydhtnn7oudokddd9c MediaWiki:Gadget-TreeDescs.js 8 17946 88894 2025-09-07T20:15:03Z en>Catonif 0 fix the desctree issue, while keeping separate uls when immediate 88894 javascript text/javascript mw.loader.load("ext.gadget.TreeDescs-pagestyles"); $(".mw-heading").filter(function() { return $(this).children().first().text() === "Descendants" }).each(function() { let $selected = $(this).nextUntil(".mw-heading"); $selected.find("ul + ul").each(function () { $(this).prev("ul").append($(this).children()); $(this).remove(); }); $selected.filter("ul").addClass("treeview"); $selected.filter(":not(ul)").find("ul").addClass("treeview"); }); n0tnt5mcbjkodiy8ft24phf4kqc4xh2 88895 88894 2026-08-06T23:10:14Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TreeDescs.js]] 88894 javascript text/javascript mw.loader.load("ext.gadget.TreeDescs-pagestyles"); $(".mw-heading").filter(function() { return $(this).children().first().text() === "Descendants" }).each(function() { let $selected = $(this).nextUntil(".mw-heading"); $selected.find("ul + ul").each(function () { $(this).prev("ul").append($(this).children()); $(this).remove(); }); $selected.filter("ul").addClass("treeview"); $selected.filter(":not(ul)").find("ul").addClass("treeview"); }); n0tnt5mcbjkodiy8ft24phf4kqc4xh2 MediaWiki:Gadget-NoMiniToc.js 8 17947 88896 2025-09-10T17:33:46Z en>Surjection 0 88896 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ $(document).ready(() => { // If the TOC is inside a div with the data-toc-length attribute, move it out of there. const toc = document.querySelector("#mw-content-text #toc"); if (toc) { const minitocWrapped = toc.closest("[data-toc-length]"); if (minitocWrapped) { minitocWrapped.parentNode.insertBefore(toc, minitocWrapped); minitocWrapped.style.display = "none"; } } }); t0zb45l3ptr8xj0nyq01roj43h4k2ek 88897 88896 2026-08-06T23:10:22Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-NoMiniToc.js]] 88896 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw */ $(document).ready(() => { // If the TOC is inside a div with the data-toc-length attribute, move it out of there. const toc = document.querySelector("#mw-content-text #toc"); if (toc) { const minitocWrapped = toc.closest("[data-toc-length]"); if (minitocWrapped) { minitocWrapped.parentNode.insertBefore(toc, minitocWrapped); minitocWrapped.style.display = "none"; } } }); t0zb45l3ptr8xj0nyq01roj43h4k2ek MediaWiki:Gadget-NoMiniToc.css 8 17948 88898 2025-12-11T13:21:48Z en>Surjection 0 88898 css text/css .minitoc { display: none; } /* increased specificity */ .minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc { display: none; } /* selector intentionally repeated a bunch of times - CSS specificity trick */ div[data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length] > #toc { display: inline-block; } .mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc { display: block; } oh53ebe99fwlaunck0mn8xdzcph7qfw 88899 88898 2026-08-06T23:10:30Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-NoMiniToc.css]] 88898 css text/css .minitoc { display: none; } /* increased specificity */ .minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc.minitoc { display: none; } /* selector intentionally repeated a bunch of times - CSS specificity trick */ div[data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length][data-toc-length] > #toc { display: inline-block; } .mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc.mammoth-minitoc { display: block; } oh53ebe99fwlaunck0mn8xdzcph7qfw MediaWiki:Gadget-NsfwOverride.js 8 17949 88900 2026-04-23T18:11:56Z en>Fenakhay 0 Created page with "// <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:8 */ /* global mw */ /** * Disable NSFW blur/overlay used in {{multiple images}}/{{img}}. * * Author(s): Fenakhay * Last updated: 2026-04-23 */ ( function () { "use strict"; function applyNsfwOverride( $content ) { if ( !$content || !$content.length ) return; $content.find( ".tmulti-nsfw .thumbimage" ).each( function () { this.classList.add( "tmulti-nsfw-gadget-ready"..." 88900 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:8 */ /* global mw */ /** * Disable NSFW blur/overlay used in {{multiple images}}/{{img}}. * * Author(s): Fenakhay * Last updated: 2026-04-23 */ ( function () { "use strict"; function applyNsfwOverride( $content ) { if ( !$content || !$content.length ) return; $content.find( ".tmulti-nsfw .thumbimage" ).each( function () { this.classList.add( "tmulti-nsfw-gadget-ready" ); } ); } mw.hook( "wikipage.content" ).add( function ( $content ) { if ( mw.config.get( "wgAction" ) !== "view" ) return; applyNsfwOverride( $content ); } ); }() ); // </nowiki> nbwkx51vnqmj9njp5j9c14tt2nplxj6 88901 88900 2026-08-06T23:10:39Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-NsfwOverride.js]] 88900 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:8 */ /* global mw */ /** * Disable NSFW blur/overlay used in {{multiple images}}/{{img}}. * * Author(s): Fenakhay * Last updated: 2026-04-23 */ ( function () { "use strict"; function applyNsfwOverride( $content ) { if ( !$content || !$content.length ) return; $content.find( ".tmulti-nsfw .thumbimage" ).each( function () { this.classList.add( "tmulti-nsfw-gadget-ready" ); } ); } mw.hook( "wikipage.content" ).add( function ( $content ) { if ( mw.config.get( "wgAction" ) !== "view" ) return; applyNsfwOverride( $content ); } ); }() ); // </nowiki> nbwkx51vnqmj9njp5j9c14tt2nplxj6 MediaWiki:Gadget-NsfwOverride.css 8 17950 88902 2026-04-23T18:12:27Z en>Fenakhay 0 Created page with ".tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready { position: relative !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media { filter: none !important; -webkit-filter: none !important; clip-path: none !important; -webkit-clip-path: none !important; margin: 0 !important; padding: 0 !important; transform: none !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media > span, .tmulti-nsfw .thumbimage.tmulti-nsf..." 88902 css text/css .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready { position: relative !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media { filter: none !important; -webkit-filter: none !important; clip-path: none !important; -webkit-clip-path: none !important; margin: 0 !important; padding: 0 !important; transform: none !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media > span, .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media > span > a { display: block !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media img { display: block !important; width: auto !important; max-width: 100% !important; margin: 0 !important; transform: none !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-warning { display: none !important; } ps9qxz4iwfe6m04chv8o3qfzdw1b5e5 88903 88902 2026-08-06T23:10:46Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-NsfwOverride.css]] 88902 css text/css .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready { position: relative !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media { filter: none !important; -webkit-filter: none !important; clip-path: none !important; -webkit-clip-path: none !important; margin: 0 !important; padding: 0 !important; transform: none !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media > span, .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media > span > a { display: block !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-media img { display: block !important; width: auto !important; max-width: 100% !important; margin: 0 !important; transform: none !important; } .tmulti-nsfw .thumbimage.tmulti-nsfw-gadget-ready .tmulti-nsfw-warning { display: none !important; } ps9qxz4iwfe6m04chv8o3qfzdw1b5e5 MediaWiki:Gadget-MobileCollapseCategories.js 8 17951 88904 2026-05-15T17:37:56Z en>Surjection 0 Created page with "// <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw, window.VisibilityToggles */ /** * Makes the category list at the bottom of the page collapsible * (intended for use with the mobile Minerva skin). * * Author(s): Surjection * Last updated: 2026-05-15 */ function makeCategoriesCollapsible($el) { const $ul = $("#mw-normal-catlinks > ul, #mw-hidden-catlinks > ul", $el); if (!$(".category-list-toggle")..." 88904 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw, window.VisibilityToggles */ /** * Makes the category list at the bottom of the page collapsible * (intended for use with the mobile Minerva skin). * * Author(s): Surjection * Last updated: 2026-05-15 */ function makeCategoriesCollapsible($el) { const $ul = $("#mw-normal-catlinks > ul, #mw-hidden-catlinks > ul", $el); if (!$(".category-list-toggle").length && $ul.length) { const $toggleElement = $("<div>").addClass("category-list-toggle"); const $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", ""); const $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); const toggleCategory = "page categories"; const showButtonText = "show ▼"; const hideButtonText = "hide ▲"; $navToggle.append($toggleButton).appendTo($toggleElement); $toggleElement.insertBefore($ul.parent()[0]); $toggleElement.show(); $toggleButton.text(hideButtonText); $toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { $toggleButton.text(hideButtonText); $ul.removeClass("category-list-hidden"); }, function hide() { $toggleButton.text(showButtonText); $ul.addClass("category-list-hidden"); }) ); } } mw.util.addCSS(` /* Specificity hacks */ .category-list-hidden, .category-list-hidden.category-list-hidden.category-list-hidden, .catlinks .category-list-hidden.category-list-hidden.category-list-hidden { display: none; } `); $(document).ready(function () { if (window.VisibilityToggles) { $("#catlinks").each(function () { makeCategoriesCollapsible($(this)); }); } }); // </nowiki> sxz94g45qyu55ne1e3s6c7edsy0zoom 88905 88904 2026-08-06T23:10:55Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-MobileCollapseCategories.js]] 88904 javascript text/javascript // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw, window.VisibilityToggles */ /** * Makes the category list at the bottom of the page collapsible * (intended for use with the mobile Minerva skin). * * Author(s): Surjection * Last updated: 2026-05-15 */ function makeCategoriesCollapsible($el) { const $ul = $("#mw-normal-catlinks > ul, #mw-hidden-catlinks > ul", $el); if (!$(".category-list-toggle").length && $ul.length) { const $toggleElement = $("<div>").addClass("category-list-toggle"); const $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", ""); const $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0"); const toggleCategory = "page categories"; const showButtonText = "show ▼"; const hideButtonText = "hide ▲"; $navToggle.append($toggleButton).appendTo($toggleElement); $toggleElement.insertBefore($ul.parent()[0]); $toggleElement.show(); $toggleButton.text(hideButtonText); $toggleElement.on("click", window.VisibilityToggles.register(toggleCategory, function show() { $toggleButton.text(hideButtonText); $ul.removeClass("category-list-hidden"); }, function hide() { $toggleButton.text(showButtonText); $ul.addClass("category-list-hidden"); }) ); } } mw.util.addCSS(` /* Specificity hacks */ .category-list-hidden, .category-list-hidden.category-list-hidden.category-list-hidden, .catlinks .category-list-hidden.category-list-hidden.category-list-hidden { display: none; } `); $(document).ready(function () { if (window.VisibilityToggles) { $("#catlinks").each(function () { makeCategoriesCollapsible($(this)); }); } }); // </nowiki> sxz94g45qyu55ne1e3s6c7edsy0zoom MediaWiki:Gadget-Palette.css 8 17952 88906 2026-07-23T16:12:33Z en>Surjection 0 add scoped shorthand 88906 css text/css /* Wiktionary's palette of colors that work equally well in light and dark mode. */ /* Inspired by [[:ru:w:MediaWiki:Gadget-common-site.css]] */ :root, .skin-invert, .notheme { --wikt-palette-white: #ffffff; /* Same as <code>--background-color-base</code> */ --wikt-palette-black: #202122; /* Body text; same as <code>--color-base</code> */ --wikt-palette-beige: #fffbf2; --wikt-palette-darkgrey: #54595d; --wikt-palette-grey: #9e9e9e; --wikt-palette-lightgrey: #cccccc; --wikt-palette-lightergrey: #eeeeee; --wikt-palette-cream: #f8f8f0; --wikt-palette-pink: #ffe0f0; --wikt-palette-peach: #e4d4c0; --wikt-palette-gold: #b88d00; --wikt-palette-dullgold: #826f34; --wikt-palette-yellow: #ebe8b9; --wikt-palette-dullyellow: #dedbc1; --wikt-palette-brightyellow: #ffee77; --wikt-palette-palegreen: #e2f6e2; --wikt-palette-palergreen: #f8fffa; --wikt-palette-mint: #c0e4c0; --wikt-palette-green: #33d733; --wikt-palette-forestgreen: #235923; --wikt-palette-luminousgreen: #dafdda; --wikt-palette-paleblue: #f8f9fa; --wikt-palette-cyan: #eefbf9; --wikt-palette-palecyan: #f6f7f7; --wikt-palette-lightblue: #d9ebff; --wikt-palette-dulllightblue: #aabbdd; --wikt-palette-blue: #3333ff; --wikt-palette-dullblue: #49555f; --wikt-palette-dullcyan: #eaecf0; --wikt-palette-deepblue: #2f445c; --wikt-palette-lavender: #f8f8ff; --wikt-palette-lightyellow: #ffffe0; --wikt-palette-red: #d73333; /* Same as <code>--background-color-destructive</code> */ --wikt-palette-darkred: #660000; --wikt-palette-deepred: #bf0218; --wikt-palette-orange: #f2caa4; --wikt-palette-lighterblue: #ebf4ff; --wikt-palette-dulllighterblue: #e2eaf9; --wikt-palette-lightred: #fee7e6; --wikt-palette-indigo: #aaaaee; --wikt-palette-lightindigo: #e9e9ff; --wikt-palette-palerpink: #fff3f5; --wikt-palette-honey: #81540e; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #fef9f9; --wikt-palette-red-1: #fdeef0; --wikt-palette-red-2: #fce4e6; --wikt-palette-red-3: #fad9dc; --wikt-palette-red-4: #f7c2c6; --wikt-palette-red-5: #f5afb5; --wikt-palette-red-6: #f29ba3; --wikt-palette-red-7: #f0858e; --wikt-palette-red-8: #ed6d78; --wikt-palette-red-9: #ce4350; --wikt-palette-scarlet-0: #fef9f7; --wikt-palette-scarlet-1: #fcefeb; --wikt-palette-scarlet-2: #fae5de; --wikt-palette-scarlet-3: #f8dad1; --wikt-palette-scarlet-4: #f4c4b5; --wikt-palette-scarlet-5: #f1b3a0; --wikt-palette-scarlet-6: #eea088; --wikt-palette-scarlet-7: #ea8c70; --wikt-palette-scarlet-8: #e67553; --wikt-palette-scarlet-9: #c25433; --wikt-palette-orange-0: #fdfaf5; --wikt-palette-orange-1: #fbf0e4; --wikt-palette-orange-2: #f8e7d4; --wikt-palette-orange-3: #f5ddc3; --wikt-palette-orange-4: #f0c89e; --wikt-palette-orange-5: #ebb882; --wikt-palette-orange-6: #e6a662; --wikt-palette-orange-7: #e19341; --wikt-palette-orange-8: #db7f1e; --wikt-palette-orange-9: #b16210; --wikt-palette-amber-0: #fdfaf3; --wikt-palette-amber-1: #f9f1df; --wikt-palette-amber-2: #f5e8cc; --wikt-palette-amber-3: #f1dfb8; --wikt-palette-amber-4: #e8cc8f; --wikt-palette-amber-5: #e2bc6d; --wikt-palette-amber-6: #dbac4a; --wikt-palette-amber-7: #d39b24; --wikt-palette-amber-8: #c38c17; --wikt-palette-amber-9: #9b6f10; --wikt-palette-yellow-0: #fbfbf4; --wikt-palette-yellow-1: #f5f2e0; --wikt-palette-yellow-2: #eeeacc; --wikt-palette-yellow-3: #e8e2b9; --wikt-palette-yellow-4: #dbd191; --wikt-palette-yellow-5: #d0c370; --wikt-palette-yellow-6: #c5b44f; --wikt-palette-yellow-7: #b6a63f; --wikt-palette-yellow-8: #a69737; --wikt-palette-yellow-9: #847827; --wikt-palette-lime-0: #f9fbf3; --wikt-palette-lime-1: #eff4e1; --wikt-palette-lime-2: #e5edce; --wikt-palette-lime-3: #dbe5bc; --wikt-palette-lime-4: #c5d693; --wikt-palette-lime-5: #b5ca73; --wikt-palette-lime-6: #a3be52; --wikt-palette-lime-7: #97af4e; --wikt-palette-lime-8: #889f43; --wikt-palette-lime-9: #6b7f2f; --wikt-palette-green-0: #f8fbf5; --wikt-palette-green-1: #eaf5e4; --wikt-palette-green-2: #ddefd3; --wikt-palette-green-3: #cee8c1; --wikt-palette-green-4: #b3da9d; --wikt-palette-green-5: #9cd080; --wikt-palette-green-6: #83c460; --wikt-palette-green-7: #69b840; --wikt-palette-green-8: #64a640; --wikt-palette-green-9: #4b852d; --wikt-palette-teal-0: #f6fcf9; --wikt-palette-teal-1: #e5f6ee; --wikt-palette-teal-2: #d5efe3; --wikt-palette-teal-3: #c3e9d7; --wikt-palette-teal-4: #9fdcc0; --wikt-palette-teal-5: #82d1ac; --wikt-palette-teal-6: #64c599; --wikt-palette-teal-7: #41b982; --wikt-palette-teal-8: #3fa878; --wikt-palette-teal-9: #2c865d; --wikt-palette-cyan-0: #f6fbfc; --wikt-palette-cyan-1: #e7f4f7; --wikt-palette-cyan-2: #d7edf1; --wikt-palette-cyan-3: #c7e6ec; --wikt-palette-cyan-4: #a6d7e0; --wikt-palette-cyan-5: #8accd7; --wikt-palette-cyan-6: #6ebfcd; --wikt-palette-cyan-7: #50b2c3; --wikt-palette-cyan-8: #2ea3b7; --wikt-palette-cyan-9: #288191; --wikt-palette-blue-0: #f8fafe; --wikt-palette-blue-1: #ecf2fe; --wikt-palette-blue-2: #e0eafd; --wikt-palette-blue-3: #d3e1fc; --wikt-palette-blue-4: #bbd0fa; --wikt-palette-blue-5: #a6c2f9; --wikt-palette-blue-6: #92b3f7; --wikt-palette-blue-7: #7ca4f5; --wikt-palette-blue-8: #6494f4; --wikt-palette-blue-9: #3d72db; --wikt-palette-indigo-0: #fafafe; --wikt-palette-indigo-1: #f1f1fd; --wikt-palette-indigo-2: #e9e7fc; --wikt-palette-indigo-3: #e0defa; --wikt-palette-indigo-4: #cecbf8; --wikt-palette-indigo-5: #bfbcf5; --wikt-palette-indigo-6: #b0acf3; --wikt-palette-indigo-7: #a19cf1; --wikt-palette-indigo-8: #918aef; --wikt-palette-indigo-9: #6e66e0; --wikt-palette-purple-0: #fcfafe; --wikt-palette-purple-1: #f5f0fd; --wikt-palette-purple-2: #efe6fc; --wikt-palette-purple-3: #e8dbfb; --wikt-palette-purple-4: #dbc6f8; --wikt-palette-purple-5: #d0b6f7; --wikt-palette-purple-6: #c5a5f5; --wikt-palette-purple-7: #b993f2; --wikt-palette-purple-8: #ad7ff0; --wikt-palette-purple-9: #9053eb; --wikt-palette-magenta-0: #fcf9fe; --wikt-palette-magenta-1: #f7effc; --wikt-palette-magenta-2: #f3e4fa; --wikt-palette-magenta-3: #eedaf9; --wikt-palette-magenta-4: #e3c4f5; --wikt-palette-magenta-5: #dbb2f2; --wikt-palette-magenta-6: #d3a0ef; --wikt-palette-magenta-7: #ca8deb; --wikt-palette-magenta-8: #c078e8; --wikt-palette-magenta-9: #a844df; --wikt-palette-rose-0: #fcf9fc; --wikt-palette-rose-1: #f8f0f6; --wikt-palette-rose-2: #f3e6ef; --wikt-palette-rose-3: #eedbe9; --wikt-palette-rose-4: #e4c7dc; --wikt-palette-rose-5: #dcb6d2; --wikt-palette-rose-6: #d4a5c8; --wikt-palette-rose-7: #cc94bd; --wikt-palette-rose-8: #c381b1; --wikt-palette-rose-9: #af5797; --wikt-palette-brown-0: #fbfaf9; --wikt-palette-brown-1: #f4f1ee; --wikt-palette-brown-2: #eee8e4; --wikt-palette-brown-3: #e7dfd9; --wikt-palette-brown-4: #d8cdc3; --wikt-palette-brown-5: #cdbfb2; --wikt-palette-brown-6: #c2b1a1; --wikt-palette-brown-7: #b7a18f; --wikt-palette-brown-8: #ab927c; --wikt-palette-brown-9: #917155; --wikt-palette-grey-red-0: #fef9f9; --wikt-palette-grey-red-1: #fbeff0; --wikt-palette-grey-red-2: #f9e5e6; --wikt-palette-grey-red-3: #f7dadc; --wikt-palette-grey-red-4: #f2c3c8; --wikt-palette-grey-red-5: #eeb2b7; --wikt-palette-grey-red-6: #dca5ab; --wikt-palette-grey-red-7: #ce979c; --wikt-palette-grey-red-8: #c0878c; --wikt-palette-grey-red-9: #9f686d; --wikt-palette-grey-scarlet-0: #fdfaf8; --wikt-palette-grey-scarlet-1: #faf0ec; --wikt-palette-grey-scarlet-2: #f7e6e0; --wikt-palette-grey-scarlet-3: #f4dcd4; --wikt-palette-grey-scarlet-4: #eec7bb; --wikt-palette-grey-scarlet-5: #e8b6a7; --wikt-palette-grey-scarlet-6: #d6a99c; --wikt-palette-grey-scarlet-7: #c89b8d; --wikt-palette-grey-scarlet-8: #b98c7e; --wikt-palette-grey-scarlet-9: #986d5f; --wikt-palette-grey-orange-0: #fdfaf6; --wikt-palette-grey-orange-1: #f9f0e8; --wikt-palette-grey-orange-2: #f4e7d9; --wikt-palette-grey-orange-3: #f0deca; --wikt-palette-grey-orange-4: #e8caaa; --wikt-palette-grey-orange-5: #e1bb92; --wikt-palette-grey-orange-6: #cfae8a; --wikt-palette-grey-orange-7: #c19f7c; --wikt-palette-grey-orange-8: #b2906d; --wikt-palette-grey-orange-9: #917151; --wikt-palette-grey-amber-0: #fcfaf5; --wikt-palette-grey-amber-1: #f7f1e6; --wikt-palette-grey-amber-2: #f1e9d6; --wikt-palette-grey-amber-3: #ece0c6; --wikt-palette-grey-amber-4: #e0cda3; --wikt-palette-grey-amber-5: #d8bf8a; --wikt-palette-grey-amber-6: #c6b185; --wikt-palette-grey-amber-7: #b7a377; --wikt-palette-grey-amber-8: #a89468; --wikt-palette-grey-amber-9: #88754c; --wikt-palette-grey-yellow-0: #fbfaf6; --wikt-palette-grey-yellow-1: #f3f2e7; --wikt-palette-grey-yellow-2: #ecead9; --wikt-palette-grey-yellow-3: #e5e1ca; --wikt-palette-grey-yellow-4: #d5d0ab; --wikt-palette-grey-yellow-5: #cac394; --wikt-palette-grey-yellow-6: #beb57c; --wikt-palette-grey-yellow-7: #aca67f; --wikt-palette-grey-yellow-8: #9e9770; --wikt-palette-grey-yellow-9: #7e7851; --wikt-palette-grey-lime-0: #fafbf7; --wikt-palette-grey-lime-1: #f0f3e8; --wikt-palette-grey-lime-2: #e7ebda; --wikt-palette-grey-lime-3: #dee3cc; --wikt-palette-grey-lime-4: #cad3ae; --wikt-palette-grey-lime-5: #bbc798; --wikt-palette-grey-lime-6: #abba81; --wikt-palette-grey-lime-7: #a0a984; --wikt-palette-grey-lime-8: #919b74; --wikt-palette-grey-lime-9: #727c55; --wikt-palette-grey-green-0: #f8fbf7; --wikt-palette-grey-green-1: #edf4ea; --wikt-palette-grey-green-2: #e2ecdd; --wikt-palette-grey-green-3: #d6e5ce; --wikt-palette-grey-green-4: #bfd6b3; --wikt-palette-grey-green-5: #acca9d; --wikt-palette-grey-green-6: #9abe87; --wikt-palette-grey-green-7: #93ad86; --wikt-palette-grey-green-8: #839e75; --wikt-palette-grey-green-9: #647f56; --wikt-palette-grey-teal-0: #f7fbf9; --wikt-palette-grey-teal-1: #eaf4ef; --wikt-palette-grey-teal-2: #ddede5; --wikt-palette-grey-teal-3: #d0e6dc; --wikt-palette-grey-teal-4: #b4d7c7; --wikt-palette-grey-teal-5: #9ecbb6; --wikt-palette-grey-teal-6: #88bfa5; --wikt-palette-grey-teal-7: #86ae9b; --wikt-palette-grey-teal-8: #769f8c; --wikt-palette-grey-teal-9: #56806d; --wikt-palette-grey-cyan-0: #f7fbfb; --wikt-palette-grey-cyan-1: #ebf3f5; --wikt-palette-grey-cyan-2: #deecee; --wikt-palette-grey-cyan-3: #d1e4e7; --wikt-palette-grey-cyan-4: #b6d4da; --wikt-palette-grey-cyan-5: #a1c8cf; --wikt-palette-grey-cyan-6: #8cbbc4; --wikt-palette-grey-cyan-7: #86acb2; --wikt-palette-grey-cyan-8: #769da3; --wikt-palette-grey-cyan-9: #577e84; --wikt-palette-grey-blue-0: #f8fafe; --wikt-palette-grey-blue-1: #ecf2fc; --wikt-palette-grey-blue-2: #e1eafb; --wikt-palette-grey-blue-3: #d5e1f9; --wikt-palette-grey-blue-4: #bdd0f6; --wikt-palette-grey-blue-5: #aec2ea; --wikt-palette-grey-blue-6: #9fb4dd; --wikt-palette-grey-blue-7: #91a6cf; --wikt-palette-grey-blue-8: #8297c0; --wikt-palette-grey-blue-9: #6477a0; --wikt-palette-grey-indigo-0: #fafafe; --wikt-palette-grey-indigo-1: #f1f1fb; --wikt-palette-grey-indigo-2: #e9e8f9; --wikt-palette-grey-indigo-3: #e0def7; --wikt-palette-grey-indigo-4: #cdcbf2; --wikt-palette-grey-indigo-5: #c0bcee; --wikt-palette-grey-indigo-6: #b2afdc; --wikt-palette-grey-indigo-7: #a4a1d0; --wikt-palette-grey-indigo-8: #9592c2; --wikt-palette-grey-indigo-9: #7572a3; --wikt-palette-grey-purple-0: #fbfafe; --wikt-palette-grey-purple-1: #f5f0fc; --wikt-palette-grey-purple-2: #eee6fa; --wikt-palette-grey-purple-3: #e7dcf8; --wikt-palette-grey-purple-4: #d9c8f3; --wikt-palette-grey-purple-5: #ceb8f0; --wikt-palette-grey-purple-6: #c0aae1; --wikt-palette-grey-purple-7: #b19bd3; --wikt-palette-grey-purple-8: #a38cc5; --wikt-palette-grey-purple-9: #846da5; --wikt-palette-grey-magenta-0: #fcf9fd; --wikt-palette-grey-magenta-1: #f7effa; --wikt-palette-grey-magenta-2: #f1e5f7; --wikt-palette-grey-magenta-3: #ebdbf4; --wikt-palette-grey-magenta-4: #e0c6ee; --wikt-palette-grey-magenta-5: #d7b5e9; --wikt-palette-grey-magenta-6: #cda4e4; --wikt-palette-grey-magenta-7: #bc98d0; --wikt-palette-grey-magenta-8: #ae89c2; --wikt-palette-grey-magenta-9: #8e69a2; --wikt-palette-grey-rose-0: #fcfafb; --wikt-palette-grey-rose-1: #f6f0f4; --wikt-palette-grey-rose-2: #efe7ed; --wikt-palette-grey-rose-3: #e9dde6; --wikt-palette-grey-rose-4: #ddcad8; --wikt-palette-grey-rose-5: #d3bacc; --wikt-palette-grey-rose-6: #c9abc1; --wikt-palette-grey-rose-7: #be9bb5; --wikt-palette-grey-rose-8: #b38aa8; --wikt-palette-grey-rose-9: #8c6e84; --wikt-palette-grey-brown-0: #fafaf9; --wikt-palette-grey-brown-1: #f3f2f0; --wikt-palette-grey-brown-2: #ebe9e6; --wikt-palette-grey-brown-3: #e4e0dc; --wikt-palette-grey-brown-4: #d4cec8; --wikt-palette-grey-brown-5: #c8c0b9; --wikt-palette-grey-brown-6: #bcb2a9; --wikt-palette-grey-brown-7: #afa398; --wikt-palette-grey-brown-8: #a19488; --wikt-palette-grey-brown-9: #7f766d; --wikt-palette-grey-0: #fafafa; --wikt-palette-grey-1: #f2f2f2; --wikt-palette-grey-2: #e9e9e9; --wikt-palette-grey-3: #e1e1e1; --wikt-palette-grey-4: #cfcfcf; --wikt-palette-grey-5: #c2c2c2; --wikt-palette-grey-6: #b4b4b4; --wikt-palette-grey-7: #a5a5a5; --wikt-palette-grey-8: #979797; --wikt-palette-grey-9: #777777; } /* Styles need to be duplicated exactly between these two selectors. */ @media screen { html.skin-theme-clientpref-night { --wikt-palette-white: #101418; --wikt-palette-black: #eaecf0; --wikt-palette-beige: #2f1f10; --wikt-palette-darkgrey: #b2bbc3; --wikt-palette-grey: #4e4e4e; --wikt-palette-lightgrey: #3d3d3d; --wikt-palette-lightergrey: #242424; --wikt-palette-cream: #2c2c21; --wikt-palette-pink: #612042; --wikt-palette-peach: #58230a; --wikt-palette-gold: #c9b163; --wikt-palette-dullgold: #ab995e; --wikt-palette-yellow: #4a3912; --wikt-palette-dullyellow: #3a3520; --wikt-palette-brightyellow: #5e5300; --wikt-palette-palegreen: #112511; --wikt-palette-palergreen: #051f0c; --wikt-palette-mint: #194819; --wikt-palette-green: #aad7aa; --wikt-palette-forestgreen: #499149; --wikt-palette-luminousgreen: #103310; --wikt-palette-paleblue: #1c2229; --wikt-palette-cyan: #0a3239; --wikt-palette-palecyan: #171c21; --wikt-palette-lightblue: #092f58; --wikt-palette-dulllightblue: #305070; --wikt-palette-blue: #aaaaff; --wikt-palette-dullblue: #b8c0c5; --wikt-palette-dullcyan: #27292d; --wikt-palette-deepblue: #a5c3e1; --wikt-palette-lavender: #1a1a2a; --wikt-palette-lightyellow: #24241a; --wikt-palette-red: #d73333; --wikt-palette-darkred: #ffcccc; --wikt-palette-deepred: #e36a79; --wikt-palette-orange: #593e02; --wikt-palette-lighterblue: #0e1e33; --wikt-palette-dulllighterblue: #102437; --wikt-palette-lightred: #421211; --wikt-palette-indigo: #30306f; --wikt-palette-lightindigo: #242448; --wikt-palette-palerpink: #251111; --wikt-palette-honey: #feefb3; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #28070a; --wikt-palette-red-1: #3e0c11; --wikt-palette-red-2: #5a131a; --wikt-palette-red-3: #731b24; --wikt-palette-red-4: #89242d; --wikt-palette-red-5: #a12d38; --wikt-palette-red-6: #bf3b48; --wikt-palette-red-7: #e95462; --wikt-palette-red-8: #ee7984; --wikt-palette-red-9: #f3a2aa; --wikt-palette-scarlet-0: #250c05; --wikt-palette-scarlet-1: #3a1409; --wikt-palette-scarlet-2: #521d0e; --wikt-palette-scarlet-3: #692814; --wikt-palette-scarlet-4: #7f311a; --wikt-palette-scarlet-5: #953c22; --wikt-palette-scarlet-6: #b24b2c; --wikt-palette-scarlet-7: #e25e37; --wikt-palette-scarlet-8: #e88062; --wikt-palette-scarlet-9: #efa791; --wikt-palette-orange-0: #211101; --wikt-palette-orange-1: #331b03; --wikt-palette-orange-2: #462604; --wikt-palette-orange-3: #5c3206; --wikt-palette-orange-4: #703d08; --wikt-palette-orange-5: #85490a; --wikt-palette-orange-6: #a0580e; --wikt-palette-orange-7: #cb7114; --wikt-palette-orange-8: #de8931; --wikt-palette-orange-9: #e8ac6e; --wikt-palette-amber-0: #1c1401; --wikt-palette-amber-1: #2c1f03; --wikt-palette-amber-2: #3d2a04; --wikt-palette-amber-3: #503806; --wikt-palette-amber-4: #614508; --wikt-palette-amber-5: #74520a; --wikt-palette-amber-6: #8c640d; --wikt-palette-amber-7: #b17f13; --wikt-palette-amber-8: #cc9218; --wikt-palette-amber-9: #ddb258; --wikt-palette-yellow-0: #181504; --wikt-palette-yellow-1: #262107; --wikt-palette-yellow-2: #342e0a; --wikt-palette-yellow-3: #443c0f; --wikt-palette-yellow-4: #534a13; --wikt-palette-yellow-5: #625819; --wikt-palette-yellow-6: #776b21; --wikt-palette-yellow-7: #97882f; --wikt-palette-yellow-8: #ae9e3b; --wikt-palette-yellow-9: #c8b95b; --wikt-palette-lime-0: #131705; --wikt-palette-lime-1: #1e2409; --wikt-palette-lime-2: #28310d; --wikt-palette-lime-3: #354112; --wikt-palette-lime-4: #424f18; --wikt-palette-lime-5: #4f5e1f; --wikt-palette-lime-6: #607228; --wikt-palette-lime-7: #7b903a; --wikt-palette-lime-8: #8fa648; --wikt-palette-lime-9: #aac25f; --wikt-palette-green-0: #0c1805; --wikt-palette-green-1: #122608; --wikt-palette-green-2: #1a340c; --wikt-palette-green-3: #234411; --wikt-palette-green-4: #2c5317; --wikt-palette-green-5: #35631d; --wikt-palette-green-6: #427726; --wikt-palette-green-7: #599737; --wikt-palette-green-8: #6aae45; --wikt-palette-green-9: #8dc86d; --wikt-palette-teal-0: #04180f; --wikt-palette-teal-1: #082618; --wikt-palette-teal-2: #0c3422; --wikt-palette-teal-3: #11452d; --wikt-palette-teal-4: #165438; --wikt-palette-teal-5: #1c6443; --wikt-palette-teal-6: #267953; --wikt-palette-teal-7: #36986b; --wikt-palette-teal-8: #43af7e; --wikt-palette-teal-9: #6fc9a0; --wikt-palette-cyan-0: #04171b; --wikt-palette-cyan-1: #07242a; --wikt-palette-cyan-2: #0a3239; --wikt-palette-cyan-3: #0f424b; --wikt-palette-cyan-4: #14515c; --wikt-palette-cyan-5: #1a606d; --wikt-palette-cyan-6: #227583; --wikt-palette-cyan-7: #3194a6; --wikt-palette-cyan-8: #40aabd; --wikt-palette-cyan-9: #78c4d1; --wikt-palette-blue-0: #07132d; --wikt-palette-blue-1: #0b1f45; --wikt-palette-blue-2: #122b60; --wikt-palette-blue-3: #19397b; --wikt-palette-blue-4: #214692; --wikt-palette-blue-5: #2954ab; --wikt-palette-blue-6: #3667c9; --wikt-palette-blue-7: #4e84f2; --wikt-palette-blue-8: #709cf5; --wikt-palette-blue-9: #99b8f8; --wikt-palette-indigo-0: #100e36; --wikt-palette-indigo-1: #1b1751; --wikt-palette-indigo-2: #27226c; --wikt-palette-indigo-3: #352f88; --wikt-palette-indigo-4: #423b9e; --wikt-palette-indigo-5: #5049b4; --wikt-palette-indigo-6: #5f55e7; --wikt-palette-indigo-7: #8179ec; --wikt-palette-indigo-8: #9992f0; --wikt-palette-indigo-9: #b6b1f4; --wikt-palette-purple-0: #1a0934; --wikt-palette-purple-1: #29104e; --wikt-palette-purple-2: #3a196d; --wikt-palette-purple-3: #4c238a; --wikt-palette-purple-4: #5c2da3; --wikt-palette-purple-5: #6e38bc; --wikt-palette-purple-6: #8541e9; --wikt-palette-purple-7: #a16cee; --wikt-palette-purple-8: #b389f1; --wikt-palette-purple-9: #c9abf5; --wikt-palette-magenta-0: #20062d; --wikt-palette-magenta-1: #310b46; --wikt-palette-magenta-2: #471363; --wikt-palette-magenta-3: #5c1b7f; --wikt-palette-magenta-4: #6e2398; --wikt-palette-magenta-5: #822cb1; --wikt-palette-magenta-6: #9f30dc; --wikt-palette-magenta-7: #b663e4; --wikt-palette-magenta-8: #c581ea; --wikt-palette-magenta-9: #d6a6f0; --wikt-palette-rose-0: #240b1d; --wikt-palette-rose-1: #37122d; --wikt-palette-rose-2: #4b1c3f; --wikt-palette-rose-3: #5f2751; --wikt-palette-rose-4: #723362; --wikt-palette-rose-5: #844072; --wikt-palette-rose-6: #a7478e; --wikt-palette-rose-7: #ba6fa6; --wikt-palette-rose-8: #c78ab7; --wikt-palette-rose-9: #d7abcc; --wikt-palette-brown-0: #1d130b; --wikt-palette-brown-1: #2d1e12; --wikt-palette-brown-2: #3c2a1b; --wikt-palette-brown-3: #4d3826; --wikt-palette-brown-4: #5d4532; --wikt-palette-brown-5: #6c533e; --wikt-palette-brown-6: #876446; --wikt-palette-brown-7: #9f826a; --wikt-palette-brown-8: #b19986; --wikt-palette-brown-9: #c6b5a7; --wikt-palette-grey-red-0: #230f11; --wikt-palette-grey-red-1: #34191b; --wikt-palette-grey-red-2: #462327; --wikt-palette-grey-red-3: #5a3034; --wikt-palette-grey-red-4: #6b3c41; --wikt-palette-grey-red-5: #7c4a4f; --wikt-palette-grey-red-6: #925c61; --wikt-palette-grey-red-7: #b1797e; --wikt-palette-grey-red-8: #c78e94; --wikt-palette-grey-red-9: #eba6ad; --wikt-palette-grey-scarlet-0: #20110d; --wikt-palette-grey-scarlet-1: #311c16; --wikt-palette-grey-scarlet-2: #422720; --wikt-palette-grey-scarlet-3: #54342b; --wikt-palette-grey-scarlet-4: #654137; --wikt-palette-grey-scarlet-5: #764e43; --wikt-palette-grey-scarlet-6: #8b6154; --wikt-palette-grey-scarlet-7: #aa7d70; --wikt-palette-grey-scarlet-8: #c19386; --wikt-palette-grey-scarlet-9: #e5ab9a; --wikt-palette-grey-orange-0: #1c140a; --wikt-palette-grey-orange-1: #2c1f11; --wikt-palette-grey-orange-2: #3b2a19; --wikt-palette-grey-orange-3: #4d3823; --wikt-palette-grey-orange-4: #5d452c; --wikt-palette-grey-orange-5: #6e5337; --wikt-palette-grey-orange-6: #836547; --wikt-palette-grey-orange-7: #a28260; --wikt-palette-grey-orange-8: #b99774; --wikt-palette-grey-orange-9: #ddb082; --wikt-palette-grey-amber-0: #1a150a; --wikt-palette-grey-amber-1: #282010; --wikt-palette-grey-amber-2: #372c17; --wikt-palette-grey-amber-3: #473b20; --wikt-palette-grey-amber-4: #57482a; --wikt-palette-grey-amber-5: #675634; --wikt-palette-grey-amber-6: #7b6943; --wikt-palette-grey-amber-7: #99855b; --wikt-palette-grey-amber-8: #b09b70; --wikt-palette-grey-amber-9: #d2b579; --wikt-palette-grey-yellow-0: #17160a; --wikt-palette-grey-yellow-1: #242211; --wikt-palette-grey-yellow-2: #322e19; --wikt-palette-grey-yellow-3: #413d22; --wikt-palette-grey-yellow-4: #4f4a2c; --wikt-palette-grey-yellow-5: #5e5837; --wikt-palette-grey-yellow-6: #716b47; --wikt-palette-grey-yellow-7: #8f8861; --wikt-palette-grey-yellow-8: #a59e78; --wikt-palette-grey-yellow-9: #c2b984; --wikt-palette-grey-lime-0: #13160b; --wikt-palette-grey-lime-1: #1f2312; --wikt-palette-grey-lime-2: #2b3019; --wikt-palette-grey-lime-3: #383f23; --wikt-palette-grey-lime-4: #454d2d; --wikt-palette-grey-lime-5: #535c39; --wikt-palette-grey-lime-6: #666f49; --wikt-palette-grey-lime-7: #838c65; --wikt-palette-grey-lime-8: #98a27c; --wikt-palette-grey-lime-9: #b1be8a; --wikt-palette-grey-green-0: #0f170b; --wikt-palette-grey-green-1: #182512; --wikt-palette-grey-green-2: #22321a; --wikt-palette-grey-green-3: #2e4124; --wikt-palette-grey-green-4: #3a502e; --wikt-palette-grey-green-5: #465f3a; --wikt-palette-grey-green-6: #58724a; --wikt-palette-grey-green-7: #748f66; --wikt-palette-grey-green-8: #8ba57e; --wikt-palette-grey-green-9: #a1c290; --wikt-palette-grey-teal-0: #0b1812; --wikt-palette-grey-teal-1: #12251d; --wikt-palette-grey-teal-2: #1a3227; --wikt-palette-grey-teal-3: #244235; --wikt-palette-grey-teal-4: #2e5041; --wikt-palette-grey-teal-5: #3a5f4e; --wikt-palette-grey-teal-6: #4b7361; --wikt-palette-grey-teal-7: #66907d; --wikt-palette-grey-teal-8: #7ea694; --wikt-palette-grey-teal-9: #91c3ac; --wikt-palette-grey-cyan-0: #0b171a; --wikt-palette-grey-cyan-1: #122428; --wikt-palette-grey-cyan-2: #1a3136; --wikt-palette-grey-cyan-3: #244145; --wikt-palette-grey-cyan-4: #2f4f54; --wikt-palette-grey-cyan-5: #3a5d64; --wikt-palette-grey-cyan-6: #4b7178; --wikt-palette-grey-cyan-7: #678e95; --wikt-palette-grey-cyan-8: #7ea4ab; --wikt-palette-grey-cyan-9: #94c0c8; --wikt-palette-grey-blue-0: #0f1523; --wikt-palette-grey-blue-1: #182134; --wikt-palette-grey-blue-2: #212d46; --wikt-palette-grey-blue-3: #2e3c5a; --wikt-palette-grey-blue-4: #394a6a; --wikt-palette-grey-blue-5: #47587c; --wikt-palette-grey-blue-6: #586b92; --wikt-palette-grey-blue-7: #7488b2; --wikt-palette-grey-blue-8: #899ec8; --wikt-palette-grey-blue-9: #9cb8f2; --wikt-palette-grey-indigo-0: #141327; --wikt-palette-grey-indigo-1: #201e3a; --wikt-palette-grey-indigo-2: #2c2a4c; --wikt-palette-grey-indigo-3: #3a385f; --wikt-palette-grey-indigo-4: #484571; --wikt-palette-grey-indigo-5: #565382; --wikt-palette-grey-indigo-6: #696696; --wikt-palette-grey-indigo-7: #8682b4; --wikt-palette-grey-indigo-8: #9c98c8; --wikt-palette-grey-indigo-9: #b6b2ec; --wikt-palette-grey-purple-0: #1a1126; --wikt-palette-grey-purple-1: #271b39; --wikt-palette-grey-purple-2: #35264b; --wikt-palette-grey-purple-3: #453460; --wikt-palette-grey-purple-4: #544071; --wikt-palette-grey-purple-5: #634e83; --wikt-palette-grey-purple-6: #776098; --wikt-palette-grey-purple-7: #957db7; --wikt-palette-grey-purple-8: #aa93cc; --wikt-palette-grey-purple-9: #c7acee; --wikt-palette-grey-magenta-0: #1d0f24; --wikt-palette-grey-magenta-1: #2c1937; --wikt-palette-grey-magenta-2: #3c244a; --wikt-palette-grey-magenta-3: #4d315d; --wikt-palette-grey-magenta-4: #5d3d6e; --wikt-palette-grey-magenta-5: #6c4b7f; --wikt-palette-grey-magenta-6: #815d95; --wikt-palette-grey-magenta-7: #9f7ab4; --wikt-palette-grey-magenta-8: #be88dc; --wikt-palette-grey-magenta-9: #d1aae6; --wikt-palette-grey-rose-0: #1f101b; --wikt-palette-grey-rose-1: #2f1a29; --wikt-palette-grey-rose-2: #3e2538; --wikt-palette-grey-rose-3: #503348; --wikt-palette-grey-rose-4: #5f4057; --wikt-palette-grey-rose-5: #6e4e66; --wikt-palette-grey-rose-6: #816179; --wikt-palette-grey-rose-7: #a9799c; --wikt-palette-grey-rose-8: #b992ae; --wikt-palette-grey-rose-9: #ccb0c5; --wikt-palette-grey-brown-0: #1a140f; --wikt-palette-grey-brown-1: #282019; --wikt-palette-grey-brown-2: #362c23; --wikt-palette-grey-brown-3: #463a31; --wikt-palette-grey-brown-4: #53473d; --wikt-palette-grey-brown-5: #62564c; --wikt-palette-grey-brown-6: #746960; --wikt-palette-grey-brown-7: #958578; --wikt-palette-grey-brown-8: #a89b90; --wikt-palette-grey-brown-9: #c0b7af; --wikt-palette-grey-0: #151515; --wikt-palette-grey-1: #212121; --wikt-palette-grey-2: #2d2d2d; --wikt-palette-grey-3: #3c3c3c; --wikt-palette-grey-4: #494949; --wikt-palette-grey-5: #585858; --wikt-palette-grey-6: #6b6b6b; --wikt-palette-grey-7: #878787; --wikt-palette-grey-8: #9d9d9d; --wikt-palette-grey-9: #b8b8b8; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os { --wikt-palette-white: #101418; --wikt-palette-black: #eaecf0; --wikt-palette-beige: #2f1f10; --wikt-palette-darkgrey: #b2bbc3; --wikt-palette-grey: #4e4e4e; --wikt-palette-lightgrey: #3d3d3d; --wikt-palette-lightergrey: #242424; --wikt-palette-cream: #2c2c21; --wikt-palette-pink: #612042; --wikt-palette-peach: #58230a; --wikt-palette-gold: #c9b163; --wikt-palette-dullgold: #ab995e; --wikt-palette-yellow: #4a3912; --wikt-palette-dullyellow: #3a3520; --wikt-palette-brightyellow: #5e5300; --wikt-palette-palegreen: #112511; --wikt-palette-palergreen: #051f0c; --wikt-palette-mint: #194819; --wikt-palette-green: #aad7aa; --wikt-palette-forestgreen: #499149; --wikt-palette-luminousgreen: #103310; --wikt-palette-paleblue: #1c2229; --wikt-palette-cyan: #0a3239; --wikt-palette-palecyan: #171c21; --wikt-palette-lightblue: #092f58; --wikt-palette-dulllightblue: #305070; --wikt-palette-blue: #aaaaff; --wikt-palette-dullblue: #b8c0c5; --wikt-palette-dullcyan: #27292d; --wikt-palette-deepblue: #a5c3e1; --wikt-palette-lavender: #1a1a2a; --wikt-palette-lightyellow: #24241a; --wikt-palette-red: #d73333; --wikt-palette-darkred: #ffcccc; --wikt-palette-deepred: #e36a79; --wikt-palette-orange: #593e02; --wikt-palette-lighterblue: #0e1e33; --wikt-palette-dulllighterblue: #102437; --wikt-palette-lightred: #421211; --wikt-palette-indigo: #30306f; --wikt-palette-lightindigo: #242448; --wikt-palette-palerpink: #251111; --wikt-palette-honey: #feefb3; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #28070a; --wikt-palette-red-1: #3e0c11; --wikt-palette-red-2: #5a131a; --wikt-palette-red-3: #731b24; --wikt-palette-red-4: #89242d; --wikt-palette-red-5: #a12d38; --wikt-palette-red-6: #bf3b48; --wikt-palette-red-7: #e95462; --wikt-palette-red-8: #ee7984; --wikt-palette-red-9: #f3a2aa; --wikt-palette-scarlet-0: #250c05; --wikt-palette-scarlet-1: #3a1409; --wikt-palette-scarlet-2: #521d0e; --wikt-palette-scarlet-3: #692814; --wikt-palette-scarlet-4: #7f311a; --wikt-palette-scarlet-5: #953c22; --wikt-palette-scarlet-6: #b24b2c; --wikt-palette-scarlet-7: #e25e37; --wikt-palette-scarlet-8: #e88062; --wikt-palette-scarlet-9: #efa791; --wikt-palette-orange-0: #211101; --wikt-palette-orange-1: #331b03; --wikt-palette-orange-2: #462604; --wikt-palette-orange-3: #5c3206; --wikt-palette-orange-4: #703d08; --wikt-palette-orange-5: #85490a; --wikt-palette-orange-6: #a0580e; --wikt-palette-orange-7: #cb7114; --wikt-palette-orange-8: #de8931; --wikt-palette-orange-9: #e8ac6e; --wikt-palette-amber-0: #1c1401; --wikt-palette-amber-1: #2c1f03; --wikt-palette-amber-2: #3d2a04; --wikt-palette-amber-3: #503806; --wikt-palette-amber-4: #614508; --wikt-palette-amber-5: #74520a; --wikt-palette-amber-6: #8c640d; --wikt-palette-amber-7: #b17f13; --wikt-palette-amber-8: #cc9218; --wikt-palette-amber-9: #ddb258; --wikt-palette-yellow-0: #181504; --wikt-palette-yellow-1: #262107; --wikt-palette-yellow-2: #342e0a; --wikt-palette-yellow-3: #443c0f; --wikt-palette-yellow-4: #534a13; --wikt-palette-yellow-5: #625819; --wikt-palette-yellow-6: #776b21; --wikt-palette-yellow-7: #97882f; --wikt-palette-yellow-8: #ae9e3b; --wikt-palette-yellow-9: #c8b95b; --wikt-palette-lime-0: #131705; --wikt-palette-lime-1: #1e2409; --wikt-palette-lime-2: #28310d; --wikt-palette-lime-3: #354112; --wikt-palette-lime-4: #424f18; --wikt-palette-lime-5: #4f5e1f; --wikt-palette-lime-6: #607228; --wikt-palette-lime-7: #7b903a; --wikt-palette-lime-8: #8fa648; --wikt-palette-lime-9: #aac25f; --wikt-palette-green-0: #0c1805; --wikt-palette-green-1: #122608; --wikt-palette-green-2: #1a340c; --wikt-palette-green-3: #234411; --wikt-palette-green-4: #2c5317; --wikt-palette-green-5: #35631d; --wikt-palette-green-6: #427726; --wikt-palette-green-7: #599737; --wikt-palette-green-8: #6aae45; --wikt-palette-green-9: #8dc86d; --wikt-palette-teal-0: #04180f; --wikt-palette-teal-1: #082618; --wikt-palette-teal-2: #0c3422; --wikt-palette-teal-3: #11452d; --wikt-palette-teal-4: #165438; --wikt-palette-teal-5: #1c6443; --wikt-palette-teal-6: #267953; --wikt-palette-teal-7: #36986b; --wikt-palette-teal-8: #43af7e; --wikt-palette-teal-9: #6fc9a0; --wikt-palette-cyan-0: #04171b; --wikt-palette-cyan-1: #07242a; --wikt-palette-cyan-2: #0a3239; --wikt-palette-cyan-3: #0f424b; --wikt-palette-cyan-4: #14515c; --wikt-palette-cyan-5: #1a606d; --wikt-palette-cyan-6: #227583; --wikt-palette-cyan-7: #3194a6; --wikt-palette-cyan-8: #40aabd; --wikt-palette-cyan-9: #78c4d1; --wikt-palette-blue-0: #07132d; --wikt-palette-blue-1: #0b1f45; --wikt-palette-blue-2: #122b60; --wikt-palette-blue-3: #19397b; --wikt-palette-blue-4: #214692; --wikt-palette-blue-5: #2954ab; --wikt-palette-blue-6: #3667c9; --wikt-palette-blue-7: #4e84f2; --wikt-palette-blue-8: #709cf5; --wikt-palette-blue-9: #99b8f8; --wikt-palette-indigo-0: #100e36; --wikt-palette-indigo-1: #1b1751; --wikt-palette-indigo-2: #27226c; --wikt-palette-indigo-3: #352f88; --wikt-palette-indigo-4: #423b9e; --wikt-palette-indigo-5: #5049b4; --wikt-palette-indigo-6: #5f55e7; --wikt-palette-indigo-7: #8179ec; --wikt-palette-indigo-8: #9992f0; --wikt-palette-indigo-9: #b6b1f4; --wikt-palette-purple-0: #1a0934; --wikt-palette-purple-1: #29104e; --wikt-palette-purple-2: #3a196d; --wikt-palette-purple-3: #4c238a; --wikt-palette-purple-4: #5c2da3; --wikt-palette-purple-5: #6e38bc; --wikt-palette-purple-6: #8541e9; --wikt-palette-purple-7: #a16cee; --wikt-palette-purple-8: #b389f1; --wikt-palette-purple-9: #c9abf5; --wikt-palette-magenta-0: #20062d; --wikt-palette-magenta-1: #310b46; --wikt-palette-magenta-2: #471363; --wikt-palette-magenta-3: #5c1b7f; --wikt-palette-magenta-4: #6e2398; --wikt-palette-magenta-5: #822cb1; --wikt-palette-magenta-6: #9f30dc; --wikt-palette-magenta-7: #b663e4; --wikt-palette-magenta-8: #c581ea; --wikt-palette-magenta-9: #d6a6f0; --wikt-palette-rose-0: #240b1d; --wikt-palette-rose-1: #37122d; --wikt-palette-rose-2: #4b1c3f; --wikt-palette-rose-3: #5f2751; --wikt-palette-rose-4: #723362; --wikt-palette-rose-5: #844072; --wikt-palette-rose-6: #a7478e; --wikt-palette-rose-7: #ba6fa6; --wikt-palette-rose-8: #c78ab7; --wikt-palette-rose-9: #d7abcc; --wikt-palette-brown-0: #1d130b; --wikt-palette-brown-1: #2d1e12; --wikt-palette-brown-2: #3c2a1b; --wikt-palette-brown-3: #4d3826; --wikt-palette-brown-4: #5d4532; --wikt-palette-brown-5: #6c533e; --wikt-palette-brown-6: #876446; --wikt-palette-brown-7: #9f826a; --wikt-palette-brown-8: #b19986; --wikt-palette-brown-9: #c6b5a7; --wikt-palette-grey-red-0: #230f11; --wikt-palette-grey-red-1: #34191b; --wikt-palette-grey-red-2: #462327; --wikt-palette-grey-red-3: #5a3034; --wikt-palette-grey-red-4: #6b3c41; --wikt-palette-grey-red-5: #7c4a4f; --wikt-palette-grey-red-6: #925c61; --wikt-palette-grey-red-7: #b1797e; --wikt-palette-grey-red-8: #c78e94; --wikt-palette-grey-red-9: #eba6ad; --wikt-palette-grey-scarlet-0: #20110d; --wikt-palette-grey-scarlet-1: #311c16; --wikt-palette-grey-scarlet-2: #422720; --wikt-palette-grey-scarlet-3: #54342b; --wikt-palette-grey-scarlet-4: #654137; --wikt-palette-grey-scarlet-5: #764e43; --wikt-palette-grey-scarlet-6: #8b6154; --wikt-palette-grey-scarlet-7: #aa7d70; --wikt-palette-grey-scarlet-8: #c19386; --wikt-palette-grey-scarlet-9: #e5ab9a; --wikt-palette-grey-orange-0: #1c140a; --wikt-palette-grey-orange-1: #2c1f11; --wikt-palette-grey-orange-2: #3b2a19; --wikt-palette-grey-orange-3: #4d3823; --wikt-palette-grey-orange-4: #5d452c; --wikt-palette-grey-orange-5: #6e5337; --wikt-palette-grey-orange-6: #836547; --wikt-palette-grey-orange-7: #a28260; --wikt-palette-grey-orange-8: #b99774; --wikt-palette-grey-orange-9: #ddb082; --wikt-palette-grey-amber-0: #1a150a; --wikt-palette-grey-amber-1: #282010; --wikt-palette-grey-amber-2: #372c17; --wikt-palette-grey-amber-3: #473b20; --wikt-palette-grey-amber-4: #57482a; --wikt-palette-grey-amber-5: #675634; --wikt-palette-grey-amber-6: #7b6943; --wikt-palette-grey-amber-7: #99855b; --wikt-palette-grey-amber-8: #b09b70; --wikt-palette-grey-amber-9: #d2b579; --wikt-palette-grey-yellow-0: #17160a; --wikt-palette-grey-yellow-1: #242211; --wikt-palette-grey-yellow-2: #322e19; --wikt-palette-grey-yellow-3: #413d22; --wikt-palette-grey-yellow-4: #4f4a2c; --wikt-palette-grey-yellow-5: #5e5837; --wikt-palette-grey-yellow-6: #716b47; --wikt-palette-grey-yellow-7: #8f8861; --wikt-palette-grey-yellow-8: #a59e78; --wikt-palette-grey-yellow-9: #c2b984; --wikt-palette-grey-lime-0: #13160b; --wikt-palette-grey-lime-1: #1f2312; --wikt-palette-grey-lime-2: #2b3019; --wikt-palette-grey-lime-3: #383f23; --wikt-palette-grey-lime-4: #454d2d; --wikt-palette-grey-lime-5: #535c39; --wikt-palette-grey-lime-6: #666f49; --wikt-palette-grey-lime-7: #838c65; --wikt-palette-grey-lime-8: #98a27c; --wikt-palette-grey-lime-9: #b1be8a; --wikt-palette-grey-green-0: #0f170b; --wikt-palette-grey-green-1: #182512; --wikt-palette-grey-green-2: #22321a; --wikt-palette-grey-green-3: #2e4124; --wikt-palette-grey-green-4: #3a502e; --wikt-palette-grey-green-5: #465f3a; --wikt-palette-grey-green-6: #58724a; --wikt-palette-grey-green-7: #748f66; --wikt-palette-grey-green-8: #8ba57e; --wikt-palette-grey-green-9: #a1c290; --wikt-palette-grey-teal-0: #0b1812; --wikt-palette-grey-teal-1: #12251d; --wikt-palette-grey-teal-2: #1a3227; --wikt-palette-grey-teal-3: #244235; --wikt-palette-grey-teal-4: #2e5041; --wikt-palette-grey-teal-5: #3a5f4e; --wikt-palette-grey-teal-6: #4b7361; --wikt-palette-grey-teal-7: #66907d; --wikt-palette-grey-teal-8: #7ea694; --wikt-palette-grey-teal-9: #91c3ac; --wikt-palette-grey-cyan-0: #0b171a; --wikt-palette-grey-cyan-1: #122428; --wikt-palette-grey-cyan-2: #1a3136; --wikt-palette-grey-cyan-3: #244145; --wikt-palette-grey-cyan-4: #2f4f54; --wikt-palette-grey-cyan-5: #3a5d64; --wikt-palette-grey-cyan-6: #4b7178; --wikt-palette-grey-cyan-7: #678e95; --wikt-palette-grey-cyan-8: #7ea4ab; --wikt-palette-grey-cyan-9: #94c0c8; --wikt-palette-grey-blue-0: #0f1523; --wikt-palette-grey-blue-1: #182134; --wikt-palette-grey-blue-2: #212d46; --wikt-palette-grey-blue-3: #2e3c5a; --wikt-palette-grey-blue-4: #394a6a; --wikt-palette-grey-blue-5: #47587c; --wikt-palette-grey-blue-6: #586b92; --wikt-palette-grey-blue-7: #7488b2; --wikt-palette-grey-blue-8: #899ec8; --wikt-palette-grey-blue-9: #9cb8f2; --wikt-palette-grey-indigo-0: #141327; --wikt-palette-grey-indigo-1: #201e3a; --wikt-palette-grey-indigo-2: #2c2a4c; --wikt-palette-grey-indigo-3: #3a385f; --wikt-palette-grey-indigo-4: #484571; --wikt-palette-grey-indigo-5: #565382; --wikt-palette-grey-indigo-6: #696696; --wikt-palette-grey-indigo-7: #8682b4; --wikt-palette-grey-indigo-8: #9c98c8; --wikt-palette-grey-indigo-9: #b6b2ec; --wikt-palette-grey-purple-0: #1a1126; --wikt-palette-grey-purple-1: #271b39; --wikt-palette-grey-purple-2: #35264b; --wikt-palette-grey-purple-3: #453460; --wikt-palette-grey-purple-4: #544071; --wikt-palette-grey-purple-5: #634e83; --wikt-palette-grey-purple-6: #776098; --wikt-palette-grey-purple-7: #957db7; --wikt-palette-grey-purple-8: #aa93cc; --wikt-palette-grey-purple-9: #c7acee; --wikt-palette-grey-magenta-0: #1d0f24; --wikt-palette-grey-magenta-1: #2c1937; --wikt-palette-grey-magenta-2: #3c244a; --wikt-palette-grey-magenta-3: #4d315d; --wikt-palette-grey-magenta-4: #5d3d6e; --wikt-palette-grey-magenta-5: #6c4b7f; --wikt-palette-grey-magenta-6: #815d95; --wikt-palette-grey-magenta-7: #9f7ab4; --wikt-palette-grey-magenta-8: #be88dc; --wikt-palette-grey-magenta-9: #d1aae6; --wikt-palette-grey-rose-0: #1f101b; --wikt-palette-grey-rose-1: #2f1a29; --wikt-palette-grey-rose-2: #3e2538; --wikt-palette-grey-rose-3: #503348; --wikt-palette-grey-rose-4: #5f4057; --wikt-palette-grey-rose-5: #6e4e66; --wikt-palette-grey-rose-6: #816179; --wikt-palette-grey-rose-7: #a9799c; --wikt-palette-grey-rose-8: #b992ae; --wikt-palette-grey-rose-9: #ccb0c5; --wikt-palette-grey-brown-0: #1a140f; --wikt-palette-grey-brown-1: #282019; --wikt-palette-grey-brown-2: #362c23; --wikt-palette-grey-brown-3: #463a31; --wikt-palette-grey-brown-4: #53473d; --wikt-palette-grey-brown-5: #62564c; --wikt-palette-grey-brown-6: #746960; --wikt-palette-grey-brown-7: #958578; --wikt-palette-grey-brown-8: #a89b90; --wikt-palette-grey-brown-9: #c0b7af; --wikt-palette-grey-0: #151515; --wikt-palette-grey-1: #212121; --wikt-palette-grey-2: #2d2d2d; --wikt-palette-grey-3: #3c3c3c; --wikt-palette-grey-4: #494949; --wikt-palette-grey-5: #585858; --wikt-palette-grey-6: #6b6b6b; --wikt-palette-grey-7: #878787; --wikt-palette-grey-8: #9d9d9d; --wikt-palette-grey-9: #b8b8b8; } } /* Shorthand available with data-wikt-palette-p and scoping */ [data-wikt-palette-p="red"] { --wikt-p-0: var(--wikt-palette-red-0); --wikt-p-1: var(--wikt-palette-red-1); --wikt-p-2: var(--wikt-palette-red-2); --wikt-p-3: var(--wikt-palette-red-3); --wikt-p-4: var(--wikt-palette-red-4); --wikt-p-5: var(--wikt-palette-red-5); --wikt-p-6: var(--wikt-palette-red-6); --wikt-p-7: var(--wikt-palette-red-7); --wikt-p-8: var(--wikt-palette-red-8); --wikt-p-9: var(--wikt-palette-red-9); --wikt-p-g-0: var(--wikt-palette-grey-red-0); --wikt-p-g-1: var(--wikt-palette-grey-red-1); --wikt-p-g-2: var(--wikt-palette-grey-red-2); --wikt-p-g-3: var(--wikt-palette-grey-red-3); --wikt-p-g-4: var(--wikt-palette-grey-red-4); --wikt-p-g-5: var(--wikt-palette-grey-red-5); --wikt-p-g-6: var(--wikt-palette-grey-red-6); --wikt-p-g-7: var(--wikt-palette-grey-red-7); --wikt-p-g-8: var(--wikt-palette-grey-red-8); --wikt-p-g-9: var(--wikt-palette-grey-red-9); } [data-wikt-palette-p="scarlet"] { --wikt-p-0: var(--wikt-palette-scarlet-0); --wikt-p-1: var(--wikt-palette-scarlet-1); --wikt-p-2: var(--wikt-palette-scarlet-2); --wikt-p-3: var(--wikt-palette-scarlet-3); --wikt-p-4: var(--wikt-palette-scarlet-4); --wikt-p-5: var(--wikt-palette-scarlet-5); --wikt-p-6: var(--wikt-palette-scarlet-6); --wikt-p-7: var(--wikt-palette-scarlet-7); --wikt-p-8: var(--wikt-palette-scarlet-8); --wikt-p-9: var(--wikt-palette-scarlet-9); --wikt-p-g-0: var(--wikt-palette-grey-scarlet-0); --wikt-p-g-1: var(--wikt-palette-grey-scarlet-1); --wikt-p-g-2: var(--wikt-palette-grey-scarlet-2); --wikt-p-g-3: var(--wikt-palette-grey-scarlet-3); --wikt-p-g-4: var(--wikt-palette-grey-scarlet-4); --wikt-p-g-5: var(--wikt-palette-grey-scarlet-5); --wikt-p-g-6: var(--wikt-palette-grey-scarlet-6); --wikt-p-g-7: var(--wikt-palette-grey-scarlet-7); --wikt-p-g-8: var(--wikt-palette-grey-scarlet-8); --wikt-p-g-9: var(--wikt-palette-grey-scarlet-9); } [data-wikt-palette-p="orange"] { --wikt-p-0: var(--wikt-palette-orange-0); --wikt-p-1: var(--wikt-palette-orange-1); --wikt-p-2: var(--wikt-palette-orange-2); --wikt-p-3: var(--wikt-palette-orange-3); --wikt-p-4: var(--wikt-palette-orange-4); --wikt-p-5: var(--wikt-palette-orange-5); --wikt-p-6: var(--wikt-palette-orange-6); --wikt-p-7: var(--wikt-palette-orange-7); --wikt-p-8: var(--wikt-palette-orange-8); --wikt-p-9: var(--wikt-palette-orange-9); --wikt-p-g-0: var(--wikt-palette-grey-orange-0); --wikt-p-g-1: var(--wikt-palette-grey-orange-1); --wikt-p-g-2: var(--wikt-palette-grey-orange-2); --wikt-p-g-3: var(--wikt-palette-grey-orange-3); --wikt-p-g-4: var(--wikt-palette-grey-orange-4); --wikt-p-g-5: var(--wikt-palette-grey-orange-5); --wikt-p-g-6: var(--wikt-palette-grey-orange-6); --wikt-p-g-7: var(--wikt-palette-grey-orange-7); --wikt-p-g-8: var(--wikt-palette-grey-orange-8); --wikt-p-g-9: var(--wikt-palette-grey-orange-9); } [data-wikt-palette-p="amber"] { --wikt-p-0: var(--wikt-palette-amber-0); --wikt-p-1: var(--wikt-palette-amber-1); --wikt-p-2: var(--wikt-palette-amber-2); --wikt-p-3: var(--wikt-palette-amber-3); --wikt-p-4: var(--wikt-palette-amber-4); --wikt-p-5: var(--wikt-palette-amber-5); --wikt-p-6: var(--wikt-palette-amber-6); --wikt-p-7: var(--wikt-palette-amber-7); --wikt-p-8: var(--wikt-palette-amber-8); --wikt-p-9: var(--wikt-palette-amber-9); --wikt-p-g-0: var(--wikt-palette-grey-amber-0); --wikt-p-g-1: var(--wikt-palette-grey-amber-1); --wikt-p-g-2: var(--wikt-palette-grey-amber-2); --wikt-p-g-3: var(--wikt-palette-grey-amber-3); --wikt-p-g-4: var(--wikt-palette-grey-amber-4); --wikt-p-g-5: var(--wikt-palette-grey-amber-5); --wikt-p-g-6: var(--wikt-palette-grey-amber-6); --wikt-p-g-7: var(--wikt-palette-grey-amber-7); --wikt-p-g-8: var(--wikt-palette-grey-amber-8); --wikt-p-g-9: var(--wikt-palette-grey-amber-9); } [data-wikt-palette-p="yellow"] { --wikt-p-0: var(--wikt-palette-yellow-0); --wikt-p-1: var(--wikt-palette-yellow-1); --wikt-p-2: var(--wikt-palette-yellow-2); --wikt-p-3: var(--wikt-palette-yellow-3); --wikt-p-4: var(--wikt-palette-yellow-4); --wikt-p-5: var(--wikt-palette-yellow-5); --wikt-p-6: var(--wikt-palette-yellow-6); --wikt-p-7: var(--wikt-palette-yellow-7); --wikt-p-8: var(--wikt-palette-yellow-8); --wikt-p-9: var(--wikt-palette-yellow-9); --wikt-p-g-0: var(--wikt-palette-grey-yellow-0); --wikt-p-g-1: var(--wikt-palette-grey-yellow-1); --wikt-p-g-2: var(--wikt-palette-grey-yellow-2); --wikt-p-g-3: var(--wikt-palette-grey-yellow-3); --wikt-p-g-4: var(--wikt-palette-grey-yellow-4); --wikt-p-g-5: var(--wikt-palette-grey-yellow-5); --wikt-p-g-6: var(--wikt-palette-grey-yellow-6); --wikt-p-g-7: var(--wikt-palette-grey-yellow-7); --wikt-p-g-8: var(--wikt-palette-grey-yellow-8); --wikt-p-g-9: var(--wikt-palette-grey-yellow-9); } [data-wikt-palette-p="lime"] { --wikt-p-0: var(--wikt-palette-lime-0); --wikt-p-1: var(--wikt-palette-lime-1); --wikt-p-2: var(--wikt-palette-lime-2); --wikt-p-3: var(--wikt-palette-lime-3); --wikt-p-4: var(--wikt-palette-lime-4); --wikt-p-5: var(--wikt-palette-lime-5); --wikt-p-6: var(--wikt-palette-lime-6); --wikt-p-7: var(--wikt-palette-lime-7); --wikt-p-8: var(--wikt-palette-lime-8); --wikt-p-9: var(--wikt-palette-lime-9); --wikt-p-g-0: var(--wikt-palette-grey-lime-0); --wikt-p-g-1: var(--wikt-palette-grey-lime-1); --wikt-p-g-2: var(--wikt-palette-grey-lime-2); --wikt-p-g-3: var(--wikt-palette-grey-lime-3); --wikt-p-g-4: var(--wikt-palette-grey-lime-4); --wikt-p-g-5: var(--wikt-palette-grey-lime-5); --wikt-p-g-6: var(--wikt-palette-grey-lime-6); --wikt-p-g-7: var(--wikt-palette-grey-lime-7); --wikt-p-g-8: var(--wikt-palette-grey-lime-8); --wikt-p-g-9: var(--wikt-palette-grey-lime-9); } [data-wikt-palette-p="green"] { --wikt-p-0: var(--wikt-palette-green-0); --wikt-p-1: var(--wikt-palette-green-1); --wikt-p-2: var(--wikt-palette-green-2); --wikt-p-3: var(--wikt-palette-green-3); --wikt-p-4: var(--wikt-palette-green-4); --wikt-p-5: var(--wikt-palette-green-5); --wikt-p-6: var(--wikt-palette-green-6); --wikt-p-7: var(--wikt-palette-green-7); --wikt-p-8: var(--wikt-palette-green-8); --wikt-p-9: var(--wikt-palette-green-9); --wikt-p-g-0: var(--wikt-palette-grey-green-0); --wikt-p-g-1: var(--wikt-palette-grey-green-1); --wikt-p-g-2: var(--wikt-palette-grey-green-2); --wikt-p-g-3: var(--wikt-palette-grey-green-3); --wikt-p-g-4: var(--wikt-palette-grey-green-4); --wikt-p-g-5: var(--wikt-palette-grey-green-5); --wikt-p-g-6: var(--wikt-palette-grey-green-6); --wikt-p-g-7: var(--wikt-palette-grey-green-7); --wikt-p-g-8: var(--wikt-palette-grey-green-8); --wikt-p-g-9: var(--wikt-palette-grey-green-9); } [data-wikt-palette-p="teal"] { --wikt-p-0: var(--wikt-palette-teal-0); --wikt-p-1: var(--wikt-palette-teal-1); --wikt-p-2: var(--wikt-palette-teal-2); --wikt-p-3: var(--wikt-palette-teal-3); --wikt-p-4: var(--wikt-palette-teal-4); --wikt-p-5: var(--wikt-palette-teal-5); --wikt-p-6: var(--wikt-palette-teal-6); --wikt-p-7: var(--wikt-palette-teal-7); --wikt-p-8: var(--wikt-palette-teal-8); --wikt-p-9: var(--wikt-palette-teal-9); --wikt-p-g-0: var(--wikt-palette-grey-teal-0); --wikt-p-g-1: var(--wikt-palette-grey-teal-1); --wikt-p-g-2: var(--wikt-palette-grey-teal-2); --wikt-p-g-3: var(--wikt-palette-grey-teal-3); --wikt-p-g-4: var(--wikt-palette-grey-teal-4); --wikt-p-g-5: var(--wikt-palette-grey-teal-5); --wikt-p-g-6: var(--wikt-palette-grey-teal-6); --wikt-p-g-7: var(--wikt-palette-grey-teal-7); --wikt-p-g-8: var(--wikt-palette-grey-teal-8); --wikt-p-g-9: var(--wikt-palette-grey-teal-9); } [data-wikt-palette-p="cyan"] { --wikt-p-0: var(--wikt-palette-cyan-0); --wikt-p-1: var(--wikt-palette-cyan-1); --wikt-p-2: var(--wikt-palette-cyan-2); --wikt-p-3: var(--wikt-palette-cyan-3); --wikt-p-4: var(--wikt-palette-cyan-4); --wikt-p-5: var(--wikt-palette-cyan-5); --wikt-p-6: var(--wikt-palette-cyan-6); --wikt-p-7: var(--wikt-palette-cyan-7); --wikt-p-8: var(--wikt-palette-cyan-8); --wikt-p-9: var(--wikt-palette-cyan-9); --wikt-p-g-0: var(--wikt-palette-grey-cyan-0); --wikt-p-g-1: var(--wikt-palette-grey-cyan-1); --wikt-p-g-2: var(--wikt-palette-grey-cyan-2); --wikt-p-g-3: var(--wikt-palette-grey-cyan-3); --wikt-p-g-4: var(--wikt-palette-grey-cyan-4); --wikt-p-g-5: var(--wikt-palette-grey-cyan-5); --wikt-p-g-6: var(--wikt-palette-grey-cyan-6); --wikt-p-g-7: var(--wikt-palette-grey-cyan-7); --wikt-p-g-8: var(--wikt-palette-grey-cyan-8); --wikt-p-g-9: var(--wikt-palette-grey-cyan-9); } [data-wikt-palette-p="blue"] { --wikt-p-0: var(--wikt-palette-blue-0); --wikt-p-1: var(--wikt-palette-blue-1); --wikt-p-2: var(--wikt-palette-blue-2); --wikt-p-3: var(--wikt-palette-blue-3); --wikt-p-4: var(--wikt-palette-blue-4); --wikt-p-5: var(--wikt-palette-blue-5); --wikt-p-6: var(--wikt-palette-blue-6); --wikt-p-7: var(--wikt-palette-blue-7); --wikt-p-8: var(--wikt-palette-blue-8); --wikt-p-9: var(--wikt-palette-blue-9); --wikt-p-g-0: var(--wikt-palette-grey-blue-0); --wikt-p-g-1: var(--wikt-palette-grey-blue-1); --wikt-p-g-2: var(--wikt-palette-grey-blue-2); --wikt-p-g-3: var(--wikt-palette-grey-blue-3); --wikt-p-g-4: var(--wikt-palette-grey-blue-4); --wikt-p-g-5: var(--wikt-palette-grey-blue-5); --wikt-p-g-6: var(--wikt-palette-grey-blue-6); --wikt-p-g-7: var(--wikt-palette-grey-blue-7); --wikt-p-g-8: var(--wikt-palette-grey-blue-8); --wikt-p-g-9: var(--wikt-palette-grey-blue-9); } [data-wikt-palette-p="indigo"] { --wikt-p-0: var(--wikt-palette-indigo-0); --wikt-p-1: var(--wikt-palette-indigo-1); --wikt-p-2: var(--wikt-palette-indigo-2); --wikt-p-3: var(--wikt-palette-indigo-3); --wikt-p-4: var(--wikt-palette-indigo-4); --wikt-p-5: var(--wikt-palette-indigo-5); --wikt-p-6: var(--wikt-palette-indigo-6); --wikt-p-7: var(--wikt-palette-indigo-7); --wikt-p-8: var(--wikt-palette-indigo-8); --wikt-p-9: var(--wikt-palette-indigo-9); --wikt-p-g-0: var(--wikt-palette-grey-indigo-0); --wikt-p-g-1: var(--wikt-palette-grey-indigo-1); --wikt-p-g-2: var(--wikt-palette-grey-indigo-2); --wikt-p-g-3: var(--wikt-palette-grey-indigo-3); --wikt-p-g-4: var(--wikt-palette-grey-indigo-4); --wikt-p-g-5: var(--wikt-palette-grey-indigo-5); --wikt-p-g-6: var(--wikt-palette-grey-indigo-6); --wikt-p-g-7: var(--wikt-palette-grey-indigo-7); --wikt-p-g-8: var(--wikt-palette-grey-indigo-8); --wikt-p-g-9: var(--wikt-palette-grey-indigo-9); } [data-wikt-palette-p="purple"] { --wikt-p-0: var(--wikt-palette-purple-0); --wikt-p-1: var(--wikt-palette-purple-1); --wikt-p-2: var(--wikt-palette-purple-2); --wikt-p-3: var(--wikt-palette-purple-3); --wikt-p-4: var(--wikt-palette-purple-4); --wikt-p-5: var(--wikt-palette-purple-5); --wikt-p-6: var(--wikt-palette-purple-6); --wikt-p-7: var(--wikt-palette-purple-7); --wikt-p-8: var(--wikt-palette-purple-8); --wikt-p-9: var(--wikt-palette-purple-9); --wikt-p-g-0: var(--wikt-palette-grey-purple-0); --wikt-p-g-1: var(--wikt-palette-grey-purple-1); --wikt-p-g-2: var(--wikt-palette-grey-purple-2); --wikt-p-g-3: var(--wikt-palette-grey-purple-3); --wikt-p-g-4: var(--wikt-palette-grey-purple-4); --wikt-p-g-5: var(--wikt-palette-grey-purple-5); --wikt-p-g-6: var(--wikt-palette-grey-purple-6); --wikt-p-g-7: var(--wikt-palette-grey-purple-7); --wikt-p-g-8: var(--wikt-palette-grey-purple-8); --wikt-p-g-9: var(--wikt-palette-grey-purple-9); } [data-wikt-palette-p="magenta"] { --wikt-p-0: var(--wikt-palette-magenta-0); --wikt-p-1: var(--wikt-palette-magenta-1); --wikt-p-2: var(--wikt-palette-magenta-2); --wikt-p-3: var(--wikt-palette-magenta-3); --wikt-p-4: var(--wikt-palette-magenta-4); --wikt-p-5: var(--wikt-palette-magenta-5); --wikt-p-6: var(--wikt-palette-magenta-6); --wikt-p-7: var(--wikt-palette-magenta-7); --wikt-p-8: var(--wikt-palette-magenta-8); --wikt-p-9: var(--wikt-palette-magenta-9); --wikt-p-g-0: var(--wikt-palette-grey-magenta-0); --wikt-p-g-1: var(--wikt-palette-grey-magenta-1); --wikt-p-g-2: var(--wikt-palette-grey-magenta-2); --wikt-p-g-3: var(--wikt-palette-grey-magenta-3); --wikt-p-g-4: var(--wikt-palette-grey-magenta-4); --wikt-p-g-5: var(--wikt-palette-grey-magenta-5); --wikt-p-g-6: var(--wikt-palette-grey-magenta-6); --wikt-p-g-7: var(--wikt-palette-grey-magenta-7); --wikt-p-g-8: var(--wikt-palette-grey-magenta-8); --wikt-p-g-9: var(--wikt-palette-grey-magenta-9); } [data-wikt-palette-p="rose"] { --wikt-p-0: var(--wikt-palette-rose-0); --wikt-p-1: var(--wikt-palette-rose-1); --wikt-p-2: var(--wikt-palette-rose-2); --wikt-p-3: var(--wikt-palette-rose-3); --wikt-p-4: var(--wikt-palette-rose-4); --wikt-p-5: var(--wikt-palette-rose-5); --wikt-p-6: var(--wikt-palette-rose-6); --wikt-p-7: var(--wikt-palette-rose-7); --wikt-p-8: var(--wikt-palette-rose-8); --wikt-p-9: var(--wikt-palette-rose-9); --wikt-p-g-0: var(--wikt-palette-grey-rose-0); --wikt-p-g-1: var(--wikt-palette-grey-rose-1); --wikt-p-g-2: var(--wikt-palette-grey-rose-2); --wikt-p-g-3: var(--wikt-palette-grey-rose-3); --wikt-p-g-4: var(--wikt-palette-grey-rose-4); --wikt-p-g-5: var(--wikt-palette-grey-rose-5); --wikt-p-g-6: var(--wikt-palette-grey-rose-6); --wikt-p-g-7: var(--wikt-palette-grey-rose-7); --wikt-p-g-8: var(--wikt-palette-grey-rose-8); --wikt-p-g-9: var(--wikt-palette-grey-rose-9); } [data-wikt-palette-p="brown"] { --wikt-p-0: var(--wikt-palette-brown-0); --wikt-p-1: var(--wikt-palette-brown-1); --wikt-p-2: var(--wikt-palette-brown-2); --wikt-p-3: var(--wikt-palette-brown-3); --wikt-p-4: var(--wikt-palette-brown-4); --wikt-p-5: var(--wikt-palette-brown-5); --wikt-p-6: var(--wikt-palette-brown-6); --wikt-p-7: var(--wikt-palette-brown-7); --wikt-p-8: var(--wikt-palette-brown-8); --wikt-p-9: var(--wikt-palette-brown-9); --wikt-p-g-0: var(--wikt-palette-grey-brown-0); --wikt-p-g-1: var(--wikt-palette-grey-brown-1); --wikt-p-g-2: var(--wikt-palette-grey-brown-2); --wikt-p-g-3: var(--wikt-palette-grey-brown-3); --wikt-p-g-4: var(--wikt-palette-grey-brown-4); --wikt-p-g-5: var(--wikt-palette-grey-brown-5); --wikt-p-g-6: var(--wikt-palette-grey-brown-6); --wikt-p-g-7: var(--wikt-palette-grey-brown-7); --wikt-p-g-8: var(--wikt-palette-grey-brown-8); --wikt-p-g-9: var(--wikt-palette-grey-brown-9); } [data-wikt-palette-p="grey"] { --wikt-p-0: var(--wikt-palette-grey-0); --wikt-p-1: var(--wikt-palette-grey-1); --wikt-p-2: var(--wikt-palette-grey-2); --wikt-p-3: var(--wikt-palette-grey-3); --wikt-p-4: var(--wikt-palette-grey-4); --wikt-p-5: var(--wikt-palette-grey-5); --wikt-p-6: var(--wikt-palette-grey-6); --wikt-p-7: var(--wikt-palette-grey-7); --wikt-p-8: var(--wikt-palette-grey-8); --wikt-p-9: var(--wikt-palette-grey-9); --wikt-p-g-0: var(--wikt-palette-grey-0); --wikt-p-g-1: var(--wikt-palette-grey-1); --wikt-p-g-2: var(--wikt-palette-grey-2); --wikt-p-g-3: var(--wikt-palette-grey-3); --wikt-p-g-4: var(--wikt-palette-grey-4); --wikt-p-g-5: var(--wikt-palette-grey-5); --wikt-p-g-6: var(--wikt-palette-grey-6); --wikt-p-g-7: var(--wikt-palette-grey-7); --wikt-p-g-8: var(--wikt-palette-grey-8); --wikt-p-g-9: var(--wikt-palette-grey-9); } t46x6el1qmhny2nrq55ifhccynp1qdz 88907 88906 2026-08-06T23:11:29Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Palette.css]] 88906 css text/css /* Wiktionary's palette of colors that work equally well in light and dark mode. */ /* Inspired by [[:ru:w:MediaWiki:Gadget-common-site.css]] */ :root, .skin-invert, .notheme { --wikt-palette-white: #ffffff; /* Same as <code>--background-color-base</code> */ --wikt-palette-black: #202122; /* Body text; same as <code>--color-base</code> */ --wikt-palette-beige: #fffbf2; --wikt-palette-darkgrey: #54595d; --wikt-palette-grey: #9e9e9e; --wikt-palette-lightgrey: #cccccc; --wikt-palette-lightergrey: #eeeeee; --wikt-palette-cream: #f8f8f0; --wikt-palette-pink: #ffe0f0; --wikt-palette-peach: #e4d4c0; --wikt-palette-gold: #b88d00; --wikt-palette-dullgold: #826f34; --wikt-palette-yellow: #ebe8b9; --wikt-palette-dullyellow: #dedbc1; --wikt-palette-brightyellow: #ffee77; --wikt-palette-palegreen: #e2f6e2; --wikt-palette-palergreen: #f8fffa; --wikt-palette-mint: #c0e4c0; --wikt-palette-green: #33d733; --wikt-palette-forestgreen: #235923; --wikt-palette-luminousgreen: #dafdda; --wikt-palette-paleblue: #f8f9fa; --wikt-palette-cyan: #eefbf9; --wikt-palette-palecyan: #f6f7f7; --wikt-palette-lightblue: #d9ebff; --wikt-palette-dulllightblue: #aabbdd; --wikt-palette-blue: #3333ff; --wikt-palette-dullblue: #49555f; --wikt-palette-dullcyan: #eaecf0; --wikt-palette-deepblue: #2f445c; --wikt-palette-lavender: #f8f8ff; --wikt-palette-lightyellow: #ffffe0; --wikt-palette-red: #d73333; /* Same as <code>--background-color-destructive</code> */ --wikt-palette-darkred: #660000; --wikt-palette-deepred: #bf0218; --wikt-palette-orange: #f2caa4; --wikt-palette-lighterblue: #ebf4ff; --wikt-palette-dulllighterblue: #e2eaf9; --wikt-palette-lightred: #fee7e6; --wikt-palette-indigo: #aaaaee; --wikt-palette-lightindigo: #e9e9ff; --wikt-palette-palerpink: #fff3f5; --wikt-palette-honey: #81540e; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #fef9f9; --wikt-palette-red-1: #fdeef0; --wikt-palette-red-2: #fce4e6; --wikt-palette-red-3: #fad9dc; --wikt-palette-red-4: #f7c2c6; --wikt-palette-red-5: #f5afb5; --wikt-palette-red-6: #f29ba3; --wikt-palette-red-7: #f0858e; --wikt-palette-red-8: #ed6d78; --wikt-palette-red-9: #ce4350; --wikt-palette-scarlet-0: #fef9f7; --wikt-palette-scarlet-1: #fcefeb; --wikt-palette-scarlet-2: #fae5de; --wikt-palette-scarlet-3: #f8dad1; --wikt-palette-scarlet-4: #f4c4b5; --wikt-palette-scarlet-5: #f1b3a0; --wikt-palette-scarlet-6: #eea088; --wikt-palette-scarlet-7: #ea8c70; --wikt-palette-scarlet-8: #e67553; --wikt-palette-scarlet-9: #c25433; --wikt-palette-orange-0: #fdfaf5; --wikt-palette-orange-1: #fbf0e4; --wikt-palette-orange-2: #f8e7d4; --wikt-palette-orange-3: #f5ddc3; --wikt-palette-orange-4: #f0c89e; --wikt-palette-orange-5: #ebb882; --wikt-palette-orange-6: #e6a662; --wikt-palette-orange-7: #e19341; --wikt-palette-orange-8: #db7f1e; --wikt-palette-orange-9: #b16210; --wikt-palette-amber-0: #fdfaf3; --wikt-palette-amber-1: #f9f1df; --wikt-palette-amber-2: #f5e8cc; --wikt-palette-amber-3: #f1dfb8; --wikt-palette-amber-4: #e8cc8f; --wikt-palette-amber-5: #e2bc6d; --wikt-palette-amber-6: #dbac4a; --wikt-palette-amber-7: #d39b24; --wikt-palette-amber-8: #c38c17; --wikt-palette-amber-9: #9b6f10; --wikt-palette-yellow-0: #fbfbf4; --wikt-palette-yellow-1: #f5f2e0; --wikt-palette-yellow-2: #eeeacc; --wikt-palette-yellow-3: #e8e2b9; --wikt-palette-yellow-4: #dbd191; --wikt-palette-yellow-5: #d0c370; --wikt-palette-yellow-6: #c5b44f; --wikt-palette-yellow-7: #b6a63f; --wikt-palette-yellow-8: #a69737; --wikt-palette-yellow-9: #847827; --wikt-palette-lime-0: #f9fbf3; --wikt-palette-lime-1: #eff4e1; --wikt-palette-lime-2: #e5edce; --wikt-palette-lime-3: #dbe5bc; --wikt-palette-lime-4: #c5d693; --wikt-palette-lime-5: #b5ca73; --wikt-palette-lime-6: #a3be52; --wikt-palette-lime-7: #97af4e; --wikt-palette-lime-8: #889f43; --wikt-palette-lime-9: #6b7f2f; --wikt-palette-green-0: #f8fbf5; --wikt-palette-green-1: #eaf5e4; --wikt-palette-green-2: #ddefd3; --wikt-palette-green-3: #cee8c1; --wikt-palette-green-4: #b3da9d; --wikt-palette-green-5: #9cd080; --wikt-palette-green-6: #83c460; --wikt-palette-green-7: #69b840; --wikt-palette-green-8: #64a640; --wikt-palette-green-9: #4b852d; --wikt-palette-teal-0: #f6fcf9; --wikt-palette-teal-1: #e5f6ee; --wikt-palette-teal-2: #d5efe3; --wikt-palette-teal-3: #c3e9d7; --wikt-palette-teal-4: #9fdcc0; --wikt-palette-teal-5: #82d1ac; --wikt-palette-teal-6: #64c599; --wikt-palette-teal-7: #41b982; --wikt-palette-teal-8: #3fa878; --wikt-palette-teal-9: #2c865d; --wikt-palette-cyan-0: #f6fbfc; --wikt-palette-cyan-1: #e7f4f7; --wikt-palette-cyan-2: #d7edf1; --wikt-palette-cyan-3: #c7e6ec; --wikt-palette-cyan-4: #a6d7e0; --wikt-palette-cyan-5: #8accd7; --wikt-palette-cyan-6: #6ebfcd; --wikt-palette-cyan-7: #50b2c3; --wikt-palette-cyan-8: #2ea3b7; --wikt-palette-cyan-9: #288191; --wikt-palette-blue-0: #f8fafe; --wikt-palette-blue-1: #ecf2fe; --wikt-palette-blue-2: #e0eafd; --wikt-palette-blue-3: #d3e1fc; --wikt-palette-blue-4: #bbd0fa; --wikt-palette-blue-5: #a6c2f9; --wikt-palette-blue-6: #92b3f7; --wikt-palette-blue-7: #7ca4f5; --wikt-palette-blue-8: #6494f4; --wikt-palette-blue-9: #3d72db; --wikt-palette-indigo-0: #fafafe; --wikt-palette-indigo-1: #f1f1fd; --wikt-palette-indigo-2: #e9e7fc; --wikt-palette-indigo-3: #e0defa; --wikt-palette-indigo-4: #cecbf8; --wikt-palette-indigo-5: #bfbcf5; --wikt-palette-indigo-6: #b0acf3; --wikt-palette-indigo-7: #a19cf1; --wikt-palette-indigo-8: #918aef; --wikt-palette-indigo-9: #6e66e0; --wikt-palette-purple-0: #fcfafe; --wikt-palette-purple-1: #f5f0fd; --wikt-palette-purple-2: #efe6fc; --wikt-palette-purple-3: #e8dbfb; --wikt-palette-purple-4: #dbc6f8; --wikt-palette-purple-5: #d0b6f7; --wikt-palette-purple-6: #c5a5f5; --wikt-palette-purple-7: #b993f2; --wikt-palette-purple-8: #ad7ff0; --wikt-palette-purple-9: #9053eb; --wikt-palette-magenta-0: #fcf9fe; --wikt-palette-magenta-1: #f7effc; --wikt-palette-magenta-2: #f3e4fa; --wikt-palette-magenta-3: #eedaf9; --wikt-palette-magenta-4: #e3c4f5; --wikt-palette-magenta-5: #dbb2f2; --wikt-palette-magenta-6: #d3a0ef; --wikt-palette-magenta-7: #ca8deb; --wikt-palette-magenta-8: #c078e8; --wikt-palette-magenta-9: #a844df; --wikt-palette-rose-0: #fcf9fc; --wikt-palette-rose-1: #f8f0f6; --wikt-palette-rose-2: #f3e6ef; --wikt-palette-rose-3: #eedbe9; --wikt-palette-rose-4: #e4c7dc; --wikt-palette-rose-5: #dcb6d2; --wikt-palette-rose-6: #d4a5c8; --wikt-palette-rose-7: #cc94bd; --wikt-palette-rose-8: #c381b1; --wikt-palette-rose-9: #af5797; --wikt-palette-brown-0: #fbfaf9; --wikt-palette-brown-1: #f4f1ee; --wikt-palette-brown-2: #eee8e4; --wikt-palette-brown-3: #e7dfd9; --wikt-palette-brown-4: #d8cdc3; --wikt-palette-brown-5: #cdbfb2; --wikt-palette-brown-6: #c2b1a1; --wikt-palette-brown-7: #b7a18f; --wikt-palette-brown-8: #ab927c; --wikt-palette-brown-9: #917155; --wikt-palette-grey-red-0: #fef9f9; --wikt-palette-grey-red-1: #fbeff0; --wikt-palette-grey-red-2: #f9e5e6; --wikt-palette-grey-red-3: #f7dadc; --wikt-palette-grey-red-4: #f2c3c8; --wikt-palette-grey-red-5: #eeb2b7; --wikt-palette-grey-red-6: #dca5ab; --wikt-palette-grey-red-7: #ce979c; --wikt-palette-grey-red-8: #c0878c; --wikt-palette-grey-red-9: #9f686d; --wikt-palette-grey-scarlet-0: #fdfaf8; --wikt-palette-grey-scarlet-1: #faf0ec; --wikt-palette-grey-scarlet-2: #f7e6e0; --wikt-palette-grey-scarlet-3: #f4dcd4; --wikt-palette-grey-scarlet-4: #eec7bb; --wikt-palette-grey-scarlet-5: #e8b6a7; --wikt-palette-grey-scarlet-6: #d6a99c; --wikt-palette-grey-scarlet-7: #c89b8d; --wikt-palette-grey-scarlet-8: #b98c7e; --wikt-palette-grey-scarlet-9: #986d5f; --wikt-palette-grey-orange-0: #fdfaf6; --wikt-palette-grey-orange-1: #f9f0e8; --wikt-palette-grey-orange-2: #f4e7d9; --wikt-palette-grey-orange-3: #f0deca; --wikt-palette-grey-orange-4: #e8caaa; --wikt-palette-grey-orange-5: #e1bb92; --wikt-palette-grey-orange-6: #cfae8a; --wikt-palette-grey-orange-7: #c19f7c; --wikt-palette-grey-orange-8: #b2906d; --wikt-palette-grey-orange-9: #917151; --wikt-palette-grey-amber-0: #fcfaf5; --wikt-palette-grey-amber-1: #f7f1e6; --wikt-palette-grey-amber-2: #f1e9d6; --wikt-palette-grey-amber-3: #ece0c6; --wikt-palette-grey-amber-4: #e0cda3; --wikt-palette-grey-amber-5: #d8bf8a; --wikt-palette-grey-amber-6: #c6b185; --wikt-palette-grey-amber-7: #b7a377; --wikt-palette-grey-amber-8: #a89468; --wikt-palette-grey-amber-9: #88754c; --wikt-palette-grey-yellow-0: #fbfaf6; --wikt-palette-grey-yellow-1: #f3f2e7; --wikt-palette-grey-yellow-2: #ecead9; --wikt-palette-grey-yellow-3: #e5e1ca; --wikt-palette-grey-yellow-4: #d5d0ab; --wikt-palette-grey-yellow-5: #cac394; --wikt-palette-grey-yellow-6: #beb57c; --wikt-palette-grey-yellow-7: #aca67f; --wikt-palette-grey-yellow-8: #9e9770; --wikt-palette-grey-yellow-9: #7e7851; --wikt-palette-grey-lime-0: #fafbf7; --wikt-palette-grey-lime-1: #f0f3e8; --wikt-palette-grey-lime-2: #e7ebda; --wikt-palette-grey-lime-3: #dee3cc; --wikt-palette-grey-lime-4: #cad3ae; --wikt-palette-grey-lime-5: #bbc798; --wikt-palette-grey-lime-6: #abba81; --wikt-palette-grey-lime-7: #a0a984; --wikt-palette-grey-lime-8: #919b74; --wikt-palette-grey-lime-9: #727c55; --wikt-palette-grey-green-0: #f8fbf7; --wikt-palette-grey-green-1: #edf4ea; --wikt-palette-grey-green-2: #e2ecdd; --wikt-palette-grey-green-3: #d6e5ce; --wikt-palette-grey-green-4: #bfd6b3; --wikt-palette-grey-green-5: #acca9d; --wikt-palette-grey-green-6: #9abe87; --wikt-palette-grey-green-7: #93ad86; --wikt-palette-grey-green-8: #839e75; --wikt-palette-grey-green-9: #647f56; --wikt-palette-grey-teal-0: #f7fbf9; --wikt-palette-grey-teal-1: #eaf4ef; --wikt-palette-grey-teal-2: #ddede5; --wikt-palette-grey-teal-3: #d0e6dc; --wikt-palette-grey-teal-4: #b4d7c7; --wikt-palette-grey-teal-5: #9ecbb6; --wikt-palette-grey-teal-6: #88bfa5; --wikt-palette-grey-teal-7: #86ae9b; --wikt-palette-grey-teal-8: #769f8c; --wikt-palette-grey-teal-9: #56806d; --wikt-palette-grey-cyan-0: #f7fbfb; --wikt-palette-grey-cyan-1: #ebf3f5; --wikt-palette-grey-cyan-2: #deecee; --wikt-palette-grey-cyan-3: #d1e4e7; --wikt-palette-grey-cyan-4: #b6d4da; --wikt-palette-grey-cyan-5: #a1c8cf; --wikt-palette-grey-cyan-6: #8cbbc4; --wikt-palette-grey-cyan-7: #86acb2; --wikt-palette-grey-cyan-8: #769da3; --wikt-palette-grey-cyan-9: #577e84; --wikt-palette-grey-blue-0: #f8fafe; --wikt-palette-grey-blue-1: #ecf2fc; --wikt-palette-grey-blue-2: #e1eafb; --wikt-palette-grey-blue-3: #d5e1f9; --wikt-palette-grey-blue-4: #bdd0f6; --wikt-palette-grey-blue-5: #aec2ea; --wikt-palette-grey-blue-6: #9fb4dd; --wikt-palette-grey-blue-7: #91a6cf; --wikt-palette-grey-blue-8: #8297c0; --wikt-palette-grey-blue-9: #6477a0; --wikt-palette-grey-indigo-0: #fafafe; --wikt-palette-grey-indigo-1: #f1f1fb; --wikt-palette-grey-indigo-2: #e9e8f9; --wikt-palette-grey-indigo-3: #e0def7; --wikt-palette-grey-indigo-4: #cdcbf2; --wikt-palette-grey-indigo-5: #c0bcee; --wikt-palette-grey-indigo-6: #b2afdc; --wikt-palette-grey-indigo-7: #a4a1d0; --wikt-palette-grey-indigo-8: #9592c2; --wikt-palette-grey-indigo-9: #7572a3; --wikt-palette-grey-purple-0: #fbfafe; --wikt-palette-grey-purple-1: #f5f0fc; --wikt-palette-grey-purple-2: #eee6fa; --wikt-palette-grey-purple-3: #e7dcf8; --wikt-palette-grey-purple-4: #d9c8f3; --wikt-palette-grey-purple-5: #ceb8f0; --wikt-palette-grey-purple-6: #c0aae1; --wikt-palette-grey-purple-7: #b19bd3; --wikt-palette-grey-purple-8: #a38cc5; --wikt-palette-grey-purple-9: #846da5; --wikt-palette-grey-magenta-0: #fcf9fd; --wikt-palette-grey-magenta-1: #f7effa; --wikt-palette-grey-magenta-2: #f1e5f7; --wikt-palette-grey-magenta-3: #ebdbf4; --wikt-palette-grey-magenta-4: #e0c6ee; --wikt-palette-grey-magenta-5: #d7b5e9; --wikt-palette-grey-magenta-6: #cda4e4; --wikt-palette-grey-magenta-7: #bc98d0; --wikt-palette-grey-magenta-8: #ae89c2; --wikt-palette-grey-magenta-9: #8e69a2; --wikt-palette-grey-rose-0: #fcfafb; --wikt-palette-grey-rose-1: #f6f0f4; --wikt-palette-grey-rose-2: #efe7ed; --wikt-palette-grey-rose-3: #e9dde6; --wikt-palette-grey-rose-4: #ddcad8; --wikt-palette-grey-rose-5: #d3bacc; --wikt-palette-grey-rose-6: #c9abc1; --wikt-palette-grey-rose-7: #be9bb5; --wikt-palette-grey-rose-8: #b38aa8; --wikt-palette-grey-rose-9: #8c6e84; --wikt-palette-grey-brown-0: #fafaf9; --wikt-palette-grey-brown-1: #f3f2f0; --wikt-palette-grey-brown-2: #ebe9e6; --wikt-palette-grey-brown-3: #e4e0dc; --wikt-palette-grey-brown-4: #d4cec8; --wikt-palette-grey-brown-5: #c8c0b9; --wikt-palette-grey-brown-6: #bcb2a9; --wikt-palette-grey-brown-7: #afa398; --wikt-palette-grey-brown-8: #a19488; --wikt-palette-grey-brown-9: #7f766d; --wikt-palette-grey-0: #fafafa; --wikt-palette-grey-1: #f2f2f2; --wikt-palette-grey-2: #e9e9e9; --wikt-palette-grey-3: #e1e1e1; --wikt-palette-grey-4: #cfcfcf; --wikt-palette-grey-5: #c2c2c2; --wikt-palette-grey-6: #b4b4b4; --wikt-palette-grey-7: #a5a5a5; --wikt-palette-grey-8: #979797; --wikt-palette-grey-9: #777777; } /* Styles need to be duplicated exactly between these two selectors. */ @media screen { html.skin-theme-clientpref-night { --wikt-palette-white: #101418; --wikt-palette-black: #eaecf0; --wikt-palette-beige: #2f1f10; --wikt-palette-darkgrey: #b2bbc3; --wikt-palette-grey: #4e4e4e; --wikt-palette-lightgrey: #3d3d3d; --wikt-palette-lightergrey: #242424; --wikt-palette-cream: #2c2c21; --wikt-palette-pink: #612042; --wikt-palette-peach: #58230a; --wikt-palette-gold: #c9b163; --wikt-palette-dullgold: #ab995e; --wikt-palette-yellow: #4a3912; --wikt-palette-dullyellow: #3a3520; --wikt-palette-brightyellow: #5e5300; --wikt-palette-palegreen: #112511; --wikt-palette-palergreen: #051f0c; --wikt-palette-mint: #194819; --wikt-palette-green: #aad7aa; --wikt-palette-forestgreen: #499149; --wikt-palette-luminousgreen: #103310; --wikt-palette-paleblue: #1c2229; --wikt-palette-cyan: #0a3239; --wikt-palette-palecyan: #171c21; --wikt-palette-lightblue: #092f58; --wikt-palette-dulllightblue: #305070; --wikt-palette-blue: #aaaaff; --wikt-palette-dullblue: #b8c0c5; --wikt-palette-dullcyan: #27292d; --wikt-palette-deepblue: #a5c3e1; --wikt-palette-lavender: #1a1a2a; --wikt-palette-lightyellow: #24241a; --wikt-palette-red: #d73333; --wikt-palette-darkred: #ffcccc; --wikt-palette-deepred: #e36a79; --wikt-palette-orange: #593e02; --wikt-palette-lighterblue: #0e1e33; --wikt-palette-dulllighterblue: #102437; --wikt-palette-lightred: #421211; --wikt-palette-indigo: #30306f; --wikt-palette-lightindigo: #242448; --wikt-palette-palerpink: #251111; --wikt-palette-honey: #feefb3; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #28070a; --wikt-palette-red-1: #3e0c11; --wikt-palette-red-2: #5a131a; --wikt-palette-red-3: #731b24; --wikt-palette-red-4: #89242d; --wikt-palette-red-5: #a12d38; --wikt-palette-red-6: #bf3b48; --wikt-palette-red-7: #e95462; --wikt-palette-red-8: #ee7984; --wikt-palette-red-9: #f3a2aa; --wikt-palette-scarlet-0: #250c05; --wikt-palette-scarlet-1: #3a1409; --wikt-palette-scarlet-2: #521d0e; --wikt-palette-scarlet-3: #692814; --wikt-palette-scarlet-4: #7f311a; --wikt-palette-scarlet-5: #953c22; --wikt-palette-scarlet-6: #b24b2c; --wikt-palette-scarlet-7: #e25e37; --wikt-palette-scarlet-8: #e88062; --wikt-palette-scarlet-9: #efa791; --wikt-palette-orange-0: #211101; --wikt-palette-orange-1: #331b03; --wikt-palette-orange-2: #462604; --wikt-palette-orange-3: #5c3206; --wikt-palette-orange-4: #703d08; --wikt-palette-orange-5: #85490a; --wikt-palette-orange-6: #a0580e; --wikt-palette-orange-7: #cb7114; --wikt-palette-orange-8: #de8931; --wikt-palette-orange-9: #e8ac6e; --wikt-palette-amber-0: #1c1401; --wikt-palette-amber-1: #2c1f03; --wikt-palette-amber-2: #3d2a04; --wikt-palette-amber-3: #503806; --wikt-palette-amber-4: #614508; --wikt-palette-amber-5: #74520a; --wikt-palette-amber-6: #8c640d; --wikt-palette-amber-7: #b17f13; --wikt-palette-amber-8: #cc9218; --wikt-palette-amber-9: #ddb258; --wikt-palette-yellow-0: #181504; --wikt-palette-yellow-1: #262107; --wikt-palette-yellow-2: #342e0a; --wikt-palette-yellow-3: #443c0f; --wikt-palette-yellow-4: #534a13; --wikt-palette-yellow-5: #625819; --wikt-palette-yellow-6: #776b21; --wikt-palette-yellow-7: #97882f; --wikt-palette-yellow-8: #ae9e3b; --wikt-palette-yellow-9: #c8b95b; --wikt-palette-lime-0: #131705; --wikt-palette-lime-1: #1e2409; --wikt-palette-lime-2: #28310d; --wikt-palette-lime-3: #354112; --wikt-palette-lime-4: #424f18; --wikt-palette-lime-5: #4f5e1f; --wikt-palette-lime-6: #607228; --wikt-palette-lime-7: #7b903a; --wikt-palette-lime-8: #8fa648; --wikt-palette-lime-9: #aac25f; --wikt-palette-green-0: #0c1805; --wikt-palette-green-1: #122608; --wikt-palette-green-2: #1a340c; --wikt-palette-green-3: #234411; --wikt-palette-green-4: #2c5317; --wikt-palette-green-5: #35631d; --wikt-palette-green-6: #427726; --wikt-palette-green-7: #599737; --wikt-palette-green-8: #6aae45; --wikt-palette-green-9: #8dc86d; --wikt-palette-teal-0: #04180f; --wikt-palette-teal-1: #082618; --wikt-palette-teal-2: #0c3422; --wikt-palette-teal-3: #11452d; --wikt-palette-teal-4: #165438; --wikt-palette-teal-5: #1c6443; --wikt-palette-teal-6: #267953; --wikt-palette-teal-7: #36986b; --wikt-palette-teal-8: #43af7e; --wikt-palette-teal-9: #6fc9a0; --wikt-palette-cyan-0: #04171b; --wikt-palette-cyan-1: #07242a; --wikt-palette-cyan-2: #0a3239; --wikt-palette-cyan-3: #0f424b; --wikt-palette-cyan-4: #14515c; --wikt-palette-cyan-5: #1a606d; --wikt-palette-cyan-6: #227583; --wikt-palette-cyan-7: #3194a6; --wikt-palette-cyan-8: #40aabd; --wikt-palette-cyan-9: #78c4d1; --wikt-palette-blue-0: #07132d; --wikt-palette-blue-1: #0b1f45; --wikt-palette-blue-2: #122b60; --wikt-palette-blue-3: #19397b; --wikt-palette-blue-4: #214692; --wikt-palette-blue-5: #2954ab; --wikt-palette-blue-6: #3667c9; --wikt-palette-blue-7: #4e84f2; --wikt-palette-blue-8: #709cf5; --wikt-palette-blue-9: #99b8f8; --wikt-palette-indigo-0: #100e36; --wikt-palette-indigo-1: #1b1751; --wikt-palette-indigo-2: #27226c; --wikt-palette-indigo-3: #352f88; --wikt-palette-indigo-4: #423b9e; --wikt-palette-indigo-5: #5049b4; --wikt-palette-indigo-6: #5f55e7; --wikt-palette-indigo-7: #8179ec; --wikt-palette-indigo-8: #9992f0; --wikt-palette-indigo-9: #b6b1f4; --wikt-palette-purple-0: #1a0934; --wikt-palette-purple-1: #29104e; --wikt-palette-purple-2: #3a196d; --wikt-palette-purple-3: #4c238a; --wikt-palette-purple-4: #5c2da3; --wikt-palette-purple-5: #6e38bc; --wikt-palette-purple-6: #8541e9; --wikt-palette-purple-7: #a16cee; --wikt-palette-purple-8: #b389f1; --wikt-palette-purple-9: #c9abf5; --wikt-palette-magenta-0: #20062d; --wikt-palette-magenta-1: #310b46; --wikt-palette-magenta-2: #471363; --wikt-palette-magenta-3: #5c1b7f; --wikt-palette-magenta-4: #6e2398; --wikt-palette-magenta-5: #822cb1; --wikt-palette-magenta-6: #9f30dc; --wikt-palette-magenta-7: #b663e4; --wikt-palette-magenta-8: #c581ea; --wikt-palette-magenta-9: #d6a6f0; --wikt-palette-rose-0: #240b1d; --wikt-palette-rose-1: #37122d; --wikt-palette-rose-2: #4b1c3f; --wikt-palette-rose-3: #5f2751; --wikt-palette-rose-4: #723362; --wikt-palette-rose-5: #844072; --wikt-palette-rose-6: #a7478e; --wikt-palette-rose-7: #ba6fa6; --wikt-palette-rose-8: #c78ab7; --wikt-palette-rose-9: #d7abcc; --wikt-palette-brown-0: #1d130b; --wikt-palette-brown-1: #2d1e12; --wikt-palette-brown-2: #3c2a1b; --wikt-palette-brown-3: #4d3826; --wikt-palette-brown-4: #5d4532; --wikt-palette-brown-5: #6c533e; --wikt-palette-brown-6: #876446; --wikt-palette-brown-7: #9f826a; --wikt-palette-brown-8: #b19986; --wikt-palette-brown-9: #c6b5a7; --wikt-palette-grey-red-0: #230f11; --wikt-palette-grey-red-1: #34191b; --wikt-palette-grey-red-2: #462327; --wikt-palette-grey-red-3: #5a3034; --wikt-palette-grey-red-4: #6b3c41; --wikt-palette-grey-red-5: #7c4a4f; --wikt-palette-grey-red-6: #925c61; --wikt-palette-grey-red-7: #b1797e; --wikt-palette-grey-red-8: #c78e94; --wikt-palette-grey-red-9: #eba6ad; --wikt-palette-grey-scarlet-0: #20110d; --wikt-palette-grey-scarlet-1: #311c16; --wikt-palette-grey-scarlet-2: #422720; --wikt-palette-grey-scarlet-3: #54342b; --wikt-palette-grey-scarlet-4: #654137; --wikt-palette-grey-scarlet-5: #764e43; --wikt-palette-grey-scarlet-6: #8b6154; --wikt-palette-grey-scarlet-7: #aa7d70; --wikt-palette-grey-scarlet-8: #c19386; --wikt-palette-grey-scarlet-9: #e5ab9a; --wikt-palette-grey-orange-0: #1c140a; --wikt-palette-grey-orange-1: #2c1f11; --wikt-palette-grey-orange-2: #3b2a19; --wikt-palette-grey-orange-3: #4d3823; --wikt-palette-grey-orange-4: #5d452c; --wikt-palette-grey-orange-5: #6e5337; --wikt-palette-grey-orange-6: #836547; --wikt-palette-grey-orange-7: #a28260; --wikt-palette-grey-orange-8: #b99774; --wikt-palette-grey-orange-9: #ddb082; --wikt-palette-grey-amber-0: #1a150a; --wikt-palette-grey-amber-1: #282010; --wikt-palette-grey-amber-2: #372c17; --wikt-palette-grey-amber-3: #473b20; --wikt-palette-grey-amber-4: #57482a; --wikt-palette-grey-amber-5: #675634; --wikt-palette-grey-amber-6: #7b6943; --wikt-palette-grey-amber-7: #99855b; --wikt-palette-grey-amber-8: #b09b70; --wikt-palette-grey-amber-9: #d2b579; --wikt-palette-grey-yellow-0: #17160a; --wikt-palette-grey-yellow-1: #242211; --wikt-palette-grey-yellow-2: #322e19; --wikt-palette-grey-yellow-3: #413d22; --wikt-palette-grey-yellow-4: #4f4a2c; --wikt-palette-grey-yellow-5: #5e5837; --wikt-palette-grey-yellow-6: #716b47; --wikt-palette-grey-yellow-7: #8f8861; --wikt-palette-grey-yellow-8: #a59e78; --wikt-palette-grey-yellow-9: #c2b984; --wikt-palette-grey-lime-0: #13160b; --wikt-palette-grey-lime-1: #1f2312; --wikt-palette-grey-lime-2: #2b3019; --wikt-palette-grey-lime-3: #383f23; --wikt-palette-grey-lime-4: #454d2d; --wikt-palette-grey-lime-5: #535c39; --wikt-palette-grey-lime-6: #666f49; --wikt-palette-grey-lime-7: #838c65; --wikt-palette-grey-lime-8: #98a27c; --wikt-palette-grey-lime-9: #b1be8a; --wikt-palette-grey-green-0: #0f170b; --wikt-palette-grey-green-1: #182512; --wikt-palette-grey-green-2: #22321a; --wikt-palette-grey-green-3: #2e4124; --wikt-palette-grey-green-4: #3a502e; --wikt-palette-grey-green-5: #465f3a; --wikt-palette-grey-green-6: #58724a; --wikt-palette-grey-green-7: #748f66; --wikt-palette-grey-green-8: #8ba57e; --wikt-palette-grey-green-9: #a1c290; --wikt-palette-grey-teal-0: #0b1812; --wikt-palette-grey-teal-1: #12251d; --wikt-palette-grey-teal-2: #1a3227; --wikt-palette-grey-teal-3: #244235; --wikt-palette-grey-teal-4: #2e5041; --wikt-palette-grey-teal-5: #3a5f4e; --wikt-palette-grey-teal-6: #4b7361; --wikt-palette-grey-teal-7: #66907d; --wikt-palette-grey-teal-8: #7ea694; --wikt-palette-grey-teal-9: #91c3ac; --wikt-palette-grey-cyan-0: #0b171a; --wikt-palette-grey-cyan-1: #122428; --wikt-palette-grey-cyan-2: #1a3136; --wikt-palette-grey-cyan-3: #244145; --wikt-palette-grey-cyan-4: #2f4f54; --wikt-palette-grey-cyan-5: #3a5d64; --wikt-palette-grey-cyan-6: #4b7178; --wikt-palette-grey-cyan-7: #678e95; --wikt-palette-grey-cyan-8: #7ea4ab; --wikt-palette-grey-cyan-9: #94c0c8; --wikt-palette-grey-blue-0: #0f1523; --wikt-palette-grey-blue-1: #182134; --wikt-palette-grey-blue-2: #212d46; --wikt-palette-grey-blue-3: #2e3c5a; --wikt-palette-grey-blue-4: #394a6a; --wikt-palette-grey-blue-5: #47587c; --wikt-palette-grey-blue-6: #586b92; --wikt-palette-grey-blue-7: #7488b2; --wikt-palette-grey-blue-8: #899ec8; --wikt-palette-grey-blue-9: #9cb8f2; --wikt-palette-grey-indigo-0: #141327; --wikt-palette-grey-indigo-1: #201e3a; --wikt-palette-grey-indigo-2: #2c2a4c; --wikt-palette-grey-indigo-3: #3a385f; --wikt-palette-grey-indigo-4: #484571; --wikt-palette-grey-indigo-5: #565382; --wikt-palette-grey-indigo-6: #696696; --wikt-palette-grey-indigo-7: #8682b4; --wikt-palette-grey-indigo-8: #9c98c8; --wikt-palette-grey-indigo-9: #b6b2ec; --wikt-palette-grey-purple-0: #1a1126; --wikt-palette-grey-purple-1: #271b39; --wikt-palette-grey-purple-2: #35264b; --wikt-palette-grey-purple-3: #453460; --wikt-palette-grey-purple-4: #544071; --wikt-palette-grey-purple-5: #634e83; --wikt-palette-grey-purple-6: #776098; --wikt-palette-grey-purple-7: #957db7; --wikt-palette-grey-purple-8: #aa93cc; --wikt-palette-grey-purple-9: #c7acee; --wikt-palette-grey-magenta-0: #1d0f24; --wikt-palette-grey-magenta-1: #2c1937; --wikt-palette-grey-magenta-2: #3c244a; --wikt-palette-grey-magenta-3: #4d315d; --wikt-palette-grey-magenta-4: #5d3d6e; --wikt-palette-grey-magenta-5: #6c4b7f; --wikt-palette-grey-magenta-6: #815d95; --wikt-palette-grey-magenta-7: #9f7ab4; --wikt-palette-grey-magenta-8: #be88dc; --wikt-palette-grey-magenta-9: #d1aae6; --wikt-palette-grey-rose-0: #1f101b; --wikt-palette-grey-rose-1: #2f1a29; --wikt-palette-grey-rose-2: #3e2538; --wikt-palette-grey-rose-3: #503348; --wikt-palette-grey-rose-4: #5f4057; --wikt-palette-grey-rose-5: #6e4e66; --wikt-palette-grey-rose-6: #816179; --wikt-palette-grey-rose-7: #a9799c; --wikt-palette-grey-rose-8: #b992ae; --wikt-palette-grey-rose-9: #ccb0c5; --wikt-palette-grey-brown-0: #1a140f; --wikt-palette-grey-brown-1: #282019; --wikt-palette-grey-brown-2: #362c23; --wikt-palette-grey-brown-3: #463a31; --wikt-palette-grey-brown-4: #53473d; --wikt-palette-grey-brown-5: #62564c; --wikt-palette-grey-brown-6: #746960; --wikt-palette-grey-brown-7: #958578; --wikt-palette-grey-brown-8: #a89b90; --wikt-palette-grey-brown-9: #c0b7af; --wikt-palette-grey-0: #151515; --wikt-palette-grey-1: #212121; --wikt-palette-grey-2: #2d2d2d; --wikt-palette-grey-3: #3c3c3c; --wikt-palette-grey-4: #494949; --wikt-palette-grey-5: #585858; --wikt-palette-grey-6: #6b6b6b; --wikt-palette-grey-7: #878787; --wikt-palette-grey-8: #9d9d9d; --wikt-palette-grey-9: #b8b8b8; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os { --wikt-palette-white: #101418; --wikt-palette-black: #eaecf0; --wikt-palette-beige: #2f1f10; --wikt-palette-darkgrey: #b2bbc3; --wikt-palette-grey: #4e4e4e; --wikt-palette-lightgrey: #3d3d3d; --wikt-palette-lightergrey: #242424; --wikt-palette-cream: #2c2c21; --wikt-palette-pink: #612042; --wikt-palette-peach: #58230a; --wikt-palette-gold: #c9b163; --wikt-palette-dullgold: #ab995e; --wikt-palette-yellow: #4a3912; --wikt-palette-dullyellow: #3a3520; --wikt-palette-brightyellow: #5e5300; --wikt-palette-palegreen: #112511; --wikt-palette-palergreen: #051f0c; --wikt-palette-mint: #194819; --wikt-palette-green: #aad7aa; --wikt-palette-forestgreen: #499149; --wikt-palette-luminousgreen: #103310; --wikt-palette-paleblue: #1c2229; --wikt-palette-cyan: #0a3239; --wikt-palette-palecyan: #171c21; --wikt-palette-lightblue: #092f58; --wikt-palette-dulllightblue: #305070; --wikt-palette-blue: #aaaaff; --wikt-palette-dullblue: #b8c0c5; --wikt-palette-dullcyan: #27292d; --wikt-palette-deepblue: #a5c3e1; --wikt-palette-lavender: #1a1a2a; --wikt-palette-lightyellow: #24241a; --wikt-palette-red: #d73333; --wikt-palette-darkred: #ffcccc; --wikt-palette-deepred: #e36a79; --wikt-palette-orange: #593e02; --wikt-palette-lighterblue: #0e1e33; --wikt-palette-dulllighterblue: #102437; --wikt-palette-lightred: #421211; --wikt-palette-indigo: #30306f; --wikt-palette-lightindigo: #242448; --wikt-palette-palerpink: #251111; --wikt-palette-honey: #feefb3; /* Autogenerated with [[Wiktionary:Palette/numbered]] */ --wikt-palette-red-0: #28070a; --wikt-palette-red-1: #3e0c11; --wikt-palette-red-2: #5a131a; --wikt-palette-red-3: #731b24; --wikt-palette-red-4: #89242d; --wikt-palette-red-5: #a12d38; --wikt-palette-red-6: #bf3b48; --wikt-palette-red-7: #e95462; --wikt-palette-red-8: #ee7984; --wikt-palette-red-9: #f3a2aa; --wikt-palette-scarlet-0: #250c05; --wikt-palette-scarlet-1: #3a1409; --wikt-palette-scarlet-2: #521d0e; --wikt-palette-scarlet-3: #692814; --wikt-palette-scarlet-4: #7f311a; --wikt-palette-scarlet-5: #953c22; --wikt-palette-scarlet-6: #b24b2c; --wikt-palette-scarlet-7: #e25e37; --wikt-palette-scarlet-8: #e88062; --wikt-palette-scarlet-9: #efa791; --wikt-palette-orange-0: #211101; --wikt-palette-orange-1: #331b03; --wikt-palette-orange-2: #462604; --wikt-palette-orange-3: #5c3206; --wikt-palette-orange-4: #703d08; --wikt-palette-orange-5: #85490a; --wikt-palette-orange-6: #a0580e; --wikt-palette-orange-7: #cb7114; --wikt-palette-orange-8: #de8931; --wikt-palette-orange-9: #e8ac6e; --wikt-palette-amber-0: #1c1401; --wikt-palette-amber-1: #2c1f03; --wikt-palette-amber-2: #3d2a04; --wikt-palette-amber-3: #503806; --wikt-palette-amber-4: #614508; --wikt-palette-amber-5: #74520a; --wikt-palette-amber-6: #8c640d; --wikt-palette-amber-7: #b17f13; --wikt-palette-amber-8: #cc9218; --wikt-palette-amber-9: #ddb258; --wikt-palette-yellow-0: #181504; --wikt-palette-yellow-1: #262107; --wikt-palette-yellow-2: #342e0a; --wikt-palette-yellow-3: #443c0f; --wikt-palette-yellow-4: #534a13; --wikt-palette-yellow-5: #625819; --wikt-palette-yellow-6: #776b21; --wikt-palette-yellow-7: #97882f; --wikt-palette-yellow-8: #ae9e3b; --wikt-palette-yellow-9: #c8b95b; --wikt-palette-lime-0: #131705; --wikt-palette-lime-1: #1e2409; --wikt-palette-lime-2: #28310d; --wikt-palette-lime-3: #354112; --wikt-palette-lime-4: #424f18; --wikt-palette-lime-5: #4f5e1f; --wikt-palette-lime-6: #607228; --wikt-palette-lime-7: #7b903a; --wikt-palette-lime-8: #8fa648; --wikt-palette-lime-9: #aac25f; --wikt-palette-green-0: #0c1805; --wikt-palette-green-1: #122608; --wikt-palette-green-2: #1a340c; --wikt-palette-green-3: #234411; --wikt-palette-green-4: #2c5317; --wikt-palette-green-5: #35631d; --wikt-palette-green-6: #427726; --wikt-palette-green-7: #599737; --wikt-palette-green-8: #6aae45; --wikt-palette-green-9: #8dc86d; --wikt-palette-teal-0: #04180f; --wikt-palette-teal-1: #082618; --wikt-palette-teal-2: #0c3422; --wikt-palette-teal-3: #11452d; --wikt-palette-teal-4: #165438; --wikt-palette-teal-5: #1c6443; --wikt-palette-teal-6: #267953; --wikt-palette-teal-7: #36986b; --wikt-palette-teal-8: #43af7e; --wikt-palette-teal-9: #6fc9a0; --wikt-palette-cyan-0: #04171b; --wikt-palette-cyan-1: #07242a; --wikt-palette-cyan-2: #0a3239; --wikt-palette-cyan-3: #0f424b; --wikt-palette-cyan-4: #14515c; --wikt-palette-cyan-5: #1a606d; --wikt-palette-cyan-6: #227583; --wikt-palette-cyan-7: #3194a6; --wikt-palette-cyan-8: #40aabd; --wikt-palette-cyan-9: #78c4d1; --wikt-palette-blue-0: #07132d; --wikt-palette-blue-1: #0b1f45; --wikt-palette-blue-2: #122b60; --wikt-palette-blue-3: #19397b; --wikt-palette-blue-4: #214692; --wikt-palette-blue-5: #2954ab; --wikt-palette-blue-6: #3667c9; --wikt-palette-blue-7: #4e84f2; --wikt-palette-blue-8: #709cf5; --wikt-palette-blue-9: #99b8f8; --wikt-palette-indigo-0: #100e36; --wikt-palette-indigo-1: #1b1751; --wikt-palette-indigo-2: #27226c; --wikt-palette-indigo-3: #352f88; --wikt-palette-indigo-4: #423b9e; --wikt-palette-indigo-5: #5049b4; --wikt-palette-indigo-6: #5f55e7; --wikt-palette-indigo-7: #8179ec; --wikt-palette-indigo-8: #9992f0; --wikt-palette-indigo-9: #b6b1f4; --wikt-palette-purple-0: #1a0934; --wikt-palette-purple-1: #29104e; --wikt-palette-purple-2: #3a196d; --wikt-palette-purple-3: #4c238a; --wikt-palette-purple-4: #5c2da3; --wikt-palette-purple-5: #6e38bc; --wikt-palette-purple-6: #8541e9; --wikt-palette-purple-7: #a16cee; --wikt-palette-purple-8: #b389f1; --wikt-palette-purple-9: #c9abf5; --wikt-palette-magenta-0: #20062d; --wikt-palette-magenta-1: #310b46; --wikt-palette-magenta-2: #471363; --wikt-palette-magenta-3: #5c1b7f; --wikt-palette-magenta-4: #6e2398; --wikt-palette-magenta-5: #822cb1; --wikt-palette-magenta-6: #9f30dc; --wikt-palette-magenta-7: #b663e4; --wikt-palette-magenta-8: #c581ea; --wikt-palette-magenta-9: #d6a6f0; --wikt-palette-rose-0: #240b1d; --wikt-palette-rose-1: #37122d; --wikt-palette-rose-2: #4b1c3f; --wikt-palette-rose-3: #5f2751; --wikt-palette-rose-4: #723362; --wikt-palette-rose-5: #844072; --wikt-palette-rose-6: #a7478e; --wikt-palette-rose-7: #ba6fa6; --wikt-palette-rose-8: #c78ab7; --wikt-palette-rose-9: #d7abcc; --wikt-palette-brown-0: #1d130b; --wikt-palette-brown-1: #2d1e12; --wikt-palette-brown-2: #3c2a1b; --wikt-palette-brown-3: #4d3826; --wikt-palette-brown-4: #5d4532; --wikt-palette-brown-5: #6c533e; --wikt-palette-brown-6: #876446; --wikt-palette-brown-7: #9f826a; --wikt-palette-brown-8: #b19986; --wikt-palette-brown-9: #c6b5a7; --wikt-palette-grey-red-0: #230f11; --wikt-palette-grey-red-1: #34191b; --wikt-palette-grey-red-2: #462327; --wikt-palette-grey-red-3: #5a3034; --wikt-palette-grey-red-4: #6b3c41; --wikt-palette-grey-red-5: #7c4a4f; --wikt-palette-grey-red-6: #925c61; --wikt-palette-grey-red-7: #b1797e; --wikt-palette-grey-red-8: #c78e94; --wikt-palette-grey-red-9: #eba6ad; --wikt-palette-grey-scarlet-0: #20110d; --wikt-palette-grey-scarlet-1: #311c16; --wikt-palette-grey-scarlet-2: #422720; --wikt-palette-grey-scarlet-3: #54342b; --wikt-palette-grey-scarlet-4: #654137; --wikt-palette-grey-scarlet-5: #764e43; --wikt-palette-grey-scarlet-6: #8b6154; --wikt-palette-grey-scarlet-7: #aa7d70; --wikt-palette-grey-scarlet-8: #c19386; --wikt-palette-grey-scarlet-9: #e5ab9a; --wikt-palette-grey-orange-0: #1c140a; --wikt-palette-grey-orange-1: #2c1f11; --wikt-palette-grey-orange-2: #3b2a19; --wikt-palette-grey-orange-3: #4d3823; --wikt-palette-grey-orange-4: #5d452c; --wikt-palette-grey-orange-5: #6e5337; --wikt-palette-grey-orange-6: #836547; --wikt-palette-grey-orange-7: #a28260; --wikt-palette-grey-orange-8: #b99774; --wikt-palette-grey-orange-9: #ddb082; --wikt-palette-grey-amber-0: #1a150a; --wikt-palette-grey-amber-1: #282010; --wikt-palette-grey-amber-2: #372c17; --wikt-palette-grey-amber-3: #473b20; --wikt-palette-grey-amber-4: #57482a; --wikt-palette-grey-amber-5: #675634; --wikt-palette-grey-amber-6: #7b6943; --wikt-palette-grey-amber-7: #99855b; --wikt-palette-grey-amber-8: #b09b70; --wikt-palette-grey-amber-9: #d2b579; --wikt-palette-grey-yellow-0: #17160a; --wikt-palette-grey-yellow-1: #242211; --wikt-palette-grey-yellow-2: #322e19; --wikt-palette-grey-yellow-3: #413d22; --wikt-palette-grey-yellow-4: #4f4a2c; --wikt-palette-grey-yellow-5: #5e5837; --wikt-palette-grey-yellow-6: #716b47; --wikt-palette-grey-yellow-7: #8f8861; --wikt-palette-grey-yellow-8: #a59e78; --wikt-palette-grey-yellow-9: #c2b984; --wikt-palette-grey-lime-0: #13160b; --wikt-palette-grey-lime-1: #1f2312; --wikt-palette-grey-lime-2: #2b3019; --wikt-palette-grey-lime-3: #383f23; --wikt-palette-grey-lime-4: #454d2d; --wikt-palette-grey-lime-5: #535c39; --wikt-palette-grey-lime-6: #666f49; --wikt-palette-grey-lime-7: #838c65; --wikt-palette-grey-lime-8: #98a27c; --wikt-palette-grey-lime-9: #b1be8a; --wikt-palette-grey-green-0: #0f170b; --wikt-palette-grey-green-1: #182512; --wikt-palette-grey-green-2: #22321a; --wikt-palette-grey-green-3: #2e4124; --wikt-palette-grey-green-4: #3a502e; --wikt-palette-grey-green-5: #465f3a; --wikt-palette-grey-green-6: #58724a; --wikt-palette-grey-green-7: #748f66; --wikt-palette-grey-green-8: #8ba57e; --wikt-palette-grey-green-9: #a1c290; --wikt-palette-grey-teal-0: #0b1812; --wikt-palette-grey-teal-1: #12251d; --wikt-palette-grey-teal-2: #1a3227; --wikt-palette-grey-teal-3: #244235; --wikt-palette-grey-teal-4: #2e5041; --wikt-palette-grey-teal-5: #3a5f4e; --wikt-palette-grey-teal-6: #4b7361; --wikt-palette-grey-teal-7: #66907d; --wikt-palette-grey-teal-8: #7ea694; --wikt-palette-grey-teal-9: #91c3ac; --wikt-palette-grey-cyan-0: #0b171a; --wikt-palette-grey-cyan-1: #122428; --wikt-palette-grey-cyan-2: #1a3136; --wikt-palette-grey-cyan-3: #244145; --wikt-palette-grey-cyan-4: #2f4f54; --wikt-palette-grey-cyan-5: #3a5d64; --wikt-palette-grey-cyan-6: #4b7178; --wikt-palette-grey-cyan-7: #678e95; --wikt-palette-grey-cyan-8: #7ea4ab; --wikt-palette-grey-cyan-9: #94c0c8; --wikt-palette-grey-blue-0: #0f1523; --wikt-palette-grey-blue-1: #182134; --wikt-palette-grey-blue-2: #212d46; --wikt-palette-grey-blue-3: #2e3c5a; --wikt-palette-grey-blue-4: #394a6a; --wikt-palette-grey-blue-5: #47587c; --wikt-palette-grey-blue-6: #586b92; --wikt-palette-grey-blue-7: #7488b2; --wikt-palette-grey-blue-8: #899ec8; --wikt-palette-grey-blue-9: #9cb8f2; --wikt-palette-grey-indigo-0: #141327; --wikt-palette-grey-indigo-1: #201e3a; --wikt-palette-grey-indigo-2: #2c2a4c; --wikt-palette-grey-indigo-3: #3a385f; --wikt-palette-grey-indigo-4: #484571; --wikt-palette-grey-indigo-5: #565382; --wikt-palette-grey-indigo-6: #696696; --wikt-palette-grey-indigo-7: #8682b4; --wikt-palette-grey-indigo-8: #9c98c8; --wikt-palette-grey-indigo-9: #b6b2ec; --wikt-palette-grey-purple-0: #1a1126; --wikt-palette-grey-purple-1: #271b39; --wikt-palette-grey-purple-2: #35264b; --wikt-palette-grey-purple-3: #453460; --wikt-palette-grey-purple-4: #544071; --wikt-palette-grey-purple-5: #634e83; --wikt-palette-grey-purple-6: #776098; --wikt-palette-grey-purple-7: #957db7; --wikt-palette-grey-purple-8: #aa93cc; --wikt-palette-grey-purple-9: #c7acee; --wikt-palette-grey-magenta-0: #1d0f24; --wikt-palette-grey-magenta-1: #2c1937; --wikt-palette-grey-magenta-2: #3c244a; --wikt-palette-grey-magenta-3: #4d315d; --wikt-palette-grey-magenta-4: #5d3d6e; --wikt-palette-grey-magenta-5: #6c4b7f; --wikt-palette-grey-magenta-6: #815d95; --wikt-palette-grey-magenta-7: #9f7ab4; --wikt-palette-grey-magenta-8: #be88dc; --wikt-palette-grey-magenta-9: #d1aae6; --wikt-palette-grey-rose-0: #1f101b; --wikt-palette-grey-rose-1: #2f1a29; --wikt-palette-grey-rose-2: #3e2538; --wikt-palette-grey-rose-3: #503348; --wikt-palette-grey-rose-4: #5f4057; --wikt-palette-grey-rose-5: #6e4e66; --wikt-palette-grey-rose-6: #816179; --wikt-palette-grey-rose-7: #a9799c; --wikt-palette-grey-rose-8: #b992ae; --wikt-palette-grey-rose-9: #ccb0c5; --wikt-palette-grey-brown-0: #1a140f; --wikt-palette-grey-brown-1: #282019; --wikt-palette-grey-brown-2: #362c23; --wikt-palette-grey-brown-3: #463a31; --wikt-palette-grey-brown-4: #53473d; --wikt-palette-grey-brown-5: #62564c; --wikt-palette-grey-brown-6: #746960; --wikt-palette-grey-brown-7: #958578; --wikt-palette-grey-brown-8: #a89b90; --wikt-palette-grey-brown-9: #c0b7af; --wikt-palette-grey-0: #151515; --wikt-palette-grey-1: #212121; --wikt-palette-grey-2: #2d2d2d; --wikt-palette-grey-3: #3c3c3c; --wikt-palette-grey-4: #494949; --wikt-palette-grey-5: #585858; --wikt-palette-grey-6: #6b6b6b; --wikt-palette-grey-7: #878787; --wikt-palette-grey-8: #9d9d9d; --wikt-palette-grey-9: #b8b8b8; } } /* Shorthand available with data-wikt-palette-p and scoping */ [data-wikt-palette-p="red"] { --wikt-p-0: var(--wikt-palette-red-0); --wikt-p-1: var(--wikt-palette-red-1); --wikt-p-2: var(--wikt-palette-red-2); --wikt-p-3: var(--wikt-palette-red-3); --wikt-p-4: var(--wikt-palette-red-4); --wikt-p-5: var(--wikt-palette-red-5); --wikt-p-6: var(--wikt-palette-red-6); --wikt-p-7: var(--wikt-palette-red-7); --wikt-p-8: var(--wikt-palette-red-8); --wikt-p-9: var(--wikt-palette-red-9); --wikt-p-g-0: var(--wikt-palette-grey-red-0); --wikt-p-g-1: var(--wikt-palette-grey-red-1); --wikt-p-g-2: var(--wikt-palette-grey-red-2); --wikt-p-g-3: var(--wikt-palette-grey-red-3); --wikt-p-g-4: var(--wikt-palette-grey-red-4); --wikt-p-g-5: var(--wikt-palette-grey-red-5); --wikt-p-g-6: var(--wikt-palette-grey-red-6); --wikt-p-g-7: var(--wikt-palette-grey-red-7); --wikt-p-g-8: var(--wikt-palette-grey-red-8); --wikt-p-g-9: var(--wikt-palette-grey-red-9); } [data-wikt-palette-p="scarlet"] { --wikt-p-0: var(--wikt-palette-scarlet-0); --wikt-p-1: var(--wikt-palette-scarlet-1); --wikt-p-2: var(--wikt-palette-scarlet-2); --wikt-p-3: var(--wikt-palette-scarlet-3); --wikt-p-4: var(--wikt-palette-scarlet-4); --wikt-p-5: var(--wikt-palette-scarlet-5); --wikt-p-6: var(--wikt-palette-scarlet-6); --wikt-p-7: var(--wikt-palette-scarlet-7); --wikt-p-8: var(--wikt-palette-scarlet-8); --wikt-p-9: var(--wikt-palette-scarlet-9); --wikt-p-g-0: var(--wikt-palette-grey-scarlet-0); --wikt-p-g-1: var(--wikt-palette-grey-scarlet-1); --wikt-p-g-2: var(--wikt-palette-grey-scarlet-2); --wikt-p-g-3: var(--wikt-palette-grey-scarlet-3); --wikt-p-g-4: var(--wikt-palette-grey-scarlet-4); --wikt-p-g-5: var(--wikt-palette-grey-scarlet-5); --wikt-p-g-6: var(--wikt-palette-grey-scarlet-6); --wikt-p-g-7: var(--wikt-palette-grey-scarlet-7); --wikt-p-g-8: var(--wikt-palette-grey-scarlet-8); --wikt-p-g-9: var(--wikt-palette-grey-scarlet-9); } [data-wikt-palette-p="orange"] { --wikt-p-0: var(--wikt-palette-orange-0); --wikt-p-1: var(--wikt-palette-orange-1); --wikt-p-2: var(--wikt-palette-orange-2); --wikt-p-3: var(--wikt-palette-orange-3); --wikt-p-4: var(--wikt-palette-orange-4); --wikt-p-5: var(--wikt-palette-orange-5); --wikt-p-6: var(--wikt-palette-orange-6); --wikt-p-7: var(--wikt-palette-orange-7); --wikt-p-8: var(--wikt-palette-orange-8); --wikt-p-9: var(--wikt-palette-orange-9); --wikt-p-g-0: var(--wikt-palette-grey-orange-0); --wikt-p-g-1: var(--wikt-palette-grey-orange-1); --wikt-p-g-2: var(--wikt-palette-grey-orange-2); --wikt-p-g-3: var(--wikt-palette-grey-orange-3); --wikt-p-g-4: var(--wikt-palette-grey-orange-4); --wikt-p-g-5: var(--wikt-palette-grey-orange-5); --wikt-p-g-6: var(--wikt-palette-grey-orange-6); --wikt-p-g-7: var(--wikt-palette-grey-orange-7); --wikt-p-g-8: var(--wikt-palette-grey-orange-8); --wikt-p-g-9: var(--wikt-palette-grey-orange-9); } [data-wikt-palette-p="amber"] { --wikt-p-0: var(--wikt-palette-amber-0); --wikt-p-1: var(--wikt-palette-amber-1); --wikt-p-2: var(--wikt-palette-amber-2); --wikt-p-3: var(--wikt-palette-amber-3); --wikt-p-4: var(--wikt-palette-amber-4); --wikt-p-5: var(--wikt-palette-amber-5); --wikt-p-6: var(--wikt-palette-amber-6); --wikt-p-7: var(--wikt-palette-amber-7); --wikt-p-8: var(--wikt-palette-amber-8); --wikt-p-9: var(--wikt-palette-amber-9); --wikt-p-g-0: var(--wikt-palette-grey-amber-0); --wikt-p-g-1: var(--wikt-palette-grey-amber-1); --wikt-p-g-2: var(--wikt-palette-grey-amber-2); --wikt-p-g-3: var(--wikt-palette-grey-amber-3); --wikt-p-g-4: var(--wikt-palette-grey-amber-4); --wikt-p-g-5: var(--wikt-palette-grey-amber-5); --wikt-p-g-6: var(--wikt-palette-grey-amber-6); --wikt-p-g-7: var(--wikt-palette-grey-amber-7); --wikt-p-g-8: var(--wikt-palette-grey-amber-8); --wikt-p-g-9: var(--wikt-palette-grey-amber-9); } [data-wikt-palette-p="yellow"] { --wikt-p-0: var(--wikt-palette-yellow-0); --wikt-p-1: var(--wikt-palette-yellow-1); --wikt-p-2: var(--wikt-palette-yellow-2); --wikt-p-3: var(--wikt-palette-yellow-3); --wikt-p-4: var(--wikt-palette-yellow-4); --wikt-p-5: var(--wikt-palette-yellow-5); --wikt-p-6: var(--wikt-palette-yellow-6); --wikt-p-7: var(--wikt-palette-yellow-7); --wikt-p-8: var(--wikt-palette-yellow-8); --wikt-p-9: var(--wikt-palette-yellow-9); --wikt-p-g-0: var(--wikt-palette-grey-yellow-0); --wikt-p-g-1: var(--wikt-palette-grey-yellow-1); --wikt-p-g-2: var(--wikt-palette-grey-yellow-2); --wikt-p-g-3: var(--wikt-palette-grey-yellow-3); --wikt-p-g-4: var(--wikt-palette-grey-yellow-4); --wikt-p-g-5: var(--wikt-palette-grey-yellow-5); --wikt-p-g-6: var(--wikt-palette-grey-yellow-6); --wikt-p-g-7: var(--wikt-palette-grey-yellow-7); --wikt-p-g-8: var(--wikt-palette-grey-yellow-8); --wikt-p-g-9: var(--wikt-palette-grey-yellow-9); } [data-wikt-palette-p="lime"] { --wikt-p-0: var(--wikt-palette-lime-0); --wikt-p-1: var(--wikt-palette-lime-1); --wikt-p-2: var(--wikt-palette-lime-2); --wikt-p-3: var(--wikt-palette-lime-3); --wikt-p-4: var(--wikt-palette-lime-4); --wikt-p-5: var(--wikt-palette-lime-5); --wikt-p-6: var(--wikt-palette-lime-6); --wikt-p-7: var(--wikt-palette-lime-7); --wikt-p-8: var(--wikt-palette-lime-8); --wikt-p-9: var(--wikt-palette-lime-9); --wikt-p-g-0: var(--wikt-palette-grey-lime-0); --wikt-p-g-1: var(--wikt-palette-grey-lime-1); --wikt-p-g-2: var(--wikt-palette-grey-lime-2); --wikt-p-g-3: var(--wikt-palette-grey-lime-3); --wikt-p-g-4: var(--wikt-palette-grey-lime-4); --wikt-p-g-5: var(--wikt-palette-grey-lime-5); --wikt-p-g-6: var(--wikt-palette-grey-lime-6); --wikt-p-g-7: var(--wikt-palette-grey-lime-7); --wikt-p-g-8: var(--wikt-palette-grey-lime-8); --wikt-p-g-9: var(--wikt-palette-grey-lime-9); } [data-wikt-palette-p="green"] { --wikt-p-0: var(--wikt-palette-green-0); --wikt-p-1: var(--wikt-palette-green-1); --wikt-p-2: var(--wikt-palette-green-2); --wikt-p-3: var(--wikt-palette-green-3); --wikt-p-4: var(--wikt-palette-green-4); --wikt-p-5: var(--wikt-palette-green-5); --wikt-p-6: var(--wikt-palette-green-6); --wikt-p-7: var(--wikt-palette-green-7); --wikt-p-8: var(--wikt-palette-green-8); --wikt-p-9: var(--wikt-palette-green-9); --wikt-p-g-0: var(--wikt-palette-grey-green-0); --wikt-p-g-1: var(--wikt-palette-grey-green-1); --wikt-p-g-2: var(--wikt-palette-grey-green-2); --wikt-p-g-3: var(--wikt-palette-grey-green-3); --wikt-p-g-4: var(--wikt-palette-grey-green-4); --wikt-p-g-5: var(--wikt-palette-grey-green-5); --wikt-p-g-6: var(--wikt-palette-grey-green-6); --wikt-p-g-7: var(--wikt-palette-grey-green-7); --wikt-p-g-8: var(--wikt-palette-grey-green-8); --wikt-p-g-9: var(--wikt-palette-grey-green-9); } [data-wikt-palette-p="teal"] { --wikt-p-0: var(--wikt-palette-teal-0); --wikt-p-1: var(--wikt-palette-teal-1); --wikt-p-2: var(--wikt-palette-teal-2); --wikt-p-3: var(--wikt-palette-teal-3); --wikt-p-4: var(--wikt-palette-teal-4); --wikt-p-5: var(--wikt-palette-teal-5); --wikt-p-6: var(--wikt-palette-teal-6); --wikt-p-7: var(--wikt-palette-teal-7); --wikt-p-8: var(--wikt-palette-teal-8); --wikt-p-9: var(--wikt-palette-teal-9); --wikt-p-g-0: var(--wikt-palette-grey-teal-0); --wikt-p-g-1: var(--wikt-palette-grey-teal-1); --wikt-p-g-2: var(--wikt-palette-grey-teal-2); --wikt-p-g-3: var(--wikt-palette-grey-teal-3); --wikt-p-g-4: var(--wikt-palette-grey-teal-4); --wikt-p-g-5: var(--wikt-palette-grey-teal-5); --wikt-p-g-6: var(--wikt-palette-grey-teal-6); --wikt-p-g-7: var(--wikt-palette-grey-teal-7); --wikt-p-g-8: var(--wikt-palette-grey-teal-8); --wikt-p-g-9: var(--wikt-palette-grey-teal-9); } [data-wikt-palette-p="cyan"] { --wikt-p-0: var(--wikt-palette-cyan-0); --wikt-p-1: var(--wikt-palette-cyan-1); --wikt-p-2: var(--wikt-palette-cyan-2); --wikt-p-3: var(--wikt-palette-cyan-3); --wikt-p-4: var(--wikt-palette-cyan-4); --wikt-p-5: var(--wikt-palette-cyan-5); --wikt-p-6: var(--wikt-palette-cyan-6); --wikt-p-7: var(--wikt-palette-cyan-7); --wikt-p-8: var(--wikt-palette-cyan-8); --wikt-p-9: var(--wikt-palette-cyan-9); --wikt-p-g-0: var(--wikt-palette-grey-cyan-0); --wikt-p-g-1: var(--wikt-palette-grey-cyan-1); --wikt-p-g-2: var(--wikt-palette-grey-cyan-2); --wikt-p-g-3: var(--wikt-palette-grey-cyan-3); --wikt-p-g-4: var(--wikt-palette-grey-cyan-4); --wikt-p-g-5: var(--wikt-palette-grey-cyan-5); --wikt-p-g-6: var(--wikt-palette-grey-cyan-6); --wikt-p-g-7: var(--wikt-palette-grey-cyan-7); --wikt-p-g-8: var(--wikt-palette-grey-cyan-8); --wikt-p-g-9: var(--wikt-palette-grey-cyan-9); } [data-wikt-palette-p="blue"] { --wikt-p-0: var(--wikt-palette-blue-0); --wikt-p-1: var(--wikt-palette-blue-1); --wikt-p-2: var(--wikt-palette-blue-2); --wikt-p-3: var(--wikt-palette-blue-3); --wikt-p-4: var(--wikt-palette-blue-4); --wikt-p-5: var(--wikt-palette-blue-5); --wikt-p-6: var(--wikt-palette-blue-6); --wikt-p-7: var(--wikt-palette-blue-7); --wikt-p-8: var(--wikt-palette-blue-8); --wikt-p-9: var(--wikt-palette-blue-9); --wikt-p-g-0: var(--wikt-palette-grey-blue-0); --wikt-p-g-1: var(--wikt-palette-grey-blue-1); --wikt-p-g-2: var(--wikt-palette-grey-blue-2); --wikt-p-g-3: var(--wikt-palette-grey-blue-3); --wikt-p-g-4: var(--wikt-palette-grey-blue-4); --wikt-p-g-5: var(--wikt-palette-grey-blue-5); --wikt-p-g-6: var(--wikt-palette-grey-blue-6); --wikt-p-g-7: var(--wikt-palette-grey-blue-7); --wikt-p-g-8: var(--wikt-palette-grey-blue-8); --wikt-p-g-9: var(--wikt-palette-grey-blue-9); } [data-wikt-palette-p="indigo"] { --wikt-p-0: var(--wikt-palette-indigo-0); --wikt-p-1: var(--wikt-palette-indigo-1); --wikt-p-2: var(--wikt-palette-indigo-2); --wikt-p-3: var(--wikt-palette-indigo-3); --wikt-p-4: var(--wikt-palette-indigo-4); --wikt-p-5: var(--wikt-palette-indigo-5); --wikt-p-6: var(--wikt-palette-indigo-6); --wikt-p-7: var(--wikt-palette-indigo-7); --wikt-p-8: var(--wikt-palette-indigo-8); --wikt-p-9: var(--wikt-palette-indigo-9); --wikt-p-g-0: var(--wikt-palette-grey-indigo-0); --wikt-p-g-1: var(--wikt-palette-grey-indigo-1); --wikt-p-g-2: var(--wikt-palette-grey-indigo-2); --wikt-p-g-3: var(--wikt-palette-grey-indigo-3); --wikt-p-g-4: var(--wikt-palette-grey-indigo-4); --wikt-p-g-5: var(--wikt-palette-grey-indigo-5); --wikt-p-g-6: var(--wikt-palette-grey-indigo-6); --wikt-p-g-7: var(--wikt-palette-grey-indigo-7); --wikt-p-g-8: var(--wikt-palette-grey-indigo-8); --wikt-p-g-9: var(--wikt-palette-grey-indigo-9); } [data-wikt-palette-p="purple"] { --wikt-p-0: var(--wikt-palette-purple-0); --wikt-p-1: var(--wikt-palette-purple-1); --wikt-p-2: var(--wikt-palette-purple-2); --wikt-p-3: var(--wikt-palette-purple-3); --wikt-p-4: var(--wikt-palette-purple-4); --wikt-p-5: var(--wikt-palette-purple-5); --wikt-p-6: var(--wikt-palette-purple-6); --wikt-p-7: var(--wikt-palette-purple-7); --wikt-p-8: var(--wikt-palette-purple-8); --wikt-p-9: var(--wikt-palette-purple-9); --wikt-p-g-0: var(--wikt-palette-grey-purple-0); --wikt-p-g-1: var(--wikt-palette-grey-purple-1); --wikt-p-g-2: var(--wikt-palette-grey-purple-2); --wikt-p-g-3: var(--wikt-palette-grey-purple-3); --wikt-p-g-4: var(--wikt-palette-grey-purple-4); --wikt-p-g-5: var(--wikt-palette-grey-purple-5); --wikt-p-g-6: var(--wikt-palette-grey-purple-6); --wikt-p-g-7: var(--wikt-palette-grey-purple-7); --wikt-p-g-8: var(--wikt-palette-grey-purple-8); --wikt-p-g-9: var(--wikt-palette-grey-purple-9); } [data-wikt-palette-p="magenta"] { --wikt-p-0: var(--wikt-palette-magenta-0); --wikt-p-1: var(--wikt-palette-magenta-1); --wikt-p-2: var(--wikt-palette-magenta-2); --wikt-p-3: var(--wikt-palette-magenta-3); --wikt-p-4: var(--wikt-palette-magenta-4); --wikt-p-5: var(--wikt-palette-magenta-5); --wikt-p-6: var(--wikt-palette-magenta-6); --wikt-p-7: var(--wikt-palette-magenta-7); --wikt-p-8: var(--wikt-palette-magenta-8); --wikt-p-9: var(--wikt-palette-magenta-9); --wikt-p-g-0: var(--wikt-palette-grey-magenta-0); --wikt-p-g-1: var(--wikt-palette-grey-magenta-1); --wikt-p-g-2: var(--wikt-palette-grey-magenta-2); --wikt-p-g-3: var(--wikt-palette-grey-magenta-3); --wikt-p-g-4: var(--wikt-palette-grey-magenta-4); --wikt-p-g-5: var(--wikt-palette-grey-magenta-5); --wikt-p-g-6: var(--wikt-palette-grey-magenta-6); --wikt-p-g-7: var(--wikt-palette-grey-magenta-7); --wikt-p-g-8: var(--wikt-palette-grey-magenta-8); --wikt-p-g-9: var(--wikt-palette-grey-magenta-9); } [data-wikt-palette-p="rose"] { --wikt-p-0: var(--wikt-palette-rose-0); --wikt-p-1: var(--wikt-palette-rose-1); --wikt-p-2: var(--wikt-palette-rose-2); --wikt-p-3: var(--wikt-palette-rose-3); --wikt-p-4: var(--wikt-palette-rose-4); --wikt-p-5: var(--wikt-palette-rose-5); --wikt-p-6: var(--wikt-palette-rose-6); --wikt-p-7: var(--wikt-palette-rose-7); --wikt-p-8: var(--wikt-palette-rose-8); --wikt-p-9: var(--wikt-palette-rose-9); --wikt-p-g-0: var(--wikt-palette-grey-rose-0); --wikt-p-g-1: var(--wikt-palette-grey-rose-1); --wikt-p-g-2: var(--wikt-palette-grey-rose-2); --wikt-p-g-3: var(--wikt-palette-grey-rose-3); --wikt-p-g-4: var(--wikt-palette-grey-rose-4); --wikt-p-g-5: var(--wikt-palette-grey-rose-5); --wikt-p-g-6: var(--wikt-palette-grey-rose-6); --wikt-p-g-7: var(--wikt-palette-grey-rose-7); --wikt-p-g-8: var(--wikt-palette-grey-rose-8); --wikt-p-g-9: var(--wikt-palette-grey-rose-9); } [data-wikt-palette-p="brown"] { --wikt-p-0: var(--wikt-palette-brown-0); --wikt-p-1: var(--wikt-palette-brown-1); --wikt-p-2: var(--wikt-palette-brown-2); --wikt-p-3: var(--wikt-palette-brown-3); --wikt-p-4: var(--wikt-palette-brown-4); --wikt-p-5: var(--wikt-palette-brown-5); --wikt-p-6: var(--wikt-palette-brown-6); --wikt-p-7: var(--wikt-palette-brown-7); --wikt-p-8: var(--wikt-palette-brown-8); --wikt-p-9: var(--wikt-palette-brown-9); --wikt-p-g-0: var(--wikt-palette-grey-brown-0); --wikt-p-g-1: var(--wikt-palette-grey-brown-1); --wikt-p-g-2: var(--wikt-palette-grey-brown-2); --wikt-p-g-3: var(--wikt-palette-grey-brown-3); --wikt-p-g-4: var(--wikt-palette-grey-brown-4); --wikt-p-g-5: var(--wikt-palette-grey-brown-5); --wikt-p-g-6: var(--wikt-palette-grey-brown-6); --wikt-p-g-7: var(--wikt-palette-grey-brown-7); --wikt-p-g-8: var(--wikt-palette-grey-brown-8); --wikt-p-g-9: var(--wikt-palette-grey-brown-9); } [data-wikt-palette-p="grey"] { --wikt-p-0: var(--wikt-palette-grey-0); --wikt-p-1: var(--wikt-palette-grey-1); --wikt-p-2: var(--wikt-palette-grey-2); --wikt-p-3: var(--wikt-palette-grey-3); --wikt-p-4: var(--wikt-palette-grey-4); --wikt-p-5: var(--wikt-palette-grey-5); --wikt-p-6: var(--wikt-palette-grey-6); --wikt-p-7: var(--wikt-palette-grey-7); --wikt-p-8: var(--wikt-palette-grey-8); --wikt-p-9: var(--wikt-palette-grey-9); --wikt-p-g-0: var(--wikt-palette-grey-0); --wikt-p-g-1: var(--wikt-palette-grey-1); --wikt-p-g-2: var(--wikt-palette-grey-2); --wikt-p-g-3: var(--wikt-palette-grey-3); --wikt-p-g-4: var(--wikt-palette-grey-4); --wikt-p-g-5: var(--wikt-palette-grey-5); --wikt-p-g-6: var(--wikt-palette-grey-6); --wikt-p-g-7: var(--wikt-palette-grey-7); --wikt-p-g-8: var(--wikt-palette-grey-8); --wikt-p-g-9: var(--wikt-palette-grey-9); } t46x6el1qmhny2nrq55ifhccynp1qdz MediaWiki:Gadget-Edittools.js 8 17953 88908 2024-01-30T19:15:04Z en>Erutuon 0 incorrect change as these elements are created in the loop 88908 javascript text/javascript // <nowiki> // implicit dependencies: mediawiki.cookie, jquery.textselection (function charInsertIIFE () { "use strict"; function CharInsertCookieLegacy(key) { this.key = key; } CharInsertCookieLegacy.prototype = { get: function () { return parseInt(mw.cookie.get(this.key), 10) || 0; }, set: function (value) { if (typeof value === 'number') value = value.toString(10); if (!(typeof value === 'string' && !isNaN(parseInt(value, 10)))) throw new TypeError("Expected string or number"); return mw.cookie.set(this.key, value); }, }; function CharInsertCookie(key) { this.key = key; } CharInsertCookie.prototype = { get: function () { return mw.cookie.get(this.key); }, set: function (value) { if (typeof value !== 'string') throw new TypeError("Expected string"); return mw.cookie.set(this.key, value); }, }; var charInsertCookieLegacy = new CharInsertCookieLegacy('edittoolscharsubset'); var charInsertCookie = new CharInsertCookie('edittoolscharsubsetname'); /* ===applyCharinserts=== */ /* handle <span class="charinsert"> like <charinsert> */ function applyCharinserts() { var textbox = $('#wpTextbox1'); textbox.encapsulate = function (left, right) { return this.textSelection( 'encapsulateSelection', { pre: left.replace(/^ */, '') .replace(/\u0640(.)/g, '$1'), // remove ARABIC TATWEEL before Arabic diacritic peri: '', post: right } ); }; // Must set insertArgs in the element for which this is an event handler. function clickFunction () { textbox.encapsulate.apply(textbox, this.insertArgs); return false; } function getInsertArg(string, start, end) { string = string.substring(start, end); return string !== '' ? string.replace(/\x22/g, '&quot;') : string; } function makeInsertArgs(string) { var index = string.indexOf('+'); if (index === -1) index = string.length; var left = getInsertArg(string, 0, index); var right = getInsertArg(string, index + 1); return [ left, right ]; } function makeCharInserter(string) { var charInserter = document.createElement('a'); charInserter.onclick = clickFunction; charInserter.href = '#'; charInserter.classList.add("charinserter"); var insertArgs = makeInsertArgs(string); charInserter.insertArgs = insertArgs.map(function(arg) { return arg // No-break space (&nbsp;) must become an ASCII space in the inserted // text, but it must be displayed as a no-break space so that combining // characters are clickable. .replace(/\xA0/g, ' ') // Dotted circle can be used as a seat for diacritics // but shouldn't be inserted into the text box. .replace(/^\u25CC(.)/, '$1'); }); var visibleText = insertArgs.join(''); charInserter.appendChild(document.createTextNode(visibleText)); return charInserter; } function charInsertify(parent) { if (parent.charInsertified) return; parent.charInsertified = true; // Go through all child nodes of parent. for (var childNode = parent.firstChild; childNode !== null; childNode = childNode.nextSibling) { if (childNode.nodeType === 1) { // Element node charInsertify(childNode); } else if (childNode.nodeType === 3) { // Text node // There is a newline when the wikitext has a line break // followed by a character entity reference such as &#x2002;. // Remove the newline because we don't want to see multiple spaces. childNode.nodeValue = childNode.nodeValue .replace(/^\n+/, ''); var strings = childNode.nodeValue // Split text content on ASCII whitespace characters // and en space (U+2002) character references. .split(/[ \f\n\r\t\v\u2002]+/g) .filter(function(string) { return string !== ''; }); var addedNew = false; for (var i = 0; i < strings.length; ++i) { if (i > 0) parent.insertBefore(document.createTextNode(' '), childNode); parent.insertBefore(makeCharInserter(strings[i]), childNode); addedNew = true; } if (addedNew) parent.removeChild(childNode); } } } var charInsertSpans = document.querySelectorAll('#editpage-specialchars .charinsert'); Array.prototype.forEach.call(charInsertSpans, charInsertify); } function makeCharSubsetMenuText(slug) { return decodeURIComponent(slug .replace(/\.([0-9A-F][0-9A-F])/g, '%$1') .replace(/_/g, '%20')); } /* ===addCharSubsetMenu=== */ /* add menu for selecting subsets of secial characters */ function addCharSubsetMenu() { var edittools = $('#editpage-specialchars'); if (edittools.length === 0) return; var menu = $('<select>') .attr("id", 'charSubsetControl').css("display", "inline") .on("change", function() { chooseCharSubset($(this).val()); }); var sections = edittools.find('p'); if (sections.length === 0) return; sections.each(function() { var slug = ($(this).attr("id") || '').replace(/^edittools-/, ''); $('<option>').text(makeCharSubsetMenuText(slug)).val(slug).appendTo(menu); }); /* default subset from cookie */ var sectionIndex = charInsertCookieLegacy.get(); var sectionName = charInsertCookie.get(); if (!sectionName) { sectionName = menu.children()[sectionIndex].value; } /* update dropdown control to value of cookie */ menu.val(sectionName); /* display the subset indicated by the cookie */ chooseCharSubset(sectionName); edittools.prepend(menu); } /* ===chooseCharSubsetMenu=== */ /* select subsection of special characters */ function chooseCharSubset(sectionSlug) { var sections = $('#editpage-specialchars').find('p'); var idToShow = 'edittools-' + sectionSlug; for (var i = 0; i < sections.length; i++) { var style = sections[i].style; style.display = sections[i].id == idToShow ? 'inline' : 'none'; } charInsertCookie.set(sectionSlug); } $(function() { var action = mw.config.get('wgAction'); if (window.testNewEditJs || !(action === 'edit' || action === 'submit' || $('#editpage-specialchars').length > 0)) return; if (!window.doNotUseDefaultEditTools) // [[User:Conrad.Irwin/edittools.js]] addCharSubsetMenu(); applyCharinserts(); // Provide three arguments to add one category; // provide an array with [{name: categoryName, insertBefore: categoryInsertBefore, html: categoryHtml}] // to add more than one. mw.hook('enwiktionary.edittools.addCategory').add(function (categoryName, categoryInsertBefore, categoryHtml) { var categories = (categoryInsertBefore !== undefined) ? [{name: categoryName, insertBefore: categoryInsertBefore, html: categoryHtml}] : categoryName; var edittools = $('#editpage-specialchars'); if (edittools.length === 0) return; var menu = edittools.find('#charSubsetControl'); if (menu.length === 0) return; for (var i = 0; i < categories.length; i++) { var category = categories[i]; var name = category.name, insertBefore = category.insertBefore, html = category.html; name = name.replace(/\s/g, '_'); var selector = insertBefore ? '#charSubsetControl option[value="' + insertBefore.replace('"', '\\"') + '"]' : null; var option = $('<option>').text(makeCharSubsetMenuText(name)).val(name); $('<p>').attr('id', 'edittools-' + name).addClass('speciallang').css('display', 'none').html(html).appendTo(edittools); if (selector && menu.find(selector)) { option.insertBefore(selector); } else { option.appendTo(menu); } } applyCharinserts(); var cookieVal = charInsertCookie.get(); menu.val(cookieVal); chooseCharSubset(cookieVal); }); }); })(); // </nowiki> av4h0w783rxittyviie2wjvdsukc936 88909 88908 2026-08-06T23:11:42Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Edittools.js]] 88908 javascript text/javascript // <nowiki> // implicit dependencies: mediawiki.cookie, jquery.textselection (function charInsertIIFE () { "use strict"; function CharInsertCookieLegacy(key) { this.key = key; } CharInsertCookieLegacy.prototype = { get: function () { return parseInt(mw.cookie.get(this.key), 10) || 0; }, set: function (value) { if (typeof value === 'number') value = value.toString(10); if (!(typeof value === 'string' && !isNaN(parseInt(value, 10)))) throw new TypeError("Expected string or number"); return mw.cookie.set(this.key, value); }, }; function CharInsertCookie(key) { this.key = key; } CharInsertCookie.prototype = { get: function () { return mw.cookie.get(this.key); }, set: function (value) { if (typeof value !== 'string') throw new TypeError("Expected string"); return mw.cookie.set(this.key, value); }, }; var charInsertCookieLegacy = new CharInsertCookieLegacy('edittoolscharsubset'); var charInsertCookie = new CharInsertCookie('edittoolscharsubsetname'); /* ===applyCharinserts=== */ /* handle <span class="charinsert"> like <charinsert> */ function applyCharinserts() { var textbox = $('#wpTextbox1'); textbox.encapsulate = function (left, right) { return this.textSelection( 'encapsulateSelection', { pre: left.replace(/^ */, '') .replace(/\u0640(.)/g, '$1'), // remove ARABIC TATWEEL before Arabic diacritic peri: '', post: right } ); }; // Must set insertArgs in the element for which this is an event handler. function clickFunction () { textbox.encapsulate.apply(textbox, this.insertArgs); return false; } function getInsertArg(string, start, end) { string = string.substring(start, end); return string !== '' ? string.replace(/\x22/g, '&quot;') : string; } function makeInsertArgs(string) { var index = string.indexOf('+'); if (index === -1) index = string.length; var left = getInsertArg(string, 0, index); var right = getInsertArg(string, index + 1); return [ left, right ]; } function makeCharInserter(string) { var charInserter = document.createElement('a'); charInserter.onclick = clickFunction; charInserter.href = '#'; charInserter.classList.add("charinserter"); var insertArgs = makeInsertArgs(string); charInserter.insertArgs = insertArgs.map(function(arg) { return arg // No-break space (&nbsp;) must become an ASCII space in the inserted // text, but it must be displayed as a no-break space so that combining // characters are clickable. .replace(/\xA0/g, ' ') // Dotted circle can be used as a seat for diacritics // but shouldn't be inserted into the text box. .replace(/^\u25CC(.)/, '$1'); }); var visibleText = insertArgs.join(''); charInserter.appendChild(document.createTextNode(visibleText)); return charInserter; } function charInsertify(parent) { if (parent.charInsertified) return; parent.charInsertified = true; // Go through all child nodes of parent. for (var childNode = parent.firstChild; childNode !== null; childNode = childNode.nextSibling) { if (childNode.nodeType === 1) { // Element node charInsertify(childNode); } else if (childNode.nodeType === 3) { // Text node // There is a newline when the wikitext has a line break // followed by a character entity reference such as &#x2002;. // Remove the newline because we don't want to see multiple spaces. childNode.nodeValue = childNode.nodeValue .replace(/^\n+/, ''); var strings = childNode.nodeValue // Split text content on ASCII whitespace characters // and en space (U+2002) character references. .split(/[ \f\n\r\t\v\u2002]+/g) .filter(function(string) { return string !== ''; }); var addedNew = false; for (var i = 0; i < strings.length; ++i) { if (i > 0) parent.insertBefore(document.createTextNode(' '), childNode); parent.insertBefore(makeCharInserter(strings[i]), childNode); addedNew = true; } if (addedNew) parent.removeChild(childNode); } } } var charInsertSpans = document.querySelectorAll('#editpage-specialchars .charinsert'); Array.prototype.forEach.call(charInsertSpans, charInsertify); } function makeCharSubsetMenuText(slug) { return decodeURIComponent(slug .replace(/\.([0-9A-F][0-9A-F])/g, '%$1') .replace(/_/g, '%20')); } /* ===addCharSubsetMenu=== */ /* add menu for selecting subsets of secial characters */ function addCharSubsetMenu() { var edittools = $('#editpage-specialchars'); if (edittools.length === 0) return; var menu = $('<select>') .attr("id", 'charSubsetControl').css("display", "inline") .on("change", function() { chooseCharSubset($(this).val()); }); var sections = edittools.find('p'); if (sections.length === 0) return; sections.each(function() { var slug = ($(this).attr("id") || '').replace(/^edittools-/, ''); $('<option>').text(makeCharSubsetMenuText(slug)).val(slug).appendTo(menu); }); /* default subset from cookie */ var sectionIndex = charInsertCookieLegacy.get(); var sectionName = charInsertCookie.get(); if (!sectionName) { sectionName = menu.children()[sectionIndex].value; } /* update dropdown control to value of cookie */ menu.val(sectionName); /* display the subset indicated by the cookie */ chooseCharSubset(sectionName); edittools.prepend(menu); } /* ===chooseCharSubsetMenu=== */ /* select subsection of special characters */ function chooseCharSubset(sectionSlug) { var sections = $('#editpage-specialchars').find('p'); var idToShow = 'edittools-' + sectionSlug; for (var i = 0; i < sections.length; i++) { var style = sections[i].style; style.display = sections[i].id == idToShow ? 'inline' : 'none'; } charInsertCookie.set(sectionSlug); } $(function() { var action = mw.config.get('wgAction'); if (window.testNewEditJs || !(action === 'edit' || action === 'submit' || $('#editpage-specialchars').length > 0)) return; if (!window.doNotUseDefaultEditTools) // [[User:Conrad.Irwin/edittools.js]] addCharSubsetMenu(); applyCharinserts(); // Provide three arguments to add one category; // provide an array with [{name: categoryName, insertBefore: categoryInsertBefore, html: categoryHtml}] // to add more than one. mw.hook('enwiktionary.edittools.addCategory').add(function (categoryName, categoryInsertBefore, categoryHtml) { var categories = (categoryInsertBefore !== undefined) ? [{name: categoryName, insertBefore: categoryInsertBefore, html: categoryHtml}] : categoryName; var edittools = $('#editpage-specialchars'); if (edittools.length === 0) return; var menu = edittools.find('#charSubsetControl'); if (menu.length === 0) return; for (var i = 0; i < categories.length; i++) { var category = categories[i]; var name = category.name, insertBefore = category.insertBefore, html = category.html; name = name.replace(/\s/g, '_'); var selector = insertBefore ? '#charSubsetControl option[value="' + insertBefore.replace('"', '\\"') + '"]' : null; var option = $('<option>').text(makeCharSubsetMenuText(name)).val(name); $('<p>').attr('id', 'edittools-' + name).addClass('speciallang').css('display', 'none').html(html).appendTo(edittools); if (selector && menu.find(selector)) { option.insertBefore(selector); } else { option.appendTo(menu); } } applyCharinserts(); var cookieVal = charInsertCookie.get(); menu.val(cookieVal); chooseCharSubset(cookieVal); }); }); })(); // </nowiki> av4h0w783rxittyviie2wjvdsukc936 MediaWiki:Gadget-Edittools.css 8 17954 88910 2022-08-18T20:23:30Z en>Erutuon 0 Created page with "/* CSS borrowed from Wikipedia's [[w:MediaWiki:Gadget-charinsert-styles.css]]. */ .charinserter { /*background-color: #f9f9f9;*/ /*border: 1px solid #ddd;*/ padding: 1px 4px; }" 88910 css text/css /* CSS borrowed from Wikipedia's [[w:MediaWiki:Gadget-charinsert-styles.css]]. */ .charinserter { /*background-color: #f9f9f9;*/ /*border: 1px solid #ddd;*/ padding: 1px 4px; } bksa5383zgxhkcuw7l53pphz0jvw3mm 88911 88910 2026-08-06T23:11:51Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Edittools.css]] 88910 css text/css /* CSS borrowed from Wikipedia's [[w:MediaWiki:Gadget-charinsert-styles.css]]. */ .charinserter { /*background-color: #f9f9f9;*/ /*border: 1px solid #ddd;*/ padding: 1px 4px; } bksa5383zgxhkcuw7l53pphz0jvw3mm MediaWiki:Gadget-NoAutoCaseRedirect.js 8 17955 88912 2024-01-17T04:27:30Z en>This, that and the other 0 Created page with "window.disableAutoRedirect = true;" 88912 javascript text/javascript window.disableAutoRedirect = true; 24pdvveeqbc3n84c6t533ssk2ibayrv 88913 88912 2026-08-06T23:12:14Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-NoAutoCaseRedirect.js]] 88912 javascript text/javascript window.disableAutoRedirect = true; 24pdvveeqbc3n84c6t533ssk2ibayrv MediaWiki:Gadget-DotsSyntaxHighlighter.js 8 17956 88914 2017-05-13T17:20:26Z en>-sche 0 88914 javascript text/javascript // {{documentation}} mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-DotsSyntaxHighlighter.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400'); erifp41x2kc6dejtdqketyrzpihcwtm 88915 88914 2026-08-06T23:12:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-DotsSyntaxHighlighter.js]] 88914 javascript text/javascript // {{documentation}} mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-DotsSyntaxHighlighter.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400'); erifp41x2kc6dejtdqketyrzpihcwtm MediaWiki:Gadget-TranslationAdder.js 8 17957 88916 2026-02-08T07:09:50Z en>This, that and the other 0 remove special case for nds ([[Wiktionary:Language treatment requests#Merge Dutch Low Saxon (nds-nl) and German Low German (nds-de) into Low German (nds)]]) 88916 javascript text/javascript // <syntaxhighlight lang="javascript"> // <nowiki> // implicit dependencies : ext.gadget.Editor,ext.gadget.LegacyScriptsNewNode,mediawiki.cookie,ext.gadget.LanguageUtils,mediawiki.util /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, sub:true */ /* global mw, importScript, importScriptURI, $, AdderWrapper, LangMetadata */ // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** /** * Storage of "string" preferences. */ function CookiePreferences(context) { //Repeated calls with the same context should get the same preferences object. if (arguments.callee[context]) return arguments.callee[context]; else arguments.callee[context] = this; var storage = {}; var defaults = {}; /** * Change the value of a preference and store into a cookie. */ this.set = function (name, value) { if (value === null || storage[name] === value) return; storage[name] = value; updateCookie(); }; /** * Get the value of a preference from the cookie or default * * If the preference isn't set, return the second argument or undefined. */ this.get = function (name, def) { return storage[name] || defaults[name] || def; }; /** * let the default for get(name) be value for this session */ this.setDefault = function (name, value) { defaults[name] = value; }; // Save storage into the cookie, and if available, the local storage. function updateCookie() { if ('localStorage' in window && window.localStorage) { window.localStorage.setItem('TranslationAdderSettings', JSON.stringify(storage)); } var value = ""; for (var name in storage) { value += '&' + encodeURIComponent(name) + "=" + encodeURIComponent(storage[name]); } mw.cookie.set('preferences' + context, value, { expires: 30 }); } // Load storage from the cookie. // NOTE: If you wish to update the cookie format, both loading and storing // must continue to work for 30 days. function updateStorage() { var value; if ('localStorage' in window && window.localStorage) { value = window.localStorage.getItem('TranslationAdderSettings'); if (value) { try { var inLocal = JSON.parse(value); for (var key in inLocal) { if (inLocal.hasOwnProperty(key)) { storage[key] = inLocal[key]; } } return; } catch (e) { } } } value = mw.cookie.set('preferences' + context, value, { expires: 30 }) || ''; var pairs = value.split('&'); for (var i = 1; i < pairs.length; i++) { var val = pairs[i].split('='); if (storage[val[0]] === val[1]) continue; storage[val[0]] = val[1]; } } //__init__ updateStorage(); updateCookie(); // update this too } var util = { getVanillaIndexOf: function (str, text, pos) { function getIndex(string, regex, pos) { var newPos = string.substring(pos).search(regex); return newPos === -1 ? -1 : newPos + pos; } if (!pos) pos = 0; var cpos = 0, mpos = 0; tpos = 0, wpos = 0, spos = 0; do { cpos = text.indexOf('<!--', pos); mpos = getIndex(text, /\{\{\s*multitrans\s*\|/, pos); tpos = text.indexOf('{{', pos); wpos = text.indexOf('<nowiki>', pos); spos = text.indexOf(str, pos); pos = Math.min( cpos == -1 ? Infinity : cpos, tpos == -1 ? Infinity : tpos, wpos == -1 ? Infinity : wpos, spos == -1 ? Infinity : spos ); if (pos == spos) return pos == Infinity ? -1 : pos; else if (pos == cpos) pos = text.indexOf('-->', pos) + 3; else if (pos == wpos) pos = text.indexOf('<\/nowiki>', pos) + 9; else if (pos == mpos) pos = getIndex(text, /\|\s*data\s*=/, pos); else if (pos == tpos) pos = text.indexOf('}}', pos) + 2; } while (pos < Infinity); return -1; }, validateNoWikisyntax: function (field, nonempty) { return function (txt, error) { if (/[\{\}#]/.test(txt)) return error("Please don't use wiki markup ({}#) in the " + field + "."); if (nonempty && !txt) return error("Please specify a " + field + "."); return txt; }; }, // pos is a position in the line containing the gloss getWikitextGloss: function (txt, pos) { var start = txt.lastIndexOf('\n{{trans-top', pos) + 1; var end = txt.indexOf('\n', pos); var line = txt.substring(start, end); var parametersMatch = /\{\{trans-top[^\|\}]*(\|[^\{\}]+)/.exec(line); var gloss = ""; if (parametersMatch) { var parameterText = parametersMatch[1]; var parameterRegex = /\|(?:([^\|=]*)=([^\|]+)|([^\|]*))/g; var parameterMatch; var index = 0; while ((parameterMatch = parameterRegex.exec(parameterText))) { var key = parameterMatch[1], value = parameterMatch[2], unnamedValue = parameterMatch[3]; if (key) { if (key === "1") { gloss = value; } } else { index++; if (index === 1) { gloss = unnamedValue; } } } } return gloss; }, // get [start_pos, end_pos] of position of wikitext for trans_table containing node in text getTransTable: function (text, node, recursive) { var gloss = util.getTransGloss(node); var pos = 0; var transect = []; while (pos > -1) { pos = util.getVanillaIndexOf('{{trans-top', text, pos + 1); if (pos > -1 && util.matchGloss(util.getWikitextGloss(text, pos), gloss)) { transect.push(pos); } } if (transect.length > 1) { var poss = transect; transect = []; for (var i = 0; i < poss.length; i++) { pos = poss[i]; if (util.matchGloss(gloss, util.getWikitextGloss(text, pos))) { transect.push(pos); } } if (transect.length > 1 && !recursive) transect = util.tieBreakTransTable(text, transect, node); } if (transect.length == 1) { pos = transect[0]; pos = util.getVanillaIndexOf("\n", text, pos) + 1; var endpos = text.indexOf('{{trans-bottom}}', pos); if (endpos > -1 && pos > 0) return [pos, endpos]; } console.trace("getTransTable failure; text = %o, node = %o, recursive = %o, gloss = %o", text, node, recursive, gloss); return false; }, // try to narrow down the correct poss if multiple matching trans tables tieBreakTransTable: function (text, poss, node) { if (node.nodeName == 'DIV') { while (node && !(node.classList && node.classList.contains('NavFrame'))) node = node.parentNode; var nodes = node.getElementsByTagName('table'); if (!nodes.length) return poss; node = nodes[0]; } else { while (node && node.nodeName != 'TABLE') node = node.parentNode; } var before_count = 0; var after_count = 0; var is_found = false; $("table.translations").each(function () { var gloss = util.getTransGloss(this); if (gloss == "Translations to be checked") return; if (this == node) { is_found = true; return; } var pos = util.getTransTable(text, this, true); if (pos) { for (var j = 0; j < poss.length; j++) { if (poss[j] == pos) return util.tieBreakTransTable(poss.splice(j, 1), node); } } else { var matched = 0; for (var j = 0; j < poss.length; j++) { if (util.matchGloss(util.getWikitextGloss(text, poss[j]), gloss) && util.matchGloss(gloss, util.getWikitextGloss(text, poss[j]))) { matched++; } } if (matched == poss.length) { if (is_found) after_count++; else before_count++; } } }); if (before_count + 1 + after_count == poss.length) return [poss[before_count]]; else return poss; }, matchGloss: function (line, gloss) { if (gloss.match(/^ *$/)) return !!(line.match(/\{\{trans-top\|? *\}\}/) || line.match(/^ *$/)); var words = gloss.split(/\W+/); var pos = 0; for (var i = 0; i < words.length; i++) { pos = line.indexOf(words[i], pos); if (pos == -1) return false; } return pos > -1; }, // If the translationNode is a NavHead, this goes up to the NavFrame and then // down to the translation table. If the translationNode is the translation // table or is inside the translation table, it goes up till it finds the // translation table. Then it retrieves the data-gloss="..." attribute // that is provided by {{trans-top}} and the other translation header // templates. // This function returns a gloss after it has been transformed by the parser // into HTML. So the gloss will not match the gloss in the wikitext if the // gloss in the wikitext contains templates, for instance. getTransGloss: function(translationNode) { var node = translationNode; if (translationNode.nodeType === Node.ELEMENT_NODE && translationNode.nodeName === 'DIV' && translationNode.classList.contains('NavHead')) { var navFrame = translationNode.parentNode; if (!navFrame.classList.contains('NavFrame')) { console.trace('No NavFrame parent of %o', translationNode); return ''; } node = navFrame.getElementsByClassName('translations')[0]; if (!node) { console.trace('No child of parent of %o with "translations" class', translationNode); return ''; } } while (true) { if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'TABLE' && node.classList.contains('translations')) { return node.dataset.gloss; } node = node.parentNode; if (!node || node.id === 'mw-parser-output') break; } console.trace('Found no gloss in <table class="translations" data-gloss="..."> at or above %o', translationNode); return ''; }, isTrreq: function (li) { var span = li.getElementsByTagName('span')[0]; return (span && span.classList.contains("trreq")); }, genderList: { "s": "singular", "d": "dual", "p": "plural", "m": "masc.", "m-d": "masc. dual", "m-p": "masc. pl.", "f": "fem.", "f-d": "fem. dual", "f-p": "fem. pl.", "c": "common", "c-d": "common dual", "c-p": "common pl.", "n": "neuter", "n-d": "neuter dual", "n-p": "neuter pl.", "impf": "imperfective", "pf": "perfective" } }; // An adder for translations on en.wikt function TranslationAdders(editor) { function TranslationLabeller(insertDiv) { var original_span; var adder_form; var initial_value; var edit_button; var editing = false; var adderInterface = { 'fields': { 'gloss': function (txt, error) { return util.validateNoWikisyntax('gloss', true)(txt, error); } }, 'createForm': function () { var thisId = "a" + String(Math.random()).replace(".", ""); adder_form = newNode('form', { style: 'display: inline', width: 'auto', click: kill_event }, newNode('label', { 'for': thisId }, "Gloss: "), newNode('input', { type: 'text', name: 'gloss', value: initial_value, style: 'width: 50%', title: 'Insert a summary of the relevant definition', id: thisId }), newNode('input', { type: 'submit', name: 'preview', value: 'Preview' }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!') ); return adder_form; }, 'onsubmit': function (values, render) { render(values.gloss, function (new_html) { if (editing) toggle_editing(false); var old_html = original_span.innerHTML; editor.addEdit({ 'undo': function () { original_span.innerHTML = old_html; if (!editing) toggle_editing(); }, 'redo': function () { original_span.innerHTML = new_html; if (editing) toggle_editing(); }, 'edit': function (text) { return perform_edit(text, values.gloss); }, 'summary': 'tgloss:"' + (values.gloss.length > 50 ? values.gloss.substr(0, 50) + '...' : values.gloss + '"') }, original_span); }); } }; // The actual modification to the wikitext function perform_edit(wikitext, gloss) { var pos = util.getTransTable(wikitext, insertDiv)[0] - 4; var g_start = wikitext.lastIndexOf('\n{{trans-top', pos) + 1; var g_end = wikitext.indexOf('}}\n', pos) + 2; if (g_start === 0 || wikitext.substr(g_start, g_end - g_start).indexOf("\n") > -1) { editor.error("Could not find translation table."); return wikitext; } else { return wikitext.substr(0, g_start) + '{{trans-top|' + gloss + '}}' + wikitext.substr(g_end); } } // Don't open and close box when interacting with form. function kill_event(e) { e.stopPropagation(); } // What to do when the +/- button is clicked. function toggle_editing() { if (editing) { adder_form.style.display = "none"; original_span.style.display = "inline"; editing = false; return; } editing = true; edit_button.text("Loading..."); editor.withCurrentText(function (currentText) { var pos = util.getTransTable(currentText, insertDiv); edit_button.text('±'); if (!pos) return editor.error("Could not find translation table"); var gloss_line = currentText.substr(currentText.lastIndexOf('\n', pos[0] - 2) + 1); gloss_line = gloss_line.substr(0, gloss_line.indexOf('\n')); initial_value = gloss_line.replace(/^\{\{trans-top(\|(.*)|)\}\}\s*$/, "$2"); if (initial_value.indexOf("\n") > 0) return editor.error("Internal error: guess spanning multiple lines"); if (!original_span) { original_span = newNode('span', { 'class': 'wt-edit-recurse' }); for (var i = 0; i < insertDiv.childNodes.length; i++) { var child = insertDiv.childNodes[i]; if (child != edit_button[0] && child.className !== 'NavToggle') { original_span.appendChild(insertDiv.removeChild(child)); i--; } } insertDiv.appendChild(original_span); new AdderWrapper(editor, adderInterface, insertDiv, original_span); } original_span.style.display = "none"; adder_form.style.display = "inline"; adder_form.getElementsByTagName('input')[0].focus(); }); } edit_button = $('<a href="#">±</a>') //.addClass("translation-gloss-edit-button") .attr("title", "Edit table heading").css("padding", "2px").css("margin-left", "-5px") .on("click", function (e) { if (e && e.preventDefault) e.preventDefault(); kill_event(e); toggle_editing(); return false; }); $(insertDiv).prepend(edit_button); //XXX: this places anchor before NavToggle which may not be a good idea } function TranslationAdder(insertUl) { // Hippietrail var langmetadata = new LangMetadata(); this.fields = { lang: function (txt, error) { if (txt == 'en') return error("Please choose a foreign language. (fr, es, aaa)"); if (!/^[a-z]{2,3}(?:-[a-z]{2,3}){0,2}$/.test(txt)) return error("Please use a language code. (fr, es, aaa)"); return txt; }, word: function (txt, error) { if (txt == '{{trreq}}') return '{{t-needed}}'; if (txt == '{{t-needed}}') return txt; if (txt.indexOf(',') == -1 || forceComma) { forceComma = false; if (langmetadata.expectedCase(thiz.elements.lang.value, mw.config.get('wgTitle'), txt) || forceCase) { forceCase = false; return util.validateNoWikisyntax('translation', true)(txt, error); } if (prefs.get('case-knowledge', 'none') == 'none') { return error(newNode('span', "Translations normally don't have capital letters. If you're certain it does, you can ", newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { forceCase = true; inputForm.onsubmit(); prefs.set('case-knowledge', 'guru'); } }, "continue by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { prefs.set('case-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " unless you are certain that this translation has a capital letter."); error(msg); return txt; } } if (prefs.get('comma-knowledge', 'none') == 'none') { return error(newNode('span', "You can only add one translation at a time. If this is one translation that contains a comma, you can ", newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { forceComma = true; inputForm.onsubmit(); prefs.set('comma-knowledge', 'guru'); } }, "add it by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { prefs.set('comma-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " if you were trying to create a list of translations in one go, this is currently not supported."); error(msg); return txt; } }, qual: util.validateNoWikisyntax('qualifier'), tr: util.validateNoWikisyntax('transcription'), lit: util.validateNoWikisyntax('literal'), rawPageName: util.validateNoWikisyntax('raw page name'), nested: util.validateNoWikisyntax('nested'), "s": 'checkbox', "d": 'checkbox', "p": 'checkbox', "m": 'checkbox', "m-d": 'checkbox', "m-p": 'checkbox', "f": 'checkbox', "f-d": 'checkbox', "f-p": 'checkbox', "c": 'checkbox', "c-d": 'checkbox', "c-p": 'checkbox', "n": 'checkbox', "n-d": 'checkbox', "n-p": 'checkbox', "impf": 'checkbox', "pf": 'checkbox', nclass1: util.validateNoWikisyntax('noun class'), nclass2: util.validateNoWikisyntax('plural class') }; this.createForm = function () { function createGenderNode(name, text) { var inp = document.createElement("input"); inp.type = "checkbox"; inp.name = name; var lbl = document.createElement("label"); lbl.appendChild(inp); lbl.appendChild(document.createTextNode(text)); return lbl; } var genderControls = {}; for (var g in util.genderList) genderControls[g] = createGenderNode(g, util.genderList[g]); var controls = { lang: newNode('input', { size: 4, type: 'text', name: 'lang', value: prefs.get('curlang', ''), title: 'The two or three letter ISO 639 language code' }), transliteration: newNode('p', newNode('a', { href: '/wiki/Wiktionary:Transliteration' }, "Transliteration"), ": ", newNode('input', { name: "tr", title: "The word transliterated into the Latin alphabet." }), " (e.g. zìmǔ for 字母)"), literal: newNode('p', "Literal translation: ", newNode('input', { name: "lit", title: "The literal translation of the term." })), qualifier: newNode('p', "Qualifier: ", newNode('input', { name: 'qual', title: "A qualifier for the word" }), " (e.g. literally, formally, slang)"), display: newNode('p', "Raw page name: ", newNode('input', { name: 'rawPageName', title: "A link to lemma, if a translation is not a lemma." }), " (e.g. 疲れる for 疲れた)"), nested: newNode('p', "Nesting: ", newNode('input', { name: 'nested', title: "The nesting of this language" }), " (e.g. Serbo-Croatian/Cyrillic)"), // Genders genders: genderControls, // Noun class nclass: newNode('p', "Noun class: ", newNode('input', { type: 'text', size: 4, name: 'nclass1', title: "The noun class of the word in the singular or citation form." }), " Plural class: ", newNode('input', { type: 'text', size: 4, name: 'nclass2', title: "The noun class of the word in the plural form, if any." })) }; // suppress unused script field function createGenderDiv(genderz) { var $div = $("<div>"); for (var i = 1; i < arguments.length; i++) $div.append(genderz[arguments[i]]); return $div; } var $mdiv = createGenderDiv(controls.genders, "m", "m-d", "m-p"); var $fdiv = createGenderDiv(controls.genders, "f", "f-d", "f-p"); var $cdiv = createGenderDiv(controls.genders, "c", "c-d", "c-p"); var $ndiv = createGenderDiv(controls.genders, "n", "n-d", "n-p"); var $sdpdiv = createGenderDiv(controls.genders, "s", "d", "p"); var $pfdiv = createGenderDiv(controls.genders, "impf", "pf"); controls.gender = $("<p>").append($mdiv).append($fdiv).append($cdiv).append($ndiv).append($sdpdiv).append($pfdiv)[0]; langInput = controls.lang; var showButton = newNode('span', { 'click': function () { if (!advancedMode) { advancedMode = true; showButton.innerHTML = " Less"; } else { advancedMode = false; showButton.innerHTML = " More"; } updateFieldVisibility.call(langInput, true); }, 'style': "color: var(--wikt-palette-blue,#0000FF); cursor: pointer;" }, advancedMode ? " Less" : " More"); function autoTransliterate() { var rawPageName = langmetadata.computeRawPageName(thiz.elements.lang.value, thiz.elements.word.value); if (rawPageName && rawPageName !== thiz.elements.word.value) thiz.elements.rawPageName.value = rawPageName; } function updateFieldVisibility(preserve) { preserve = (preserve === true); //show all arguments function show() { for (var i = 0; i < arguments.length; i++) { if (arguments[i].nodeName == 'P') arguments[i].style.display = "block"; else arguments[i].style.display = "inline"; } } //hide all arguments function hide() { for (var i = 0; i < arguments.length; i++) arguments[i].style.display = "none"; } //if the first argument is false hide the remaining arguments, otherwise show them. function toggle(condition) { if (condition) //eww... show.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); else hide.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); } if (!preserve) langInput.value = langmetadata.cleanLangCode(langInput.value); var scriptGuess = langmetadata.guessScript(langInput.value || ''); if (!preserve) { thiz.elements.nested.value = langmetadata.getNested(langInput.value || ''); thiz.elements.nested.dataset.initialValue = thiz.elements.nested.value; autoTransliterate(); } var lang = langInput.value; if (!advancedMode) { var g = langmetadata.getGenders(lang); if (!lang) { hide(controls.gender); } else if (g === undefined) { hide(controls.gender); } else { for (var genderName in util.genderList) { toggle(g.indexOf(genderName) != -1, controls.genders[genderName]); } } toggle(g, controls.gender); toggle(langmetadata.hasNounClasses(lang), controls.nclass); var hasAutomaticTransliteration = new window.LanguageUtils().HasAutomaticTransliteration(lang); toggle(scriptGuess && scriptGuess != 'Latn' && !hasAutomaticTransliteration, controls.transliteration); toggle(langmetadata.needsRawPageName(lang), controls.display); hide(controls.literal, controls.qualifier, controls.nested); //only in more } else { show( controls.gender, controls.genders['s'], controls.genders['d'], controls.genders['p'], controls.genders['m'], controls.genders['m-d'], controls.genders['m-p'], controls.genders['f'], controls.genders['f-d'], controls.genders['f-p'], controls.genders['c'], controls.genders['c-d'], controls.genders['c-p'], controls.genders['n'], controls.genders['n-d'], controls.genders['n-p'], controls.genders['impf'], controls.genders['pf'], controls.nclass, controls.transliteration, controls.literal, controls.qualifier, controls.display, controls.nested); } } //autocomplete language names function langAutoFill(e) { e = (e || event).keyCode; if ((e >= 33 && e <= 40) || e == 8 || e == 46 || e == 27 || e == 16) { return; } var t = this, langPrefix = t.value; if (langPrefix.substr(0, 1) != langPrefix.substr(0, 1).toUpperCase()) { return; } new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:languages/javascript-interface|GetSingleLanguageByLanguagePrefix|" + langPrefix + "}}", "prop": "wikitext" }).done(function (r) { if (r.expandtemplates && r.expandtemplates.wikitext !== "") { var langcode = r.expandtemplates.wikitext.split(":")[0]; var langname = r.expandtemplates.wikitext.split(":")[1]; var oldLength = t.value.length; t.value = langname; $(t).data("langcode", langcode); if (t.setSelectionRange) { t.setSelectionRange(oldLength, langname.length); } else if (t.createTextRange) { var z = t.createTextRange(); z.moveEnd('character', 0 - z.move('character', [t.value.length, t.value = langname][0]) + t.value.length); z.select(); } } else { $(t).removeData("langcode"); } }); } langInput.onkeyup = langAutoFill; langInput.onblur = function () { if ($(this).data("langcode")) $(this).val($(this).data("langcode")); updateFieldVisibility.call(langInput); }; window.setTimeout(function () { updateFieldVisibility.call(langInput); }, 0); inputForm = newNode('form', newNode('p', newNode('a', { href: "/wiki/MediaWiki:Gadget-TranslationAdder.js/help#Usage" }, "Add translation"), ' ', langInput, newNode('b', ': '), newNode('input', { 'name': 'word', size: 20, keyup: autoTransliterate, change: autoTransliterate }), newNode('input', { 'type': 'submit', 'value': 'Preview translation' }), showButton ), controls.gender, controls.nclass, controls.transliteration, controls.literal, controls.display, controls.qualifier, controls.nested ); return inputForm; }; this.onsubmit = function (values, render) { var wikitext; function callRender() { render(wikitext, function (html) { registerEdits(values, wikitext, html); }); } // Keep track of whether the "nested" field has changed // so that we can tag the edit values.nestedChanged = inputForm.nested.dataset.initialValue !== values.nested; var languagePrefix = '{{subst:#invoke:languages/templates|getByCodeAllowEtym|' + values.lang + '|getCanonicalName}}: '; if (values.word.indexOf('{{t-needed') === 0) { wikitext = languagePrefix + ' {{t-needed|' + values.lang + '}}'; callRender(); } else { langmetadata.retrieveRawPageName(values.lang, values.word, values.rawPageName, function (rawPageName, needsRawPageName) { if (needsRawPageName) { values.rawPageName = rawPageName; values.wordMinus = ''; } else { values.rawPageName = ''; values.wordMinus = rawPageName; } langmetadata.hasWiktionaryWithEntry(values.lang, values.rawPageName || values.wordMinus, function (hasInterwiki) { var templateBody = '|' + values.lang + '|' + langmetadata.applyOrthographicalCorrections(values.lang, values.rawPageName || values.word) + (values.nclass1 ? '|c' + values.nclass1 : '') + (values.nclass2 ? '|c' + values.nclass2 : ''); // Add gender codes templateBody += [ 's', 'd', 'p', 'm', 'm-d', 'm-p', 'f', 'f-d', 'f-p', 'c', 'c-d', 'c-p', 'n', 'n-d', 'n-p', 'impf', 'pf' ].map(function(k) { return values[k] ? '|' + k : ''; }).join(""); templateBody += (values.tr ? '|tr=' + values.tr : '') + (values.lit ? '|lit=' + values.lit : '') + (values.rawPageName ? '|alt=' + values.word : ''); var qualifier = values.qual ? ' {{q|' + values.qual + '}}' : ''; wikitext = languagePrefix + "{{" + (hasInterwiki ? "t+" : "t") + templateBody + "}}" + qualifier; callRender(); }); }); } }; var thiz = this; var prefs = new CookiePreferences('EditorJs'); var langInput; var inputForm; var advancedMode = prefs.get('more-display', 'none') != 'none'; var forceComma = false; var forceCase = false; //Reset elements to default values. function resetElements() { if (prefs.get('more-display', 'none') != advancedMode ? 'block' : 'none') prefs.set('more-display', advancedMode ? 'block' : 'none'); //named for compatibility thiz.elements.word.value = thiz.elements.nclass1.value = thiz.elements.nclass2.value = thiz.elements.lit.value = thiz.elements.tr.value = thiz.elements.rawPageName.value = thiz.elements.qual.value = ''; thiz.elements['s'].checked = false; thiz.elements['d'].checked = false; thiz.elements['p'].checked = false; thiz.elements['m'].checked = false; thiz.elements['m-d'].checked = false; thiz.elements['m-p'].checked = false; thiz.elements['f'].checked = false; thiz.elements['f-d'].checked = false; thiz.elements['f-p'].checked = false; thiz.elements['c'].checked = false; thiz.elements['c-d'].checked = false; thiz.elements['c-p'].checked = false; thiz.elements['n'].checked = false; thiz.elements['n-d'].checked = false; thiz.elements['n-p'].checked = false; thiz.elements['impf'].checked = false; thiz.elements['pf'].checked = false; prefs.set('curlang', thiz.elements.lang.value); } // This is onsubmit after the wikitext has been rendered to give content function registerEdits(values, wikitext, content) { var li = newNode('li', { 'class': 'trans-' + values.lang }); li.innerHTML = content; var lang = getLangName(li); var x = langmetadata.applyOrthographicalCorrections(values.lang, values.rawPageName || values.word); var resp = x; var langCodeBad = false; if (x.indexOf("{{") < 0) { new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{ll|" + values.lang + "|" + x + "}}", "prop": "wikitext" }, {"async": false}).done(function (r) { if (r.expandtemplates && r.expandtemplates.wikitext) { // [[page#Language|display]] // resp = r.expandtemplates.wikitext; // [[page|display]] // resp = r.expandtemplates.wikitext.replace(/#[^|]*/, ""); // [[page]] resp = r.expandtemplates.wikitext.replace(/#[^\]]*/, ""); try { if (DOMParser && new DOMParser().parseFromString(r.expandtemplates.wikitext, "text/html").querySelector(".scribunto-error")) langCodeBad = true; } catch (e) { } } }).fail(function(r) { console.error(r); resp = resp.includes("[[") ? resp : "[[" + resp + "]]"; }); } if (langCodeBad) return editor.error("Unrecognized language code '" + values.lang + "'"); var summary = 't+' + values.lang + ':' + resp; var insertBefore = null; var nextLanguage = null; var nestedHeading, nestedLang; var nested = values.nested.split('/'); if (nested.length > 1) { nestedHeading = nested[0]; nestedLang = (nested[1] === 'Roman' ? 'Latin' : nested[1]); // [[Wiktionary:Beer parlour/2026/January#sorting and reformating translation tables]] if (nestedHeading === '') nestedHeading = lang; content = content.replace(/.*: /, nestedLang + ": "); wikitext = wikitext.replace("subst:", "").replace(/.*: /, nestedLang + ": "); } else { nestedHeading = values.nested; nestedLang = lang; } var nestedWikitext = "\n* " + nestedHeading + ":\n*: " + wikitext; function addEdit(edit, span) { var fields = ["lang", "word", "nclass1", "nclass2", "rawPageName", "qual", "tr", "lit"]; editor.addEdit({ 'undo': function () { edit.undo(); if (thiz.elements.word.value === "" && thiz.elements.nclass1.value === "" && thiz.elements.nclass2.value === "" && thiz.elements.tr.value === "" && thiz.elements.lit.value === "" && thiz.elements.rawPageName.value === "" && thiz.elements.qual.value === "") { for (var i = 0; i < fields.length; i++) { thiz.elements[fields[i]].value = values[fields[i]]; } for (var genderName in util.genderList) { thiz.elements[genderName].checked = values[genderName]; } } }, 'redo': function () { edit.redo(); for (var i = 0; i < fields.length; i++) { if (thiz.elements[fields[i]].value != values[fields[i]]) return; } resetElements(); }, 'edit': edit.edit, 'tags': [values.nestedChanged ? 'translation-adder-custom-nesting' : null], 'summary': summary }, span); } // Compare language names without accents and punctuation marks var normalizeAndStrip = s => s.normalize("NFD").replace(/[\u0300-\u036f'ʼ", -]/g, '').toUpperCase(); var compare = function(a, b) { if (normalizeAndStrip(a) < normalizeAndStrip(b)) { return -1; } if (normalizeAndStrip(a) > normalizeAndStrip(b)) { return 1; } if (a < b) { return -1; } if (a > b) { return 1; } return 0; } if (lang) { //Get all li's in this table row. var lss = $(insertUl).parent().parent().find('li').get(); var dds = $(insertUl).parent().parent().find('dd').get(); var lis = lss.concat(dds); for (var j = 0; j < lis.length; j++) { if (lis[j].getElementsByTagName('form').length > 0) continue; var ln = getLangName(lis[j]); if (ln == lang) { if (values.word == '{{t-needed}}') { addEdit({ 'redo': function () { }, 'undo': function () { }, 'edit': function () { return editor.error("Can not add a translation request for a language with translations"); } }); return resetElements(); } var span = newNode('span'); var parent = lis[j]; if (util.isTrreq(parent)) { span.innerHTML = content.substr(content.indexOf(':') + 1); var trspan = parent.getElementsByTagName('span')[0]; addEdit({ 'redo': function () { parent.removeChild(trspan); parent.appendChild(span); }, 'undo': function () { parent.removeChild(span); parent.appendChild(trspan); }, 'edit': getEditFunction(values, wikitext, ln, values.lang, true, function (text, ipos) { //Converting a Translation request into a translation var lineend = text.indexOf('\n', ipos); return text.substr(0, ipos) + wikitext + text.substr(lineend); }) }, span); return resetElements(); } else if (parent.tagName !== 'DD' || lang !== 'Latin') { if (parent.getElementsByTagName('ul').length + parent.getElementsByTagName('dl').length == 0) { span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.appendChild(span) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) { //We are adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + text.substr(lineend); }) }, span); return resetElements(); } else { var node = parent.firstChild; var hastrans = false; while (node) { if (node.nodeType == 1) { var nn = node.nodeName; if (nn == 'UL' || nn == 'DL') { // If we want to use the dialectical nesting for orthographical nesting // then we need to skip this (otherwise perfect) match. if (!hastrans && nestedHeading == ln) { node = node.nextSibling; continue; } span.innerHTML = (hastrans ? ", " : " ") + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.insertBefore(span, node) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) { //Adding the translation to a language that has nested translations under it var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + (hastrans ? "," : "") + wt + text.substr(lineend); }) }, span); return resetElements(); } else { hastrans = true; } } node = node.nextSibling; } } } } else if (ln && compare(ln, lang) > 0 && (!nextLanguage || compare(ln, nextLanguage) < 0) && lis[j].parentNode.parentNode.nodeName != 'LI') { nextLanguage = ln; var parent = lis[j]; insertBefore = [{ 'redo': function () { parent.parentNode.insertBefore(li, parent); }, 'undo': function () { parent.parentNode.removeChild(li) }, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new language's translation before another language's translation var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + "\n* " + wikitext + text.substr(lineend); }) }, li]; } } } if (values.nested) { nextLanguage = null; insertBefore = null; li.innerHTML = nestedHeading + ":" + "<dl><dd class=\"trans-" + values.lang + "\">" + content + "</dd></dl>"; var lis = insertUl.parentNode.parentNode.getElementsByTagName('li'); for (var j = 0; j < lis.length; j++) { //Ignore the editor form if (lis[j].getElementsByTagName('form').length > 0) continue; //Don't look at nested translations if (lis[j].parentNode.parentNode.nodeName != 'TD') continue; var ln = getLangName(lis[j]); if (ln == nestedHeading) { var sublis = lis[j].getElementsByTagName('li'); if (!sublis.length) sublis = lis[j].getElementsByTagName('dd'); if (sublis.length == 0) { var parent = lis[j]; var dd = newNode('dd', { 'class': 'trans-' + values.lang }); var dl = newNode('dl', dd); dd.innerHTML = content; addEdit({ 'redo': function () { parent.appendChild(dl); }, 'undo': function () { parent.removeChild(dl); }, 'edit': getEditFunction(values, wikitext, nestedHeading, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new dl to an existing translation line var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + "\n*: " + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } else { var dd = newNode(sublis[0].nodeName, { 'class': 'trans-' + values.lang }); var linestart = dd.nodeName == 'DD' ? '\n*: ' : '\n** '; dd.innerHTML = content; for (var k = 0; k < sublis.length; k++) { var subln = getLangName(sublis[k]); var parent = sublis[k]; if (subln == nestedLang) { var span = newNode('span'); span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.appendChild(span) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, nestedLang, values.lang, false, function (text, ipos) { // Adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + text.substr(lineend); }) }, span); return resetElements(); } else if (langmetadata.nestsBefore(nestedLang, subln)) { addEdit({ 'redo': function () { parent.parentNode.insertBefore(dd, parent); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation in-order var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } addEdit({ 'redo': function () { parent.parentNode.appendChild(dd); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation at the end of its group var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } else if (ln && compare(ln, nestedHeading) > 0 && (!nextLanguage || compare(ln, nextLanguage) < 0)) { nextLanguage = ln; var parent = lis[j]; insertBefore = [{ 'redo': function () { parent.parentNode.insertBefore(li, parent); }, 'undo': function () { parent.parentNode.removeChild(li) }, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new nested translation section. var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + nestedWikitext + text.substr(lineend); }) }, li]; } } wikitext = nestedHeading + ":\n*: " + wikitext; } li.className = "trans-" + values.lang; if (insertBefore) { addEdit(insertBefore[0], insertBefore[1]); } else { //Append the translations to the end (no better way found) addEdit({ 'redo': function () { insertUl.appendChild(li); }, 'undo': function () { insertUl.removeChild(li) }, 'edit': getEditFunction(values, wikitext) }, li); } return resetElements(); } //Get the wikitext modification for the current form submission. function getEditFunction(values, wikitext, findLanguage, findLangCode, trreq, callback) { return function (text) { var p = util.getTransTable(text, insertUl); if (!p) return editor.error("Could not find translation table for '" + values.lang + ":" + values.word + "'. Glosses should be unique"); var stapos = p[0]; var endpos = p[1]; if (findLanguage) { var ipos = 0; if (trreq) { ipos = text.substr(stapos).search(new RegExp(mw.util.escapeRegExp(findLanguage) + ":\\s*\\{\\{t-needed(?:\\|" + findLangCode + "}})?")) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLanguage + '}}', stapos); if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLangCode + '}}', stapos); } // If we have a nested trreq, then we still need to look for the non-trreq form of the heading language if (!trreq || ipos < stapos || ipos > endpos) { var escapedLang = mw.util.escapeRegExp(findLanguage); //if the translation should not be nested it should not go before any nested language var regexByShouldFindSubLanguage = values.nested != "" ? "[:*]?" : ""; var possibleRegexes = [ RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\[\\[" + escapedLang + "\\]\\]:"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?" + escapedLang + ":"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\{\\{ttbc\\|" + escapedLang + "}}:") ]; ipos = text.substr(stapos).search(possibleRegexes[0]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[1]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[2]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{subst:#invoke:languages/templates|getByCodeAllowEtym|' + findLangCode + '|getCanonicalName}}:', stapos); } if (ipos >= stapos && ipos < endpos) { return callback(text, ipos, trreq); } else { return editor.error("Could not find translation entry for '" + values.lang + ":" + values.word + "'. Please reformat"); } } return text.substr(0, endpos) + "* " + wikitext + "\n" + text.substr(endpos); }; } // For an <li> in well-formed translation sections, return the language name. function getLangName(li) { var guess = li.textContent || li.innerText; if (guess) guess = guess.substr(0, guess.indexOf(':')); if (guess == 'Template') { return false; } return guess.replace(/^[\s\n]*/, ''); } // Try to get the language code from an <li> containing {{t}}, {{t+}} or {{t-}} function getLangCode(li) { if (li.className.indexOf('trans-') === 0) return li.className.substr(6); var spans = li.getElementsByTagName('span'); for (var i = 0; i < spans.length; i++) { if (spans[i].lang) { return spans[i].lang; } if (spans[i].dataset && spans[i].dataset.lang) { return spans[i].dataset.lang; } } return false; } } function createTranslationAdderRow(li) { var $ul = $("<ul>").append(li); return $("<tr>") .append($("<td>")) .append($("<td>")) .append($("<td>").css("text-align", "left").append($ul)); } $('table.translations').each(function () { if (util.getTransGloss(this) != 'Translations to be checked') { var tdSelector = "td:not(.mw-hiero-table td):not(.targeted-translations-select)"; var uls = $(this).find(tdSelector + " > ul").get(); if (uls.length == 0) { $(this).find(tdSelector)[0].appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } if (uls.length == 1) { var td = $(this).find(tdSelector)[2]; if (td) { td.appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } } if (uls) { var li = document.createElement('li'); var ul = uls[uls.length - 1]; $(this).append(createTranslationAdderRow(li)); new AdderWrapper(editor, new TranslationAdder(ul), li); if (true) {// XXX: why not? (new CookiePreferences('EditorJs')).get('labeller') == 'true') { var div = $(this).parent().parent().find('div.NavHead')[0]; if (div) { new TranslationLabeller(div) } } } } }); } $(function () { // Check if we are on a sensible page var isOnPrintable = mw.util.getParamValue("printable") !== null; var isDiff = mw.util.getParamValue("diff") !== null || mw.util.getParamValue("oldid") !== null; if (mw.config.get('wgAction') != 'view' || isOnPrintable || isDiff) return; var editor = new Editor(); TranslationAdders(editor); /* // Check that we have not been disabled var prefs = new CookiePreferences('EditorJs'); if (prefs.get('enabled', 'true') == 'true') { if (!window.loadedEditor) { prefs.setDefault('labeller', mw.config.get('wgUserName') ? 'true' : 'false'); window.loadedEditor = true; } } // The enable-disable button on WT:EDIT var node = document.getElementById('editor-js-disable-button'); if (node) { node.innerHTML = ""; var toggle = newNode('span', { click: function() { if (prefs.get('enabled', 'true') == 'true') { toggle.innerHTML = "Enable"; prefs.set('enabled', 'false'); } else { toggle.innerHTML = "Disable"; prefs.set('enabled', 'true'); } } }, (prefs.get('enabled', 'true') == 'true' ? 'Disable' : 'Enable')) node.appendChild(toggle); } var node = document.getElementById("editor-js-labeller-button"); if (node) { node.innerHTML = ""; var toggle2 = newNode('span', { click: function() { if (prefs.get('labeller') == 'true') { toggle2.innerHTML = "Enable"; prefs.set('labeller', 'false'); } else { toggle2.innerHTML = "Disable"; prefs.set('labeller', 'true'); } } }, (prefs.get('labeller') == 'true' ? 'Disable' : 'Enable')) node.appendChild(toggle2); }*/ }); //</nowiki> // </syntaxhighlight> fenbzaedj1d7qphc980f0ohcrd0z8qg 88917 88916 2026-08-06T23:12:43Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TranslationAdder.js]] 88916 javascript text/javascript // <syntaxhighlight lang="javascript"> // <nowiki> // implicit dependencies : ext.gadget.Editor,ext.gadget.LegacyScriptsNewNode,mediawiki.cookie,ext.gadget.LanguageUtils,mediawiki.util /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, sub:true */ /* global mw, importScript, importScriptURI, $, AdderWrapper, LangMetadata */ // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** /** * Storage of "string" preferences. */ function CookiePreferences(context) { //Repeated calls with the same context should get the same preferences object. if (arguments.callee[context]) return arguments.callee[context]; else arguments.callee[context] = this; var storage = {}; var defaults = {}; /** * Change the value of a preference and store into a cookie. */ this.set = function (name, value) { if (value === null || storage[name] === value) return; storage[name] = value; updateCookie(); }; /** * Get the value of a preference from the cookie or default * * If the preference isn't set, return the second argument or undefined. */ this.get = function (name, def) { return storage[name] || defaults[name] || def; }; /** * let the default for get(name) be value for this session */ this.setDefault = function (name, value) { defaults[name] = value; }; // Save storage into the cookie, and if available, the local storage. function updateCookie() { if ('localStorage' in window && window.localStorage) { window.localStorage.setItem('TranslationAdderSettings', JSON.stringify(storage)); } var value = ""; for (var name in storage) { value += '&' + encodeURIComponent(name) + "=" + encodeURIComponent(storage[name]); } mw.cookie.set('preferences' + context, value, { expires: 30 }); } // Load storage from the cookie. // NOTE: If you wish to update the cookie format, both loading and storing // must continue to work for 30 days. function updateStorage() { var value; if ('localStorage' in window && window.localStorage) { value = window.localStorage.getItem('TranslationAdderSettings'); if (value) { try { var inLocal = JSON.parse(value); for (var key in inLocal) { if (inLocal.hasOwnProperty(key)) { storage[key] = inLocal[key]; } } return; } catch (e) { } } } value = mw.cookie.set('preferences' + context, value, { expires: 30 }) || ''; var pairs = value.split('&'); for (var i = 1; i < pairs.length; i++) { var val = pairs[i].split('='); if (storage[val[0]] === val[1]) continue; storage[val[0]] = val[1]; } } //__init__ updateStorage(); updateCookie(); // update this too } var util = { getVanillaIndexOf: function (str, text, pos) { function getIndex(string, regex, pos) { var newPos = string.substring(pos).search(regex); return newPos === -1 ? -1 : newPos + pos; } if (!pos) pos = 0; var cpos = 0, mpos = 0; tpos = 0, wpos = 0, spos = 0; do { cpos = text.indexOf('<!--', pos); mpos = getIndex(text, /\{\{\s*multitrans\s*\|/, pos); tpos = text.indexOf('{{', pos); wpos = text.indexOf('<nowiki>', pos); spos = text.indexOf(str, pos); pos = Math.min( cpos == -1 ? Infinity : cpos, tpos == -1 ? Infinity : tpos, wpos == -1 ? Infinity : wpos, spos == -1 ? Infinity : spos ); if (pos == spos) return pos == Infinity ? -1 : pos; else if (pos == cpos) pos = text.indexOf('-->', pos) + 3; else if (pos == wpos) pos = text.indexOf('<\/nowiki>', pos) + 9; else if (pos == mpos) pos = getIndex(text, /\|\s*data\s*=/, pos); else if (pos == tpos) pos = text.indexOf('}}', pos) + 2; } while (pos < Infinity); return -1; }, validateNoWikisyntax: function (field, nonempty) { return function (txt, error) { if (/[\{\}#]/.test(txt)) return error("Please don't use wiki markup ({}#) in the " + field + "."); if (nonempty && !txt) return error("Please specify a " + field + "."); return txt; }; }, // pos is a position in the line containing the gloss getWikitextGloss: function (txt, pos) { var start = txt.lastIndexOf('\n{{trans-top', pos) + 1; var end = txt.indexOf('\n', pos); var line = txt.substring(start, end); var parametersMatch = /\{\{trans-top[^\|\}]*(\|[^\{\}]+)/.exec(line); var gloss = ""; if (parametersMatch) { var parameterText = parametersMatch[1]; var parameterRegex = /\|(?:([^\|=]*)=([^\|]+)|([^\|]*))/g; var parameterMatch; var index = 0; while ((parameterMatch = parameterRegex.exec(parameterText))) { var key = parameterMatch[1], value = parameterMatch[2], unnamedValue = parameterMatch[3]; if (key) { if (key === "1") { gloss = value; } } else { index++; if (index === 1) { gloss = unnamedValue; } } } } return gloss; }, // get [start_pos, end_pos] of position of wikitext for trans_table containing node in text getTransTable: function (text, node, recursive) { var gloss = util.getTransGloss(node); var pos = 0; var transect = []; while (pos > -1) { pos = util.getVanillaIndexOf('{{trans-top', text, pos + 1); if (pos > -1 && util.matchGloss(util.getWikitextGloss(text, pos), gloss)) { transect.push(pos); } } if (transect.length > 1) { var poss = transect; transect = []; for (var i = 0; i < poss.length; i++) { pos = poss[i]; if (util.matchGloss(gloss, util.getWikitextGloss(text, pos))) { transect.push(pos); } } if (transect.length > 1 && !recursive) transect = util.tieBreakTransTable(text, transect, node); } if (transect.length == 1) { pos = transect[0]; pos = util.getVanillaIndexOf("\n", text, pos) + 1; var endpos = text.indexOf('{{trans-bottom}}', pos); if (endpos > -1 && pos > 0) return [pos, endpos]; } console.trace("getTransTable failure; text = %o, node = %o, recursive = %o, gloss = %o", text, node, recursive, gloss); return false; }, // try to narrow down the correct poss if multiple matching trans tables tieBreakTransTable: function (text, poss, node) { if (node.nodeName == 'DIV') { while (node && !(node.classList && node.classList.contains('NavFrame'))) node = node.parentNode; var nodes = node.getElementsByTagName('table'); if (!nodes.length) return poss; node = nodes[0]; } else { while (node && node.nodeName != 'TABLE') node = node.parentNode; } var before_count = 0; var after_count = 0; var is_found = false; $("table.translations").each(function () { var gloss = util.getTransGloss(this); if (gloss == "Translations to be checked") return; if (this == node) { is_found = true; return; } var pos = util.getTransTable(text, this, true); if (pos) { for (var j = 0; j < poss.length; j++) { if (poss[j] == pos) return util.tieBreakTransTable(poss.splice(j, 1), node); } } else { var matched = 0; for (var j = 0; j < poss.length; j++) { if (util.matchGloss(util.getWikitextGloss(text, poss[j]), gloss) && util.matchGloss(gloss, util.getWikitextGloss(text, poss[j]))) { matched++; } } if (matched == poss.length) { if (is_found) after_count++; else before_count++; } } }); if (before_count + 1 + after_count == poss.length) return [poss[before_count]]; else return poss; }, matchGloss: function (line, gloss) { if (gloss.match(/^ *$/)) return !!(line.match(/\{\{trans-top\|? *\}\}/) || line.match(/^ *$/)); var words = gloss.split(/\W+/); var pos = 0; for (var i = 0; i < words.length; i++) { pos = line.indexOf(words[i], pos); if (pos == -1) return false; } return pos > -1; }, // If the translationNode is a NavHead, this goes up to the NavFrame and then // down to the translation table. If the translationNode is the translation // table or is inside the translation table, it goes up till it finds the // translation table. Then it retrieves the data-gloss="..." attribute // that is provided by {{trans-top}} and the other translation header // templates. // This function returns a gloss after it has been transformed by the parser // into HTML. So the gloss will not match the gloss in the wikitext if the // gloss in the wikitext contains templates, for instance. getTransGloss: function(translationNode) { var node = translationNode; if (translationNode.nodeType === Node.ELEMENT_NODE && translationNode.nodeName === 'DIV' && translationNode.classList.contains('NavHead')) { var navFrame = translationNode.parentNode; if (!navFrame.classList.contains('NavFrame')) { console.trace('No NavFrame parent of %o', translationNode); return ''; } node = navFrame.getElementsByClassName('translations')[0]; if (!node) { console.trace('No child of parent of %o with "translations" class', translationNode); return ''; } } while (true) { if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'TABLE' && node.classList.contains('translations')) { return node.dataset.gloss; } node = node.parentNode; if (!node || node.id === 'mw-parser-output') break; } console.trace('Found no gloss in <table class="translations" data-gloss="..."> at or above %o', translationNode); return ''; }, isTrreq: function (li) { var span = li.getElementsByTagName('span')[0]; return (span && span.classList.contains("trreq")); }, genderList: { "s": "singular", "d": "dual", "p": "plural", "m": "masc.", "m-d": "masc. dual", "m-p": "masc. pl.", "f": "fem.", "f-d": "fem. dual", "f-p": "fem. pl.", "c": "common", "c-d": "common dual", "c-p": "common pl.", "n": "neuter", "n-d": "neuter dual", "n-p": "neuter pl.", "impf": "imperfective", "pf": "perfective" } }; // An adder for translations on en.wikt function TranslationAdders(editor) { function TranslationLabeller(insertDiv) { var original_span; var adder_form; var initial_value; var edit_button; var editing = false; var adderInterface = { 'fields': { 'gloss': function (txt, error) { return util.validateNoWikisyntax('gloss', true)(txt, error); } }, 'createForm': function () { var thisId = "a" + String(Math.random()).replace(".", ""); adder_form = newNode('form', { style: 'display: inline', width: 'auto', click: kill_event }, newNode('label', { 'for': thisId }, "Gloss: "), newNode('input', { type: 'text', name: 'gloss', value: initial_value, style: 'width: 50%', title: 'Insert a summary of the relevant definition', id: thisId }), newNode('input', { type: 'submit', name: 'preview', value: 'Preview' }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!') ); return adder_form; }, 'onsubmit': function (values, render) { render(values.gloss, function (new_html) { if (editing) toggle_editing(false); var old_html = original_span.innerHTML; editor.addEdit({ 'undo': function () { original_span.innerHTML = old_html; if (!editing) toggle_editing(); }, 'redo': function () { original_span.innerHTML = new_html; if (editing) toggle_editing(); }, 'edit': function (text) { return perform_edit(text, values.gloss); }, 'summary': 'tgloss:"' + (values.gloss.length > 50 ? values.gloss.substr(0, 50) + '...' : values.gloss + '"') }, original_span); }); } }; // The actual modification to the wikitext function perform_edit(wikitext, gloss) { var pos = util.getTransTable(wikitext, insertDiv)[0] - 4; var g_start = wikitext.lastIndexOf('\n{{trans-top', pos) + 1; var g_end = wikitext.indexOf('}}\n', pos) + 2; if (g_start === 0 || wikitext.substr(g_start, g_end - g_start).indexOf("\n") > -1) { editor.error("Could not find translation table."); return wikitext; } else { return wikitext.substr(0, g_start) + '{{trans-top|' + gloss + '}}' + wikitext.substr(g_end); } } // Don't open and close box when interacting with form. function kill_event(e) { e.stopPropagation(); } // What to do when the +/- button is clicked. function toggle_editing() { if (editing) { adder_form.style.display = "none"; original_span.style.display = "inline"; editing = false; return; } editing = true; edit_button.text("Loading..."); editor.withCurrentText(function (currentText) { var pos = util.getTransTable(currentText, insertDiv); edit_button.text('±'); if (!pos) return editor.error("Could not find translation table"); var gloss_line = currentText.substr(currentText.lastIndexOf('\n', pos[0] - 2) + 1); gloss_line = gloss_line.substr(0, gloss_line.indexOf('\n')); initial_value = gloss_line.replace(/^\{\{trans-top(\|(.*)|)\}\}\s*$/, "$2"); if (initial_value.indexOf("\n") > 0) return editor.error("Internal error: guess spanning multiple lines"); if (!original_span) { original_span = newNode('span', { 'class': 'wt-edit-recurse' }); for (var i = 0; i < insertDiv.childNodes.length; i++) { var child = insertDiv.childNodes[i]; if (child != edit_button[0] && child.className !== 'NavToggle') { original_span.appendChild(insertDiv.removeChild(child)); i--; } } insertDiv.appendChild(original_span); new AdderWrapper(editor, adderInterface, insertDiv, original_span); } original_span.style.display = "none"; adder_form.style.display = "inline"; adder_form.getElementsByTagName('input')[0].focus(); }); } edit_button = $('<a href="#">±</a>') //.addClass("translation-gloss-edit-button") .attr("title", "Edit table heading").css("padding", "2px").css("margin-left", "-5px") .on("click", function (e) { if (e && e.preventDefault) e.preventDefault(); kill_event(e); toggle_editing(); return false; }); $(insertDiv).prepend(edit_button); //XXX: this places anchor before NavToggle which may not be a good idea } function TranslationAdder(insertUl) { // Hippietrail var langmetadata = new LangMetadata(); this.fields = { lang: function (txt, error) { if (txt == 'en') return error("Please choose a foreign language. (fr, es, aaa)"); if (!/^[a-z]{2,3}(?:-[a-z]{2,3}){0,2}$/.test(txt)) return error("Please use a language code. (fr, es, aaa)"); return txt; }, word: function (txt, error) { if (txt == '{{trreq}}') return '{{t-needed}}'; if (txt == '{{t-needed}}') return txt; if (txt.indexOf(',') == -1 || forceComma) { forceComma = false; if (langmetadata.expectedCase(thiz.elements.lang.value, mw.config.get('wgTitle'), txt) || forceCase) { forceCase = false; return util.validateNoWikisyntax('translation', true)(txt, error); } if (prefs.get('case-knowledge', 'none') == 'none') { return error(newNode('span', "Translations normally don't have capital letters. If you're certain it does, you can ", newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { forceCase = true; inputForm.onsubmit(); prefs.set('case-knowledge', 'guru'); } }, "continue by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { prefs.set('case-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " unless you are certain that this translation has a capital letter."); error(msg); return txt; } } if (prefs.get('comma-knowledge', 'none') == 'none') { return error(newNode('span', "You can only add one translation at a time. If this is one translation that contains a comma, you can ", newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { forceComma = true; inputForm.onsubmit(); prefs.set('comma-knowledge', 'guru'); } }, "add it by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: var(--wikt-palette-blue, #0000FF); text-decoration: underline; cursor: pointer;", click: function () { prefs.set('comma-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " if you were trying to create a list of translations in one go, this is currently not supported."); error(msg); return txt; } }, qual: util.validateNoWikisyntax('qualifier'), tr: util.validateNoWikisyntax('transcription'), lit: util.validateNoWikisyntax('literal'), rawPageName: util.validateNoWikisyntax('raw page name'), nested: util.validateNoWikisyntax('nested'), "s": 'checkbox', "d": 'checkbox', "p": 'checkbox', "m": 'checkbox', "m-d": 'checkbox', "m-p": 'checkbox', "f": 'checkbox', "f-d": 'checkbox', "f-p": 'checkbox', "c": 'checkbox', "c-d": 'checkbox', "c-p": 'checkbox', "n": 'checkbox', "n-d": 'checkbox', "n-p": 'checkbox', "impf": 'checkbox', "pf": 'checkbox', nclass1: util.validateNoWikisyntax('noun class'), nclass2: util.validateNoWikisyntax('plural class') }; this.createForm = function () { function createGenderNode(name, text) { var inp = document.createElement("input"); inp.type = "checkbox"; inp.name = name; var lbl = document.createElement("label"); lbl.appendChild(inp); lbl.appendChild(document.createTextNode(text)); return lbl; } var genderControls = {}; for (var g in util.genderList) genderControls[g] = createGenderNode(g, util.genderList[g]); var controls = { lang: newNode('input', { size: 4, type: 'text', name: 'lang', value: prefs.get('curlang', ''), title: 'The two or three letter ISO 639 language code' }), transliteration: newNode('p', newNode('a', { href: '/wiki/Wiktionary:Transliteration' }, "Transliteration"), ": ", newNode('input', { name: "tr", title: "The word transliterated into the Latin alphabet." }), " (e.g. zìmǔ for 字母)"), literal: newNode('p', "Literal translation: ", newNode('input', { name: "lit", title: "The literal translation of the term." })), qualifier: newNode('p', "Qualifier: ", newNode('input', { name: 'qual', title: "A qualifier for the word" }), " (e.g. literally, formally, slang)"), display: newNode('p', "Raw page name: ", newNode('input', { name: 'rawPageName', title: "A link to lemma, if a translation is not a lemma." }), " (e.g. 疲れる for 疲れた)"), nested: newNode('p', "Nesting: ", newNode('input', { name: 'nested', title: "The nesting of this language" }), " (e.g. Serbo-Croatian/Cyrillic)"), // Genders genders: genderControls, // Noun class nclass: newNode('p', "Noun class: ", newNode('input', { type: 'text', size: 4, name: 'nclass1', title: "The noun class of the word in the singular or citation form." }), " Plural class: ", newNode('input', { type: 'text', size: 4, name: 'nclass2', title: "The noun class of the word in the plural form, if any." })) }; // suppress unused script field function createGenderDiv(genderz) { var $div = $("<div>"); for (var i = 1; i < arguments.length; i++) $div.append(genderz[arguments[i]]); return $div; } var $mdiv = createGenderDiv(controls.genders, "m", "m-d", "m-p"); var $fdiv = createGenderDiv(controls.genders, "f", "f-d", "f-p"); var $cdiv = createGenderDiv(controls.genders, "c", "c-d", "c-p"); var $ndiv = createGenderDiv(controls.genders, "n", "n-d", "n-p"); var $sdpdiv = createGenderDiv(controls.genders, "s", "d", "p"); var $pfdiv = createGenderDiv(controls.genders, "impf", "pf"); controls.gender = $("<p>").append($mdiv).append($fdiv).append($cdiv).append($ndiv).append($sdpdiv).append($pfdiv)[0]; langInput = controls.lang; var showButton = newNode('span', { 'click': function () { if (!advancedMode) { advancedMode = true; showButton.innerHTML = " Less"; } else { advancedMode = false; showButton.innerHTML = " More"; } updateFieldVisibility.call(langInput, true); }, 'style': "color: var(--wikt-palette-blue,#0000FF); cursor: pointer;" }, advancedMode ? " Less" : " More"); function autoTransliterate() { var rawPageName = langmetadata.computeRawPageName(thiz.elements.lang.value, thiz.elements.word.value); if (rawPageName && rawPageName !== thiz.elements.word.value) thiz.elements.rawPageName.value = rawPageName; } function updateFieldVisibility(preserve) { preserve = (preserve === true); //show all arguments function show() { for (var i = 0; i < arguments.length; i++) { if (arguments[i].nodeName == 'P') arguments[i].style.display = "block"; else arguments[i].style.display = "inline"; } } //hide all arguments function hide() { for (var i = 0; i < arguments.length; i++) arguments[i].style.display = "none"; } //if the first argument is false hide the remaining arguments, otherwise show them. function toggle(condition) { if (condition) //eww... show.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); else hide.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); } if (!preserve) langInput.value = langmetadata.cleanLangCode(langInput.value); var scriptGuess = langmetadata.guessScript(langInput.value || ''); if (!preserve) { thiz.elements.nested.value = langmetadata.getNested(langInput.value || ''); thiz.elements.nested.dataset.initialValue = thiz.elements.nested.value; autoTransliterate(); } var lang = langInput.value; if (!advancedMode) { var g = langmetadata.getGenders(lang); if (!lang) { hide(controls.gender); } else if (g === undefined) { hide(controls.gender); } else { for (var genderName in util.genderList) { toggle(g.indexOf(genderName) != -1, controls.genders[genderName]); } } toggle(g, controls.gender); toggle(langmetadata.hasNounClasses(lang), controls.nclass); var hasAutomaticTransliteration = new window.LanguageUtils().HasAutomaticTransliteration(lang); toggle(scriptGuess && scriptGuess != 'Latn' && !hasAutomaticTransliteration, controls.transliteration); toggle(langmetadata.needsRawPageName(lang), controls.display); hide(controls.literal, controls.qualifier, controls.nested); //only in more } else { show( controls.gender, controls.genders['s'], controls.genders['d'], controls.genders['p'], controls.genders['m'], controls.genders['m-d'], controls.genders['m-p'], controls.genders['f'], controls.genders['f-d'], controls.genders['f-p'], controls.genders['c'], controls.genders['c-d'], controls.genders['c-p'], controls.genders['n'], controls.genders['n-d'], controls.genders['n-p'], controls.genders['impf'], controls.genders['pf'], controls.nclass, controls.transliteration, controls.literal, controls.qualifier, controls.display, controls.nested); } } //autocomplete language names function langAutoFill(e) { e = (e || event).keyCode; if ((e >= 33 && e <= 40) || e == 8 || e == 46 || e == 27 || e == 16) { return; } var t = this, langPrefix = t.value; if (langPrefix.substr(0, 1) != langPrefix.substr(0, 1).toUpperCase()) { return; } new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:languages/javascript-interface|GetSingleLanguageByLanguagePrefix|" + langPrefix + "}}", "prop": "wikitext" }).done(function (r) { if (r.expandtemplates && r.expandtemplates.wikitext !== "") { var langcode = r.expandtemplates.wikitext.split(":")[0]; var langname = r.expandtemplates.wikitext.split(":")[1]; var oldLength = t.value.length; t.value = langname; $(t).data("langcode", langcode); if (t.setSelectionRange) { t.setSelectionRange(oldLength, langname.length); } else if (t.createTextRange) { var z = t.createTextRange(); z.moveEnd('character', 0 - z.move('character', [t.value.length, t.value = langname][0]) + t.value.length); z.select(); } } else { $(t).removeData("langcode"); } }); } langInput.onkeyup = langAutoFill; langInput.onblur = function () { if ($(this).data("langcode")) $(this).val($(this).data("langcode")); updateFieldVisibility.call(langInput); }; window.setTimeout(function () { updateFieldVisibility.call(langInput); }, 0); inputForm = newNode('form', newNode('p', newNode('a', { href: "/wiki/MediaWiki:Gadget-TranslationAdder.js/help#Usage" }, "Add translation"), ' ', langInput, newNode('b', ': '), newNode('input', { 'name': 'word', size: 20, keyup: autoTransliterate, change: autoTransliterate }), newNode('input', { 'type': 'submit', 'value': 'Preview translation' }), showButton ), controls.gender, controls.nclass, controls.transliteration, controls.literal, controls.display, controls.qualifier, controls.nested ); return inputForm; }; this.onsubmit = function (values, render) { var wikitext; function callRender() { render(wikitext, function (html) { registerEdits(values, wikitext, html); }); } // Keep track of whether the "nested" field has changed // so that we can tag the edit values.nestedChanged = inputForm.nested.dataset.initialValue !== values.nested; var languagePrefix = '{{subst:#invoke:languages/templates|getByCodeAllowEtym|' + values.lang + '|getCanonicalName}}: '; if (values.word.indexOf('{{t-needed') === 0) { wikitext = languagePrefix + ' {{t-needed|' + values.lang + '}}'; callRender(); } else { langmetadata.retrieveRawPageName(values.lang, values.word, values.rawPageName, function (rawPageName, needsRawPageName) { if (needsRawPageName) { values.rawPageName = rawPageName; values.wordMinus = ''; } else { values.rawPageName = ''; values.wordMinus = rawPageName; } langmetadata.hasWiktionaryWithEntry(values.lang, values.rawPageName || values.wordMinus, function (hasInterwiki) { var templateBody = '|' + values.lang + '|' + langmetadata.applyOrthographicalCorrections(values.lang, values.rawPageName || values.word) + (values.nclass1 ? '|c' + values.nclass1 : '') + (values.nclass2 ? '|c' + values.nclass2 : ''); // Add gender codes templateBody += [ 's', 'd', 'p', 'm', 'm-d', 'm-p', 'f', 'f-d', 'f-p', 'c', 'c-d', 'c-p', 'n', 'n-d', 'n-p', 'impf', 'pf' ].map(function(k) { return values[k] ? '|' + k : ''; }).join(""); templateBody += (values.tr ? '|tr=' + values.tr : '') + (values.lit ? '|lit=' + values.lit : '') + (values.rawPageName ? '|alt=' + values.word : ''); var qualifier = values.qual ? ' {{q|' + values.qual + '}}' : ''; wikitext = languagePrefix + "{{" + (hasInterwiki ? "t+" : "t") + templateBody + "}}" + qualifier; callRender(); }); }); } }; var thiz = this; var prefs = new CookiePreferences('EditorJs'); var langInput; var inputForm; var advancedMode = prefs.get('more-display', 'none') != 'none'; var forceComma = false; var forceCase = false; //Reset elements to default values. function resetElements() { if (prefs.get('more-display', 'none') != advancedMode ? 'block' : 'none') prefs.set('more-display', advancedMode ? 'block' : 'none'); //named for compatibility thiz.elements.word.value = thiz.elements.nclass1.value = thiz.elements.nclass2.value = thiz.elements.lit.value = thiz.elements.tr.value = thiz.elements.rawPageName.value = thiz.elements.qual.value = ''; thiz.elements['s'].checked = false; thiz.elements['d'].checked = false; thiz.elements['p'].checked = false; thiz.elements['m'].checked = false; thiz.elements['m-d'].checked = false; thiz.elements['m-p'].checked = false; thiz.elements['f'].checked = false; thiz.elements['f-d'].checked = false; thiz.elements['f-p'].checked = false; thiz.elements['c'].checked = false; thiz.elements['c-d'].checked = false; thiz.elements['c-p'].checked = false; thiz.elements['n'].checked = false; thiz.elements['n-d'].checked = false; thiz.elements['n-p'].checked = false; thiz.elements['impf'].checked = false; thiz.elements['pf'].checked = false; prefs.set('curlang', thiz.elements.lang.value); } // This is onsubmit after the wikitext has been rendered to give content function registerEdits(values, wikitext, content) { var li = newNode('li', { 'class': 'trans-' + values.lang }); li.innerHTML = content; var lang = getLangName(li); var x = langmetadata.applyOrthographicalCorrections(values.lang, values.rawPageName || values.word); var resp = x; var langCodeBad = false; if (x.indexOf("{{") < 0) { new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{ll|" + values.lang + "|" + x + "}}", "prop": "wikitext" }, {"async": false}).done(function (r) { if (r.expandtemplates && r.expandtemplates.wikitext) { // [[page#Language|display]] // resp = r.expandtemplates.wikitext; // [[page|display]] // resp = r.expandtemplates.wikitext.replace(/#[^|]*/, ""); // [[page]] resp = r.expandtemplates.wikitext.replace(/#[^\]]*/, ""); try { if (DOMParser && new DOMParser().parseFromString(r.expandtemplates.wikitext, "text/html").querySelector(".scribunto-error")) langCodeBad = true; } catch (e) { } } }).fail(function(r) { console.error(r); resp = resp.includes("[[") ? resp : "[[" + resp + "]]"; }); } if (langCodeBad) return editor.error("Unrecognized language code '" + values.lang + "'"); var summary = 't+' + values.lang + ':' + resp; var insertBefore = null; var nextLanguage = null; var nestedHeading, nestedLang; var nested = values.nested.split('/'); if (nested.length > 1) { nestedHeading = nested[0]; nestedLang = (nested[1] === 'Roman' ? 'Latin' : nested[1]); // [[Wiktionary:Beer parlour/2026/January#sorting and reformating translation tables]] if (nestedHeading === '') nestedHeading = lang; content = content.replace(/.*: /, nestedLang + ": "); wikitext = wikitext.replace("subst:", "").replace(/.*: /, nestedLang + ": "); } else { nestedHeading = values.nested; nestedLang = lang; } var nestedWikitext = "\n* " + nestedHeading + ":\n*: " + wikitext; function addEdit(edit, span) { var fields = ["lang", "word", "nclass1", "nclass2", "rawPageName", "qual", "tr", "lit"]; editor.addEdit({ 'undo': function () { edit.undo(); if (thiz.elements.word.value === "" && thiz.elements.nclass1.value === "" && thiz.elements.nclass2.value === "" && thiz.elements.tr.value === "" && thiz.elements.lit.value === "" && thiz.elements.rawPageName.value === "" && thiz.elements.qual.value === "") { for (var i = 0; i < fields.length; i++) { thiz.elements[fields[i]].value = values[fields[i]]; } for (var genderName in util.genderList) { thiz.elements[genderName].checked = values[genderName]; } } }, 'redo': function () { edit.redo(); for (var i = 0; i < fields.length; i++) { if (thiz.elements[fields[i]].value != values[fields[i]]) return; } resetElements(); }, 'edit': edit.edit, 'tags': [values.nestedChanged ? 'translation-adder-custom-nesting' : null], 'summary': summary }, span); } // Compare language names without accents and punctuation marks var normalizeAndStrip = s => s.normalize("NFD").replace(/[\u0300-\u036f'ʼ", -]/g, '').toUpperCase(); var compare = function(a, b) { if (normalizeAndStrip(a) < normalizeAndStrip(b)) { return -1; } if (normalizeAndStrip(a) > normalizeAndStrip(b)) { return 1; } if (a < b) { return -1; } if (a > b) { return 1; } return 0; } if (lang) { //Get all li's in this table row. var lss = $(insertUl).parent().parent().find('li').get(); var dds = $(insertUl).parent().parent().find('dd').get(); var lis = lss.concat(dds); for (var j = 0; j < lis.length; j++) { if (lis[j].getElementsByTagName('form').length > 0) continue; var ln = getLangName(lis[j]); if (ln == lang) { if (values.word == '{{t-needed}}') { addEdit({ 'redo': function () { }, 'undo': function () { }, 'edit': function () { return editor.error("Can not add a translation request for a language with translations"); } }); return resetElements(); } var span = newNode('span'); var parent = lis[j]; if (util.isTrreq(parent)) { span.innerHTML = content.substr(content.indexOf(':') + 1); var trspan = parent.getElementsByTagName('span')[0]; addEdit({ 'redo': function () { parent.removeChild(trspan); parent.appendChild(span); }, 'undo': function () { parent.removeChild(span); parent.appendChild(trspan); }, 'edit': getEditFunction(values, wikitext, ln, values.lang, true, function (text, ipos) { //Converting a Translation request into a translation var lineend = text.indexOf('\n', ipos); return text.substr(0, ipos) + wikitext + text.substr(lineend); }) }, span); return resetElements(); } else if (parent.tagName !== 'DD' || lang !== 'Latin') { if (parent.getElementsByTagName('ul').length + parent.getElementsByTagName('dl').length == 0) { span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.appendChild(span) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) { //We are adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + text.substr(lineend); }) }, span); return resetElements(); } else { var node = parent.firstChild; var hastrans = false; while (node) { if (node.nodeType == 1) { var nn = node.nodeName; if (nn == 'UL' || nn == 'DL') { // If we want to use the dialectical nesting for orthographical nesting // then we need to skip this (otherwise perfect) match. if (!hastrans && nestedHeading == ln) { node = node.nextSibling; continue; } span.innerHTML = (hastrans ? ", " : " ") + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.insertBefore(span, node) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) { //Adding the translation to a language that has nested translations under it var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + (hastrans ? "," : "") + wt + text.substr(lineend); }) }, span); return resetElements(); } else { hastrans = true; } } node = node.nextSibling; } } } } else if (ln && compare(ln, lang) > 0 && (!nextLanguage || compare(ln, nextLanguage) < 0) && lis[j].parentNode.parentNode.nodeName != 'LI') { nextLanguage = ln; var parent = lis[j]; insertBefore = [{ 'redo': function () { parent.parentNode.insertBefore(li, parent); }, 'undo': function () { parent.parentNode.removeChild(li) }, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new language's translation before another language's translation var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + "\n* " + wikitext + text.substr(lineend); }) }, li]; } } } if (values.nested) { nextLanguage = null; insertBefore = null; li.innerHTML = nestedHeading + ":" + "<dl><dd class=\"trans-" + values.lang + "\">" + content + "</dd></dl>"; var lis = insertUl.parentNode.parentNode.getElementsByTagName('li'); for (var j = 0; j < lis.length; j++) { //Ignore the editor form if (lis[j].getElementsByTagName('form').length > 0) continue; //Don't look at nested translations if (lis[j].parentNode.parentNode.nodeName != 'TD') continue; var ln = getLangName(lis[j]); if (ln == nestedHeading) { var sublis = lis[j].getElementsByTagName('li'); if (!sublis.length) sublis = lis[j].getElementsByTagName('dd'); if (sublis.length == 0) { var parent = lis[j]; var dd = newNode('dd', { 'class': 'trans-' + values.lang }); var dl = newNode('dl', dd); dd.innerHTML = content; addEdit({ 'redo': function () { parent.appendChild(dl); }, 'undo': function () { parent.removeChild(dl); }, 'edit': getEditFunction(values, wikitext, nestedHeading, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new dl to an existing translation line var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + "\n*: " + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } else { var dd = newNode(sublis[0].nodeName, { 'class': 'trans-' + values.lang }); var linestart = dd.nodeName == 'DD' ? '\n*: ' : '\n** '; dd.innerHTML = content; for (var k = 0; k < sublis.length; k++) { var subln = getLangName(sublis[k]); var parent = sublis[k]; if (subln == nestedLang) { var span = newNode('span'); span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.appendChild(span) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, nestedLang, values.lang, false, function (text, ipos) { // Adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + text.substr(lineend); }) }, span); return resetElements(); } else if (langmetadata.nestsBefore(nestedLang, subln)) { addEdit({ 'redo': function () { parent.parentNode.insertBefore(dd, parent); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation in-order var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } addEdit({ 'redo': function () { parent.parentNode.appendChild(dd); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation at the end of its group var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } else if (ln && compare(ln, nestedHeading) > 0 && (!nextLanguage || compare(ln, nextLanguage) < 0)) { nextLanguage = ln; var parent = lis[j]; insertBefore = [{ 'redo': function () { parent.parentNode.insertBefore(li, parent); }, 'undo': function () { parent.parentNode.removeChild(li) }, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { //Adding a new nested translation section. var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + nestedWikitext + text.substr(lineend); }) }, li]; } } wikitext = nestedHeading + ":\n*: " + wikitext; } li.className = "trans-" + values.lang; if (insertBefore) { addEdit(insertBefore[0], insertBefore[1]); } else { //Append the translations to the end (no better way found) addEdit({ 'redo': function () { insertUl.appendChild(li); }, 'undo': function () { insertUl.removeChild(li) }, 'edit': getEditFunction(values, wikitext) }, li); } return resetElements(); } //Get the wikitext modification for the current form submission. function getEditFunction(values, wikitext, findLanguage, findLangCode, trreq, callback) { return function (text) { var p = util.getTransTable(text, insertUl); if (!p) return editor.error("Could not find translation table for '" + values.lang + ":" + values.word + "'. Glosses should be unique"); var stapos = p[0]; var endpos = p[1]; if (findLanguage) { var ipos = 0; if (trreq) { ipos = text.substr(stapos).search(new RegExp(mw.util.escapeRegExp(findLanguage) + ":\\s*\\{\\{t-needed(?:\\|" + findLangCode + "}})?")) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLanguage + '}}', stapos); if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLangCode + '}}', stapos); } // If we have a nested trreq, then we still need to look for the non-trreq form of the heading language if (!trreq || ipos < stapos || ipos > endpos) { var escapedLang = mw.util.escapeRegExp(findLanguage); //if the translation should not be nested it should not go before any nested language var regexByShouldFindSubLanguage = values.nested != "" ? "[:*]?" : ""; var possibleRegexes = [ RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\[\\[" + escapedLang + "\\]\\]:"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?" + escapedLang + ":"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\{\\{ttbc\\|" + escapedLang + "}}:") ]; ipos = text.substr(stapos).search(possibleRegexes[0]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[1]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[2]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{subst:#invoke:languages/templates|getByCodeAllowEtym|' + findLangCode + '|getCanonicalName}}:', stapos); } if (ipos >= stapos && ipos < endpos) { return callback(text, ipos, trreq); } else { return editor.error("Could not find translation entry for '" + values.lang + ":" + values.word + "'. Please reformat"); } } return text.substr(0, endpos) + "* " + wikitext + "\n" + text.substr(endpos); }; } // For an <li> in well-formed translation sections, return the language name. function getLangName(li) { var guess = li.textContent || li.innerText; if (guess) guess = guess.substr(0, guess.indexOf(':')); if (guess == 'Template') { return false; } return guess.replace(/^[\s\n]*/, ''); } // Try to get the language code from an <li> containing {{t}}, {{t+}} or {{t-}} function getLangCode(li) { if (li.className.indexOf('trans-') === 0) return li.className.substr(6); var spans = li.getElementsByTagName('span'); for (var i = 0; i < spans.length; i++) { if (spans[i].lang) { return spans[i].lang; } if (spans[i].dataset && spans[i].dataset.lang) { return spans[i].dataset.lang; } } return false; } } function createTranslationAdderRow(li) { var $ul = $("<ul>").append(li); return $("<tr>") .append($("<td>")) .append($("<td>")) .append($("<td>").css("text-align", "left").append($ul)); } $('table.translations').each(function () { if (util.getTransGloss(this) != 'Translations to be checked') { var tdSelector = "td:not(.mw-hiero-table td):not(.targeted-translations-select)"; var uls = $(this).find(tdSelector + " > ul").get(); if (uls.length == 0) { $(this).find(tdSelector)[0].appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } if (uls.length == 1) { var td = $(this).find(tdSelector)[2]; if (td) { td.appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } } if (uls) { var li = document.createElement('li'); var ul = uls[uls.length - 1]; $(this).append(createTranslationAdderRow(li)); new AdderWrapper(editor, new TranslationAdder(ul), li); if (true) {// XXX: why not? (new CookiePreferences('EditorJs')).get('labeller') == 'true') { var div = $(this).parent().parent().find('div.NavHead')[0]; if (div) { new TranslationLabeller(div) } } } } }); } $(function () { // Check if we are on a sensible page var isOnPrintable = mw.util.getParamValue("printable") !== null; var isDiff = mw.util.getParamValue("diff") !== null || mw.util.getParamValue("oldid") !== null; if (mw.config.get('wgAction') != 'view' || isOnPrintable || isDiff) return; var editor = new Editor(); TranslationAdders(editor); /* // Check that we have not been disabled var prefs = new CookiePreferences('EditorJs'); if (prefs.get('enabled', 'true') == 'true') { if (!window.loadedEditor) { prefs.setDefault('labeller', mw.config.get('wgUserName') ? 'true' : 'false'); window.loadedEditor = true; } } // The enable-disable button on WT:EDIT var node = document.getElementById('editor-js-disable-button'); if (node) { node.innerHTML = ""; var toggle = newNode('span', { click: function() { if (prefs.get('enabled', 'true') == 'true') { toggle.innerHTML = "Enable"; prefs.set('enabled', 'false'); } else { toggle.innerHTML = "Disable"; prefs.set('enabled', 'true'); } } }, (prefs.get('enabled', 'true') == 'true' ? 'Disable' : 'Enable')) node.appendChild(toggle); } var node = document.getElementById("editor-js-labeller-button"); if (node) { node.innerHTML = ""; var toggle2 = newNode('span', { click: function() { if (prefs.get('labeller') == 'true') { toggle2.innerHTML = "Enable"; prefs.set('labeller', 'false'); } else { toggle2.innerHTML = "Disable"; prefs.set('labeller', 'true'); } } }, (prefs.get('labeller') == 'true' ? 'Disable' : 'Enable')) node.appendChild(toggle2); }*/ }); //</nowiki> // </syntaxhighlight> fenbzaedj1d7qphc980f0ohcrd0z8qg MediaWiki:Gadget-BlockInfo.js 8 17958 88918 2017-05-13T16:14:01Z en>-sche 0 88918 javascript text/javascript // {{documentation}} /*jshint undef:true */ /*global jQuery, mw */ (function(){ 'use strict'; var api = new mw.Api(); function el(tag, child, attr, events) { var key, node = document.createElement(tag); if (child) { if (typeof child !== 'object') child = [child]; for (var i = 0; i < child.length; ++i) { var ch = child[i]; if ((ch === void(null)) || (ch === null)) continue; else if (typeof ch !== 'object') ch = document.createTextNode(String(ch)); node.appendChild(ch); } } if (attr) for (key in attr) { node.setAttribute(key, String(attr[key])); } if (events) for (key in events) { node.addEventListener(key, events[key], false); } return node; } function fmtDate(date) { // XXX: uses browser's time zone instead of preferences date = new Date(date); switch (mw.user.options.get('date')) { case 'dmy' : return date.toLocaleTimeString() + ', ' + date.getDate() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear(); case 'mdy' : return date.toLocaleTimeString() + ', ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear() + ', ' + date.getDate(); case 'ymd' : return date.toLocaleTimeString() + ', ' + date.getFullYear() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getDate(); case 'default' : return date.toLocaleString(); case 'ISO 8601': return date.toISOString(); } } var wd2iw = { 'metawiki': 'm' }; function buildList(user, callback) { var isAnon = mw.util.isIPv4Address(user) || mw.util.isIPv6Address(user); var rq = api.get({ action: 'query', list: 'blocks' + (isAnon ? '|globalblocks' : '|globalallusers'), // blocks bkip: isAnon ? user : void(window.warranty), bkusers: isAnon ? void(window.warranty) : user, bkprop: 'id|user|range|timestamp|expiry|by|reason|flags', bkdir: 'older', // globalblocks bgip: isAnon ? user : void(window.warranty), bgprop: isAnon ? 'id|address|range|timestamp|expiry|by|reason' : void(window.warranty), bgdir: isAnon ? 'older' : void(window.warranty), // globalallusers agufrom: !isAnon ? user : void(window.warranty), aguto: !isAnon ? user : void(window.warranty), agulimit: !isAnon ? 1 : void(window.warranty), aguprop: !isAnon ? 'lockinfo' : void(window.warranty) }); rq.then(function (result) { var list = el('ul'), item, i; if (result.query.globalallusers && result.query.globalallusers[0] && ('locked' in result.query.globalallusers[0])) { list.appendChild(el('li', [ "This account is globally locked", " (", el('a', "globalauth log", { href: mw.util.getUrl('m:Special:Log/globalauth', { page: 'User:' + user + '@global' }) }), ")." ])); } for (i = 0; i < result.query.blocks.length; ++i) { item = result.query.blocks[i]; list.appendChild(el('li', [ fmtDate(item.timestamp), ': ', el('a', item.by, { href: mw.util.getUrl('User:' + item.by) }), " blocked ", el('b', item.user), " (", el('a', 'block log', { href: mw.util.getUrl('Special:Log/block', { page: 'User:' + item.user }) }), "),", ' expiring ', el('b', item.expiry === 'infinity' ? 'never' : fmtDate(item.expiry)), item.reason && " (", item.reason, item.reason && ")", ])); } if (result.query.globalblocks) for (i = 0; i < result.query.globalblocks.length; ++i) { item = result.query.globalblocks[i]; list.appendChild(el('li', [ fmtDate(item.timestamp), ': ', el('a', item.by, { href: mw.util.getUrl(wd2iw[item.bywiki] + ':User:' + item.by) }), " at ", el('code', item.bywiki), " globally blocked ", el('b', item.address), " (", el('a', "gblblock log", { href: mw.util.getUrl(wd2iw[item.bywiki] + ':Special:Log/gblblock', { page: 'User:' + item.address }) }), "),", " expiring ", el('b', item.expiry === 'infinity' ? "never" : fmtDate(item.expiry)), item.reason && " (", item.reason, item.reason && ")", ])); } callback(list); }); return rq; } function makeBox(user, relTo) { if (!user) return; relTo = relTo || document.getElementById('mw-content-text'); var afterList, box = el('div', [ el('p', [el('strong', user), ' is currently blocked.']), afterList = el('small', [ el('a', "block log" , { href: mw.util.getUrl('Special:Log/block', { page: 'User:' + user }) }) ]) ], { 'class': 'mw-warning-with-logexcerpt' }); relTo.rq = buildList(user, function (list) { relTo.rq = null; if (!list.hasChildNodes()) return; box.insertBefore(list, afterList); relTo.parentNode.insertBefore(box, relTo); }); return box; } var user; var wgNamespaceNumber = mw.config.get('wgNamespaceNumber'); var wgNamespaceIds = mw.config.get('wgNamespaceIds'); var wgTitle = mw.config.get('wgTitle'); if ((wgNamespaceNumber & ~1) === wgNamespaceIds.user) { makeBox(wgTitle.replace(/\/.*$/, '')); } else if ((mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') || (mw.config.get('wgCanonicalSpecialPageName') === 'DeletedContributions')) { makeBox(wgTitle.indexOf('/') !== -1 ? wgTitle.replace(/^.*?\//, '') : mw.util.getParamValue('target')); } else if (mw.config.get('wgCanonicalSpecialPageName') === 'Log') { user = mw.util.getParamValue('user'); if (/^[^\/]+\/(block|delete)$/.test(wgTitle)) return; if (wgTitle.indexOf('/') !== -1) user = wgTitle.replace(/^.*\//, ''); makeBox(user); } else if (mw.config.get('wgCanonicalSpecialPageName') === 'Block') { var ipinput = document.getElementById('mw-bi-target'); var relTo = ipinput.form.getElementsByTagName('legend')[0].nextSibling; var warnnode = null; var refresh = function () { if (relTo.rq) relTo.rq.abort(); if (warnnode && warnnode.parentNode) { warnnode.parentNode.removeChild(warnnode); warnnode = null; } if (!ipinput.value) return; warnnode = makeBox(ipinput.value, relTo); }; var tmout; ipinput.addEventListener('input', function () { clearTimeout(tmout); tmout = setTimeout(refresh, 500); }, false); ipinput.addEventListener('change', function () { refresh(); }, false); refresh(); return; } })(); r2okjk3b3yr52txn6t4pem85ctk3im8 88919 88918 2026-08-06T23:13:15Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-BlockInfo.js]] 88918 javascript text/javascript // {{documentation}} /*jshint undef:true */ /*global jQuery, mw */ (function(){ 'use strict'; var api = new mw.Api(); function el(tag, child, attr, events) { var key, node = document.createElement(tag); if (child) { if (typeof child !== 'object') child = [child]; for (var i = 0; i < child.length; ++i) { var ch = child[i]; if ((ch === void(null)) || (ch === null)) continue; else if (typeof ch !== 'object') ch = document.createTextNode(String(ch)); node.appendChild(ch); } } if (attr) for (key in attr) { node.setAttribute(key, String(attr[key])); } if (events) for (key in events) { node.addEventListener(key, events[key], false); } return node; } function fmtDate(date) { // XXX: uses browser's time zone instead of preferences date = new Date(date); switch (mw.user.options.get('date')) { case 'dmy' : return date.toLocaleTimeString() + ', ' + date.getDate() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear(); case 'mdy' : return date.toLocaleTimeString() + ', ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear() + ', ' + date.getDate(); case 'ymd' : return date.toLocaleTimeString() + ', ' + date.getFullYear() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getDate(); case 'default' : return date.toLocaleString(); case 'ISO 8601': return date.toISOString(); } } var wd2iw = { 'metawiki': 'm' }; function buildList(user, callback) { var isAnon = mw.util.isIPv4Address(user) || mw.util.isIPv6Address(user); var rq = api.get({ action: 'query', list: 'blocks' + (isAnon ? '|globalblocks' : '|globalallusers'), // blocks bkip: isAnon ? user : void(window.warranty), bkusers: isAnon ? void(window.warranty) : user, bkprop: 'id|user|range|timestamp|expiry|by|reason|flags', bkdir: 'older', // globalblocks bgip: isAnon ? user : void(window.warranty), bgprop: isAnon ? 'id|address|range|timestamp|expiry|by|reason' : void(window.warranty), bgdir: isAnon ? 'older' : void(window.warranty), // globalallusers agufrom: !isAnon ? user : void(window.warranty), aguto: !isAnon ? user : void(window.warranty), agulimit: !isAnon ? 1 : void(window.warranty), aguprop: !isAnon ? 'lockinfo' : void(window.warranty) }); rq.then(function (result) { var list = el('ul'), item, i; if (result.query.globalallusers && result.query.globalallusers[0] && ('locked' in result.query.globalallusers[0])) { list.appendChild(el('li', [ "This account is globally locked", " (", el('a', "globalauth log", { href: mw.util.getUrl('m:Special:Log/globalauth', { page: 'User:' + user + '@global' }) }), ")." ])); } for (i = 0; i < result.query.blocks.length; ++i) { item = result.query.blocks[i]; list.appendChild(el('li', [ fmtDate(item.timestamp), ': ', el('a', item.by, { href: mw.util.getUrl('User:' + item.by) }), " blocked ", el('b', item.user), " (", el('a', 'block log', { href: mw.util.getUrl('Special:Log/block', { page: 'User:' + item.user }) }), "),", ' expiring ', el('b', item.expiry === 'infinity' ? 'never' : fmtDate(item.expiry)), item.reason && " (", item.reason, item.reason && ")", ])); } if (result.query.globalblocks) for (i = 0; i < result.query.globalblocks.length; ++i) { item = result.query.globalblocks[i]; list.appendChild(el('li', [ fmtDate(item.timestamp), ': ', el('a', item.by, { href: mw.util.getUrl(wd2iw[item.bywiki] + ':User:' + item.by) }), " at ", el('code', item.bywiki), " globally blocked ", el('b', item.address), " (", el('a', "gblblock log", { href: mw.util.getUrl(wd2iw[item.bywiki] + ':Special:Log/gblblock', { page: 'User:' + item.address }) }), "),", " expiring ", el('b', item.expiry === 'infinity' ? "never" : fmtDate(item.expiry)), item.reason && " (", item.reason, item.reason && ")", ])); } callback(list); }); return rq; } function makeBox(user, relTo) { if (!user) return; relTo = relTo || document.getElementById('mw-content-text'); var afterList, box = el('div', [ el('p', [el('strong', user), ' is currently blocked.']), afterList = el('small', [ el('a', "block log" , { href: mw.util.getUrl('Special:Log/block', { page: 'User:' + user }) }) ]) ], { 'class': 'mw-warning-with-logexcerpt' }); relTo.rq = buildList(user, function (list) { relTo.rq = null; if (!list.hasChildNodes()) return; box.insertBefore(list, afterList); relTo.parentNode.insertBefore(box, relTo); }); return box; } var user; var wgNamespaceNumber = mw.config.get('wgNamespaceNumber'); var wgNamespaceIds = mw.config.get('wgNamespaceIds'); var wgTitle = mw.config.get('wgTitle'); if ((wgNamespaceNumber & ~1) === wgNamespaceIds.user) { makeBox(wgTitle.replace(/\/.*$/, '')); } else if ((mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') || (mw.config.get('wgCanonicalSpecialPageName') === 'DeletedContributions')) { makeBox(wgTitle.indexOf('/') !== -1 ? wgTitle.replace(/^.*?\//, '') : mw.util.getParamValue('target')); } else if (mw.config.get('wgCanonicalSpecialPageName') === 'Log') { user = mw.util.getParamValue('user'); if (/^[^\/]+\/(block|delete)$/.test(wgTitle)) return; if (wgTitle.indexOf('/') !== -1) user = wgTitle.replace(/^.*\//, ''); makeBox(user); } else if (mw.config.get('wgCanonicalSpecialPageName') === 'Block') { var ipinput = document.getElementById('mw-bi-target'); var relTo = ipinput.form.getElementsByTagName('legend')[0].nextSibling; var warnnode = null; var refresh = function () { if (relTo.rq) relTo.rq.abort(); if (warnnode && warnnode.parentNode) { warnnode.parentNode.removeChild(warnnode); warnnode = null; } if (!ipinput.value) return; warnnode = makeBox(ipinput.value, relTo); }; var tmout; ipinput.addEventListener('input', function () { clearTimeout(tmout); tmout = setTimeout(refresh, 500); }, false); ipinput.addEventListener('change', function () { refresh(); }, false); refresh(); return; } })(); r2okjk3b3yr52txn6t4pem85ctk3im8 MediaWiki:Gadget-RevdelInfo.js 8 17959 88920 2025-09-17T22:20:59Z en>Ioaxxere 0 [[mw:Migrating mw.Uri to URL]] 88920 javascript text/javascript // {{documentation}} /*jshint undef:true */ /*global mw, jQuery */ (function(){ var api = new mw.Api(); function el(tag, child, attr, events) { var node = document.createElement(tag); if (child) { if (typeof child !== 'object') child = [child]; for (var i = 0; i < child.length; ++i) { var ch = child[i]; if ((ch === void(null)) || (ch === null)) continue; else if (typeof ch !== 'object') ch = document.createTextNode(String(ch)); node.appendChild(ch); } } if (attr) for (var key in attr) { node.setAttribute(key, String(attr[key])); } if (events) for (var key in events) { node.addEventListener(key, events[key], false); } return node; } function fmtDate(date) { // XXX: uses browser's time zone instead of preferences date = new Date(date); switch (mw.user.options.get('date')) { case 'dmy' : return date.toLocaleTimeString() + ', ' + date.getDate() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear(); case 'mdy' : return date.toLocaleTimeString() + ', ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear() + ', ' + date.getDate(); case 'ymd' : return date.toLocaleTimeString() + ', ' + date.getFullYear() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getDate(); case 'default' : return date.toLocaleString(); case 'ISO 8601': return date.toISOString(); } } function makeBox(rev1, rev2) { var query = { 'action': 'query', 'list': 'logevents', 'leaction': 'delete/revision', 'letitle': mw.config.get('wgPageName'), 'continue': '' }; var list, node = el('div', [ el('p', 'Details from the deletion log:'), list = el('ul') ], { 'class': 'mw-warning-with-logexcerpt', 'style': 'display: none;' }); function processResult(result) { var events = result.query.logevents; for (var i = 0; i < events.length; ++i) { if ((events[i][1] === rev1) || (events[i][1] === rev2)) { var item = events[i]; // XXX: item[2] and item[3] contain flags... might as well show these too // XXX: change link to plaintext based on whether the user has the 'deleterevision' right list.appendChild(el('li', [ fmtDate(item.timestamp), ": ", el('a', item.user, { href: mw.util.getUrl('User:' + item.user) }), " changed visibility of ", el('a', ["revision ", item[1]], { href: mw.util.getUrl(mw.config.get('wgPageName'), { oldid: item[1], unhide: '1' }) }), item.comment && " (", item.comment, item.comment && ")" ])); node.style.display = ''; } } if (result['continue']) { for (var key in result['continue']) query[key] = result['continue'][key]; api.get(query).then(processResult); } } api.get(query).then(processResult); return node; } if (mw.config.get('wgAction') !== 'view') return; if (!(mw.util.getParamValue('diff') || mw.util.getParamValue('oldid'))) return; if (document.getElementById('mw-rev-deleted-no-diff') || document.getElementById('mw-rev-deleted-unhide-diff')) { var rev1, rev2; var ot = document.getElementById('mw-diff-otitle1'); var nt = document.getElementById('mw-diff-ntitle1'); if (ot) { ot = new URL(ot.getElementsByTagName('a')[0].href); rev1 = ot.searchParams.get("oldid"); } if (nt) { nt = new URL(nt.getElementsByTagName('a')[0].href); rev2 = nt.searchParams.get("oldid"); } document.getElementById('mw-content-text').appendChild(makeBox(rev1, rev2)); } else if (document.getElementById('mw-content-text').firstChild.classList.contains('mw-warning')) { // ugly, ugly hack var rev = mw.util.getParamValue('oldid'); document.getElementById('mw-content-text').appendChild(makeBox(rev, null)); } })(); qwg4k57088l5momuwnfv9a1chm6srrl 88921 88920 2026-08-06T23:13:24Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-RevdelInfo.js]] 88920 javascript text/javascript // {{documentation}} /*jshint undef:true */ /*global mw, jQuery */ (function(){ var api = new mw.Api(); function el(tag, child, attr, events) { var node = document.createElement(tag); if (child) { if (typeof child !== 'object') child = [child]; for (var i = 0; i < child.length; ++i) { var ch = child[i]; if ((ch === void(null)) || (ch === null)) continue; else if (typeof ch !== 'object') ch = document.createTextNode(String(ch)); node.appendChild(ch); } } if (attr) for (var key in attr) { node.setAttribute(key, String(attr[key])); } if (events) for (var key in events) { node.addEventListener(key, events[key], false); } return node; } function fmtDate(date) { // XXX: uses browser's time zone instead of preferences date = new Date(date); switch (mw.user.options.get('date')) { case 'dmy' : return date.toLocaleTimeString() + ', ' + date.getDate() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear(); case 'mdy' : return date.toLocaleTimeString() + ', ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getFullYear() + ', ' + date.getDate(); case 'ymd' : return date.toLocaleTimeString() + ', ' + date.getFullYear() + ' ' + mw.language.months.genitive[date.getMonth()] + ' ' + date.getDate(); case 'default' : return date.toLocaleString(); case 'ISO 8601': return date.toISOString(); } } function makeBox(rev1, rev2) { var query = { 'action': 'query', 'list': 'logevents', 'leaction': 'delete/revision', 'letitle': mw.config.get('wgPageName'), 'continue': '' }; var list, node = el('div', [ el('p', 'Details from the deletion log:'), list = el('ul') ], { 'class': 'mw-warning-with-logexcerpt', 'style': 'display: none;' }); function processResult(result) { var events = result.query.logevents; for (var i = 0; i < events.length; ++i) { if ((events[i][1] === rev1) || (events[i][1] === rev2)) { var item = events[i]; // XXX: item[2] and item[3] contain flags... might as well show these too // XXX: change link to plaintext based on whether the user has the 'deleterevision' right list.appendChild(el('li', [ fmtDate(item.timestamp), ": ", el('a', item.user, { href: mw.util.getUrl('User:' + item.user) }), " changed visibility of ", el('a', ["revision ", item[1]], { href: mw.util.getUrl(mw.config.get('wgPageName'), { oldid: item[1], unhide: '1' }) }), item.comment && " (", item.comment, item.comment && ")" ])); node.style.display = ''; } } if (result['continue']) { for (var key in result['continue']) query[key] = result['continue'][key]; api.get(query).then(processResult); } } api.get(query).then(processResult); return node; } if (mw.config.get('wgAction') !== 'view') return; if (!(mw.util.getParamValue('diff') || mw.util.getParamValue('oldid'))) return; if (document.getElementById('mw-rev-deleted-no-diff') || document.getElementById('mw-rev-deleted-unhide-diff')) { var rev1, rev2; var ot = document.getElementById('mw-diff-otitle1'); var nt = document.getElementById('mw-diff-ntitle1'); if (ot) { ot = new URL(ot.getElementsByTagName('a')[0].href); rev1 = ot.searchParams.get("oldid"); } if (nt) { nt = new URL(nt.getElementsByTagName('a')[0].href); rev2 = nt.searchParams.get("oldid"); } document.getElementById('mw-content-text').appendChild(makeBox(rev1, rev2)); } else if (document.getElementById('mw-content-text').firstChild.classList.contains('mw-warning')) { // ugly, ugly hack var rev = mw.util.getParamValue('oldid'); document.getElementById('mw-content-text').appendChild(makeBox(rev, null)); } })(); qwg4k57088l5momuwnfv9a1chm6srrl MediaWiki:Gadget-CodeLinks.js 8 17960 88922 2024-05-14T20:51:32Z en>Benwing 0 [[User:Theknightwho]] fix tracking links in modules 88922 javascript text/javascript /*jshint undef:true, latedef:true */ /*global mw, jQuery */ jQuery(function CodeLinksIIFE() { 'use strict'; // by John Gruber, from https://daringfireball.net/2010/07/improved_regex_for_matching_urls var URLRegExp = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i; function processComment(node) { var wikilinkMatch, templateMatch, URLMatch, textNode = node.firstChild; // always a text node. while ( (wikilinkMatch = /\[\[([^|{}\[\]\n]+)?(?:\|.*?)?]]/.exec(textNode.data)) || (templateMatch = /(\{\{(?:#invoke:)?)([^|{}\[\]\n#]+)(?=\||}})/i.exec(textNode.data)) || (URLMatch = URLRegExp.exec(textNode.data)) ) { var link = document.createElement('a'), start = (wikilinkMatch || templateMatch || URLMatch).index, linkText; link.classList.add("code-link"); if (URLMatch) { var URL = URLMatch[0]; link.href = URL; linkText = URL; } else { var fullPageName; if (wikilinkMatch) { linkText = wikilinkMatch[0]; fullPageName = wikilinkMatch[1]; } else if (templateMatch) { var prefix = templateMatch[1], pageName = templateMatch[2]; linkText = pageName; fullPageName = (prefix === '{{#invoke:' ? 'Module:' : 'Template:') + pageName; link.title = fullPageName; start += prefix.length; } link.href = mw.util.getUrl(fullPageName); } var beforeLink = textNode.data.substring(0, start), afterLink = textNode.data.substring(start + linkText.length); textNode.data = afterLink; link.appendChild(document.createTextNode(linkText)); node.insertBefore(link, textNode); node.insertBefore(document.createTextNode(beforeLink), link); // ensure all matches are null at beginning of loop body; is this necessary? wikilinkMatch = templateMatch = URLMatch = null; } } function each(coll, walk) { return Array.prototype.forEach.call(coll, walk); } var commentClasses = [ 'c', 'c1', 'cm' ]; each(document.getElementsByClassName('mw-highlight'), function (codeBlock) { each(commentClasses, function (commentClass) { each(codeBlock.getElementsByClassName(commentClass), processComment); }); }); // Link module names after `require` and `mw.loadData`, and tracking page // names after `require("Module:debug").track`. var copyArray = Array.from ? Array.from.bind(Array) : function copyArray(array) { return Array.prototype.slice.call(array); }; var classes = { identifier: "n", functionName: "nb", singleQuoteString: "s1", doubleQuoteString: "s2", }; var trackingPageElements = [], moduleNames = [], dataModuleNames = []; var functionNames = document.getElementsByClassName(classes.functionName); Array.prototype.forEach.call(functionNames, function (functionName) { var text = functionName.firstChild.nodeValue; if (text !== "require") return; var next = functionName.nextElementSibling; var nextText = next && next.firstChild && next.firstChild.nodeValue; var hasParenthesis = nextText === "("; if (hasParenthesis) { next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; } var classList = next.classList; if (!(classList.contains(classes.singleQuoteString) || classList.contains(classes.doubleQuoteString))) return; var string = next; var stringValue = nextText; if (!stringValue) return; next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; if (hasParenthesis && nextText && nextText[0] !== ")") return; moduleNames.push(string); // FIXME!!! Tracking code has been moved to [[Module:debug/track]]. The following needs updating // to handle calls of the form require("Module:debug/track")("foo"). if (hasParenthesis ? nextText === ")." : nextText === "." && (/^["']mod(?:ule)?:(.+)["']$/i.exec(stringValue) || [])[1] === "debug") { next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; if (nextText !== "track") return; next = next.nextElementSibling; if (!next) return; nextText = next && next.firstChild && next.firstChild.nodeValue; var trackWithParenthesis = false; if (nextText === "(") { next = next.nextElementSibling; trackWithParenthesis = true; } classList = next.classList; if (!(classList.contains(classes.singleQuoteString) || classList.contains(classes.doubleQuoteString))) return; nextText = next && next.firstChild && next.firstChild.nodeValue; if (!nextText) return; // If there was a parenthesis on one side – `track("...")` rather than // `track "..."` – make sure there's a matching parenthesis on the other side. if (trackWithParenthesis) { var after = next.nextElementSibling; var afterText = after && after.firstChild && after.firstChild.nodeValue; if (afterText !== ")") return; } trackingPageElements.push(next); } }); var strings = copyArray(document.getElementsByClassName(classes.singleQuoteString)) .concat(copyArray(document.getElementsByClassName(classes.doubleQuoteString))); Array.prototype.forEach.call(strings, function (string) { if (moduleNames.indexOf(string) !== -1 || trackingPageElements.indexOf(string) !== -1) return; var stringValue = string.firstChild.nodeValue; if (!/^["'](?:module|mod):/i.test(stringValue)) return; var prev = string.previousElementSibling; var prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText === "(") { var next = string.nextElementSibling; var nextText = next && next.firstChild && next.firstChild.nodeValue; if (!(nextText && nextText[0] === ")")) return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; } if (prevText !== "loadData") return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText !== ".") return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText !== "mw") return; dataModuleNames.push(string); }); if (moduleNames.length > 0 || trackingPageElements.length > 0 || dataModuleNames.length > 0) { mw.loader.using("mediawiki.util").done(function () { function addLink(element, page) { if (!(element instanceof Element)) throw new TypeError("Expected Element object"); var link = document.createElement("a"); link.href = mw.util.getUrl(page); // put text node from element inside link var firstChild = element.firstChild; if (!(firstChild instanceof Text)) throw new TypeError("Expected Text object"); link.appendChild(firstChild); element.appendChild(link); // put link inside syntax-highlighted string } // Link module names to module pages, or to the section in the Scribunto // manual. moduleNames.concat(dataModuleNames).forEach(function (module) { var link = document.createElement("a"); var stringValue = module.firstChild.nodeValue; var moduleName = stringValue.substring(1, stringValue.length - 1); var linkPage = /^mod(?:ule)?:/i.test(moduleName) ? moduleName : "mw:Extension:Scribunto/Lua reference manual#" + moduleName; addLink(module, linkPage); }); // Link tracking pages to [[Special:WhatLinksHere]]. trackingPageElements.forEach(function (trackingPage) { var text = trackingPage.firstChild && trackingPage.firstChild.nodeValue; if (!text) return; var trackingCode = text.substring(1, text.length - 1); addLink(trackingPage, "Special:WhatLinksHere/Wiktionary:Tracking/" + trackingCode); }); }); } }); 65v4x8jlyzdth8j2uvj9sfa5wzt9tr0 88923 88922 2026-08-06T23:13:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-CodeLinks.js]] 88922 javascript text/javascript /*jshint undef:true, latedef:true */ /*global mw, jQuery */ jQuery(function CodeLinksIIFE() { 'use strict'; // by John Gruber, from https://daringfireball.net/2010/07/improved_regex_for_matching_urls var URLRegExp = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i; function processComment(node) { var wikilinkMatch, templateMatch, URLMatch, textNode = node.firstChild; // always a text node. while ( (wikilinkMatch = /\[\[([^|{}\[\]\n]+)?(?:\|.*?)?]]/.exec(textNode.data)) || (templateMatch = /(\{\{(?:#invoke:)?)([^|{}\[\]\n#]+)(?=\||}})/i.exec(textNode.data)) || (URLMatch = URLRegExp.exec(textNode.data)) ) { var link = document.createElement('a'), start = (wikilinkMatch || templateMatch || URLMatch).index, linkText; link.classList.add("code-link"); if (URLMatch) { var URL = URLMatch[0]; link.href = URL; linkText = URL; } else { var fullPageName; if (wikilinkMatch) { linkText = wikilinkMatch[0]; fullPageName = wikilinkMatch[1]; } else if (templateMatch) { var prefix = templateMatch[1], pageName = templateMatch[2]; linkText = pageName; fullPageName = (prefix === '{{#invoke:' ? 'Module:' : 'Template:') + pageName; link.title = fullPageName; start += prefix.length; } link.href = mw.util.getUrl(fullPageName); } var beforeLink = textNode.data.substring(0, start), afterLink = textNode.data.substring(start + linkText.length); textNode.data = afterLink; link.appendChild(document.createTextNode(linkText)); node.insertBefore(link, textNode); node.insertBefore(document.createTextNode(beforeLink), link); // ensure all matches are null at beginning of loop body; is this necessary? wikilinkMatch = templateMatch = URLMatch = null; } } function each(coll, walk) { return Array.prototype.forEach.call(coll, walk); } var commentClasses = [ 'c', 'c1', 'cm' ]; each(document.getElementsByClassName('mw-highlight'), function (codeBlock) { each(commentClasses, function (commentClass) { each(codeBlock.getElementsByClassName(commentClass), processComment); }); }); // Link module names after `require` and `mw.loadData`, and tracking page // names after `require("Module:debug").track`. var copyArray = Array.from ? Array.from.bind(Array) : function copyArray(array) { return Array.prototype.slice.call(array); }; var classes = { identifier: "n", functionName: "nb", singleQuoteString: "s1", doubleQuoteString: "s2", }; var trackingPageElements = [], moduleNames = [], dataModuleNames = []; var functionNames = document.getElementsByClassName(classes.functionName); Array.prototype.forEach.call(functionNames, function (functionName) { var text = functionName.firstChild.nodeValue; if (text !== "require") return; var next = functionName.nextElementSibling; var nextText = next && next.firstChild && next.firstChild.nodeValue; var hasParenthesis = nextText === "("; if (hasParenthesis) { next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; } var classList = next.classList; if (!(classList.contains(classes.singleQuoteString) || classList.contains(classes.doubleQuoteString))) return; var string = next; var stringValue = nextText; if (!stringValue) return; next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; if (hasParenthesis && nextText && nextText[0] !== ")") return; moduleNames.push(string); // FIXME!!! Tracking code has been moved to [[Module:debug/track]]. The following needs updating // to handle calls of the form require("Module:debug/track")("foo"). if (hasParenthesis ? nextText === ")." : nextText === "." && (/^["']mod(?:ule)?:(.+)["']$/i.exec(stringValue) || [])[1] === "debug") { next = next.nextElementSibling; nextText = next && next.firstChild && next.firstChild.nodeValue; if (nextText !== "track") return; next = next.nextElementSibling; if (!next) return; nextText = next && next.firstChild && next.firstChild.nodeValue; var trackWithParenthesis = false; if (nextText === "(") { next = next.nextElementSibling; trackWithParenthesis = true; } classList = next.classList; if (!(classList.contains(classes.singleQuoteString) || classList.contains(classes.doubleQuoteString))) return; nextText = next && next.firstChild && next.firstChild.nodeValue; if (!nextText) return; // If there was a parenthesis on one side – `track("...")` rather than // `track "..."` – make sure there's a matching parenthesis on the other side. if (trackWithParenthesis) { var after = next.nextElementSibling; var afterText = after && after.firstChild && after.firstChild.nodeValue; if (afterText !== ")") return; } trackingPageElements.push(next); } }); var strings = copyArray(document.getElementsByClassName(classes.singleQuoteString)) .concat(copyArray(document.getElementsByClassName(classes.doubleQuoteString))); Array.prototype.forEach.call(strings, function (string) { if (moduleNames.indexOf(string) !== -1 || trackingPageElements.indexOf(string) !== -1) return; var stringValue = string.firstChild.nodeValue; if (!/^["'](?:module|mod):/i.test(stringValue)) return; var prev = string.previousElementSibling; var prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText === "(") { var next = string.nextElementSibling; var nextText = next && next.firstChild && next.firstChild.nodeValue; if (!(nextText && nextText[0] === ")")) return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; } if (prevText !== "loadData") return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText !== ".") return; prev = prev.previousElementSibling; prevText = prev && prev.firstChild && prev.firstChild.nodeValue; if (prevText !== "mw") return; dataModuleNames.push(string); }); if (moduleNames.length > 0 || trackingPageElements.length > 0 || dataModuleNames.length > 0) { mw.loader.using("mediawiki.util").done(function () { function addLink(element, page) { if (!(element instanceof Element)) throw new TypeError("Expected Element object"); var link = document.createElement("a"); link.href = mw.util.getUrl(page); // put text node from element inside link var firstChild = element.firstChild; if (!(firstChild instanceof Text)) throw new TypeError("Expected Text object"); link.appendChild(firstChild); element.appendChild(link); // put link inside syntax-highlighted string } // Link module names to module pages, or to the section in the Scribunto // manual. moduleNames.concat(dataModuleNames).forEach(function (module) { var link = document.createElement("a"); var stringValue = module.firstChild.nodeValue; var moduleName = stringValue.substring(1, stringValue.length - 1); var linkPage = /^mod(?:ule)?:/i.test(moduleName) ? moduleName : "mw:Extension:Scribunto/Lua reference manual#" + moduleName; addLink(module, linkPage); }); // Link tracking pages to [[Special:WhatLinksHere]]. trackingPageElements.forEach(function (trackingPage) { var text = trackingPage.firstChild && trackingPage.firstChild.nodeValue; if (!text) return; var trackingCode = text.substring(1, text.length - 1); addLink(trackingPage, "Special:WhatLinksHere/Wiktionary:Tracking/" + trackingCode); }); }); } }); 65v4x8jlyzdth8j2uvj9sfa5wzt9tr0 MediaWiki:Gadget-purgetab.js 8 17961 88924 2019-09-25T03:58:47Z en>Krinkle 0 Maintenance: [[mw:RL/MGU]] - Updated deprecated user.tokens key 88924 javascript text/javascript // {{documentation}} jQuery(document).ready(function() { if (!mw.config.get('wgArticleId')) return; var link; var portletIdToAdd = $("#p-cactions").length != 0 ? "p-cactions" : "p-views"; link = mw.util.addPortletLink( portletIdToAdd, mw.util.getUrl(mw.config.get('wgPageName'), { 'action': 'purge' }), (mw.config.get('skin') == "vector") ? "Purge" : "*", 'ca-purge', "Purge cache for this page", '*' ); var api = new mw.Api(); link = mw.util.addPortletLink( portletIdToAdd, mw.util.getUrl(mw.config.get('wgPageName'), { 'action': 'purge', 'forcelinkupdate': 1 }), // not sure if raw link works... (mw.config.get('skin') == "vector") ? "Hard purge" : "**", 'ca-purge-forcelinkupdate', "Purge with forced link table update", ',' ); link.addEventListener('click', function(ev) { api.post({ action: 'purge', pageids: mw.config.get('wgArticleId'), forcelinkupdate: 1 }).then(function() { location.reload(); }, function(code, details) { var mesg; switch (code) { case 'http': mesg = 'HTTP error: ' + details.xhr.statusText; break; case 'ok-but-empty': mesg = 'Received empty response.'; break; default: mesg = details.error.info; } mw.util.jsMessage('<b>Hard purge failed</b>: ' + mesg); console.error(arguments); }); ev.preventDefault(); }, false); link = mw.util.addPortletLink( portletIdToAdd, 'javascript:void window.warranty', (mw.config.get('skin') == "vector") ? "Null edit" : "***", 'ca-nulledit', "Null edit", '0' ); link.addEventListener('click', function(ev) { api.post({ action: 'edit', pageid: mw.config.get('wgArticleId'), appendtext: '', watchlist: 'nochange', nocreate: '1', token: mw.user.tokens.get('csrfToken') }).then(function() { location.reload(); }, function(code, details) { var mesg; switch (code) { case 'http': mesg = 'HTTP error: ' + details.xhr.statusText; break; case 'ok-but-empty': mesg = 'Received empty response.'; break; default: mesg = details.error.info; } mw.util.jsMessage('<b>Null edit failed</b>: ' + mesg); console.error(arguments); }); ev.preventDefault(); }, false); }); 0l8v0diur942q6kq5oa89o3eoji1t0e 88925 88924 2026-08-06T23:13:40Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-purgetab.js]] 88924 javascript text/javascript // {{documentation}} jQuery(document).ready(function() { if (!mw.config.get('wgArticleId')) return; var link; var portletIdToAdd = $("#p-cactions").length != 0 ? "p-cactions" : "p-views"; link = mw.util.addPortletLink( portletIdToAdd, mw.util.getUrl(mw.config.get('wgPageName'), { 'action': 'purge' }), (mw.config.get('skin') == "vector") ? "Purge" : "*", 'ca-purge', "Purge cache for this page", '*' ); var api = new mw.Api(); link = mw.util.addPortletLink( portletIdToAdd, mw.util.getUrl(mw.config.get('wgPageName'), { 'action': 'purge', 'forcelinkupdate': 1 }), // not sure if raw link works... (mw.config.get('skin') == "vector") ? "Hard purge" : "**", 'ca-purge-forcelinkupdate', "Purge with forced link table update", ',' ); link.addEventListener('click', function(ev) { api.post({ action: 'purge', pageids: mw.config.get('wgArticleId'), forcelinkupdate: 1 }).then(function() { location.reload(); }, function(code, details) { var mesg; switch (code) { case 'http': mesg = 'HTTP error: ' + details.xhr.statusText; break; case 'ok-but-empty': mesg = 'Received empty response.'; break; default: mesg = details.error.info; } mw.util.jsMessage('<b>Hard purge failed</b>: ' + mesg); console.error(arguments); }); ev.preventDefault(); }, false); link = mw.util.addPortletLink( portletIdToAdd, 'javascript:void window.warranty', (mw.config.get('skin') == "vector") ? "Null edit" : "***", 'ca-nulledit', "Null edit", '0' ); link.addEventListener('click', function(ev) { api.post({ action: 'edit', pageid: mw.config.get('wgArticleId'), appendtext: '', watchlist: 'nochange', nocreate: '1', token: mw.user.tokens.get('csrfToken') }).then(function() { location.reload(); }, function(code, details) { var mesg; switch (code) { case 'http': mesg = 'HTTP error: ' + details.xhr.statusText; break; case 'ok-but-empty': mesg = 'Received empty response.'; break; default: mesg = details.error.info; } mw.util.jsMessage('<b>Null edit failed</b>: ' + mesg); console.error(arguments); }); ev.preventDefault(); }, false); }); 0l8v0diur942q6kq5oa89o3eoji1t0e MediaWiki:Gadget-popups.js 8 17962 88926 2023-12-03T04:46:35Z en>Erutuon 0 added semicolon because of Firefox's parsing error in minified JavaScript at the end of this line 88926 javascript text/javascript // {{documentation}} // _________________________________________________________________________________________ // | | // | === WARNING: GLOBAL GADGET FILE === | // | Changes to this page affect many users. | // | Please discuss changes on the [[Wiktionary:Grease Pit]] before editing. | // |_________________________________________________________________________________________| mw.loader.load('//en.wikipedia.org/w/index.php?action=raw&title=MediaWiki:Gadget-navpop.css&ctype=text/css', "text/css"); // Forked from [[:w:MediaWiki:Gadget-popups.js]] $(function () { ////////////////////////////////////////////////// // Globals // // Trying to shove as many of these as possible into the pg (popup globals) object var pg = { re: {}, // regexps ns: {}, // namespaces string: {}, // translatable strings wiki: {}, // local site info user: {}, // current user info misc: {}, // YUCK PHOOEY option: {}, // options, see newOption etc optionDefault: {}, // default option values flag: {}, // misc flags cache: {}, // page and image cache structures: {}, // navlink structures timer: {}, // all sorts of timers (too damn many) counter: {}, // .. and all sorts of counters current: {}, // state info fn: {}, // functions endoflist: null }; /* Bail if the gadget/script is being loaded twice */ if( window.pg ) { return; } /* Export to global context */ window.pg = pg; /// Local Variables: /// /// mode:c /// /// End: /// // ENDFILE: main.js // STARTFILE: actions.js function setupTooltips(container, remove, force, popData) { log('setupTooltips, container='+container+', remove='+remove); if (!container) { //<NOLITE> // the main initial call if (getValueOf('popupOnEditSelection') && document && document.editform && document.editform.wpTextbox1) { document.editform.wpTextbox1.onmouseup=doSelectionPopup; } //</NOLITE> // article/content is a structure-dependent thing container = defaultPopupsContainer(); } if (!remove && !force && container.ranSetupTooltipsAlready) { return; } container.ranSetupTooltipsAlready = !remove; var anchors; anchors=container.getElementsByTagName('A'); setupTooltipsLoop(anchors, 0, 250, 100, remove, popData); } function defaultPopupsContainer() { if (getValueOf('popupOnlyArticleLinks')) { return document.getElementById('mw_content') || document.getElementById('content') || document.getElementById('article') || document; } return document; } function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) { log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments)); var finish=begin+howmany; var loopend = Math.min(finish, anchors.length); var j=loopend - begin; log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin + ', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove); var doTooltip= remove ? removeTooltip : addTooltip; // try a faster (?) loop construct if (j > 0) { do { var a=anchors[loopend - j]; if (typeof a==='undefined' || !a || !a.href) { log('got null anchor at index ' + loopend - j); continue; } doTooltip(a, popData); } while (--j); } if (finish < anchors.length) { setTimeout(function() { setupTooltipsLoop(anchors,finish,howmany,sleep,remove,popData);}, sleep); } else { if ( !remove && ! getValueOf('popupTocLinks')) { rmTocTooltips(); } pg.flag.finishedLoading=true; } } // eliminate popups from the TOC // This also kills any onclick stuff that used to be going on in the toc function rmTocTooltips() { var toc=document.getElementById('toc'); if (toc) { var tocLinks=toc.getElementsByTagName('A'); var tocLen = tocLinks.length; for (var j=0; j<tocLen; ++j) { removeTooltip(tocLinks[j], true); } } } function addTooltip(a, popData) { if ( !isPopupLink(a) ) { return; } a.onmouseover=mouseOverWikiLink; a.onmouseout= mouseOutWikiLink; a.onmousedown = killPopup; a.hasPopup = true; a.popData = popData; } function removeTooltip(a) { if ( !a.hasPopup ) { return; } a.onmouseover = null; a.onmouseout = null; if (a.originalTitle) { a.title = a.originalTitle; } a.hasPopup=false; } function removeTitle(a) { if (!a.originalTitle) { a.originalTitle=a.title; } a.title=''; } function restoreTitle(a) { if ( a.title || !a.originalTitle ) { return; } a.title = a.originalTitle; } function registerHooks(np) { var popupMaxWidth=getValueOf('popupMaxWidth'); if (typeof popupMaxWidth === 'number') { var setMaxWidth = function () { np.mainDiv.style.maxWidth = popupMaxWidth + 'px'; np.maxWidth = popupMaxWidth; }; np.addHook(setMaxWidth, 'unhide', 'before'); } //<NOLITE> np.addHook(addPopupShortcuts, 'unhide', 'after'); np.addHook(rmPopupShortcuts, 'hide', 'before'); //</NOLITE> } function removeModifierKeyHandler(a) { //remove listeners for modifier key if any that were added in mouseOverWikiLink document.removeEventListener('keydown', a.modifierKeyHandler, false); document.removeEventListener('keyup', a.modifierKeyHandler, false); } function mouseOverWikiLink(evt) { if (!evt && window.event) {evt=window.event;} // if the modifier is needed, listen for it, // we will remove the listener when we mouseout of this link or kill popup. if (getValueOf('popupModifier')) { // if popupModifierAction = enable, we should popup when the modifier is pressed // if popupModifierAction = disable, we should popup unless the modifier is pressed var action = getValueOf('popupModifierAction'); var key = action=='disable' ? 'keyup' : 'keydown'; var a = this; a.modifierKeyHandler = function(evt) { mouseOverWikiLink2(a, evt); }; document.addEventListener(key, a.modifierKeyHandler, false); } return mouseOverWikiLink2(this, evt); } /** * Gets the references list item that the provided footnote link targets. This * is typically a li element within the ol.references element inside the reflist. * @param {Element} a - A footnote link. * @returns {Element|boolean} The targeted element, or false if one can't be found. */ function footnoteTarget(a) { var aTitle=Title.fromAnchor(a); // We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly var anch = aTitle.anchor; if ( ! /^(cite_note-|_note-|endnote)/.test(anch) ) { return false; } var lTitle=Title.fromURL(location.href); if ( lTitle.toString(true) !== aTitle.toString(true) ) { return false; } var el=document.getElementById(anch); while ( el && typeof el.nodeName === 'string') { var nt = el.nodeName.toLowerCase(); if ( nt === 'li' ) { return el; } else if ( nt === 'body' ) { return false; } else if ( el.parentNode ) { el=el.parentNode; } else { return false; } } return false; } function footnotePreview(x, navpop) { setPopupHTML('<hr />' + x.innerHTML, 'popupPreview', navpop.idNumber); } function modifierPressed(evt) { var mod=getValueOf('popupModifier'); if (!mod) { return false; } if (!evt && window.event) {evt=window.event;} return ( evt && mod && evt[mod.toLowerCase() + 'Key'] ); } // Checks if the correct modifier pressed/unpressed if needed function isCorrectModifier(a,evt) { if (!getValueOf('popupModifier')) { return true; } // if popupModifierAction = enable, we should popup when the modifier is pressed // if popupModifierAction = disable, we should popup unless the modifier is pressed var action = getValueOf('popupModifierAction'); return ( action == 'enable' && modifierPressed(evt) || action == 'disable' && !modifierPressed(evt) ); } function mouseOverWikiLink2(a, evt) { if (!isCorrectModifier(a,evt)) { return; } if ( getValueOf('removeTitles') ) { removeTitle(a); } if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; } pg.current.link=a; if (getValueOf('simplePopups') && !pg.option.popupStructure) { // reset *default value* of popupStructure setDefault('popupStructure', 'original'); } var article=(new Title()).fromAnchor(a); // set global variable (ugh) to hold article (wikipage) pg.current.article = article; if (!a.navpopup) { a.navpopup=newNavpopup(a, article); pg.current.linksHash[a.href] = a.navpopup; pg.current.links.push(a); } if (a.navpopup.pending === null || a.navpopup.pending !== 0) { // either fresh popups or those with unfinshed business are redone from scratch simplePopupContent(a, article); } a.navpopup.showSoonIfStable(a.navpopup.delay); clearInterval(pg.timer.checkPopupPosition); pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600); if(getValueOf('simplePopups')) { if (getValueOf('popupPreviewButton') && !a.simpleNoMore) { var d=document.createElement('div'); d.className='popupPreviewButtonDiv'; var s=document.createElement('span'); d.appendChild(s); s.className='popupPreviewButton'; s['on' + getValueOf('popupPreviewButtonEvent')] = function() { a.simpleNoMore=true; d.style.display = "none"; nonsimplePopupContent(a,article); }; s.innerHTML=popupString('show preview'); setPopupHTML(d, 'popupPreview', a.navpopup.idNumber); } } if (a.navpopup.pending !== 0 ) { nonsimplePopupContent(a, article); } } // simplePopupContent: the content that do not require additional download // (it is shown even when simplePopups is true) function simplePopupContent(a, article) { /* FIXME hack */ a.navpopup.hasPopupMenu=false; a.navpopup.setInnerHTML(popupHTML(a)); fillEmptySpans({navpopup:a.navpopup}); if (getValueOf('popupDraggable')) { var dragHandle = getValueOf('popupDragHandle') || null; if (dragHandle && dragHandle != 'all') { dragHandle += a.navpopup.idNumber; } setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150); } //<NOLITE> if (getValueOf('popupRedlinkRemoval') && a.className=='new') { setPopupHTML('<br>'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber); } //</NOLITE> } function debugData(navpopup) { if(getValueOf('popupDebugging') && navpopup.idNumber) { setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending, 'popupError', navpopup.idNumber); } } function newNavpopup(a, article) { var navpopup = new Navpopup(); navpopup.fuzz=5; navpopup.delay=getValueOf('popupDelay')*1000; // increment global counter now navpopup.idNumber = ++pg.idNumber; navpopup.parentAnchor = a; navpopup.parentPopup = (a.popData && a.popData.owner); navpopup.article = article; registerHooks(navpopup); return navpopup; } // Should we show nonsimple context? // If simplePopups is set to true, then we do not show nonsimple context, // but if a bottom "show preview" was clicked we do show nonsimple context function shouldShowNonSimple(a) { return !getValueOf('simplePopups') || a.simpleNoMore; } // Should we show nonsimple context govern by the option (e.g. popupUserInfo)? // If the user explicitly asked for nonsimple context by setting the option to true, // then we show it even in nonsimple mode. function shouldShow(a,option) { if (shouldShowNonSimple(a)) { return getValueOf(option); } else { return (typeof window[option] != 'undefined' ) && window[option]; } } function nonsimplePopupContent(a, article) { var diff=null, history=null; var params=parseParams(a.href); var oldid=(typeof params.oldid=='undefined' ? null : params.oldid); //<NOLITE> if(shouldShow(a,'popupPreviewDiffs')) { diff=params.diff; } if(shouldShow(a,'popupPreviewHistory')) { history=(params.action=='history'); } //</NOLITE> a.navpopup.pending=0; var referenceElement = footnoteTarget(a); if (referenceElement) { footnotePreview(referenceElement, a.navpopup); //<NOLITE> } else if ( diff || diff === 0 ) { loadDiff(article, oldid, diff, a.navpopup); } else if ( history ) { loadAPIPreview('history', article, a.navpopup); } else if ( shouldShowNonSimple(a) && pg.re.contribs.test(a.href) ) { loadAPIPreview('contribs', article, a.navpopup); } else if ( shouldShowNonSimple(a) && pg.re.backlinks.test(a.href) ) { loadAPIPreview('backlinks', article, a.navpopup); } else if ( // FIXME should be able to get all preview combinations with options article.namespaceId()==pg.nsImageId && ( shouldShow(a,'imagePopupsForImages') || ! anchorContainsImage(a) ) ) { loadAPIPreview('imagepagepreview', article, a.navpopup); loadImage(article, a.navpopup); //</NOLITE> } else { if (article.namespaceId() == pg.nsCategoryId && shouldShow(a,'popupCategoryMembers')) { loadAPIPreview('category', article, a.navpopup); } else if ((article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) && shouldShow(a,'popupUserInfo')) { loadAPIPreview('userinfo', article, a.navpopup); } if (shouldShowNonSimple(a)) startArticlePreview(article, oldid, a.navpopup); } } function pendingNavpopTask(navpop) { if (navpop && navpop.pending === null) { navpop.pending=0; } ++navpop.pending; debugData(navpop); } function completedNavpopTask(navpop) { if (navpop && navpop.pending) { --navpop.pending; } debugData(navpop); } function startArticlePreview(article, oldid, navpop) { navpop.redir=0; loadPreview(article, oldid, navpop); } function loadPreview(article, oldid, navpop) { if (!navpop.redir) { navpop.originalArticle=article; } article.oldid = oldid; loadAPIPreview('revision', article, navpop); } function loadPreviewFromRedir(redirMatch, navpop) { // redirMatch is a regex match var target = new Title().fromWikiText(redirMatch[2]); // overwrite (or add) anchor from original target // mediawiki does overwrite; eg [[User:Lupin/foo3#Done]] if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; } navpop.redir++; navpop.redirTarget=target; //<NOLITE> var warnRedir = redirLink(target, navpop.article); setPopupHTML(warnRedir, 'popupWarnRedir', navpop.idNumber); //</NOLITE> navpop.article=target; fillEmptySpans({redir: true, redirTarget: target, navpopup:navpop}); return loadPreview(target, null, navpop); } function insertPreview(download) { if (!download.owner) { return; } var redirMatch = pg.re.redirect.exec(download.data); if (download.owner.redir === 0 && redirMatch) { loadPreviewFromRedir(redirMatch, download.owner); return; } if (download.owner.visible || !getValueOf('popupLazyPreviews')) { insertPreviewNow(download); } else { var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK'; download.owner.addHook( function(){insertPreviewNow(download); return true;}, 'unhide', 'after', id ); } } function insertPreviewNow(download) { if (!download.owner) { return; } var wikiText=download.data; var navpop=download.owner; var art=navpop.redirTarget || navpop.originalArticle; //<NOLITE> makeFixDabs(wikiText, navpop); if (getValueOf('popupSummaryData')) { getPageInfo(wikiText, download); setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber); } var imagePage=''; if (art.namespaceId()==pg.nsImageId) { imagePage=art.toString(); } else { imagePage=getValidImageFromWikiText(wikiText); } if(imagePage) { loadImage(Title.fromWikiText(imagePage), navpop); } //</NOLITE> if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); } } function insertArticlePreview(download, art, navpop) { if (download && typeof download.data == typeof ''){ if (art.namespaceId()==pg.nsTemplateId && getValueOf('popupPreviewRawTemplates')) { // FIXME compare/consolidate with diff escaping code for wikitext var h='<hr /><span style="font-family: monospace;">' + download.data.entify().split('\\n').join('<br />\\n') + '</span>'; setPopupHTML(h, 'popupPreview', navpop.idNumber); } else { var p=prepPreviewmaker(download.data, art, navpop); p.showPreview(); } } } function prepPreviewmaker(data, article, navpop) { // deal with tricksy anchors var d=anchorize(data, article.anchorString()); var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]); var p=new Previewmaker(d, urlBase, navpop); return p; } // Try to imitate the way mediawiki generates HTML anchors from section titles function anchorize(d, anch) { if (!anch) { return d; } var anchRe=RegExp('(?:=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+|\\{\\{\\s*'+getValueOf('popupAnchorRegexp')+'\\s*(?:\\|[^|}]*)*?\\s*'+literalizeRegex(anch)+'\\s*(?:\\|[^}]*)?}})'); var match=d.match(anchRe); if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); } // now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom var lines=d.split('\n'); for (var i=0; i<lines.length; ++i) { lines[i]=lines[i].replace(RegExp('[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}', 'g'), '$2') .replace(/'''([^'])/g, '$1').replace(RegExp("''([^'])", 'g'), '$1'); if (lines[i].match(anchRe)) { return d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), ''); } } return d; } function killPopup() { removeModifierKeyHandler(this); if (getValueOf('popupShortcutKeys')) { rmPopupShortcuts(); } if (!pg) { return; } if (pg.current.link && pg.current.link.navpopup) { pg.current.link.navpopup.banish(); } pg.current.link=null; abortAllDownloads(); if (pg.timer.checkPopupPosition) { clearInterval(pg.timer.checkPopupPosition); pg.timer.checkPopupPosition=null; } return true; // preserve default action } // ENDFILE: actions.js // STARTFILE: domdrag.js /** @fileoverview The {@link Drag} object, which enables objects to be dragged around. <pre> ************************************************* dom-drag.js 09.25.2001 www.youngpup.net ************************************************** 10.28.2001 - fixed minor bug where events sometimes fired off the handle, not the root. ************************************************* Pared down, some hooks added by [[User:Lupin]] Copyright Aaron Boodman. Saying stupid things daily since March 2001. </pre> */ /** Creates a new Drag object. This is used to make various DOM elements draggable. @constructor */ function Drag () { /** Condition to determine whether or not to drag. This function should take one parameter, an Event. To disable this, set it to <code>null</code>. @type Function */ this.startCondition = null; /** Hook to be run when the drag finishes. This is passed the final coordinates of the dragged object (two integers, x and y). To disables this, set it to <code>null</code>. @type Function */ this.endHook = null; } /** Gets an event in a cross-browser manner. @param {Event} e @private */ Drag.prototype.fixE = function(e) { if (typeof e == 'undefined') { e = window.event; } if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; } if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; } return e; }; /** Initialises the Drag instance by telling it which object you want to be draggable, and what you want to drag it by. @param {DOMElement} o The "handle" by which <code>oRoot</code> is dragged. @param {DOMElement} oRoot The object which moves when <code>o</code> is dragged, or <code>o</code> if omitted. */ Drag.prototype.init = function(o, oRoot) { var dragObj = this; this.obj = o; o.onmousedown = function(e) { dragObj.start.apply( dragObj, [e]); }; o.dragging = false; o.popups_draggable = true; o.hmode = true; o.vmode = true; o.root = oRoot ? oRoot : o ; if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left = "0px"; } if (isNaN(parseInt(o.root.style.top, 10))) { o.root.style.top = "0px"; } o.root.onthisStart = function(){}; o.root.onthisEnd = function(){}; o.root.onthis = function(){}; }; /** Starts the drag. @private @param {Event} e */ Drag.prototype.start = function(e) { var o = this.obj; // = this; e = this.fixE(e); if (this.startCondition && !this.startCondition(e)) { return; } var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10); o.root.onthisStart(x, y); o.lastMouseX = e.clientX; o.lastMouseY = e.clientY; var dragObj = this; o.onmousemoveDefault = document.onmousemove; o.dragging = true; document.onmousemove = function(e) { dragObj.drag.apply( dragObj, [e] ); }; document.onmouseup = function(e) { dragObj.end.apply( dragObj, [e] ); }; return false; }; /** Does the drag. @param {Event} e @private */ Drag.prototype.drag = function(e) { e = this.fixE(e); var o = this.obj; var ey = e.clientY; var ex = e.clientX; var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10 ); var nx, ny; nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1)); ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1)); this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px"; this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px"; this.obj.lastMouseX = ex; this.obj.lastMouseY = ey; this.obj.root.onthis(nx, ny); return false; }; /** Ends the drag. @private */ Drag.prototype.end = function() { document.onmousemove=this.obj.onmousemoveDefault; document.onmouseup = null; this.obj.dragging = false; if (this.endHook) { this.endHook( parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10), parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10)); } }; // ENDFILE: domdrag.js // STARTFILE: structures.js //<NOLITE> pg.structures.original={}; pg.structures.original.popupLayout=function () { return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupUserData', 'popupData', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; pg.structures.original.popupRedirSpans=function () { return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks']; }; pg.structures.original.popupTitle=function (x) { log ('defaultstructure.popupTitle'); if (!getValueOf('popupNavLinks')) { return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params); } return ''; }; pg.structures.original.popupTopLinks=function (x) { log ('defaultstructure.popupTopLinks'); if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.params); } return ''; }; pg.structures.original.popupImage=function(x) { log ('original.popupImage, x.article='+x.article+', x.navpop.idNumber='+x.navpop.idNumber); return imageHTML(x.article, x.navpop.idNumber); }; pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle; pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks; function copyStructure(oldStructure, newStructure) { pg.structures[newStructure]={}; for (var prop in pg.structures[oldStructure]) { pg.structures[newStructure][prop]=pg.structures[oldStructure][prop]; } } copyStructure('original', 'nostalgia'); pg.structures.nostalgia.popupTopLinks=function(x) { var str=''; str += '<b><<mainlink|shortcut= >></b>'; // user links // contribs - log - count - email - block // count only if applicable; block only if popupAdminLinks str += 'if(user){<br><<contribs|shortcut=c>>'; str+='if(wikimedia){*<<count|shortcut=#>>}'; str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}'; // editing links // talkpage -> edit|new - history - un|watch - article|edit // other page -> edit - history - un|watch - talk|edit|new var editstr='<<edit|shortcut=e>>'; var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'; var historystr='<<history|shortcut=h>>'; var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; str += '<br>if(talk){' + editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + '}else{' + // not a talk page editOldidStr + '*' + historystr + '*' + watchstr + '*' + '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; // misc links str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>'; str += 'if(admin){<br>}else{*}<<move|shortcut=m>>'; // admin links str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' + '<<undelete|undeleteShort>>|<<delete|shortcut=d>>}'; return navlinkStringToHTML(str, x.article, x.params); }; pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks; /** -- fancy -- **/ copyStructure('original', 'fancy'); pg.structures.fancy.popupTitle=function (x) { return navlinkStringToHTML('<font size=+0><<mainlink>></font>',x.article,x.params); }; pg.structures.fancy.popupTopLinks=function(x) { var hist='<<history|shortcut=h|hist>>|<<lastEdit|shortcut=/|last>>|<<editors|shortcut=E|eds>>'; var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; var move='<<move|shortcut=m|move>>'; return navlinkStringToHTML('if(talk){' + '<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*' + '<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move + '}else{<<edit|shortcut=e>>*' + hist + '*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>' + '*' + watch + '*' + move+'}<br>', x.article, x.params); }; pg.structures.fancy.popupOtherLinks=function(x) { var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>'; var user='<<contribs|shortcut=c>>if(wikimedia){|<<count|shortcut=#|#>>}'; user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+ popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}'; var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>'; return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}' + normal, x.article, x.params); }; pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle; pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks; pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks; /** -- fancy2 -- **/ // hack for [[User:MacGyverMagic]] copyStructure('fancy', 'fancy2'); pg.structures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning return '<br>'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),''); }; pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title return ['popupError', 'popupImage', 'popupTitle', 'popupUserData', 'popupData', 'popupTopLinks', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; /** -- menus -- **/ copyStructure('original', 'menus'); pg.structures.menus.popupLayout=function () { return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupUserData', 'popupData', 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; pg.structures.menus.popupTopLinks = function (x, shorter) { // FIXME maybe this stuff should be cached var s=[]; var dropdiv='<div class="popup_drop">'; var enddiv='</div>'; var hist='<<history|shortcut=h>>'; if (!shorter) { hist = '<menurow>' + hist + '|<<historyfeed|rss>>|<<editors|shortcut=E>></menurow>'; } var lastedit='<<lastEdit|shortcut=/|show last edit>>'; var thank='if(diff){<<thank|send thanks>>}'; var jsHistory='<<lastContrib|last set of edits>><<sinceMe|changes since mine>>'; var linkshere='<<whatLinksHere|shortcut=l|what links here>>'; var related='<<relatedChanges|shortcut=r|related changes>>'; var search='<menurow><<search|shortcut=s>>if(wikimedia){|<<globalsearch|shortcut=g|global>>}' + '|<<google|shortcut=G|web>></menurow>'; var watch='<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>'; var protect='<menurow><<unprotect|unprotectShort>>|' + '<<protect|shortcut=p>>|<<protectlog|log>></menurow>'; var del='<menurow><<undelete|undeleteShort>>|<<delete|shortcut=d>>|' + '<<deletelog|log>></menurow>'; var move='<<move|shortcut=m|move page>>'; var nullPurge='<menurow><<nullEdit|shortcut=n|null edit>>|<<purge|shortcut=P>></menurow>'; var viewOptions='<menurow><<view|shortcut=v>>|<<render|shortcut=S>>|<<raw>></menurow>'; var editRow='if(oldid){' + '<menurow><<edit|shortcut=e>>|<<editOld|shortcut=e|this&nbsp;revision>></menurow>' + '<menurow><<revert|shortcut=v>>|<<undo>></menurow>' + '}else{<<edit|shortcut=e>>}'; var markPatrolled='if(rcid){<<markpatrolled|mark patrolled>>}'; var newTopic='if(talk){<<new|shortcut=+|new topic>>}'; var protectDelete='if(admin){' + protect + del + '}'; if (getValueOf('popupActionsMenu')) { s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions')); } else { s.push( dropdiv + '<<mainlink>>'); } s.push( '<menu>'); s.push( editRow + markPatrolled + newTopic + hist + lastedit + thank ); if (!shorter) { s.push(jsHistory); } s.push( move + linkshere + related); if (!shorter) { s.push(nullPurge + search); } if (!shorter) { s.push(viewOptions); } s.push('<hr />' + watch + protectDelete); s.push('<hr />' + 'if(talk){<<article|shortcut=a|view article>><<editArticle|edit article>>}' + 'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' + '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv); // user menu starts here var email='<<email|shortcut=E|email user>>'; var contribs= 'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>if(wikimedia){</menurow>}' + 'if(admin){<menurow><<deletedContribs>></menurow>}'; s.push('if(user){*' + dropdiv + menuTitle('user')); s.push('<menu>'); s.push('<menurow><<userPage|shortcut=u|user&nbsp;page>>|<<userSpace|space>></menurow>'); s.push('<<userTalk|shortcut=t|user talk>><<editUserTalk|edit user talk>>' + '<<newUserTalk|shortcut=+|leave comment>>'); if(!shorter) { s.push( 'if(ipuser){<<arin>>}else{' + email + '}' ); } else { s.push( 'if(ipuser){}else{' + email + '}' ); } s.push('<hr />' + contribs + '<<userlog|shortcut=L|user log>>'); s.push('if(wikimedia){<<count|shortcut=#|edit counter>>}'); s.push('if(admin){<menurow><<unblock|unblockShort>>|<<block|shortcut=b|block user>></menurow>}'); s.push('<<blocklog|shortcut=B|block log>>'); s.push('</menu>' + enddiv + '}'); // popups menu starts here if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) { x.navpop.hasPopupMenu=true; s.push('*' + dropdiv + menuTitle('popupsMenu') + '<menu>'); s.push('<<togglePreviews|toggle previews>>'); s.push('<<purgePopups|reset>>'); s.push('<<disablePopups|disable>>'); s.push('</menu>'+enddiv); } return navlinkStringToHTML(s.join(''), x.article, x.params); }; function menuTitle(s) { return '<a href="#" noPopup=1>' + popupString(s) + '</a>'; } pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle; pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks; copyStructure('menus', 'shortmenus'); pg.structures.shortmenus.popupTopLinks=function(x) { return pg.structures.menus.popupTopLinks(x,true); }; pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks; //</NOLITE> pg.structures.lite={}; pg.structures.lite.popupLayout=function () { return ['popupTitle', 'popupPreview' ]; }; pg.structures.lite.popupTitle=function (x) { log (x.article + ': structures.lite.popupTitle'); //return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params); return '<div><span class="popup_mainlink"><b>' + x.article.toString() + '</b></span></div>'; }; // ENDFILE: structures.js // STARTFILE: autoedit.js //<NOLITE> function substitute(data,cmdBody) { // alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags); var fromRe=RegExp(cmdBody.from, cmdBody.flags); return data.replace(fromRe, cmdBody.to); } function execCmds(data, cmdList) { for (var i=0; i<cmdList.length; ++i) { data=cmdList[i].action(data, cmdList[i]); } return data; } function parseCmd(str) { // returns a list of commands if (!str.length) { return []; } var p=false; switch (str.charAt(0)) { case 's': p=parseSubstitute(str); break; default: return false; } if (p) { return [p].concat(parseCmd(p.remainder)); } return false; } function unEscape(str, sep) { return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n'); } function parseSubstitute(str) { // takes a string like s/a/b/flags;othercmds and parses it var from,to,flags,tmp; if (str.length<4) { return false; } var sep=str.charAt(1); str=str.substring(2); tmp=skipOver(str,sep); if (tmp) { from=tmp.segment; str=tmp.remainder; } else { return false; } tmp=skipOver(str,sep); if (tmp) { to=tmp.segment; str=tmp.remainder; } else { return false; } flags=''; if (str.length) { tmp=skipOver(str,';') || skipToEnd(str, ';'); if (tmp) {flags=tmp.segment; str=tmp.remainder; } } return {action: substitute, from: from, to: to, flags: flags, remainder: str}; } function skipOver(str,sep) { var endSegment=findNext(str,sep); if (endSegment<0) { return false; } var segment=unEscape(str.substring(0,endSegment), sep); return {segment: segment, remainder: str.substring(endSegment+1)}; } /*eslint-disable*/ function skipToEnd(str,sep) { return {segment: str, remainder: ''}; } /*eslint-enable */ function findNext(str, ch) { for (var i=0; i<str.length; ++i) { if (str.charAt(i)=='\\') { i+=2; } if (str.charAt(i)==ch) { return i; } } return -1; } function setCheckbox(param, box) { var val=mw.util.getParamValue(param); if (val) { switch (val) { case '1': case 'yes': case 'true': box.checked=true; break; case '0': case 'no': case 'false': box.checked=false; } } } function autoEdit() { setupPopups( function () { if (mw.util.getParamValue('autoimpl') !== popupString('autoedit_version') ) { return false; } if (mw.util.getParamValue('autowatchlist') && mw.util.getParamValue('actoken')===autoClickToken()) { pg.fn.modifyWatchlist(mw.util.getParamValue('title'), mw.util.getParamValue('action')); } if (!document.editform) { return false; } if (autoEdit.alreadyRan) { return false; } autoEdit.alreadyRan=true; var cmdString=mw.util.getParamValue('autoedit'); if (cmdString) { try { var editbox=document.editform.wpTextbox1; var cmdList=parseCmd(cmdString); var input=editbox.value; var output=execCmds(input, cmdList); editbox.value=output; } catch (dang) { return; } // wikEd user script compatibility if (typeof(wikEdUseWikEd) != 'undefined') { if (wikEdUseWikEd === true) { WikEdUpdateFrame(); } } } setCheckbox('autominor', document.editform.wpMinoredit); setCheckbox('autowatch', document.editform.wpWatchthis); var rvid = mw.util.getParamValue('autorv'); if (rvid) { var url=pg.wiki.apiwikibase + '?action=query&format=json&formatversion=2&prop=revisions&revids='+rvid; startDownload(url, null, autoEdit2); } else { autoEdit2(); } } ); } function autoEdit2(d) { var summary=mw.util.getParamValue('autosummary'); var summaryprompt=mw.util.getParamValue('autosummaryprompt'); var summarynotice=''; if (d && d.data && mw.util.getParamValue('autorv')) { var s = getRvSummary(summary, d.data); if (s === false) { summaryprompt=true; summarynotice=popupString('Failed to get revision information, please edit manually.\n\n'); summary = simplePrintf(summary, [mw.util.getParamValue('autorv'), '(unknown)', '(unknown)']); } else { summary = s; } } if (summaryprompt) { var txt= summarynotice + popupString('Enter a non-empty edit summary or press cancel to abort'); var response=prompt(txt, summary); if (response) { summary=response; } else { return; } } if (summary) { document.editform.wpSummary.value=summary; } // Attempt to avoid possible premature clicking of the save button // (maybe delays in updates to the DOM are to blame?? or a red herring) setTimeout(autoEdit3, 100); } function autoClickToken() { return mw.user.sessionId(); } function autoEdit3() { if( mw.util.getParamValue('actoken') != autoClickToken()) { return; } var btn=mw.util.getParamValue('autoclick'); if (btn) { if (document.editform && document.editform[btn]) { var button=document.editform[btn]; var msg=tprintf('The %s button has been automatically clicked. Please wait for the next page to load.', [ button.value ]); bannerMessage(msg); document.title='('+document.title+')'; button.click(); } else { alert(tprintf('Could not find button %s. Please check the settings in your javascript file.', [ btn ])); } } } function bannerMessage(s) { var headings=document.getElementsByTagName('h1'); if (headings) { var div=document.createElement('div'); div.innerHTML='<font size=+1><b>' + s + '</b></font>'; headings[0].parentNode.insertBefore(div, headings[0]); } } function getRvSummary(template, json) { try { var o=getJsObj(json); var edit = anyChild(o.query.pages).revisions[0]; var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, ''); return simplePrintf(template, [edit.revid, timestamp, edit.userhidden ? '(hidden)' : edit.user ]); } catch (badness) { return false; } } //</NOLITE> // ENDFILE: autoedit.js // STARTFILE: downloader.js /** @fileoverview {@link Downloader}, a xmlhttprequest wrapper, and helper functions. */ /** Creates a new Downloader @constructor @class The Downloader class. Create a new instance of this class to download stuff. @param {String} url The url to download. This can be omitted and supplied later. */ function Downloader(url) { if (typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); } /** The url to download @type String */ this.url = url; /** A universally unique ID number @type integer */ this.id=null; /** Modification date, to be culled from the incoming headers @type Date @private */ this.lastModified = null; /** What to do when the download completes successfully @type Function @private */ this.callbackFunction = null; /** What to do on failure @type Function @private */ this.onFailure = null; /** Flag set on <code>abort</code> @type boolean */ this.aborted = false; /** HTTP method. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities. @type String */ this.method='GET'; /** Async flag. @type boolean */ this.async=true; } new Downloader(); /** Submits the http request. */ Downloader.prototype.send = function (x) { if (!this.http) { return null; } return this.http.send(x); }; /** Aborts the download, setting the <code>aborted</code> field to true. */ Downloader.prototype.abort = function () { if (!this.http) { return null; } this.aborted=true; return this.http.abort(); }; /** Returns the downloaded data. */ Downloader.prototype.getData = function () {if (!this.http) { return null; } return this.http.responseText;}; /** Prepares the download. */ Downloader.prototype.setTarget = function () { if (!this.http) { return null; } this.http.open(this.method, this.url, this.async); this.http.setRequestHeader( 'Api-User-Agent', pg.misc.userAgent ); }; /** Gets the state of the download. */ Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;}; pg.misc.downloadsInProgress = { }; /** Starts the download. Note that setTarget {@link Downloader#setTarget} must be run first */ Downloader.prototype.start=function () { if (!this.http) { return; } pg.misc.downloadsInProgress[this.id] = this; this.http.send(null); }; /** Gets the 'Last-Modified' date from the download headers. Should be run after the download completes. Returns <code>null</code> on failure. @return {Date} */ Downloader.prototype.getLastModifiedDate=function () { if(!this.http) { return null; } var lastmod=null; try { lastmod=this.http.getResponseHeader('Last-Modified'); } catch (err) {} if (lastmod) { return new Date(lastmod); } return null; }; /** Sets the callback function. @param {Function} f callback function, called as <code>f(this)</code> on success */ Downloader.prototype.setCallback = function (f) { if(!this.http) { return; } this.http.onreadystatechange = f; }; Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; }; ////////////////////////////////////////////////// // helper functions /** Creates a new {@link Downloader} and prepares it for action. @param {String} url The url to download @param {integer} id The ID of the {@link Downloader} object @param {Function} callback The callback function invoked on success @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser */ function newDownload(url, id, callback, onfailure) { var d=new Downloader(url); if (!d.http) { return 'ohdear'; } d.id=id; d.setTarget(); if (!onfailure) { onfailure=2; } var f = function () { if (d.getReadyState() == 4) { delete pg.misc.downloadsInProgress[this.id]; try { if ( d.getStatus() == 200 ) { d.data=d.getData(); d.lastModified=d.getLastModifiedDate(); callback(d); } else if (typeof onfailure == typeof 1) { if (onfailure > 0) { // retry newDownload(url, id, callback, onfailure - 1); } } else if (typeof onfailure === 'function') { onfailure(d,url,id,callback); } } catch (somerr) { /* ignore it */ } } }; d.setCallback(f); return d; } /** Simulates a download from cached data. The supplied data is put into a {@link Downloader} as if it had downloaded it. @param {String} url The url. @param {integer} id The ID. @param {Function} callback The callback, which is invoked immediately as <code>callback(d)</code>, where <code>d</code> is the new {@link Downloader}. @param {String} data The (cached) data. @param {Date} lastModified The (cached) last modified date. */ function fakeDownload(url, id, callback, data, lastModified, owner) { var d=newDownload(url,callback); d.owner=owner; d.id=id; d.data=data; d.lastModified=lastModified; return callback(d); } /** Starts a download. @param {String} url The url to download @param {integer} id The ID of the {@link Downloader} object @param {Function} callback The callback function invoked on success @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser */ function startDownload(url, id, callback) { var d=newDownload(url, id, callback); if (typeof d == typeof '' ) { return d; } d.start(); return d; } /** Aborts all downloads which have been started. */ function abortAllDownloads() { for ( var x in pg.misc.downloadsInProgress ) { try { pg.misc.downloadsInProgress[x].aborted=true; pg.misc.downloadsInProgress[x].abort(); delete pg.misc.downloadsInProgress[x]; } catch (e) {} } } // ENDFILE: downloader.js // STARTFILE: livepreview.js // TODO: location is often not correct (eg relative links in previews) // NOTE: removed md5 and image and math parsing. was broken, lots of bytes. /** * InstaView - a Mediawiki to HTML converter in JavaScript * Version 0.6.1 * Copyright (C) Pedro Fayolle 2005-2006 * https://en.wikipedia.org/wiki/User:Pilaf * Distributed under the BSD license * * Changelog: * * 0.6.1 * - Fixed problem caused by \r characters * - Improved inline formatting parser * * 0.6 * - Changed name to InstaView * - Some major code reorganizations and factored out some common functions * - Handled conversion of relative links (i.e. [[/foo]]) * - Fixed misrendering of adjacent definition list items * - Fixed bug in table headings handling * - Changed date format in signatures to reflect Mediawiki's * - Fixed handling of [[:Image:...]] * - Updated MD5 function (hopefully it will work with UTF-8) * - Fixed bug in handling of links inside images * * To do: * - Better support for math tags * - Full support for <nowiki> * - Parser-based (as opposed to RegExp-based) inline wikicode handling (make it one-pass and bullet-proof) * - Support for templates (through AJAX) * - Support for coloured links (AJAX) */ var Insta = {}; function setupLivePreview() { // options Insta.conf = { baseUrl: '', user: {}, wiki: { lang: pg.wiki.lang, interwiki: pg.wiki.interwiki, default_thumb_width: 180 }, paths: { articles: pg.wiki.articlePath + '/', // Only used for Insta previews with images. (not in popups) math: '/math/', images: '//upload.wikimedia.org/wikipedia/en/', // FIXME getImageUrlStart(pg.wiki.hostname), images_fallback: '//upload.wikimedia.org/wikipedia/commons/', }, locale: { user: mw.config.get('wgFormattedNamespaces')[pg.nsUserId], image: mw.config.get('wgFormattedNamespaces')[pg.nsImageId], category: mw.config.get('wgFormattedNamespaces')[pg.nsCategoryId], // shouldn't be used in popup previews, i think months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] } }; // options with default values or backreferences Insta.conf.user.name = Insta.conf.user.name || 'Wikipedian'; Insta.conf.user.signature = '[['+Insta.conf.locale.user+':'+Insta.conf.user.name+'|'+Insta.conf.user.name+']]'; //Insta.conf.paths.images = '//upload.wikimedia.org/wikipedia/' + Insta.conf.wiki.lang + '/'; // define constants Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+ '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i'); } Insta.dump = function(from, to) { if (typeof from == 'string') { from = document.getElementById(from); } if (typeof to == 'string') { to = document.getElementById(to); } to.innerHTML = this.convert(from.value); }; Insta.convert = function(wiki) { var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode o = '', // output p = 0, // para flag $r; // result of passing a regexp to $() // some shorthands function remain() { return ll.length; } function sh() { return ll.shift(); } // shift function ps(s) { o += s; } // push // similar to C's printf, uses ? as placeholders, ?? to escape question marks function f() { var i=1, a=arguments, f=a[0], o='', c, p; for (; i<a.length; i++) { if ((p=f.indexOf('?'))+1) { // allow character escaping i -= c = f.charAt(p+1)=='?' ? 1 : 0; o += f.substring(0,p) + (c ? '?' : a[i]); f = f.substr(p+1+c); } else { break; } } return o+f; } function html_entities(s) { return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"); } // Wiki text parsing to html is a nightmare. // The below functions deliberately don't escape the ampersand since this would make it more difficult, // and we don't absolutely need to for how we need it. // This means that any unescaped ampersands in wikitext will remain unescaped and can cause invalid HTML. // Browsers should all be able to handle it though. // We also escape significant wikimarkup characters to prevent further matching on the processed text function htmlescape_text(s) { return s.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/:/g,"&#58;").replace(/\[/g,"&#91;").replace(/]/g,"&#93;"); } function htmlescape_attr(s) { return htmlescape_text(s).replace(/'/g,"&#39;").replace(/"/g,"&quot;"); } // return the first non matching character position between two strings function str_imatch(a, b) { for (var i=0, l=Math.min(a.length, b.length); i<l; i++) { if (a.charAt(i)!=b.charAt(i)) { break; } } return i; } // compare current line against a string or regexp // if passed a string it will compare only the first string.length characters // if passed a regexp the result is stored in $r function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)); } function $$(c) { return ll[0]==c; } // compare current line against a string function _(p) { return ll[0].charAt(p); } // return char at pos p function endl(s) { ps(s); sh(); } function parse_list() { var prev=''; while (remain() && $(/^([*#:;]+)(.*)$/)) { var l_match = $r; sh(); var ipos = str_imatch(prev, l_match[1]); // close uncontinued lists for (var prevPos=prev.length-1; prevPos >= ipos; prevPos--) { var pi = prev.charAt(prevPos); if (pi=='*') { ps('</ul>'); } else if (pi=='#') { ps('</ol>'); } // close a dl only if the new item is not a dl item (:, ; or empty) else if($.inArray(l_match[1].charAt(prevPos), ['','*','#'])) { ps('</dl>'); } } // open new lists for (var matchPos=ipos; matchPos<l_match[1].length; matchPos++) { var li = l_match[1].charAt(matchPos); if (li=='*') { ps('<ul>'); } else if (li=='#') { ps('<ol>'); } // open a new dl only if the prev item is not a dl item (:, ; or empty) else if ($.inArray(prev.charAt(matchPos), ['','*','#'])) { ps('<dl>'); } } switch (l_match[1].charAt(l_match[1].length-1)) { case '*': case '#': ps('<li>' + parse_inline_nowiki(l_match[2])); break; case ';': ps('<dt>'); var dt_match = l_match[2].match(/(.*?)(:.*?)$/); // handle ;dt :dd format if (dt_match) { ps(parse_inline_nowiki(dt_match[1])); ll.unshift(dt_match[2]); } else ps(parse_inline_nowiki(l_match[2])); break; case ':': ps('<dd>' + parse_inline_nowiki(l_match[2])); } prev=l_match[1]; } // close remaining lists for (var i=prev.length-1; i>=0; i--) { ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl'))); } } function parse_table() { endl(f('<table>', $(/^\{\|( .*)$/)? $r[1]: '')); for (;remain();) if ($('|')) switch (_(1)) { case '}': endl('</table>'); return; case '-': endl(f('<tr>', $(/\|-*(.*)/)[1])); break; default: parse_table_data(); } else if ($('!')) { parse_table_data(); } else { sh(); } } function parse_table_data() { var td_line, match_i; // 1: "|+", '|' or '+' // 2: ?? // 3: attributes ?? // TODO: finish commenting this regexp var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/); if (td_match[1] == '|+') ps('<caption'); else ps('<t' + ((td_match[1]=='|')?'d':'h')); if (typeof td_match[3] != 'undefined') { //ps(' ' + td_match[3]) match_i = 4; } else match_i = 2; ps('>'); if (td_match[1] != '|+') { // use || or !! as a cell separator depending on context // NOTE: when split() is passed a regexp make sure to use non-capturing brackets td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/); ps(parse_inline_nowiki(td_line.shift())); while (td_line.length) ll.unshift(td_match[1] + td_line.pop()); } else ps(td_match[match_i]); var tc = 0, td = []; while (remain()) { td.push(sh()); if ($('|')) { if (!tc) break; // we're at the outer-most level (no nested tables), skip to td parse else if (_(1)=='}') tc--; } else if (!tc && $('!')) break; else if ($('{|')) tc++; } if (td.length) ps(Insta.convert(td)); } function parse_pre() { ps('<pre>'); do { endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); } while (remain() && $(' ')); ps('</pre>'); } function parse_block_image() { ps(parse_image(sh())); } function parse_image(str) { //<NOLITE> // get what's in between "[[Image:" and "]]" var tag = str.substring(str.indexOf(':') + 1, str.length - 2); /* eslint-disable no-unused-vars */ var width; var attr = [], filename, caption = ''; var thumb=0, frame=0, center=0; var align=''; /* eslint-enable no-unused-vars */ if (tag.match(/\|/)) { // manage nested links var nesting = 0; var last_attr; for (var i = tag.length-1; i > 0; i--) { if (tag.charAt(i) == '|' && !nesting) { last_attr = tag.substr(i+1); tag = tag.substring(0, i); break; } else switch (tag.substr(i-1, 2)) { case ']]': nesting++; i--; break; case '[[': nesting--; i--; } } attr = tag.split(/\s*\|\s*/); attr.push(last_attr); filename = attr.shift(); var w_match; for (;attr.length; attr.shift()) { w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/); if (w_match) width = w_match[1]; else switch(attr[0]) { case 'thumb': case 'thumbnail': thumb=true; frame=true; break; case 'frame': frame=true; break; case 'none': case 'right': case 'left': center=false; align=attr[0]; break; case 'center': center=true; align='none'; break; default: if (attr.length == 1) caption = attr[0]; } } } else filename = tag; return ''; //</NOLITE> } function parse_inline_nowiki(str) { var start, lastend=0; var substart=0, nestlev=0, open, close, subloop; var html=''; while (-1 != (start = str.indexOf('<nowiki>', substart))) { html += parse_inline_wiki(str.substring(lastend, start)); start += 8; substart = start; subloop = true; do { open = str.indexOf('<nowiki>', substart); close = str.indexOf('</nowiki>', substart); if (close<=open || open==-1) { if (close==-1) { return html + html_entities(str.substr(start)); } substart = close+9; if (nestlev) { nestlev--; } else { lastend = substart; html += html_entities(str.substring(start, lastend-9)); subloop = false; } } else { substart = open+8; nestlev++; } } while (subloop); } return html + parse_inline_wiki(str.substr(lastend)); } function parse_inline_images(str) { //<NOLITE> var start, substart=0, nestlev=0; var loop, close, open, wiki, html; while (-1 != (start=str.indexOf('[[', substart))) { if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) { loop=true; substart=start; do { substart+=2; close=str.indexOf(']]',substart); open=str.indexOf('[[',substart); if (close<=open||open==-1) { if (close==-1) return str; substart=close; if (nestlev) { nestlev--; } else { wiki=str.substring(start,close+2); html=parse_image(wiki); str=str.replace(wiki,html); substart=start+html.length; loop=false; } } else { substart=open; nestlev++; } } while (loop); } else break; } //</NOLITE> return str; } // the output of this function doesn't respect the FILO structure of HTML // but since most browsers can handle it I'll save myself the hassle function parse_inline_formatting(str) { var em,st,i,li,o=''; while ((i=str.indexOf("''",li))+1) { o += str.substring(li,i); li=i+2; if (str.charAt(i+2)=="'") { li++; st=!st; o+=st?'<strong>':'</strong>'; } else { em=!em; o+=em?'<em>':'</em>'; } } return o+str.substr(li); } function parse_inline_wiki(str) { str = parse_inline_images(str); str = parse_inline_formatting(str); // math str = str.replace(/<(?:)math>(.*?)<\/math>/ig, ''); // Build a Mediawiki-formatted date string var date = new Date(); var minutes = date.getUTCMinutes(); if (minutes < 10) minutes = '0' + minutes; date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear()); // text formatting return str. // signatures replace(/~{5}(?!~)/g, date). replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date). replace(/~{3}(?!~)/g, Insta.conf.user.name). // [[:Category:...]], [[:Image:...]], etc... replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\\w*)','gi'), function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2));}). // remove straight category and interwiki tags replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),''). // [[:Category:...|Links]], [[:Image:...|Links]], etc... replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3));}). // [[/Relative links]] replace(/\[\[(\/[^|]*?)\]\]/g, function($0,$1){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($1)); }). // [[/Replaced|Relative links]] replace(/\[\[(\/.*?)\|(.+?)\]\]/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($2)); }). // [[Common links]] replace(/\[\[([^[|]*?)\]\](\w*)/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2)); }). // [[Replaced|Links]] replace(/\[\[([^[]*?)\|([^\]]+?)\]\](\w*)/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3)); }). // [[Stripped:Namespace|Namespace]] replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1) + htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($2)); }). // External links replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, function($0,$1,$2,$3,$4){return f("<a class='external' href='?:?'>?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($4)); }). replace(/\[http:\/\/(.*?)\]/g, function($0,$1){return f("<a class='external' href='http://?'>[#]</a>", htmlescape_attr($1)); }). replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, function($0,$1,$2,$3){return f("<a class='external' href='?:?'>?:?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($1), htmlescape_text($2) + htmlescape_text($3)); }). replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, function($0,$1,$2,$3,$4){return f("?<a class='external' href='?:?'>?:?</a>", htmlescape_text($1), htmlescape_attr($2), htmlescape_attr($3) + htmlescape_attr($4), htmlescape_text($2), htmlescape_text($3) + htmlescape_text($4)); }). replace('__NOTOC__',''). replace('__NOEDITSECTION__',''); } // begin parsing for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) { p=0; endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3])); } else if ($(/^[*#:;]/)) { p=0; parse_list(); } else if ($(' ')) { p=0; parse_pre(); } else if ($('{|')) { p=0; parse_table(); } else if ($(/^----+$/)) { p=0; endl('<hr />'); } else if ($(Insta.BLOCK_IMAGE)) { p=0; parse_block_image(); } else { // handle paragraphs if ($$('')) { p = (remain()>1 && ll[1]===('')); if (p) endl('<p><br>'); } else { if(!p) { ps('<p>'); p=1; } ps(parse_inline_nowiki(ll[0]) + ' '); } sh(); } return o; }; function wiki2html(txt,baseurl) { Insta.conf.baseUrl=baseurl; return Insta.convert(txt); } // ENDFILE: livepreview.js // STARTFILE: pageinfo.js //<NOLITE> function popupFilterPageSize(data) { return formatBytes(data.length); } function popupFilterCountLinks(data) { var num=countLinks(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink')); } function popupFilterCountImages(data) { var num=countImages(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image')); } function popupFilterCountCategories(data) { var num=countCategories(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category')); } function popupFilterLastModified(data,download) { var lastmod=download.lastModified; var now=new Date(); var age=now-lastmod; if (lastmod && getValueOf('popupLastModified')) { return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), '&nbsp;'); } return ''; } function formatAge(age) { // coerce into a number var a=0+age, aa=a; var seclen = 1000; var minlen = 60*seclen; var hourlen = 60*minlen; var daylen = 24*hourlen; var weeklen = 7*daylen; var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week'); var numdays = (a-a%daylen)/daylen; a = a-numdays*daylen; var sdays = addunit(numdays, 'day'); var numhours = (a-a%hourlen)/hourlen; a = a-numhours*hourlen; var shours = addunit(numhours,'hour'); var nummins = (a-a%minlen)/minlen; a = a-nummins*minlen; var smins = addunit(nummins, 'minute'); var numsecs = (a-a%seclen)/seclen; a = a-numsecs*seclen; var ssecs = addunit(numsecs, 'second'); if (aa > 4*weeklen) { return sweeks; } if (aa > weeklen) { return sweeks + ' ' + sdays; } if (aa > daylen) { return sdays + ' ' + shours; } if (aa > 6*hourlen) { return shours; } if (aa > hourlen) { return shours + ' ' + smins; } if (aa > 10*minlen) { return smins; } if (aa > minlen) { return smins + ' ' + ssecs; } return ssecs; } function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;} function runPopupFilters(list, data, download) { var ret=[]; for (var i=0; i<list.length; ++i) { if (list[i] && typeof list[i] == 'function') { var s=list[i](data, download, download.owner.article); if (s) { ret.push(s); } } } return ret; } function getPageInfo(data, download) { if (!data || data.length === 0) { return popupString('Empty page'); } var popupFilters=getValueOf('popupFilters') || []; var extraPopupFilters = getValueOf('extraPopupFilters') || []; var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download); var pageInfo=pageInfoArray.join(', '); if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); } return pageInfo; } // this could be improved! function countLinks(wikiText) { return wikiText.split('[[').length - 1; } // if N = # matches, n = # brackets, then // String.parenSplit(regex) intersperses the N+1 split elements // with Nn other elements. So total length is // L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1). function countImages(wikiText) { return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1); } function countCategories(wikiText) { return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1); } function popupFilterStubDetect(data, download, article) { var counts=stubCount(data, article); if (counts.real) { return popupString('stub'); } if (counts.sect) { return popupString('section stub'); } return ''; } function popupFilterDisambigDetect(data, download, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return ''; } return (isDisambig(data, article)) ? popupString('disambig') : ''; } function formatBytes(num) { return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ; } //</NOLITE> // ENDFILE: pageinfo.js // STARTFILE: titles.js /** @fileoverview Defines the {@link Title} class, and associated crufty functions. <code>Title</code> deals with article titles and their various forms. {@link Stringwrapper} is the parent class of <code>Title</code>, which exists simply to make things a little neater. */ /** Creates a new Stringwrapper. @constructor @class the Stringwrapper class. This base class is not really useful on its own; it just wraps various common string operations. */ function Stringwrapper() { /** Wrapper for this.toString().indexOf() @param {String} x @type integer */ this.indexOf=function(x){return this.toString().indexOf(x);}; /** Returns this.value. @type String */ this.toString=function(){return this.value;}; /** Wrapper for {@link String#parenSplit} applied to this.toString() @param {RegExp} x @type Array */ this.parenSplit=function(x){return this.toString().parenSplit(x);}; /** Wrapper for this.toString().substring() @param {String} x @param {String} y (optional) @type String */ this.substring=function(x,y){ if (typeof y=='undefined') { return this.toString().substring(x); } return this.toString().substring(x,y); }; /** Wrapper for this.toString().split() @param {String} x @type Array */ this.split=function(x){return this.toString().split(x);}; /** Wrapper for this.toString().replace() @param {String} x @param {String} y @type String */ this.replace=function(x,y){ return this.toString().replace(x,y); }; } /** Creates a new <code>Title</code>. @constructor @class The Title class. Holds article titles and converts them into various forms. Also deals with anchors, by which we mean the bits of the article URL after a # character, representing locations within an article. @param {String} value The initial value to assign to the article. This must be the canonical title (see {@link Title#value}. Omit this in the constructor and use another function to set the title if this is unavailable. */ function Title(val) { /** The canonical article title. This must be in UTF-8 with no entities, escaping or nasties. Also, underscores should be replaced with spaces. @type String @private */ this.value=null; /** The canonical form of the anchor. This should be exactly as it appears in the URL, i.e. with the .C3.0A bits in. @type String */ this.anchor=''; this.setUtf(val); } Title.prototype=new Stringwrapper(); /** Returns the canonical representation of the article title, optionally without anchor. @param {boolean} omitAnchor @fixme Decide specs for anchor @return String The article title and the anchor. */ Title.prototype.toString=function(omitAnchor) { return this.value + ( (!omitAnchor && this.anchor) ? '#' + this.anchorString() : '' ); }; Title.prototype.anchorString=function() { if (!this.anchor) { return ''; } var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/); var len=split.length; for (var j=1; j<len; j+=2) { // FIXME s/decodeURI/decodeURIComponent/g ? split[j]=decodeURIComponent(split[j].split('.').join('%')).split('_').join(' '); } return split.join(''); }; Title.prototype.urlAnchor=function() { var split=this.anchor.parenSplit('/((?:[%][0-9A-F]{2})+)/'); var len=split.length; for (var j=1; j<len; j+=2) { split[j]=split[j].split('%').join('.'); } return split.join(''); }; Title.prototype.anchorFromUtf=function(str) { this.anchor=encodeURIComponent(str.split(' ').join('_')) .split('%3A').join(':').split("'").join('%27').split('%').join('.'); }; Title.fromURL=function(h) { return new Title().fromURL(h); }; Title.prototype.fromURL=function(h) { if (typeof h != 'string') { this.value=null; return this; } // NOTE : playing with decodeURI, encodeURI, escape, unescape, // we seem to be able to replicate the IE borked encoding // IE doesn't do this new-fangled utf-8 thing. // and it's worse than that. // IE seems to treat the query string differently to the rest of the url // the query is treated as bona-fide utf8, but the first bit of the url is pissed around with // we fix up & for all browsers, just in case. var splitted=h.split('?'); splitted[0]=splitted[0].split('&').join('%26'); h=splitted.join('?'); var contribs=pg.re.contribs.exec(h); if (contribs) { if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); } var u=new Title(contribs[3]); this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + u.stripNamespace())); return this; } var email=pg.re.email.exec(h); if (email) { this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(email[3]).stripNamespace())); return this; } var backlinks=pg.re.backlinks.exec(h); if (backlinks) { this.setUtf(this.decodeNasties(new Title(backlinks[3]))); return this; } //A dummy title object for a Special:Diff link. var specialdiff=pg.re.specialdiff.exec(h); if (specialdiff) { this.setUtf(this.decodeNasties(new Title(mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Diff'))); return this; } // no more special cases to check -- // hopefully it's not a disguised user-related or specially treated special page var m=pg.re.main.exec(h); if(m === null) { this.value=null; } else { var fromBotInterface = /[?](.+[&])?title=/.test(h); if (fromBotInterface) { m[2]=m[2].split('+').join('_'); } var extracted = m[2] + (m[3] ? '#' + m[3] : ''); if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) { // Fix Safari issue // Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3. this.setUtf(decodeURIComponent(unescape(extracted))); } else { this.setUtf(this.decodeNasties(extracted)); } } return this; }; Title.prototype.decodeNasties=function(txt) { var ret= this.decodeEscapes(decodeURI(txt)); ret = ret.replace(/[_ ]*$/, ''); return ret; }; Title.prototype.decodeEscapes=function(txt) { var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/); var len=split.length; for (var i=1; i<len; i=i+2) { // FIXME is decodeURIComponent better? split[i]=unescape(split[i]); } return split.join(''); }; Title.fromAnchor=function(a) { return new Title().fromAnchor(a); }; Title.prototype.fromAnchor=function(a) { if (!a) { this.value=null; return this; } return this.fromURL(a.href); }; Title.fromWikiText=function(txt) { return new Title().fromWikiText(txt); }; Title.prototype.fromWikiText=function(txt) { // FIXME - testing needed txt=myDecodeURI(txt); this.setUtf(txt); return this; }; Title.prototype.hintValue=function(){ if(!this.value) { return ''; } return safeDecodeURI(this.value); }; //<NOLITE> Title.prototype.toUserName=function(withNs) { if (this.namespaceId() != pg.nsUserId && this.namespaceId() != pg.nsUsertalkId) { this.value=null; return; } this.value = (withNs ? mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' : '') + this.stripNamespace().split('/')[0]; }; Title.prototype.userName=function(withNs) { var t=(new Title(this.value)); t.toUserName(withNs); if (t.value) { return t; } return null; }; Title.prototype.toTalkPage=function() { // convert article to a talk page, or if we can't, return null // In other words: return null if this ALREADY IS a talk page // and return the corresponding talk page otherwise // // Per https://www.mediawiki.org/wiki/Manual:Namespace#Subject_and_talk_namespaces // * All discussion namespaces have odd-integer indices // * The discussion namespace index for a specific namespace with index n is n + 1 if (this.value === null) { return null; } var namespaceId = this.namespaceId(); if (namespaceId>=0 && namespaceId % 2 === 0) //non-special and subject namespace { var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId+1]; if (typeof localizedNamespace!=='undefined') { if (localizedNamespace === '') { this.value = this.stripNamespace(); } else { this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace(); } return this.value; } } this.value=null; return null; }; //</NOLITE> // Return canonical, localized namespace Title.prototype.namespace=function() { return mw.config.get('wgFormattedNamespaces')[this.namespaceId()]; }; Title.prototype.namespaceId=function() { var n=this.value.indexOf(':'); if (n<0) { return 0; } //mainspace var namespaceId = mw.config.get('wgNamespaceIds')[this.value.substring(0,n).split(' ').join('_').toLowerCase()]; if (typeof namespaceId=='undefined') return 0; //mainspace return namespaceId; }; //<NOLITE> Title.prototype.talkPage=function() { var t=new Title(this.value); t.toTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.isTalkPage=function() { if (this.talkPage()===null) { return true; } return false; }; Title.prototype.toArticleFromTalkPage=function() { //largely copy/paste from toTalkPage above. if (this.value === null) { return null; } var namespaceId = this.namespaceId(); if (namespaceId >= 0 && namespaceId % 2 == 1) //non-special and talk namespace { var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId-1]; if (typeof localizedNamespace!=='undefined') { if (localizedNamespace === '') { this.value = this.stripNamespace(); } else { this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace(); } return this.value; } } this.value=null; return null; }; Title.prototype.articleFromTalkPage=function() { var t=new Title(this.value); t.toArticleFromTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.articleFromTalkOrArticle=function() { var t=new Title(this.value); if ( t.toArticleFromTalkPage() ) { return t; } return this; }; Title.prototype.isIpUser=function() { return pg.re.ipUser.test(this.userName()); }; //</NOLITE> Title.prototype.stripNamespace=function(){ // returns a string, not a Title var n=this.value.indexOf(':'); if (n<0) { return this.value; } var namespaceId = this.namespaceId(); if (namespaceId === pg.nsMainspaceId) return this.value; return this.value.substring(n+1); }; Title.prototype.setUtf=function(value){ if (!value) { this.value=''; return; } var anch=value.indexOf('#'); if(anch < 0) { this.value=value.split('_').join(' '); this.anchor=''; return; } this.value=value.substring(0,anch).split('_').join(' '); this.anchor=value.substring(anch+1); this.ns=null; // wait until namespace() is called }; Title.prototype.setUrl=function(urlfrag) { var anch=urlfrag.indexOf('#'); this.value=safeDecodeURI(urlfrag.substring(0,anch)); this.anchor=this.value.substring(anch+1); }; Title.prototype.append=function(x){ this.setUtf(this.value + x); }; Title.prototype.urlString=function(x) { if(!x) { x={}; } var v=this.toString(true); if (!x.omitAnchor && this.anchor) { v+= '#' + this.urlAnchor(); } if (!x.keepSpaces) { v=v.split(' ').join('_'); } return encodeURI(v).split('&').join('%26').split('?').join('%3F').split('+').join('%2B'); }; Title.prototype.removeAnchor=function() { return new Title(this.toString(true)); }; Title.prototype.toUrl=function() { return pg.wiki.titlebase + this.urlString(); }; function parseParams(url) { var specialDiff = pg.re.specialdiff.exec(url); if (specialDiff) { var split= specialDiff[1].split('/'); if (split.length==1) return {oldid:split[0], diff: 'prev'}; else if (split.length==2) return {oldid: split[0], diff: split[1]}; } var ret={}; if (url.indexOf('?')==-1) { return ret; } url = url.split('#')[0]; var s=url.split('?').slice(1).join(); var t=s.split('&'); for (var i=0; i<t.length; ++i) { var z=t[i].split('='); z.push(null); ret[z[0]]=z[1]; } //Diff revision with no oldid is interpreted as a diff to the previous revision by MediaWiki if (ret.diff && typeof(ret.oldid)==='undefined') { ret.oldid = "prev"; } //Documentation seems to say something different, but oldid can also accept prev/next, and Echo is emitting such URLs. Simple fixup during parameter decoding: if (ret.oldid && (ret.oldid==='prev' || ret.oldid==='next' || ret.oldid==='cur')) { var helper = ret.diff; ret.diff = ret.oldid; ret.oldid = helper; } return ret; } // (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup) // (b) change spaces to underscores // (c) encodeURI (just the straight one, no pg.re.urlNoPopup) function myDecodeURI (str) { var ret; // FIXME decodeURIComponent?? try { ret=decodeURI(str.toString()); } catch (summat) { return str; } for (var i=0; i<pg.misc.decodeExtras.length; ++i) { var from=pg.misc.decodeExtras[i].from; var to=pg.misc.decodeExtras[i].to; ret=ret.split(from).join(to); } return ret; } function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; } /////////// // TESTS // /////////// //<NOLITE> function isDisambig(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } return ! article.isTalkPage() && pg.re.disambig.test(data); } function stubCount(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } var sectStub=0; var realStub=0; if (pg.re.stub.test(data)) { var s=data.parenSplit(pg.re.stub); for (var i=1; i<s.length; i=i+2) { if (s[i]) { ++sectStub; } else { ++realStub; } } } return { real: realStub, sect: sectStub }; } function isValidImageName(str){ // extend as needed... return ( str.indexOf('{') == -1 ); } function isInStrippableNamespace(article) { // Does the namespace allow subpages // Note, would be better if we had access to wgNamespacesWithSubpages return ( article.namespaceId() !== 0 ); } function isInMainNamespace(article) { return article.namespaceId() === 0; } function anchorContainsImage(a) { // iterate over children of anchor a // see if any are images if (a === null) { return false; } var kids=a.childNodes; for (var i=0; i<kids.length; ++i) { if (kids[i].nodeName=='IMG') { return true; } } return false; } //</NOLITE> function isPopupLink(a) { // NB for performance reasons, TOC links generally return true // they should be stripped out later if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); } if (a.inNopopupSpan) { return false; } // FIXME is this faster inline? if (a.onmousedown || a.getAttribute('nopopup')) { return false; } var h=a.href; if (h === document.location.href+'#') { return false; } if (!pg.re.basenames.test(h)) { return false; } if (!pg.re.urlNoPopup.test(h)) { return true; } return ( (pg.re.email.test(h) || pg.re.contribs.test(h) || pg.re.backlinks.test(h) || pg.re.specialdiff.test(h)) && h.indexOf('&limit=') == -1 ); } function markNopopupSpanLinks() { if( !getValueOf('popupOnlyArticleLinks')) fixVectorMenuPopups(); var s = $('.nopopups').toArray(); for (var i=0; i<s.length; ++i) { var as=s[i].getElementsByTagName('a'); for (var j=0; j<as.length; ++j) { as[j].inNopopupSpan=true; } } markNopopupSpanLinks.done=true; } function fixVectorMenuPopups() { $('div.vectorMenu h3:first a:first').prop('inNopopupSpan', true); } // ENDFILE: titles.js // STARTFILE: getpage.js ////////////////////////////////////////////////// // Wiki-specific downloading // // Schematic for a getWiki call // // getPageWithCaching // | // false | true // getPage<-[findPictureInCache]->-onComplete(a fake download) // \. // (async)->addPageToCache(download)->-onComplete(download) // check cache to see if page exists function getPageWithCaching(url, onComplete, owner) { log('getPageWithCaching, url='+url); var i=findInPageCache(url); var d; if (i > -1) { d=fakeDownload(url, owner.idNumber, onComplete, pg.cache.pages[i].data, pg.cache.pages[i].lastModified, owner); } else { d=getPage(url, onComplete, owner); if (d && owner && owner.addDownload) { owner.addDownload(d); d.owner=owner; } } } function getPage(url, onComplete, owner) { log('getPage'); var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d);} }; return startDownload(url, owner.idNumber, callback); } function findInPageCache(url) { for (var i=0; i<pg.cache.pages.length; ++i) { if (url==pg.cache.pages[i].url) { return i; } } return -1; } function addPageToCache(download) { log('addPageToCache '+download.url); var page = {url: download.url, data: download.data, lastModified: download.lastModified}; return pg.cache.pages.push(page); } // ENDFILE: getpage.js // STARTFILE: parensplit.js ////////////////////////////////////////////////// // parenSplit // String.prototype.parenSplit should do what ECMAscript says String.prototype.split does, // interspersing paren matches (regex capturing groups) between the split elements. // i.e. 'abc'.split(/(b)/)) should return ['a','b','c'], not ['a','c'] if (String('abc'.split(/(b)/))!='a,b,c') { // broken String.split, e.g. konq, IE < 10 String.prototype.parenSplit=function (re) { re=nonGlobalRegex(re); var s=this; var m=re.exec(s); var ret=[]; while (m && s) { // without the following loop, we have // 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/) for(var i=0; i<m.length; ++i) { if (typeof m[i]=='undefined') m[i]=''; } ret.push(s.substring(0,m.index)); ret = ret.concat(m.slice(1)); s=s.substring(m.index + m[0].length); m=re.exec(s); } ret.push(s); return ret; }; } else { String.prototype.parenSplit=function (re) { return this.split(re); }; String.prototype.parenSplit.isNative=true; } function nonGlobalRegex(re) { var s=re.toString(); var flags=''; for (var j=s.length; s.charAt(j) != '/'; --j) { if (s.charAt(j) != 'g') { flags += s.charAt(j); } } var t=s.substring(1,j); return RegExp(t,flags); } // ENDFILE: parensplit.js // STARTFILE: tools.js // IE madness with encoding // ======================== // // suppose throughout that the page is in utf8, like wikipedia // // if a is an anchor DOM element and a.href should consist of // // http://host.name.here/wiki/foo?bar=baz // // then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie)) // but IE gives bar=baz correctly as plain utf8 // // --------------------------------- // // IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here. // // --------------------------------- // // summat else // Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm //<NOLITE> function getJsObj(json) { try { var json_ret = JSON.parse(json); if( json_ret.warnings ) { for( var w=0; w < json_ret.warnings.length; w++ ) { if( json_ret.warnings[w]['*'] ) { log( json_ret.warnings[w]['*'] ); } else { log( json_ret.warnings[w]['warnings'] ); } } } else if ( json_ret.error ) { errlog( json_ret.error.code + ': ' + json_ret.error.info ); } return json_ret; } catch (someError) { errlog('Something went wrong with getJsObj, json='+json); return 1; } } function anyChild(obj) { for (var p in obj) { return obj[p]; } return null; } //</NOLITE> function upcaseFirst(str) { if (typeof str != typeof '' || str === '') return ''; return str.charAt(0).toUpperCase() + str.substring(1); } function findInArray(arr, foo) { if (!arr || !arr.length) { return -1; } var len=arr.length; for (var i=0; i<len; ++i) { if (arr[i]==foo) { return i; } } return -1; } /* eslint-disable no-unused-vars */ function nextOne (array, value) { // NB if the array has two consecutive entries equal // then this will loop on successive calls var i=findInArray(array, value); if (i<0) { return null; } return array[i+1]; } /* eslint-enable no-unused-vars */ function literalizeRegex(str){ return mw.util.escapeRegExp(str); } String.prototype.entify=function() { //var shy='&shy;'; return this.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;'/*+shy*/).split('"').join('&quot;'); }; // Array filter function function removeNulls(val) { return val !== null; } function joinPath(list) { return list.filter(removeNulls).join('/'); } function simplePrintf(str, subs) { if (!str || !subs) { return str; } var ret=[]; var s=str.parenSplit(/(%s|\$[0-9]+)/); var i=0; do { ret.push(s.shift()); if ( !s.length ) { break; } var cmd=s.shift(); if (cmd == '%s') { if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); } ++i; } else { var j=parseInt( cmd.replace('$', ''), 10 ) - 1; if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); } } } while (s.length > 0); return ret.join(''); } /* eslint-disable no-unused-vars */ function isString(x) { return (typeof x === 'string' || x instanceof String); } function isNumber(x) { return (typeof x === 'number' || x instanceof Number); } function isRegExp(x) { return x instanceof RegExp; } function isArray (x) { return x instanceof Array; } function isObject(x) { return x instanceof Object; } function isFunction(x) { return !isRegExp(x) && (typeof x === 'function' || x instanceof Function); } /* eslint-enable no-unused-vars */ function repeatString(s,mult) { var ret=''; for (var i=0; i<mult; ++i) { ret += s; } return ret; } function zeroFill(s, min) { min = min || 2; var t=s.toString(); return repeatString('0', min - t.length) + t; } function map(f, o) { if (isArray(o)) { return map_array(f,o); } return map_object(f,o); } function map_array(f,o) { var ret=[]; for (var i=0; i<o.length; ++i) { ret.push(f(o[i])); } return ret; } function map_object(f,o) { var ret={}; for (var i in o) { ret[o]=f(o[i]); } return ret; } pg.escapeQuotesHTML = function ( text ) { return text .replace(/&/g, "&amp;") .replace(/"/g, "&quot;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;"); }; // ENDFILE: tools.js // STARTFILE: dab.js //<NOLITE> ////////////////////////////////////////////////// // Dab-fixing code // function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) { log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget); return changeLinkTargetLink( {newTarget: newTarget, text: newTarget.split(' ').join('&nbsp;'), hint: tprintf('disambigHint', [newTarget]), summary: simplePrintf( getValueOf('popupFixDabsSummary'), [friendlyCurrentArticleName, newTarget ]), clickButton: getValueOf('popupDabsAutoClick'), minor: true, oldTarget: oldTarget, watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit}); } function listLinks(wikitext, oldTarget, titleToEdit) { // mediawiki strips trailing spaces, so we do the same // testcase: https://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633 var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi'); var ret=[]; var splitted=wikitext.parenSplit(reg); // ^[a-z]+ should match interwiki links, hopefully (case-insensitive) // and ^[a-z]* should match those and [[:Category...]] style links too var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory'); var friendlyCurrentArticleName= oldTarget.toString(); var wikPos = getValueOf('popupDabWiktionary'); for (var i=1; i<splitted.length; i=i+3) { if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) { ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) ); } /* if */ } /* for loop */ ret = rmDupesFromSortedList(ret.sort()); if (wikPos) { var wikTarget='wiktionary:' + friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' ); var meth; if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; } else { meth = 'push'; } ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) ); } ret.push(changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join('&nbsp;'), hint: popupString("remove all links to this disambig page from this article"), clickButton: getValueOf('popupDabsAutoClick'), oldTarget: oldTarget, summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]), watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit })); return ret; } function rmDupesFromSortedList(list) { var ret=[]; for (var i=0; i<list.length; ++i) { if (ret.length === 0 || list[i]!=ret[ret.length-1]) { ret.push(list[i]); } } return ret; } function makeFixDab(data, navpop) { // grab title from parent popup if there is one; default exists in changeLinkTargetLink var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString()); var list=listLinks(data, navpop.originalArticle, titleToEdit); if (list.length === 0) { log('listLinks returned empty list'); return null; } var html='<hr />' + popupString('Click to disambiguate this link to:') + '<br>'; html+=list.join(', '); return html; } function makeFixDabs(wikiText, navpop) { if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) && Title.fromURL(location.href).namespaceId() != pg.nsSpecialId && navpop.article.talkPage() ) { setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber); } } function popupRedlinkHTML(article) { return changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join('&nbsp;'), hint: popupString("remove all links to this page from this article"), clickButton: getValueOf('popupRedlinkAutoClick'), oldTarget: article.toString(), summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])}); } //</NOLITE> // ENDFILE: dab.js // STARTFILE: htmloutput.js // this has to use a timer loop as we don't know if the DOM element exists when we want to set the text function setPopupHTML (str, elementId, popupId, onSuccess, append) { if (typeof popupId === 'undefined') { //console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100)); popupId = pg.idNumber; } var popupElement=document.getElementById(elementId+popupId); if (popupElement) { if (!append) { popupElement.innerHTML=''; } if (isString(str)) { popupElement.innerHTML+=str; } else { popupElement.appendChild(str); } if (onSuccess) { onSuccess(); } setTimeout(checkPopupPosition, 100); return true; } else { // call this function again in a little while... setTimeout(function(){ setPopupHTML(str,elementId,popupId,onSuccess); }, 600); } return null; } //<NOLITE> function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);} //</NOLITE> // args.navpopup is mandatory // optional: args.redir, args.redirTarget // FIXME: ye gods, this is ugly stuff function fillEmptySpans(args) { // if redir is present and true then redirTarget is mandatory var redir=true; var rcid; if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; } var a=args.navpopup.parentAnchor; var article, hint=null, oldid=null, params={}; if (redir && typeof args.redirTarget == typeof {}) { article=args.redirTarget; //hint=article.hintValue(); } else { article=(new Title()).fromAnchor(a); hint=a.originalTitle || article.hintValue(); params=parseParams(a.href); oldid=(getValueOf('popupHistoricalLinks')) ? params.oldid : null; rcid=params.rcid; } var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params }; var structure=pg.structures[getValueOf('popupStructure')]; if (typeof structure != 'object') { setPopupHTML('popupError', 'Unknown structure (this should never happen): '+ pg.option.popupStructure, args.navpopup.idNumber); return; } var spans=flatten(pg.misc.layout); var numspans = spans.length; var redirs=pg.misc.redirSpans; for (var i=0; i<numspans; ++i) { var found = redirs && (redirs.indexOf( spans[i] ) !== -1); //log('redir='+redir+', found='+found+', spans[i]='+spans[i]); if ( (found && !redir) || (!found && redir) ) { //log('skipping this set of the loop'); continue; } var structurefn=structure[spans[i]]; var setfn = setPopupHTML; if (getValueOf('popupActiveNavlinks') && (spans[i].indexOf('popupTopLinks')===0 || spans[i].indexOf('popupRedirTopLinks')===0) ) { setfn = setPopupTipsAndHTML; } switch (typeof structurefn) { case 'function': log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})'); setfn(structurefn(x), spans[i], args.navpopup.idNumber); break; case 'string': setfn(structurefn, spans[i], args.navpopup.idNumber); break; default: errlog('unknown thing with label '+spans[i] + ' (span index was ' + i + ')'); break; } } } // flatten an array function flatten(list, start) { var ret=[]; if (typeof start == 'undefined') { start=0; } for (var i=start; i<list.length; ++i) { if (typeof list[i] == typeof []) { return ret.concat(flatten(list[i])).concat(flatten(list, i+1)); } else { ret.push(list[i]); } } return ret; } // Generate html for whole popup function popupHTML (a) { getValueOf('popupStructure'); var structure=pg.structures[pg.option.popupStructure]; if (typeof structure != 'object') { //return 'Unknown structure: '+pg.option.popupStructure; // override user choice pg.option.popupStructure=pg.optionDefault.popupStructure; return popupHTML(a); } if (typeof structure.popupLayout != 'function') { return 'Bad layout'; } pg.misc.layout=structure.popupLayout(); if (typeof structure.popupRedirSpans === 'function') { pg.misc.redirSpans=structure.popupRedirSpans(); } else { pg.misc.redirSpans=[]; } return makeEmptySpans(pg.misc.layout, a.navpopup); } function makeEmptySpans (list, navpop) { var ret=''; for (var i=0; i<list.length; ++i) { if (typeof list[i] == typeof '') { ret += emptySpanHTML(list[i], navpop.idNumber, 'div'); } else if (typeof list[i] == typeof [] && list[i].length > 0 ) { ret = ret.parenSplit(RegExp('(</[^>]*?>$)')).join(makeEmptySpans(list[i], navpop)); } else if (typeof list[i] == typeof {} && list[i].nodeType ) { ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType); } } return ret; } function emptySpanHTML(name, id, tag, classname) { tag = tag || 'span'; if (!classname) { classname = emptySpanHTML.classAliases[name]; } classname = classname || name; if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; } return simplePrintf('<%s id="%s" class="%s"></%s>', [tag, name + id, classname, tag]); } emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' }; // generate html for popup image // <a id="popupImageLinkn"><img id="popupImagen"> // where n=idNumber function imageHTML(article, idNumber) { return simplePrintf('<a id="popupImageLink$1">' + '<img align="right" valign="top" id="popupImg$1" style="display: none;"></img>' + '</a>', [ idNumber ]); } function popTipsSoonFn(id, when, popData) { if (!when) { when=250; } var popTips=function(){ setupTooltips(document.getElementById(id), false, true, popData); }; return function() { setTimeout( popTips, when, popData ); }; } function setPopupTipsAndHTML(html, divname, idnumber, popData) { setPopupHTML(html, divname, idnumber, getValueOf('popupSubpopups') ? popTipsSoonFn(divname + idnumber, null, popData) : null); } // ENDFILE: htmloutput.js // STARTFILE: mouseout.js ////////////////////////////////////////////////// // fuzzy checks function fuzzyCursorOffMenus(x,y, fuzz, parent) { if (!parent) { return null; } var uls=parent.getElementsByTagName('ul'); for (var i=0; i<uls.length; ++i) { if (uls[i].className=='popup_menu') { if (uls[i].offsetWidth > 0) return false; } // else {document.title+='.';} } return true; } function checkPopupPosition () { // stop the popup running off the right of the screen // FIXME avoid pg.current.link if (pg.current.link && pg.current.link.navpopup) pg.current.link.navpopup.limitHorizontalPosition(); } function mouseOutWikiLink () { //console ('mouseOutWikiLink'); var a=this; removeModifierKeyHandler(a); if (a.navpopup === null || typeof a.navpopup === 'undefined') return; if ( ! a.navpopup.isVisible() ) { a.navpopup.banish(); return; } restoreTitle(a); Navpopup.tracker.addHook(posCheckerHook(a.navpopup)); } function posCheckerHook(navpop) { return function() { if (!navpop.isVisible()) { return true; /* remove this hook */ } if (Navpopup.tracker.dirty) { return false; } var x=Navpopup.tracker.x, y=Navpopup.tracker.y; var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) || !fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv); // FIXME it'd be prettier to do this internal to the Navpopup objects var t=getValueOf('popupHideDelay'); if (t) { t = t * 1000; } if (!t) { if(!mouseOverNavpop) { if(navpop.parentAnchor) { restoreTitle( navpop.parentAnchor ); } navpop.banish(); return true; /* remove this hook */ } return false; } // we have a hide delay set var d=+(new Date()); if ( !navpop.mouseLeavingTime ) { navpop.mouseLeavingTime = d; return false; } if ( mouseOverNavpop ) { navpop.mouseLeavingTime=null; return false; } if (d - navpop.mouseLeavingTime > t) { navpop.mouseLeavingTime=null; navpop.banish(); return true; /* remove this hook */ } return false; }; } function runStopPopupTimer(navpop) { // at this point, we should have left the link but remain within the popup // so we call this function again until we leave the popup. if (!navpop.stopPopupTimer) { navpop.stopPopupTimer=setInterval(posCheckerHook(navpop), 500); navpop.addHook(function(){clearInterval(navpop.stopPopupTimer);}, 'hide', 'before'); } } // ENDFILE: mouseout.js // STARTFILE: previewmaker.js /** @fileoverview Defines the {@link Previewmaker} object, which generates short previews from wiki markup. */ /** Creates a new Previewmaker @constructor @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext. @param {String} wikiText The Wikitext source of the page we wish to preview. @param {String} baseUrl The url we should prepend when creating relative urls. @param {Navpopup} owner The navpop associated to this preview generator */ function Previewmaker(wikiText, baseUrl, owner) { /** The wikitext which is manipulated to generate the preview. */ this.originalData=wikiText; this.baseUrl=baseUrl; this.owner=owner; this.maxCharacters=getValueOf('popupMaxPreviewCharacters'); this.maxSentences=getValueOf('popupMaxPreviewSentences'); this.setData(); } Previewmaker.prototype.setData=function() { var maxSize=Math.max(10000, 2*this.maxCharacters); this.data=this.originalData.substring(0,maxSize); }; /** Remove HTML comments @private */ Previewmaker.prototype.killComments = function () { // this also kills one trailing newline, eg [[diamyo]] this.data=this.data.replace(RegExp('^<!--[^$]*?-->\\n|\\n<!--[^$]*?-->(?=\\n)|<!--[^$]*?-->', 'g'), ''); }; /** @private */ Previewmaker.prototype.killDivs = function () { // say goodbye, divs (can be nested, so use * not *?) this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*?< */ *div *>', 'gi'), ''); }; /** @private */ Previewmaker.prototype.killGalleries = function () { this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>', 'gi'), ''); }; /** @private */ Previewmaker.prototype.kill = function(opening, closing, subopening, subclosing, repl) { var oldk=this.data; var k=this.killStuff(this.data, opening, closing, subopening, subclosing, repl); while (k.length < oldk.length) { oldk=k; k=this.killStuff(k, opening, closing, subopening, subclosing, repl); } this.data=k; }; /** @private */ Previewmaker.prototype.killStuff = function (txt, opening, closing, subopening, subclosing, repl) { var op=this.makeRegexp(opening); var cl=this.makeRegexp(closing, '^'); var sb=subopening ? this.makeRegexp(subopening, '^') : null; var sc=subclosing ? this.makeRegexp(subclosing, '^') : cl; if (!op || !cl) { alert('Navigation Popups error: op or cl is null! something is wrong.'); return; } if (!op.test(txt)) { return txt; } var ret=''; var opResult = op.exec(txt); ret = txt.substring(0,opResult.index); txt=txt.substring(opResult.index+opResult[0].length); var depth = 1; while (txt.length > 0) { var removal=0; if (depth==1 && cl.test(txt)) { depth--; removal=cl.exec(txt)[0].length; } else if (depth > 1 && sc.test(txt)) { depth--; removal=sc.exec(txt)[0].length; }else if (sb && sb.test(txt)) { depth++; removal=sb.exec(txt)[0].length; } if ( !removal ) { removal = 1; } txt=txt.substring(removal); if (depth === 0) { break; } } return ret + (repl || '') + txt; }; /** @private */ Previewmaker.prototype.makeRegexp = function (x, prefix, suffix) { prefix = prefix || ''; suffix = suffix || ''; var reStr=''; var flags=''; if (isString(x)) { reStr=prefix + literalizeRegex(x) + suffix; } else if (isRegExp(x)) { var s=x.toString().substring(1); var sp=s.split('/'); flags=sp[sp.length-1]; sp[sp.length-1]=''; s=sp.join('/'); s=s.substring(0,s.length-1); reStr= prefix + s + suffix; } else { log ('makeRegexp failed'); } log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags); return RegExp(reStr, flags); }; /** @private */ Previewmaker.prototype.killBoxTemplates = function () { // taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general // also, have float_begin, ... float_end this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{'); // infoboxes etc // from [[User:Zyxw/popups.js]]: kill frames too this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{'); }; /** @private */ Previewmaker.prototype.killTemplates = function () { // the plus sign is to avoid transcluding [[Template:', ']] this.kill('{'+'{', '}'+'}', '{', '}', ' '); }; /** @private */ Previewmaker.prototype.killTables = function () { // tables are bad, too // this can be slow, but it's an inprovement over a browser hang // torture test: [[Comparison_of_Intel_Central_Processing_Units]] this.kill('{|', /[|]}\s*/, '{|'); this.kill(/<table.*?>/i, /<\/table.*?>/i, /<table.*?>/i); // remove lines starting with a pipe for the hell of it (?) this.data=this.data.replace(RegExp('^[|].*$', 'mg'), ''); }; /** @private */ Previewmaker.prototype.killImages = function () { var forbiddenNamespaceAliases = []; jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) { if (_namespaceId!=pg.nsImageId && _namespaceId!=pg.nsCategoryId) return; forbiddenNamespaceAliases.push(_localizedNamespaceLc.split(' ').join('[ _]')); //todo: escape regexp fragments! }); // images and categories are a nono this.kill(RegExp('[[][[]\\s*(' + forbiddenNamespaceAliases.join('|') + ')\\s*:', 'i'), /\]\]\s*/, '[', ']'); }; /** @private */ Previewmaker.prototype.killHTML = function () { // kill <ref ...>...</ref> this.kill(/<ref\b[^/>]*?>/i, /<\/ref>/i); // let's also delete entire lines starting with <. it's worth a try. this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n'); // and those pesky html tags, but not <nowiki> or <blockquote> var splitted=this.data.parenSplit(/(<[\w\W]*?(?:>|$|(?=<)))/); var len=splitted.length; for (var i=1; i<len; i=i+2) { switch (splitted[i]) { case '<nowiki>': case '</nowiki>': case '<blockquote>': case '</blockquote>': break; default: splitted[i]=''; } } this.data=splitted.join(''); }; /** @private */ Previewmaker.prototype.killChunks = function() { // heuristics alert // chunks of italic text? you crazy, man? var italicChunkRegex=new RegExp ("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)+", 'g'); // keep stuff separated, though, so stick in \n (fixes [[Union Jack]]? this.data=this.data.replace(italicChunkRegex, '\n'); }; /** @private */ Previewmaker.prototype.mopup = function () { // we simply *can't* be doing with horizontal rules right now this.data=this.data.replace(RegExp('^-{4,}','mg'),''); // no indented lines this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), ''); // replace __TOC__, __NOTOC__ and whatever else there is // this'll probably do this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),''); }; /** @private */ Previewmaker.prototype.firstBit = function () { // dont't be givin' me no subsequent paragraphs, you hear me? /// first we "normalize" section headings, removing whitespace after, adding before var d=this.data; if (getValueOf('popupPreviewCutHeadings')) { this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); /// then we want to get rid of paragraph breaks whose text ends badly this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); this.data=this.data.replace(RegExp('^[\\s\\n]*'), ''); var stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); if (stuff) { d = stuff[0]; } if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } /// now put \n\n after sections so that bullets and numbered lists work d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); } // Split sentences. Superfluous sentences are RIGHT OUT. // note: exactly 1 set of parens here needed to make the slice work d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g')); // leading space is bad, mmkay? d[0]=d[0].replace(RegExp('^\\s*'), ''); var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\[[^\\]]*|\\s[A-Zvclm])$', 'i'); d = this.fixSentenceEnds(d, notSentenceEnds); this.fullLength=d.join('').length; var n=this.maxSentences; var dd=this.firstSentences(d,n); do { dd=this.firstSentences(d,n); --n; } while ( dd.length > this.maxCharacters && n !== 0 ); this.data = dd; }; /** @private */ Previewmaker.prototype.fixSentenceEnds = function(strs, reg) { // take an array of strings, strs // join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg for (var i=0; i<strs.length-2; ++i) { if (reg.test(strs[i])) { var a=[]; for (var j=0; j<strs.length; ++j) { if (j<i) a[j]=strs[j]; if (j==i) a[i]=strs[i]+strs[i+1]+strs[i+2]; if (j>i+2) a[j-2]=strs[j]; } return this.fixSentenceEnds(a,reg); } } return strs; }; /** @private */ Previewmaker.prototype.firstSentences = function(strs, howmany) { var t=strs.slice(0, 2*howmany); return t.join(''); }; /** @private */ Previewmaker.prototype.killBadWhitespace = function() { // also cleans up isolated '''', eg [[Suntory Sungoliath]] this.data=this.data.replace(RegExp('^ *\'+ *$', 'gm'), ''); }; /** Runs the various methods to generate the preview. The preview is stored in the <code>html</html> field. @private */ Previewmaker.prototype.makePreview = function() { if (this.owner.article.namespaceId()!=pg.nsTemplateId && this.owner.article.namespaceId()!=pg.nsImageId ) { this.killComments(); this.killDivs(); this.killGalleries(); this.killBoxTemplates(); if (getValueOf('popupPreviewKillTemplates')) { this.killTemplates(); } else { this.killMultilineTemplates(); } this.killTables(); this.killImages(); this.killHTML(); this.killChunks(); this.mopup(); this.firstBit(); this.killBadWhitespace(); } else { this.killHTML(); } this.html=wiki2html(this.data, this.baseUrl); // needs livepreview this.fixHTML(); this.stripLongTemplates(); }; /** @private */ Previewmaker.prototype.esWiki2HtmlPart = function(data) { var reLinks = /(?:\[\[([^|\]]*)(?:\|([^|\]]*))*]]([a-z]*))/gi; //match a wikilink reLinks.lastIndex = 0; //reset regex var match; var result = ""; var postfixIndex = 0; while ((match = reLinks.exec(data))) //match all wikilinks { //FIXME: the way that link is built here isn't perfect. It is clickable, but popups preview won't recognize it in some cases. result += pg.escapeQuotesHTML(data.substring(postfixIndex, match.index)) + '<a href="'+Insta.conf.paths.articles+pg.escapeQuotesHTML(match[1])+'">'+pg.escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>"; postfixIndex = reLinks.lastIndex; } //append the rest result += pg.escapeQuotesHTML(data.substring(postfixIndex)); return result; }; Previewmaker.prototype.editSummaryPreview=function() { var reAes = /\/\* *(.*?) *\*\//g; //match the first section marker reAes.lastIndex = 0; //reset regex var match; match = reAes.exec(this.data); if (match) { //we have a section link. Split it, process it, combine it. var prefix = this.data.substring(0,match.index-1); var section = match[1]; var postfix = this.data.substring(reAes.lastIndex); var start = "<span class='autocomment'>"; var end = "</span>"; if (prefix.length>0) start = this.esWiki2HtmlPart(prefix) + " " + start + "- "; if (postfix.length>0) end = ": " + end + this.esWiki2HtmlPart(postfix); var t=new Title().fromURL(this.baseUrl); t.anchorFromUtf(section); var sectionLink = Insta.conf.paths.articles + pg.escapeQuotesHTML(t.toString(true)) + '#' + pg.escapeQuotesHTML(t.anchor); return start + '<a href="'+sectionLink+'">&rarr;</a> '+pg.escapeQuotesHTML(section) + end; } //else there's no section link, htmlify the whole thing. return this.esWiki2HtmlPart(this.data); }; //<NOLITE> /** Test function for debugging preview problems one step at a time. */ /*eslint-disable */ function previewSteps(txt) { try { txt=txt || document.editform.wpTextbox1.value; } catch (err) { if (pg.cache.pages.length > 0) { txt=pg.cache.pages[pg.cache.pages.length-1].data; } else { alert('provide text or use an edit page'); } } txt=txt.substring(0,10000); var base=pg.wiki.articlebase + Title.fromURL(document.location.href).urlString(); var p=new Previewmaker(txt, base, pg.current.link.navpopup); if (this.owner.article.namespaceId() != pg.nsTemplateId) { p.killComments(); if (!confirm('done killComments(). Continue?\n---\n' + p.data)) { return; } p.killDivs(); if (!confirm('done killDivs(). Continue?\n---\n' + p.data)) { return; } p.killGalleries(); if (!confirm('done killGalleries(). Continue?\n---\n' + p.data)) { return; } p.killBoxTemplates(); if (!confirm('done killBoxTemplates(). Continue?\n---\n' + p.data)) { return; } if (getValueOf('popupPreviewKillTemplates')) { p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; } } else { p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; } } p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; } p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; } p.killHTML(); if (!confirm('done killHTML(). Continue?\n---\n' + p.data)) { return; } p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; } p.mopup(); if (!confirm('done mopup(). Continue?\n---\n' + p.data)) { return; } p.firstBit(); if (!confirm('done firstBit(). Continue?\n---\n' + p.data)) { return; } p.killBadWhitespace(); if (!confirm('done killBadWhitespace(). Continue?\n---\n' + p.data)) { return; } } p.html=wiki2html(p.data, base); // needs livepreview p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; } p.stripLongTemplates(); if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { return; } alert('finished preview - end result follows.\n---\n' + p.html); } /*eslint-enable */ //</NOLITE> /** Works around livepreview bugs. @private */ Previewmaker.prototype.fixHTML = function() { if(!this.html) return; var ret = this.html; // fix question marks in wiki links // maybe this'll break some stuff :-( ret=ret.replace(RegExp('(<a href="' + pg.wiki.articlePath + '/[^"]*)[?](.*?")', 'g'), '$1%3F$2'); ret=ret.replace(RegExp('(<a href=\'' + pg.wiki.articlePath + '/[^\']*)[?](.*?\')', 'g'), '$1%3F$2'); // FIXME fix up % too this.html=ret; }; /** Generates the preview and displays it in the current popup. Does nothing if the generated preview is invalid or consists of whitespace only. Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true. */ Previewmaker.prototype.showPreview = function () { this.makePreview(); if (typeof this.html != typeof '') return; if (RegExp('^\\s*$').test(this.html)) return; setPopupHTML('<hr />', 'popupPrePreviewSep', this.owner.idNumber); setPopupTipsAndHTML(this.html, 'popupPreview', this.owner.idNumber, { owner: this.owner }); var more = (this.fullLength > this.data.length) ? this.moreLink() : ''; setPopupHTML(more, 'popupPreviewMore', this.owner.idNumber); }; /** @private */ Previewmaker.prototype.moreLink=function() { var a=document.createElement('a'); a.className='popupMoreLink'; a.innerHTML=popupString('more...'); var savedThis=this; a.onclick=function() { savedThis.maxCharacters+=2000; savedThis.maxSentences+=20; savedThis.setData(); savedThis.showPreview(); }; return a; }; /** @private */ Previewmaker.prototype.stripLongTemplates = function() { // operates on the HTML! this.html=this.html.replace(RegExp('^.{0,1000}[{][{][^}]*?(<(p|br)( /)?>\\s*){2,}([^{}]*?[}][}])?', 'gi'), ''); this.html=this.html.split('\n').join(' '); // workaround for <pre> templates this.html=this.html.replace(RegExp('[{][{][^}]*<pre>[^}]*[}][}]','gi'), ''); }; /** @private */ Previewmaker.prototype.killMultilineTemplates = function() { this.kill('{{{', '}}}'); this.kill(RegExp('\\s*[{][{][^{}]*\\n'), '}}', '{{'); }; // ENDFILE: previewmaker.js // STARTFILE: querypreview.js function loadAPIPreview(queryType, article, navpop) { var art=new Title(article).urlString(); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&'; var htmlGenerator=function(/*a, d*/){alert('invalid html generator');}; var usernameart = ''; switch (queryType) { case 'history': url += 'titles=' + art + '&prop=revisions&rvlimit=' + getValueOf('popupHistoryPreviewLimit'); htmlGenerator=APIhistoryPreviewHTML; break; case 'category': url += 'list=categorymembers&cmtitle=' + art; htmlGenerator=APIcategoryPreviewHTML; break; case 'userinfo': var username = new Title( article ).userName(); usernameart = encodeURIComponent( username ); if (pg.re.ipUser.test(username)) { url += 'list=blocks&bkprop=range|restrictions&bkip=' + usernameart; } else { url += 'list=users|usercontribs&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + usernameart + "&meta=globaluserinfo&guiprop=groups|unattached&guiuser="+ usernameart + "&uclimit=1&ucprop=timestamp&ucuser=" + usernameart; } htmlGenerator=APIuserInfoPreviewHTML; break; case 'contribs': usernameart = encodeURIComponent( new Title( article ).userName() ); url += 'list=usercontribs&ucuser=' + usernameart + '&uclimit=' + getValueOf('popupContribsPreviewLimit'); htmlGenerator=APIcontribsPreviewHTML; break; case 'imagepagepreview': var trail=''; if (getValueOf('popupImageLinks')) { trail = '&list=imageusage&iutitle=' + art; } url += 'titles=' + art + '&prop=revisions|imageinfo&rvprop=content' + trail; htmlGenerator=APIimagepagePreviewHTML; break; case 'backlinks': url += 'list=backlinks&bltitle=' + art; htmlGenerator=APIbacklinksPreviewHTML; break; case 'revision': if (article.oldid) { url += 'revids=' + article.oldid; } else { url += 'titles=' + article.removeAnchor().urlString(); } url += '&prop=revisions|pageprops|info|images|categories&rvprop=ids|timestamp|flags|comment|user|content&cllimit=max&imlimit=max'; htmlGenerator=APIrevisionPreviewHTML; break; } pendingNavpopTask(navpop); var callback=function(d){ log( "callback of API functions was hit" ); showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d); }; var go = function(){ getPageWithCaching(url, callback, navpop); return true; }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); } } function linkList(list) { list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); }); var buf=[]; for (var i=0; i<list.length; ++i) { buf.push(wikiLink({article: new Title(list[i]), text: list[i].split(' ').join('&nbsp;'), action: 'view'})); } return buf.join(', '); } function getTimeOffset() { var tz = mw.user.options.get('timecorrection'); if(tz) { if( tz.indexOf('|') > -1 ) { // New format return parseInt(tz.split('|')[1],10); } else if ( tz.indexOf(':') > -1 ) { // Old format return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) ); } } return 0; } /* * Creates a HTML table that's shown in the history and user-contribs popups. * @param {Object[]} h - a list of revisions, returned from the API * @param {boolean} reallyContribs - true only if we're displaying user contributions */ function editPreviewTable(article, h, reallyContribs, timeOffset) { var html=['<table>']; var day=null; var curart=article; var page=null; var makeFirstColumnLinks; if(reallyContribs) { // We're showing user contributions, so make (diff | hist) links makeFirstColumnLinks = function(currentRevision) { var result = '('; result += '<a href="' + pg.wiki.titlebase + new Title(currentRevision.title).urlString() + '&diff=prev' + '&oldid=' + currentRevision.revid + '">' + popupString('diff') + '</a>'; result += '&nbsp;|&nbsp;'; result += '<a href="' + pg.wiki.titlebase + new Title(currentRevision.title).urlString() + '&action=history">' + popupString('hist') + '</a>'; result += ')'; return result; }; } else { // It's a regular history page, so make (cur | last) links var firstRevid = h[0].revid; makeFirstColumnLinks = function(currentRevision) { var result = '('; result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&diff=' + firstRevid + '&oldid=' + currentRevision.revid + '">' + popupString('cur') + '</a>'; result += '&nbsp;|&nbsp;'; result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&diff=prev&oldid=' + currentRevision.revid + '">' + popupString('last') + '</a>'; result += ')'; return result; }; } for (var i=0; i<h.length; ++i) { if (reallyContribs) { page = h[i].title; curart = new Title(page); } var minor = h[i].minor ? '<b>m </b>' : ''; var editDate = adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset); var thisDay = dayFormat(editDate); var thisTime = timeFormat(editDate); if (thisDay == day) { thisDay = ''; } else { day = thisDay; } if (thisDay) { html.push( '<tr><td colspan=3><span class="popup_history_date">' + thisDay+'</span></td></tr>' ); } html.push('<tr class="popup_history_row_' + ( (i%2) ? 'odd' : 'even') + '">'); html.push('<td>' + makeFirstColumnLinks(h[i]) + '</td>'); html.push('<td>' + '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&oldid=' + h[i].revid + '">' + thisTime + '</a></td>'); var col3url='', col3txt=''; if (!reallyContribs) { var user=h[i].user; if( !h[i].userhidden ) { if( pg.re.ipUser.test(user) ) { col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Contributions&target=' + new Title(user).urlString(); } else { col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(user).urlString(); } col3txt=pg.escapeQuotesHTML(user); } else { col3url=getValueOf('popupRevDelUrl'); col3txt=pg.escapeQuotesHTML( popupString('revdel')); } } else { col3url=pg.wiki.titlebase + curart.urlString(); col3txt=pg.escapeQuotesHTML(page); } html.push('<td>' + (reallyContribs ? minor : '') + '<a href="' + col3url + '">' + col3txt + '</a></td>'); var comment=''; var c=h[i].comment || h[i].content; if (c) { comment=new Previewmaker(c, new Title(curart).toUrl()).editSummaryPreview(); } else if ( h[i].commenthidden ) { comment=popupString('revdel'); } html.push('<td>' + (!reallyContribs ? minor : '') + comment + '</td>'); html.push('</tr>'); html=[html.join('')]; } html.push('</table>'); return html.join(''); } function getDateFromTimestamp(t) { var s=t.split(/[^0-9]/); switch(s.length) { case 0: return null; case 1: return new Date(s[0]); case 2: return new Date(s[0], s[1]-1); case 3: return new Date(s[0], s[1]-1, s[2]); case 4: return new Date(s[0], s[1]-1, s[2], s[3]); case 5: return new Date(s[0], s[1]-1, s[2], s[3], s[4]); case 6: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]); default: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5], s[6]); } } function adjustDate(d, offset) { // offset is in minutes var o=offset * 60 * 1000; return new Date( +d + o); } function dayFormat(editDate, utc) { if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); } return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-'); } function timeFormat(editDate, utc) { if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); } return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':'); } function showAPIPreview(queryType, html, id, navpop, download) { // DJ: done var target='popupPreview'; completedNavpopTask(navpop); switch (queryType) { case 'imagelinks': case 'category': target='popupPostPreview'; break; case 'userinfo': target='popupUserData'; break; case 'revision': insertPreview(download); return; } setPopupTipsAndHTML(html, target, id); } function APIrevisionPreviewHTML(article, download) { try{ var jsObj=getJsObj(download.data); var page=anyChild(jsObj.query.pages); if( page.missing ) { // TODO we need to fix this proper later on download.owner = null; return; } var content = ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; if( typeof content === 'string' ) { download.data = content; download.lastModified = new Date(page.revisions[0].timestamp); } } catch(someError) { return 'Revision preview failed :('; } } function APIbacklinksPreviewHTML(article, download/*, navpop*/ ) { try { var jsObj=getJsObj(download.data); var list=jsObj.query.backlinks; var html=[]; if (!list) { return popupString('No backlinks found'); } for ( var i=0; i < list.length; i++ ) { var t=new Title(list[i].title); html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>'); } html=html.join(', '); if (jsObj['continue'] && jsObj['continue'].blcontinue) { html += popupString(' and more'); } return html; } catch (someError) { return 'backlinksPreviewHTML went wonky'; } } pg.fn.APIsharedImagePagePreviewHTML = function APIsharedImagePagePreviewHTML(obj) { log( "APIsharedImagePagePreviewHTML" ); var popupid = obj.requestid; if( obj.query && obj.query.pages ) { var page=anyChild(obj.query.pages ); var content = ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; if( typeof content === 'string' ) { /* Not entirely safe, but the best we can do */ var p=new Previewmaker(content, pg.current.link.navpopup.article, pg.current.link.navpopup); p.makePreview(); setPopupHTML( p.html, "popupSecondPreview", popupid ); } } }; function APIimagepagePreviewHTML(article, download, navpop) { try { var jsObj=getJsObj(download.data); var page=anyChild(jsObj.query.pages); var content= ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; var ret=''; var alt=''; try{alt=navpop.parentAnchor.childNodes[0].alt;} catch(e){} if (alt) { ret = ret + '<hr /><b>' + popupString('Alt text:') + '</b> ' + pg.escapeQuotesHTML(alt); } if (typeof content === 'string') { var p=prepPreviewmaker(content, article, navpop); p.makePreview(); if (p.html) { ret += '<hr />' + p.html; } if (getValueOf('popupSummaryData')) { var info=getPageInfo(content, download); log(info); setPopupTrailer(info, navpop.idNumber); } } if (page && page.imagerepository == "shared" ) { var art=new Title(article); var encart = encodeURIComponent( "File:" + art.stripNamespace() ); var shared_url = pg.wiki.apicommonsbase + '?format=json&formatversion=2' + '&callback=pg.fn.APIsharedImagePagePreviewHTML' + '&requestid=' + navpop.idNumber + '&action=query&prop=revisions&rvprop=content&titles=' + encart; ret = ret +'<hr />' + popupString( 'Image from Commons') + ': <a href="' + pg.wiki.commonsbase + '?title=' + encart + '">' + popupString( 'Description page') + '</a>'; mw.loader.load( shared_url ); } showAPIPreview('imagelinks', APIimagelinksPreviewHTML(article,download), navpop.idNumber, download); return ret; } catch (someError) { return 'API imagepage preview failed :('; } } function APIimagelinksPreviewHTML(article, download) { try { var jsobj=getJsObj(download.data); var list=jsobj.query.imageusage; if (list) { var ret=[]; for (var i=0; i < list.length; i++) { ret.push(list[i].title); } if (ret.length === 0) { return popupString('No image links found'); } return '<h2>' + popupString('File links') + '</h2>' + linkList(ret); } else { return popupString('No image links found'); } } catch(someError) { return 'Image links preview generation failed :('; } } function APIcategoryPreviewHTML(article, download) { try{ var jsobj=getJsObj(download.data); var list=jsobj.query.categorymembers; var ret=[]; for (var p=0; p < list.length; p++) { ret.push(list[p].title); } if (ret.length === 0) { return popupString('Empty category'); } ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret); if (jsobj['continue'] && jsobj['continue'].cmcontinue) { ret += popupString(' and more'); } return ret; } catch(someError) { return 'Category preview failed :('; } } function APIuserInfoPreviewHTML(article, download) { var ret=[]; var queryobj = {}; try{ queryobj=getJsObj(download.data).query; } catch(someError) { return 'Userinfo preview failed :('; } var user=anyChild(queryobj.users); if (user) { var globaluserinfo=queryobj.globaluserinfo; if (user.invalid === '') { ret.push( popupString( 'Invalid user') ); } else if (user.missing === '') { ret.push( popupString( 'Not a registered username') ); } if( user.blockedby ) { if( user.blockpartial ) { ret.push('<b>' + popupString('Has blocks') + '</b>'); } else { ret.push('<b>' + popupString('BLOCKED') + '</b>'); } } if( globaluserinfo && ( 'locked' in globaluserinfo || 'hidden' in globaluserinfo ) ) { var lockedSulAccountIsAttachedToThis = true; for( var i=0; globaluserinfo.unattached && i < globaluserinfo.unattached.length; i++) { if ( globaluserinfo.unattached[i].wiki === mw.config.get('wgDBname') ) { lockedSulAccountIsAttachedToThis=false; break; } } if (lockedSulAccountIsAttachedToThis) { if ( 'locked' in globaluserinfo ) ret.push('<b><i>' + popupString('LOCKED') + '</i></b>'); if ( 'hidden' in globaluserinfo ) ret.push('<b><i>' + popupString('HIDDEN') + '</i></b>'); } } if( getValueOf('popupShowGender') && user.gender ) { switch( user.gender ) { case "male": ret.push( popupString( "\u2642" ) ); break; case "female": ret.push( popupString( "\u2640" ) ); break; } } if( user.groups ) { for( var j=0; j < user.groups.length; j++) { var currentGroup = user.groups[j]; if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( currentGroup ) === -1 ) { ret.push( pg.escapeQuotesHTML(user.groups[j]) ); } } } if( globaluserinfo && globaluserinfo.groups ) { for( var k=0; k < globaluserinfo.groups.length; k++) { ret.push( '<i>'+pg.escapeQuotesHTML(globaluserinfo.groups[k])+'</i>' ); } } if( user.registration ) ret.push( pg.escapeQuotesHTML((user.editcount?user.editcount:'0') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'')) ); } if (queryobj.usercontribs && queryobj.usercontribs.length) { ret.push( popupString('last edit on ') + dayFormat(getDateFromTimestamp(queryobj.usercontribs[0].timestamp)) ); } if (queryobj.blocks) { ret.push( popupString( 'IP user') ); //we only request list=blocks for IPs for (var l=0; l<queryobj.blocks.length; l++) { console.log(queryobj); var rbstr = queryobj.blocks[l].rangestart === queryobj.blocks[l].rangeend ? 'BLOCK' : 'RANGEBLOCK'; rbstr = (!Array.isArray(queryobj.blocks[l].restrictions) ? 'Has ' + rbstr.toLowerCase() + 's' : rbstr + 'ED'); ret.push('<b>' + popupString(rbstr) + '</b>' ); } } ret = '<hr />' + ret.join( ', ' ); return ret; } function APIcontribsPreviewHTML(article, download, navpop) { return APIhistoryPreviewHTML(article, download, navpop, true); } function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) { try { var jsobj=getJsObj(download.data); var edits = []; if( reallyContribs ) { edits=jsobj.query.usercontribs; } else { edits=anyChild(jsobj.query.pages).revisions; } var ret=editPreviewTable(article, edits, reallyContribs, getTimeOffset()); return ret; } catch (someError) { return 'History preview failed :-('; } } //</NOLITE> // ENDFILE: querypreview.js // STARTFILE: debug.js //////////////////////////////////////////////////////////////////// // Debugging functions //////////////////////////////////////////////////////////////////// function setupDebugging() { //<NOLITE> if (window.popupDebug) { // popupDebug is set from .version window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; }; window.console.log(x); }; window.errlog=function(x) { window.console.error(x); }; log('Initializing logger'); } else { //</NOLITE> window.log = function() {}; window.errlog = function() {}; //<NOLITE> } //</NOLITE> } // ENDFILE: debug.js // STARTFILE: images.js // load image of type Title. function loadImage(image, navpop) { if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); } // API call to retrieve image info. if ( !getValueOf('popupImages') ) return; if ( !isValidImageName(image) ) return false; var art=image.urlString(); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query'; url += '&prop=imageinfo&iiprop=url|mime&iiurlwidth=' + getValueOf('popupImageSizeLarge'); url += '&titles=' + art; pendingNavpopTask(navpop); var callback=function(d){ popupsInsertImage(navpop.idNumber, navpop, d); }; var go = function(){ getPageWithCaching(url, callback, navpop); return true; }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'after', 'DOWNLOAD_IMAGE_QUERY_DATA'); } } function popupsInsertImage(id, navpop, download) { log( "popupsInsertImage"); var imageinfo; try { var jsObj=getJsObj(download.data); var imagepage=anyChild(jsObj.query.pages); if (typeof imagepage.imageinfo === 'undefined') return; imageinfo = imagepage.imageinfo[0]; } catch (someError) { log( "popupsInsertImage failed :(" ); return; } var popupImage = document.getElementById("popupImg"+id); if (!popupImage) { log( "could not find insertion point for image"); return; } popupImage.width=getValueOf('popupImageSize'); popupImage.style.display='inline'; // Set the source for the image. if( imageinfo.thumburl ) popupImage.src=imageinfo.thumburl; else if( imageinfo.mime.indexOf("image") === 0 ){ popupImage.src=imageinfo.url; log( "a thumb could not be found, using original image" ); } else log( "fullsize imagethumb, but not sure if it's an image"); var a=document.getElementById("popupImageLink"+id); if (a === null) { return null; } // Determine the action of the surrouding imagelink. switch (getValueOf('popupThumbAction')) { case 'imagepage': if (pg.current.article.namespaceId()!=pg.nsImageId) { a.href=imageinfo.descriptionurl; // FIXME: unreliable pg.idNumber popTipsSoonFn('popupImage' + id)(); break; } /* falls through */ case 'sizetoggle': a.onclick=toggleSize; a.title=popupString('Toggle image size'); return; case 'linkfull': a.href = imageinfo.url; a.title=popupString('Open full-size image'); return; } } // Toggles the image between inline small and navpop fullwidth. // It's the same image, no actual sizechange occurs, only display width. function toggleSize() { var imgContainer=this; if (!imgContainer) { alert('imgContainer is null :/'); return; } var img=imgContainer.firstChild; if (!img) { alert('img is null :/'); return; } if (!img.style.width || img.style.width==='') { img.style.width='100%'; } else { img.style.width=''; } } // Returns one title of an image from wikiText. function getValidImageFromWikiText(wikiText) { // nb in pg.re.image we're interested in the second bracketed expression // this may change if the regex changes :-( //var match=pg.re.image.exec(wikiText); var matched=null; var match; // strip html comments, used by evil bots :-( var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1, RegExp('^<!--[^[]*popup', 'i')); while ( ( match = pg.re.image.exec(t) ) ) { // now find a sane image name - exclude templates by seeking { var m = match[2] || match[6]; if ( isValidImageName(m) ) { matched=m; break; } } pg.re.image.lastIndex=0; if (!matched) { return null; } return mw.config.get('wgFormattedNamespaces')[pg.nsImageId]+':'+upcaseFirst(matched); } function removeMatchesUnless(str, re1, parencount, re2) { var split=str.parenSplit(re1); var c=parencount + 1; for (var i=0; i<split.length; ++i) { if ( i%c === 0 || re2.test(split[i]) ) { continue; } split[i]=''; } return split.join(''); } //</NOLITE> // ENDFILE: images.js // STARTFILE: namespaces.js // Set up namespaces and other non-strings.js localization // (currently that means redirs too) function setNamespaces() { pg.nsSpecialId = -1; pg.nsMainspaceId = 0; pg.nsImageId = 6; pg.nsUserId = 2; pg.nsUsertalkId = 3; pg.nsCategoryId = 14; pg.nsTemplateId = 10; } function setRedirs() { var r='redirect'; var R='REDIRECT'; var redirLists={ //<NOLITE> 'ar': [ R, 'تحويل' ], 'be': [ r, 'перанакіраваньне' ], 'bg': [ r, 'пренасочване', 'виж' ], 'bs': [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ], 'cs': [ R, 'PŘESMĚRUJ' ], 'cy': [ r, 'ail-cyfeirio' ], 'de': [ R, 'WEITERLEITUNG' ], 'el': [ R, 'ΑΝΑΚΑΤΕΥΘΥΝΣΗ'], 'eo': [ R, 'ALIDIREKTU', 'ALIDIREKTI' ], 'es': [ R, 'REDIRECCIÓN' ], 'et': [ r, 'suuna' ], 'ga': [ r, 'athsheoladh' ], 'gl': [ r, 'REDIRECCIÓN', 'REDIRECIONAMENTO'], 'he': [ R, 'הפניה' ], 'hu': [ R, 'ÁTIRÁNYÍTÁS' ], 'is': [ r, 'tilvísun', 'TILVÍSUN' ], 'it': [ R, 'RINVIA', 'Rinvia'], 'ja': [ R, '転送' ], 'mk': [ r, 'пренасочување', 'види' ], 'nds': [ r, 'wiederleiden' ], 'nl': [ R, 'DOORVERWIJZING' ], 'nn': [ r, 'omdiriger' ], 'pl': [ R, 'PATRZ', 'PRZEKIERUJ', 'TAM' ], 'pt': [ R, 'redir' ], 'ru': [ R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР' ], 'sk': [ r, 'presmeruj' ], 'sr': [ r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ], 'tt': [ R, 'yünältü', 'перенаправление', 'перенапр' ], 'uk': [ R, 'ПЕРЕНАПРАВЛЕННЯ', 'ПЕРЕНАПР' ], 'vi': [ r, 'đổi' ], 'zh': [ R, '重定向'] // no comma //</NOLITE> }; var redirList=redirLists[ pg.wiki.lang ] || [r, R]; // Mediawiki is very tolerant about what comes after the #redirect at the start pg.re.redirect=RegExp('^\\s*[#](' + redirList.join('|') + ').*?\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i'); } function setInterwiki() { if (pg.wiki.wikimedia) { // From https://meta.wikimedia.org/wiki/List_of_Wikipedias pg.wiki.interwiki='aa|ab|ace|af|ak|als|am|an|ang|ar|arc|arz|as|ast|av|ay|az|ba|bar|bat-smg|bcl|be|be-x-old|bg|bh|bi|bjn|bm|bn|bo|bpy|br|bs|bug|bxr|ca|cbk-zam|cdo|ce|ceb|ch|cho|chr|chy|ckb|co|cr|crh|cs|csb|cu|cv|cy|da|de|diq|dsb|dv|dz|ee|el|eml|en|eo|es|et|eu|ext|fa|ff|fi|fiu-vro|fj|fo|fr|frp|frr|fur|fy|ga|gag|gan|gd|gl|glk|gn|got|gu|gv|ha|hak|haw|he|hi|hif|ho|hr|hsb|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|ilo|io|is|it|iu|ja|jbo|jv|ka|kaa|kab|kbd|kg|ki|kj|kk|kl|km|kn|ko|koi|kr|krc|ks|ksh|ku|kv|kw|ky|la|lad|lb|lbe|lg|li|lij|lmo|ln|lo|lt|ltg|lv|map-bms|mdf|mg|mh|mhr|mi|mk|ml|mn|mo|mr|mrj|ms|mt|mus|mwl|my|myv|mzn|na|nah|nap|nds|nds-nl|ne|new|ng|nl|nn|no|nov|nrm|nv|ny|oc|om|or|os|pa|pag|pam|pap|pcd|pdc|pfl|pi|pih|pl|pms|pnb|pnt|ps|pt|qu|rm|rmy|rn|ro|roa-rup|roa-tara|ru|rue|rw|sa|sah|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|sn|so|sq|sr|srn|ss|st|stq|su|sv|sw|szl|ta|te|tet|tg|th|ti|tk|tl|tn|to|tpi|tr|ts|tt|tum|tw|ty|udm|ug|uk|ur|uz|ve|vec|vi|vls|vo|wa|war|wo|wuu|xal|xh|yi|yo|za|zea|zh|zh-classical|zh-min-nan|zh-yue|zu'; pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':'); } else { pg.wiki.interwiki=null; pg.re.interwiki=RegExp('^$'); } } // return a regexp pattern matching all variants to write the given namespace function nsRe(namespaceId) { var imageNamespaceVariants = []; jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) { if (_namespaceId!=namespaceId) return; _localizedNamespaceLc = upcaseFirst(_localizedNamespaceLc); imageNamespaceVariants.push(mw.util.escapeRegExp(_localizedNamespaceLc).split(' ').join('[ _]')); imageNamespaceVariants.push(mw.util.escapeRegExp(encodeURI(_localizedNamespaceLc))); }); return '(?:' + imageNamespaceVariants.join('|') + ')'; } function nsReImage() { return nsRe(pg.nsImageId); } // ENDFILE: namespaces.js // STARTFILE: selpop.js //<NOLITE> function getEditboxSelection() { // see http://www.webgurusforum.com/8/12/0 var editbox; try { editbox=document.editform.wpTextbox1; } catch (dang) { return; } // IE, Opera if (document.selection) { return document.selection.createRange().text; } // Mozilla var selStart = editbox.selectionStart; var selEnd = editbox.selectionEnd; return (editbox.value).substring(selStart, selEnd); } function doSelectionPopup() { // popup if the selection looks like [[foo|anything afterwards at all // or [[foo|bar]]text without ']]' // or [[foo|bar]] var sel=getEditboxSelection(); var open=sel.indexOf('[['); var pipe=sel.indexOf('|'); var close=sel.indexOf(']]'); if (open == -1 || ( pipe == -1 && close == -1) ) { return; } if (pipe != -1 && open > pipe || close != -1 && open > close) { return; } if (getValueOf('popupOnEditSelection')=='boxpreview') { return doSeparateSelectionPopup(sel); } var article=new Title(sel.substring(open+2, (pipe < 0) ? close : pipe)).urlString(); if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) { return; } var a=document.createElement('a'); a.href=pg.wiki.titlebase + article; mouseOverWikiLink2(a); if (a.navpopup) { a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after'); } } function doSeparateSelectionPopup(str) { var div=document.getElementById('selectionPreview'); if (!div) { div = document.createElement('div'); div.id='selectionPreview'; try { var box=document.editform.wpTextbox1; box.parentNode.insertBefore(div, box); } catch (error) { return; } } div.innerHTML=wiki2html(str); div.ranSetupTooltipsAlready = false; popTipsSoonFn('selectionPreview')(); } //</NOLITE> // ENDFILE: selpop.js // STARTFILE: navpopup.js /** @fileoverview Defines two classes: {@link Navpopup} and {@link Mousetracker}. <code>Navpopup</code> describes popups: when they appear, where, what they look like and so on. <code>Mousetracker</code> "captures" the mouse using <code>document.onmousemove</code>. */ /** Creates a new Mousetracker. @constructor @class The Mousetracker class. This monitors mouse movements and manages associated hooks. */ function Mousetracker() { /** Interval to regularly run the hooks anyway, in milliseconds. @type Integer */ this.loopDelay=400; /** Timer for the loop. @type Timer */ this.timer=null; /** Flag - are we switched on? @type Boolean */ this.active=false; /** Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position? */ this.dirty=true; /** Array of hook functions. @private @type Array */ this.hooks=[]; } /** Adds a hook, to be called when we get events. @param {Function} f A function which is called as <code>f(x,y)</code>. It should return <code>true</code> when it wants to be removed, and <code>false</code> otherwise. */ Mousetracker.prototype.addHook = function (f) { this.hooks.push(f); }; /** Runs hooks, passing them the x and y coords of the mouse. Hook functions that return true are passed to {@link Mousetracker#removeHooks} for removal. @private */ Mousetracker.prototype.runHooks = function () { if (!this.hooks || !this.hooks.length) { return; } //log('Mousetracker.runHooks; we got some hooks to run'); var remove=false; var removeObj={}; // this method gets called a LOT - // pre-cache some variables var x=this.x, y=this.y, len = this.hooks.length; for (var i=0; i<len; ++i) { //~ run the hook function, and remove it if it returns true if (this.hooks[i](x, y)===true) { remove=true; removeObj[i]=true; } } if (remove) { this.removeHooks(removeObj); } }; /** Removes hooks. @private @param {Object} removeObj An object whose keys are the index numbers of functions for removal, with values that evaluate to true */ Mousetracker.prototype.removeHooks = function(removeObj) { var newHooks=[]; var len = this.hooks.length; for (var i=0; i<len; ++i) { if (! removeObj[i]) { newHooks.push(this.hooks[i]); } } this.hooks=newHooks; }; /** Event handler for mouse wiggles. We simply grab the event, set x and y and run the hooks. This makes the cpu all hot and bothered :-( @private @param {Event} e Mousemove event */ Mousetracker.prototype.track=function (e) { //~ Apparently this is needed in IE. e = e || window.event; var x, y; if (e) { if (e.pageX) { x=e.pageX; y=e.pageY; } else if (typeof e.clientX!='undefined') { var left, top, docElt = document.documentElement; if (docElt) { left=docElt.scrollLeft; } left = left || document.body.scrollLeft || document.scrollLeft || 0; if (docElt) { top=docElt.scrollTop; } top = top || document.body.scrollTop || document.scrollTop || 0; x=e.clientX + left; y=e.clientY + top; } else { return; } this.setPosition(x,y); } }; /** Sets the x and y coordinates stored and takes appropriate action, running hooks as appropriate. @param {Integer} x, y Screen coordinates to set */ Mousetracker.prototype.setPosition=function(x,y) { this.x = x; this.y = y; if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; } if (typeof this.lastHook_x != 'number') { this.lastHook_x = -100; this.lastHook_y=-100; } var diff = (this.lastHook_x - x)*(this.lastHook_y - y); diff = (diff >= 0) ? diff : -diff; if ( diff > 1 ) { this.lastHook_x=x; this.lastHook_y=y; if (this.dirty) { this.dirty = false; } else { this.runHooks(); } } }; /** Sets things in motion, unless they are already that is, registering an event handler on <code>document.onmousemove</code>. A half-hearted attempt is made to preserve the old event handler if there is one. */ Mousetracker.prototype.enable = function () { if (this.active) { return; } this.active=true; //~ Save the current handler for mousemove events. This isn't too //~ robust, of course. this.savedHandler=document.onmousemove; //~ Gotta save @tt{this} again for the closure, and use apply for //~ the member function. var savedThis=this; document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);}; if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working'); savedThis.runHooks();}, this.loopDelay); } }; /** Disables the tracker, removing the event handler. */ Mousetracker.prototype.disable = function () { if (!this.active) { return; } if (typeof this.savedHandler === 'function') { document.onmousemove=this.savedHandler; } else { delete document.onmousemove; } if (this.timer) { clearInterval(this.timer); } this.active=false; }; /** Creates a new Navpopup. Gets a UID for the popup and @param init Contructor object. If <code>init.draggable</code> is true or absent, the popup becomes draggable. @constructor @class The Navpopup class. This generates popup hints, and does some management of them. */ function Navpopup(/*init*/) { //alert('new Navpopup(init)'); /** UID for each Navpopup instance. Read-only. @type integer */ this.uid=Navpopup.uid++; /** Read-only flag for current visibility of the popup. @type boolean @private */ this.visible=false; /** Flag to be set when we want to cancel a previous request to show the popup in a little while. @private @type boolean */ this.noshow=false; /** Categorised list of hooks. @see #runHooks @see #addHook @private @type Object */ this.hooks={ 'create': [], 'unhide': [], 'hide': [] }; /** list of unique IDs of hook functions, to avoid duplicates @private */ this.hookIds={}; /** List of downloads associated with the popup. @private @type Array */ this.downloads=[]; /** Number of uncompleted downloads. @type integer */ this.pending=null; /** Tolerance in pixels when detecting whether the mouse has left the popup. @type integer */ this.fuzz=5; /** Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position. @type boolean */ this.constrained=true; /** The popup width in pixels. @private @type integer */ this.width=0; /** The popup width in pixels. @private @type integer */ this.height=0; /** The main content DIV element. @type HTMLDivElement */ this.mainDiv=null; this.createMainDiv(); // if (!init || typeof init.popups_draggable=='undefined' || init.popups_draggable) { // this.makeDraggable(true); // } } /** A UID for each Navpopup. This constructor property is just a counter. @type integer @private */ Navpopup.uid=0; /** Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible. @type boolean */ Navpopup.prototype.isVisible=function() { return this.visible; }; /** Repositions popup using CSS style. @private @param {integer} x x-coordinate (px) @param {integer} y y-coordinate (px) @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition} */ Navpopup.prototype.reposition= function (x,y, noLimitHor) { log ('reposition('+x+','+y+','+noLimitHor+')'); if (typeof x != 'undefined' && x !== null) { this.left=x; } if (typeof y != 'undefined' && y !== null) { this.top=y; } if (typeof this.left != 'undefined' && typeof this.top != 'undefined') { this.mainDiv.style.left=this.left + 'px'; this.mainDiv.style.top=this.top + 'px'; } if (!noLimitHor) { this.limitHorizontalPosition(); } //console.log('navpop'+this.uid+' - (left,top)=(' + this.left + ',' + this.top + '), css=(' //+ this.mainDiv.style.left + ',' + this.mainDiv.style.top + ')'); }; /** Prevents popups from being in silly locations. Hopefully. Should not be run if {@link #constrained} is true. @private */ Navpopup.prototype.limitHorizontalPosition=function() { if (!this.constrained || this.tooWide) { return; } this.updateDimensions(); var x=this.left; var w=this.width; var cWidth=document.body.clientWidth; // log('limitHorizontalPosition: x='+x+ // ', this.left=' + this.left + // ', this.width=' + this.width + // ', cWidth=' + cWidth); if ( (x+w) >= cWidth || ( x > 0 && this.maxWidth && this.width < this.maxWidth && this.height > this.width && x > cWidth - this.maxWidth ) ) { // This is a very nasty hack. There has to be a better way! // We find the "natural" width of the div by positioning it at the far left // then reset it so that it should be flush right (well, nearly) this.mainDiv.style.left='-10000px'; this.mainDiv.style.width = this.maxWidth + 'px'; var naturalWidth=parseInt(this.mainDiv.offsetWidth, 10); var newLeft=cWidth - naturalWidth - 1; if (newLeft < 0) { newLeft = 0; this.tooWide=true; } // still unstable for really wide popups? log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth); this.reposition(newLeft, null, true); } }; /** Counter indicating the z-order of the "highest" popup. We start the z-index at 1000 so that popups are above everything else on the screen. @private @type integer */ Navpopup.highest=1000; /** Brings popup to the top of the z-order. We increment the {@link #highest} property of the contructor here. @private */ Navpopup.prototype.raise = function () { this.mainDiv.style.zIndex=Navpopup.highest + 1; ++Navpopup.highest; }; /** Shows the popup provided {@link #noshow} is not true. Updates the position, brings the popup to the top of the z-order and unhides it. */ Navpopup.prototype.show = function () { //document.title+='s'; if (this.noshow) { return; } //document.title+='t'; this.reposition(); this.raise(); this.unhide(); }; /** Checks to see if the mouse pointer has stabilised (checking every <code>time</code>/2 milliseconds) and runs the {@link #show} method if it has. @param {integer} time The minimum time (ms) before the popup may be shown. */ Navpopup.prototype.showSoonIfStable = function (time) { log ('showSoonIfStable, time='+time); if (this.visible) { return; } this.noshow = false; //~ initialize these variables so that we never run @tt{show} after //~ just half the time this.stable_x = -10000; this.stable_y = -10000; var stableShow = function() { log('stableShow called'); var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y; var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y; var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz; //document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] '; if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) { log ('mouse is stable'); clearInterval(savedThis.showSoonStableTimer); savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]); savedThis.show.apply(savedThis, []); savedThis.limitHorizontalPosition.apply(savedThis, []); return; } savedThis.stable_x = new_x; savedThis.stable_y = new_y; }; var savedThis = this; this.showSoonStableTimer = setInterval(stableShow, time/2); }; /** Sets the {@link #noshow} flag and hides the popup. This should be called when the mouse leaves the link before (or after) it's actually been displayed. */ Navpopup.prototype.banish = function () { log ('banish called'); // hide and prevent showing with showSoon in the future this.noshow=true; if (this.showSoonStableTimer) { log('clearing showSoonStableTimer'); clearInterval(this.showSoonStableTimer); } this.hide(); }; /** Runs hooks added with {@link #addHook}. @private @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' @param {String} when Controls exactly when the hook is run: either 'before' or 'after' */ Navpopup.prototype.runHooks = function (key, when) { if (!this.hooks[key]) { return; } var keyHooks=this.hooks[key]; var len=keyHooks.length; for (var i=0; i< len; ++i) { if (keyHooks[i] && keyHooks[i].when == when) { if (keyHooks[i].hook.apply(this, [])) { // remove the hook if (keyHooks[i].hookId) { delete this.hookIds[keyHooks[i].hookId]; } keyHooks[i]=null; } } } }; /** Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments. @param {Function} hook The hook function. Functions that return true are deleted. @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' @param {String} when Controls exactly when the hook is run: either 'before' or 'after' @param {String} uid A truthy string identifying the hook function; if it matches another hook in this position, it won't be added again. */ Navpopup.prototype.addHook = function ( hook, key, when, uid ) { when = when || 'after'; if (!this.hooks[key]) { return; } // if uid is specified, don't add duplicates var hookId=null; if (uid) { hookId=[key,when,uid].join('|'); if (this.hookIds[hookId]) { return; } this.hookIds[hookId]=true; } this.hooks[key].push( {hook: hook, when: when, hookId: hookId} ); }; /** Creates the main DIV element, which contains all the actual popup content. Runs hooks with key 'create'. @private */ Navpopup.prototype.createMainDiv = function () { if (this.mainDiv) { return; } this.runHooks('create', 'before'); var mainDiv=document.createElement('div'); var savedThis=this; mainDiv.onclick=function(e) {savedThis.onclickHandler(e);}; mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv'; mainDiv.id=mainDiv.className + this.uid; mainDiv.style.position='absolute'; mainDiv.style.minWidth = '350px'; mainDiv.style.display='none'; mainDiv.className='navpopup'; // easy access to javascript object through DOM functions mainDiv.navpopup=this; this.mainDiv=mainDiv; document.body.appendChild(mainDiv); this.runHooks('create', 'after'); }; /** Calls the {@link #raise} method. @private */ Navpopup.prototype.onclickHandler=function(/*e*/) { this.raise(); }; /** Makes the popup draggable, using a {@link Drag} object. @private */ Navpopup.prototype.makeDraggable=function(handleName) { if (!this.mainDiv) { this.createMainDiv(); } var drag=new Drag(); if (!handleName) { drag.startCondition=function(e) { try { if (!e.shiftKey) { return false; } } catch (err) { return false; } return true; }; } var dragHandle; if (handleName) dragHandle = document.getElementById(handleName); if (!dragHandle) dragHandle = this.mainDiv; var np=this; drag.endHook=function(x,y) { Navpopup.tracker.dirty=true; np.reposition(x,y); }; drag.init(dragHandle,this.mainDiv); }; /** Hides the popup using CSS. Runs hooks with key 'hide'. Sets {@link #visible} appropriately. {@link #banish} should be called externally instead of this method. @private */ Navpopup.prototype.hide = function () { this.runHooks('hide', 'before'); this.abortDownloads(); if (typeof this.visible != 'undefined' && this.visible) { this.mainDiv.style.display='none'; this.visible=false; } this.runHooks('hide', 'after'); }; /** Shows the popup using CSS. Runs hooks with key 'unhide'. Sets {@link #visible} appropriately. {@link #show} should be called externally instead of this method. @private */ Navpopup.prototype.unhide = function () { this.runHooks('unhide', 'before'); if (typeof this.visible != 'undefined' && !this.visible) { this.mainDiv.style.display='inline'; this.visible=true; } this.runHooks('unhide', 'after'); }; /** Sets the <code>innerHTML</code> attribute of the main div containing the popup content. @param {String} html The HTML to set. */ Navpopup.prototype.setInnerHTML = function (html) { this.mainDiv.innerHTML = html; }; /** Updates the {@link #width} and {@link #height} attributes with the CSS properties. @private */ Navpopup.prototype.updateDimensions = function () { this.width=parseInt(this.mainDiv.offsetWidth, 10); this.height=parseInt(this.mainDiv.offsetHeight, 10); }; /** Checks if the point (x,y) is within {@link #fuzz} of the {@link #mainDiv}. @param {integer} x x-coordinate (px) @param {integer} y y-coordinate (px) @type boolean */ Navpopup.prototype.isWithin = function(x,y) { //~ If we're not even visible, no point should be considered as //~ being within the popup. if (!this.visible) { return false; } this.updateDimensions(); var fuzz=this.fuzz || 0; //~ Use a simple box metric here. return (x+fuzz >= this.left && x-fuzz <= this.left + this.width && y+fuzz >= this.top && y-fuzz <= this.top + this.height); }; /** Adds a download to {@link #downloads}. @param {Downloader} download */ Navpopup.prototype.addDownload=function(download) { if (!download) { return; } this.downloads.push(download); }; /** Aborts the downloads listed in {@link #downloads}. @see Downloader#abort */ Navpopup.prototype.abortDownloads=function() { for(var i=0; i<this.downloads.length; ++i) { var d=this.downloads[i]; if (d && d.abort) { d.abort(); } } this.downloads=[]; }; /** A {@link Mousetracker} instance which is a property of the constructor (pseudo-global). */ Navpopup.tracker=new Mousetracker(); // ENDFILE: navpopup.js // STARTFILE: diff.js //<NOLITE> /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) and [[:en:User:Lupin]] * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ */ function delFmt(x) { if (!x.length) { return ''; } return "<del class='popupDiff'>" + x.join('') +"</del>"; } function insFmt(x) { if (!x.length) { return ''; } return "<ins class='popupDiff'>" + x.join('') +"</ins>"; } function countCrossings(a, b, i, eject) { // count the crossings on the edge starting at b[i] if (!b[i].row && b[i].row !== 0) { return -1; } var count=0; for (var j=0; j<a.length; ++j) { if (!a[j].row && a[j].row !== 0) { continue; } if ( (j-b[i].row)*(i-a[j].row) > 0) { if(eject) { return true; } count++; } } return count; } function shortenDiffString(str, context) { var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)'); var splitted=str.parenSplit(re); var ret=['']; for (var i=0; i<splitted.length; i+=2) { if (splitted[i].length < 2*context) { ret[ret.length-1] += splitted[i]; if (i+1<splitted.length) { ret[ret.length-1] += splitted[i+1]; } continue; } else { if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); } if (i+1 < splitted.length) { ret.push(splitted[i].substring(splitted[i].length-context) + splitted[i+1]); } } } while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); } return ret; } function diffString( o, n, simpleSplit ) { var splitRe=RegExp('([[]{2}|[\\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|<|>|[*:]+|\\s|\\b)'); // We need to split the strings o and n first, and entify() the parts // individually, so that the HTML entities are never cut apart. (AxelBoldt) var out, i, oSplitted, nSplitted; if (simpleSplit) { oSplitted=o.split(/\b/); nSplitted=n.split(/\b/); } else { oSplitted=o.parenSplit(splitRe); nSplitted=n.parenSplit(splitRe); } for (i=0; i<oSplitted.length; ++i) {oSplitted[i]=oSplitted[i].entify();} for (i=0; i<nSplitted.length; ++i) {nSplitted[i]=nSplitted[i].entify();} out = diff (oSplitted, nSplitted); var str = ""; var acc=[]; // accumulator for prettier output // crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out // this doesn't always do things optimally but it should be fast enough var maxOutputPair=0; for (i=0; i<out.n.length; ++i) { if ( out.n[i].paired ) { if( maxOutputPair > out.n[i].row ) { // tangle - delete pairing out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text; out.n[i]=out.n[i].text; } if (maxOutputPair < out.n[i].row) { maxOutputPair = out.n[i].row; } } } // output the stuff preceding the first paired old line for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); } str += delFmt(acc); acc=[]; // main loop for ( i = 0; i < out.n.length; ++i ) { // output unpaired new "lines" while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); } str += insFmt(acc); acc=[]; if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line" str += out.n[i].text; // output unpaired old rows starting after this new line's partner var m = out.n[i].row + 1; while ( m < out.o.length && !out.o[m].paired ) { acc.push ( out.o[m++] ); } str += delFmt(acc); acc=[]; } } return str; } // see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object // FIXME: use obj.hasOwnProperty instead of this kludge! var jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' + '|eval|hasOwnProperty|propertyIsEnumerable' + '|to(Source|String|LocaleString)|(un)?watch|valueOf)$'); function diffBugAlert(word) { if (!diffBugAlert.list[word]) { diffBugAlert.list[word]=1; alert('Bad word: '+word+'\n\nPlease report this bug.'); } } diffBugAlert.list={}; function makeDiffHashtable(src) { var ret={}; for ( var i = 0; i < src.length; i++ ) { if ( jsReservedProperties.test(src[i]) ) { src[i] += '<!-- -->'; } if ( !ret[ src[i] ] ) { ret[ src[i] ] = []; } try { ret[ src[i] ].push( i ); } catch (err) { diffBugAlert(src[i]); } } return ret; } function diff( o, n ) { // pass 1: make hashtable ns with new rows as keys var ns = makeDiffHashtable(n); // pass 2: make hashtable os with old rows as keys var os = makeDiffHashtable(o); // pass 3: pair unique new rows and matching unique old rows var i; for ( i in ns ) { if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) { n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true }; o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true }; } } // pass 4: pair matching rows immediately following paired rows (not necessarily unique) for ( i = 0; i < n.length - 1; i++ ) { if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired && n[i+1] == o[ n[i].row + 1 ] ) { n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true }; o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true }; } } // pass 5: pair matching rows immediately preceding paired rows (not necessarily unique) for ( i = n.length - 1; i > 0; i-- ) { if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired && n[i-1] == o[ n[i].row - 1 ] ) { n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true }; o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true }; } } return { o: o, n: n }; } //</NOLITE> // ENDFILE: diff.js // STARTFILE: init.js function setSiteInfo() { if (window.popupLocalDebug) { pg.wiki.hostname = 'en.wikipedia.org'; } else { pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?) } pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname); pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname); pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname); pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null; pg.wiki.lang = mw.config.get('wgContentLanguage'); var port = location.port ? ':' + location.port : ''; pg.wiki.sitebase = pg.wiki.hostname + port; } function setUserInfo() { var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'query', list: 'users', ususers: mw.config.get('wgUserName'), usprop: 'rights' }; pg.user.canReview = false; if (getValueOf('popupReview')) { api.get(params).done(function(data){ var rights = data.query.users[0].rights; pg.user.canReview = rights.indexOf('review') !== -1; // TODO: Should it be a getValueOf('ReviewRight') ? }); } } function setTitleBase() { var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol ); pg.wiki.articlePath = mw.config.get('wgArticlePath').replace(/\/\$1/, ""); // as in http://some.thing.com/wiki/Article pg.wiki.botInterfacePath = mw.config.get('wgScript'); pg.wiki.APIPath = mw.config.get('wgScriptPath') +"/api.php"; // default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo var titletail = pg.wiki.botInterfacePath + '?title='; //var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']); // other sites may need to add code here to set titletail depending on how their urls work pg.wiki.titlebase = protocol + '//' + pg.wiki.sitebase + titletail; //pg.wiki.titlebase2 = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]); pg.wiki.wikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.botInterfacePath; pg.wiki.apiwikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.APIPath; pg.wiki.articlebase = protocol + '//' + pg.wiki.sitebase + pg.wiki.articlePath; pg.wiki.commonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.botInterfacePath; pg.wiki.apicommonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.APIPath; pg.re.basenames = RegExp( '^(' + map( literalizeRegex, [ pg.wiki.titlebase, //pg.wiki.titlebase2, pg.wiki.articlebase ]).join('|') + ')' ); } ////////////////////////////////////////////////// // Global regexps function setMainRegex() { var reStart='[^:]*://'; var preTitles = literalizeRegex( mw.config.get('wgScriptPath') ) + '/(?:index[.]php|wiki[.]phtml)[?]title='; preTitles += '|' + literalizeRegex( pg.wiki.articlePath + '/' ); var reEnd='(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?'; pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd); } function setRegexps() { // TODO: We shoud use an api call to get the aliases for special pages, now it does not work for non-English wikipedias: // E.g., https://ru.wikipedia.org/w/api.php?action=query&meta=siteinfo&siprop=specialpagealiases&formatversion=2 setMainRegex(); var sp=nsRe(pg.nsSpecialId); pg.re.urlNoPopup=RegExp('((title=|/)' + sp + '(?:%3A|:)|section=[0-9]|^#$)') ; pg.re.contribs =RegExp('(title=|/)' + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + nsRe(pg.nsUserId)+':)(.*)') ; pg.re.email =RegExp('(title=|/)' + sp + '(?:%3A|:)EmailUser' + '(&target=|/|/(?:' + nsRe(pg.nsUserId)+':)?)(.*)') ; pg.re.backlinks =RegExp('(title=|/)' + sp + '(?:%3A|:)WhatLinksHere' + '(&target=|/)([^&]*)'); pg.re.specialdiff=RegExp('/' + sp + '(?:%3A|:)Diff/([^?#]*)'); //<NOLITE> var im=nsReImage(); // note: tries to get images in infobox templates too, e.g. movie pages, album pages etc // (^|\[\[)image: *([^|\]]*[^|\] ]) * // (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)? // $4 = 120 as in 120px pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' + '([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' + '(' + getValueOf('popupImageVarsRegexp') + ')' + ' *= *(?:\\[\\[ *)?(?:' + im + ':)?' + '([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ; pg.re.imageBracketCount = 6; pg.re.category = RegExp('\\[\\[' +nsRe(pg.nsCategoryId) + ': *([^|\\]]*[^|\\] ]) *', 'i'); pg.re.categoryBracketCount = 1; pg.re.ipUser=RegExp('^' + // IPv6 '(?::(?::|(?::[0-9A-Fa-f]{1,4}){1,7})|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,6}::|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){7})' + // IPv4 '|(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' + '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$'); pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im'); pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im'); //</NOLITE> // FIXME replace with general parameter parsing function, this is daft pg.re.oldid=RegExp('[?&]oldid=([^&]*)'); pg.re.diff=RegExp('[?&]diff=([^&]*)'); } ////////////////////////////////////////////////// // miscellany function setupCache() { // page caching pg.cache.pages = []; } function setMisc() { pg.current.link=null; pg.current.links=[]; pg.current.linksHash={}; setupCache(); pg.timer.checkPopupPosition=null; pg.counter.loop=0; // ids change with each popup: popupImage0, popupImage1 etc pg.idNumber=0; // for myDecodeURI pg.misc.decodeExtras = [ {from: '%2C', to: ',' }, {from: '_', to: ' ' }, {from: '%24', to: '$'}, {from: '%26', to: '&' } // no , ]; pg.misc.userAgent = 'Navigation popups/1.0 (' + mw.config.get( 'wgServerName' ) +')'; } // We need a callback since this might end up asynchronous because of // the mw.loader.using() call. function setupPopups( callback ) { if ( setupPopups.completed ) { if ( typeof callback === 'function' ) { callback(); } return; } // These dependencies are also enforced from the gadget, // but not everyone loads this as a gadget, so double check mw.loader.using( ['mediawiki.util', 'mediawiki.user', 'user.options'] ).then( function() { // NB translatable strings should be set up first (strings.js) // basics setupDebugging(); setSiteInfo(); setTitleBase(); setOptions(); // see options.js setUserInfo(); // namespaces etc setNamespaces(); setInterwiki(); // regexps setRegexps(); setRedirs(); // other stuff setMisc(); setupLivePreview(); // main deal here setupTooltips(); log('In setupPopups(), just called setupTooltips()'); Navpopup.tracker.enable(); setupPopups.completed = true; if ( typeof callback === 'function' ) { callback(); } }); } // ENDFILE: init.js // STARTFILE: navlinks.js //<NOLITE> ////////////////////////////////////////////////// // navlinks... let the fun begin // function defaultNavlinkSpec() { var str=''; str += '<b><<mainlink|shortcut= >></b>'; if (getValueOf('popupLastEditLink')) { str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}'; } // user links // contribs - log - count - email - block // count only if applicable; block only if popupAdminLinks str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>'; str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}'; str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}'; // editing links // talkpage -> edit|new - history - un|watch - article|edit // other page -> edit - history - un|watch - talk|edit|new var editstr='<<edit|shortcut=e>>'; var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'; var historystr='<<history|shortcut=h>>|<<editors|shortcut=E|>>'; var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; str+='<br>if(talk){' + editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + '}else{' + // not a talk page editOldidStr + '*' + historystr + '*' + watchstr + '*' + '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; // misc links str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>'; // admin links str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' + '<<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>>}'; return str; } function navLinksHTML (article, hint, params) { //oldid, rcid) { var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>'; // BAM return navlinkStringToHTML(str, article, params); } function expandConditionalNavlinkString(s,article,z,recursionCount) { var oldid=z.oldid, rcid=z.rcid, diff=z.diff; // nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out) if (typeof recursionCount!=typeof 0) { recursionCount=0; } var conditionalSplitRegex=RegExp( //(1 if \\( (2 2) \\) {(3 3)} (4 else {(5 5)} 4)1) '(;?\\s*if\\s*\\(\\s*([\\w]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', 'i'); var splitted=s.parenSplit(conditionalSplitRegex); // $1: whole conditional // $2: test condition // $3: true expansion // $4: else clause (possibly empty) // $5: false expansion (possibly null) var numParens=5; var ret = splitted[0]; for (var i=1; i<splitted.length; i=i+numParens+1) { var testString=splitted[i+2-1]; var trueString=splitted[i+3-1]; var falseString=splitted[i+5-1]; if (typeof falseString=='undefined' || !falseString) { falseString=''; } var testResult=null; switch (testString) { case 'user': testResult=(article.userName())?true:false; break; case 'talk': testResult=(article.talkPage())?false:true; // talkPage converts _articles_ to talkPages break; case 'admin': testResult=getValueOf('popupAdminLinks')?true:false; break; case 'oldid': testResult=(typeof oldid != 'undefined' && oldid)?true:false; break; case 'rcid': testResult=(typeof rcid != 'undefined' && rcid)?true:false; break; case 'ipuser': testResult=(article.isIpUser())?true:false; break; case 'mainspace_en': testResult=isInMainNamespace(article) && pg.wiki.hostname=='en.wikipedia.org'; break; case 'wikimedia': testResult=(pg.wiki.wikimedia) ? true : false; break; case 'diff': testResult=(typeof diff != 'undefined' && diff)?true:false; break; } switch(testResult) { case null: ret+=splitted[i]; break; case true: ret+=trueString; break; case false: ret+=falseString; break; } // append non-conditional string ret += splitted[i+numParens]; } if (conditionalSplitRegex.test(ret) && recursionCount < 10) { return expandConditionalNavlinkString(ret,article,z,recursionCount+1); } return ret; } function navlinkStringToArray(s, article, params) { s=expandConditionalNavlinkString(s,article,params); var splitted=s.parenSplit(RegExp('<<(.*?)>>')); var ret=[]; for (var i=0; i<splitted.length; ++i) { if (i%2) { // i odd, so s is a tag var t=new navlinkTag(); var ss=splitted[i].split('|'); t.id=ss[0]; for (var j=1; j<ss.length; ++j) { var sss=ss[j].split('='); if (sss.length>1) { t[sss[0]]=sss[1]; } else { // no assignment (no "="), so treat this as a title (overwriting the last one) t.text=popupString(sss[0]); } } t.article=article; var oldid=params.oldid, rcid=params.rcid, diff=params.diff; if (typeof oldid !== 'undefined' && oldid !== null) { t.oldid=oldid; } if (typeof rcid !== 'undefined' && rcid !== null) { t.rcid=rcid; } if (typeof diff !== 'undefined' && diff !== null) { t.diff=diff; } if (!t.text && t.id !== 'mainlink') { t.text=popupString(t.id); } ret.push(t); } else { // plain HTML ret.push(splitted[i]); } } return ret; } function navlinkSubstituteHTML(s) { return s.split('*').join(getValueOf('popupNavLinkSeparator')) .split('<menurow>').join('<li class="popup_menu_row">') .split('</menurow>').join('</li>') .split('<menu>').join('<ul class="popup_menu">') .split('</menu>').join('</ul>'); } function navlinkDepth(magic,s) { return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length; } // navlinkString: * becomes the separator // <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz' // and visible text 'fubar' // if(test){...} and if(test){...}else{...} work too (nested ok) function navlinkStringToHTML(s,article,params) { //limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article)); var p=navlinkStringToArray(s,article,params); var html=''; var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it var menurowdepth = 0; for (var i=0; i<p.length; ++i) { if (typeof p[i] == typeof '') { html+=navlinkSubstituteHTML(p[i]); menudepth += navlinkDepth('menu', p[i]); menurowdepth += navlinkDepth('menurow', p[i]); // if (menudepth === 0) { // tagType='span'; // } else if (menurowdepth === 0) { // tagType='li'; // } else { // tagType = null; // } } else if (typeof p[i].type != 'undefined' && p[i].type=='navlinkTag') { if (menudepth > 0 && menurowdepth === 0) { html += '<li class="popup_menu_item">' + p[i].html() + '</li>'; } else { html+=p[i].html(); } } } return html; } function navlinkTag() { this.type='navlinkTag'; } navlinkTag.prototype.html=function () { this.getNewWin(); this.getPrintFunction(); var html=''; var opening, closing; var tagType='span'; if (!tagType) { opening = ''; closing = ''; } else { opening = '<' + tagType + ' class="popup_' + this.id + '">'; closing = '</' + tagType + '>'; } if (typeof this.print!='function') { errlog ('Oh dear - invalid print function for a navlinkTag, id='+this.id); } else { html=this.print(this); if (typeof html != typeof '') {html='';} else if (typeof this.shortcut!='undefined') html=addPopupShortcut(html, this.shortcut); } return opening + html + closing; }; navlinkTag.prototype.getNewWin=function() { getValueOf('popupLinksNewWindow'); if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { this.newWin=null; } this.newWin=pg.option.popupLinksNewWindow[this.id]; }; navlinkTag.prototype.getPrintFunction=function() { //think about this some more // this.id and this.article should already be defined if (typeof this.id!=typeof '' || typeof this.article!=typeof {} ) { return; } this.noPopup=1; switch (this.id) { case 'contribs': case 'history': case 'whatLinksHere': case 'userPage': case 'monobook': case 'userTalk': case 'talk': case 'article': case 'lastEdit': this.noPopup=null; } switch (this.id) { case 'email': case 'contribs': case 'block': case 'unblock': case 'userlog': case 'userSpace': case 'deletedContribs': this.article=this.article.userName(); } switch (this.id) { case 'userTalk': case 'newUserTalk': case 'editUserTalk': case 'userPage': case 'monobook': case 'editMonobook': case 'blocklog': this.article=this.article.userName(true); /* fall through */ case 'pagelog': case 'deletelog': case 'protectlog': delete this.oldid; } if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); } if (this.id != 'mainlink') { // FIXME anchor handling should be done differently with Title object this.article=this.article.removeAnchor(); // if (typeof this.text=='undefined') this.text=popupString(this.id); } switch (this.id) { case 'undelete': this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break; case 'whatLinksHere': this.print=specialLink; this.specialpage='Whatlinkshere'; break; case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break; case 'move': this.print=specialLink; this.specialpage='Movepage'; break; case 'contribs': this.print=specialLink; this.specialpage='Contributions'; break; case 'deletedContribs':this.print=specialLink; this.specialpage='Deletedcontributions'; break; case 'email': this.print=specialLink; this.specialpage='EmailUser'; this.sep='/'; break; case 'block': this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break; case 'unblock': this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break; case 'userlog': this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break; case 'blocklog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break; case 'pagelog': this.print=specialLink; this.specialpage='Log'; this.sep='&page='; break; case 'protectlog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break; case 'deletelog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break; case 'userSpace': this.print=specialLink; this.specialpage='PrefixIndex'; this.sep='&namespace=2&prefix='; break; case 'search': this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break; case 'thank': this.print=specialLink; this.specialpage='Thanks'; this.sep='/'; this.article.value = this.diff; break; case 'unwatch': case 'watch': this.print=magicWatchLink; this.action=this.id+'&autowatchlist=1&autoimpl=' + popupString('autoedit_version') + '&actoken='+autoClickToken(); break; case 'history': case 'historyfeed': case 'unprotect': case 'protect': this.print=wikiLink; this.action=this.id; break; case 'delete': this.print=wikiLink; this.action='delete'; if (this.article.namespaceId()==pg.nsImageId) { var img=this.article.stripNamespace(); this.action+='&image='+img; } break; case 'markpatrolled': case 'edit': // editOld should keep the oldid, but edit should not. delete this.oldid; /* fall through */ case 'view': case 'purge': case 'render': this.print=wikiLink; this.action=this.id; break; case 'raw': this.print=wikiLink; this.action='raw'; break; case 'new': this.print=wikiLink; this.action='edit&section=new'; break; case 'mainlink': if (typeof this.text=='undefined') { this.text=this.article.toString().entify(); } if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) { // only show the /subpage part of the title text var s=this.text.split('/'); this.text=s[s.length-1]; if (this.text==='' && s.length > 1) { this.text=s[s.length-2]; } } this.print=titledWikiLink; if (typeof this.title==='undefined' && pg.current.link && typeof pg.current.link.href !== 'undefined') { this.title=safeDecodeURI((pg.current.link.originalTitle)?pg.current.link.originalTitle:this.article); if (typeof this.oldid !== 'undefined' && this.oldid) { this.title=tprintf('Revision %s of %s', [this.oldid, this.title]); } } this.action='view'; break; case 'userPage': case 'article': case 'monobook': case 'editMonobook': case 'editArticle': delete this.oldid; //alert(this.id+'\n'+this.article + '\n'+ typeof this.article); this.article=this.article.articleFromTalkOrArticle(); //alert(this.id+'\n'+this.article + '\n'+ typeof this.article); this.print=wikiLink; if (this.id.indexOf('edit')===0) { this.action='edit'; } else { this.action='view';} break; case 'userTalk': case 'talk': this.article=this.article.talkPage(); delete this.oldid; this.print=wikiLink; this.action='view'; break; case 'arin': this.print=arinLink; break; case 'count': this.print=editCounterLink; break; case 'google': this.print=googleLink; break; case 'editors': this.print=editorListLink; break; case 'globalsearch': this.print=globalSearchLink; break; case 'lastEdit': this.print=titledDiffLink; this.title=popupString('Show the last edit'); this.from='prev'; this.to='cur'; break; case 'oldEdit': this.print=titledDiffLink; this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid; this.from='prev'; this.to=this.oldid; break; case 'editOld': this.print=wikiLink; this.action='edit'; break; case 'undo': this.print=wikiLink; this.action='edit&undo='; break; case 'revert': this.print=wikiLink; this.action='revert'; break; case 'nullEdit': this.print=wikiLink; this.action='nullEdit'; break; case 'diffCur': this.print=titledDiffLink; this.title=tprintf('Show changes since revision %s', [this.oldid]); this.from=this.oldid; this.to='cur'; break; case 'editUserTalk': case 'editTalk': delete this.oldid; this.article=this.article.talkPage(); this.action='edit'; this.print=wikiLink; break; case 'newUserTalk': case 'newTalk': this.article=this.article.talkPage(); this.action='edit&section=new'; this.print=wikiLink; break; case 'lastContrib': case 'sinceMe': this.print=magicHistoryLink; break; case 'togglePreviews': this.text=popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews'); /* fall through */ case 'disablePopups': case 'purgePopups': this.print=popupMenuLink; break; default: this.print=function () {return 'Unknown navlink type: '+this.id+'';}; } }; // // end navlinks ////////////////////////////////////////////////// //</NOLITE> // ENDFILE: navlinks.js // STARTFILE: shortcutkeys.js //<NOLITE> function popupHandleKeypress(evt) { var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which); if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { return; } if (keyCode==27) { // escape killPopup(); return false; // swallow keypress } var letter=String.fromCharCode(keyCode); var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A'); var startLink=0; var i,j; if (popupHandleKeypress.lastPopupLinkSelected) { for (i=0; i<links.length; ++i) { if (links[i]==popupHandleKeypress.lastPopupLinkSelected) { startLink=i; } } } for (j=0; j<links.length; ++j) { i=(startLink + j + 1) % links.length; if (links[i].getAttribute('popupkey')==letter) { if (evt && evt.preventDefault) evt.preventDefault(); links[i].focus(); popupHandleKeypress.lastPopupLinkSelected=links[i]; return false; // swallow keypress } } // pass keypress on if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); } return true; } function addPopupShortcuts() { if (document.onkeypress!=popupHandleKeypress) { document.oldPopupOnkeypress=document.onkeypress; } document.onkeypress=popupHandleKeypress; } function rmPopupShortcuts() { popupHandleKeypress.lastPopupLinkSelected=null; try { if (document.oldPopupOnkeypress && document.oldPopupOnkeypress==popupHandleKeypress) { // panic document.onkeypress=null; //function () {}; return; } document.onkeypress=document.oldPopupOnkeypress; } catch (nasties) { /* IE goes here */ } } function addLinkProperty(html, property) { // take "<a href=...>...</a> and add a property // not sophisticated at all, easily broken var i=html.indexOf('>'); if (i<0) { return html; } return html.substring(0,i) + ' ' + property + html.substring(i); } function addPopupShortcut(html, key) { if (!getValueOf('popupShortcutKeys')) { return html; } var ret= addLinkProperty(html, 'popupkey="'+key+'"'); if (key==' ') { key=popupString('spacebar'); } return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4'); } //</NOLITE> // ENDFILE: shortcutkeys.js // STARTFILE: diffpreview.js //<NOLITE> //lets jump through hoops to find the rev ids we need to retrieve function loadDiff(article, oldid, diff, navpop) { navpop.diffData={ oldRev: {}, newRev: {} }; mw.loader.using( 'mediawiki.api' ).then( function() { var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'compare', prop: 'ids|title' }; if(article.title){ params.fromtitle = article.title; } switch (diff) { case 'cur': switch ( oldid ) { case null: case '': case 'prev': // this can only work if we have the title // cur -> prev params.torelative = 'prev'; break; default: params.fromrev = oldid; params.torelative = 'cur'; break; } break; case 'prev': if( oldid ) { params.fromrev = oldid; } else { params.fromtitle; } params.torelative = 'prev'; break; case 'next': params.fromrev = oldid || 0; params.torelative = 'next'; break; default: params.fromrev = oldid || 0; params.torev = diff || 0; break; } api.get( params ).then( function( data ) { navpop.diffData.oldRev.revid = data.compare.fromrevid; navpop.diffData.newRev.revid = data.compare.torevid; addReviewLink(navpop, 'popupMiscTools'); var go = function() { pendingNavpopTask(navpop); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&'; url += 'revids=' + navpop.diffData.oldRev.revid + '|' + navpop.diffData.newRev.revid; url += '&prop=revisions&rvprop=ids|timestamp|content'; getPageWithCaching(url, doneDiff, navpop); return true; // remove hook once run }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); } } ); } ); } // Put a "mark patrolled" link to an element target // TODO: Allow patrol a revision, as well as a diff function addReviewLink (navpop, target) { if (! pg.user.canReview) return; // If 'newRev' is older than 'oldRev' than it could be confusing, so we do not show the review link. if (navpop.diffData.newRev.revid <= navpop.diffData.oldRev.revid) return; var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'query', prop: 'info|flagged', revids: navpop.diffData.oldRev.revid, formatversion : 2 }; api.get (params).then(function(data){ var stable_revid = data.query.pages[0].flagged && data.query.pages[0].flagged.stable_revid || 0; // The diff can be reviewed if the old version is the last reviewed version // TODO: Other possible conditions that we may want to implement instead of this one: // * old version is patrolled and the new version is not patrolled // * old version is patrolled and the new version is more recent than the last reviewed version if (stable_revid == navpop.diffData.oldRev.revid) { var a = document.createElement('a'); a.innerHTML = popupString('mark patrolled'); a.title=popupString('markpatrolledHint'); a.onclick = function() { var params = { action: 'review', revid: navpop.diffData.newRev.revid, comment: tprintf('defaultpopupReviewedSummary', [navpop.diffData.oldRev.revid, navpop.diffData.newRev.revid]) }; api.postWithToken('csrf',params).done(function(){ a.style.display = "none"; // TODO: Update current page and other already constructed popups } ).fail(function(){ alert(popupString('Could not marked this edit as patrolled')); }); }; setPopupHTML(a, target, navpop.idNumber,null,true); } }); } function doneDiff(download) { if (!download.owner || !download.owner.diffData) { return; } var navpop=download.owner; completedNavpopTask(navpop); var pages, revisions=[]; try{ // Process the downloads pages = getJsObj(download.data).query.pages; for(var i=0; i < pages.length; i++ ) { revisions = revisions.concat(pages[i].revisions); } for(i=0; i< revisions.length; i++){ if(revisions[i].revid == navpop.diffData.oldRev.revid) { navpop.diffData.oldRev.revision = revisions[i]; } else if (revisions[i].revid == navpop.diffData.newRev.revid) { navpop.diffData.newRev.revision = revisions[i]; } } } catch(someError) { errlog( 'Could not get diff' ); } insertDiff(navpop); } function rmBoringLines(a,b,context) { if (typeof context == 'undefined') { context=2; } // this is fairly slow... i think it's quicker than doing a word-based diff from the off, though var aa=[], aaa=[]; var bb=[], bbb=[]; var i, j; // first, gather all disconnected nodes in a and all crossing nodes in a and b for (i=0; i<a.length; ++i ) { if(!a[i].paired) { aa[i]=1; } else if (countCrossings(b,a,i, true)) { aa[i]=1; bb[ a[i].row ] = 1; } } // pick up remaining disconnected nodes in b for (i=0; i<b.length; ++i ) { if (bb[i]==1) { continue; } if(!b[i].paired) { bb[i]=1; } } // another pass to gather context: we want the neighbours of included nodes which are not yet included // we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass for (i=0; i<b.length; ++i) { if ( bb[i] == 1 ) { for (j=Math.max(0,i-context); j < Math.min(b.length, i+context); ++j) { if ( !bb[j] ) { bb[j] = 1; aa[ b[j].row ] = 0.5; } } } } for (i=0; i<a.length; ++i) { if ( aa[i] == 1 ) { for (j=Math.max(0,i-context); j < Math.min(a.length, i+context); ++j) { if ( !aa[j] ) { aa[j] = 1; bb[ a[j].row ] = 0.5; } } } } for (i=0; i<bb.length; ++i) { if (bb[i] > 0) { // it's a row we need if (b[i].paired) { bbb.push(b[i].text); } // joined; partner should be in aa else { bbb.push(b[i]); } } } for (i=0; i<aa.length; ++i) { if (aa[i] > 0) { // it's a row we need if (a[i].paired) { aaa.push(a[i].text); } // joined; partner should be in aa else { aaa.push(a[i]); } } } return { a: aaa, b: bbb}; } function stripOuterCommonLines(a,b,context) { var i=0; while (i<a.length && i < b.length && a[i]==b[i]) { ++i; } var j=a.length-1; var k=b.length-1; while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; } return { a: a.slice(Math.max(0,i - 1 - context), Math.min(a.length+1, j + context+1)), b: b.slice(Math.max(0,i - 1 - context), Math.min(b.length+1, k + context+1)) }; } function insertDiff(navpop) { // for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff // FIXME: sometimes this gives misleading diffs as distant chunks are squashed together var oldlines = navpop.diffData.oldRev.revision.content.split('\n'); var newlines = navpop.diffData.newRev.revision.content.split('\n'); var inner=stripOuterCommonLines(oldlines,newlines,getValueOf('popupDiffContextLines')); oldlines=inner.a; newlines=inner.b; var truncated=false; getValueOf('popupDiffMaxLines'); if (oldlines.length > pg.option.popupDiffMaxLines || newlines.length > pg.option.popupDiffMaxLines) { // truncate truncated=true; inner=stripOuterCommonLines(oldlines.slice(0,pg.option.popupDiffMaxLines), newlines.slice(0,pg.option.popupDiffMaxLines), pg.option.popupDiffContextLines); oldlines=inner.a; newlines=inner.b; } var lineDiff=diff(oldlines, newlines); var lines2=rmBoringLines(lineDiff.o, lineDiff.n); var oldlines2=lines2.a; var newlines2=lines2.b; var simpleSplit = !String.prototype.parenSplit.isNative; var html='<hr />'; if (getValueOf('popupDiffDates')) { html += diffDatesTable(navpop); html += '<hr />'; } html += shortenDiffString( diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit), getValueOf('popupDiffContextCharacters') ).join('<hr />'); setPopupTipsAndHTML(html.split('\n').join('<br>') + (truncated ? '<hr /><b>'+popupString('Diff truncated for performance reasons')+'</b>' : '') , 'popupPreview', navpop.idNumber); } function diffDatesTable( navpop ) { var html='<table class="popup_diff_dates">'; html += diffDatesTableRow( navpop.diffData.newRev.revision, tprintf('New revision')); html += diffDatesTableRow( navpop.diffData.oldRev.revision, tprintf('Old revision')); html += '</table>'; return html; } function diffDatesTableRow( revision, label ) { var txt=''; var lastModifiedDate = new Date(revision.timestamp); var datePrint=getValueOf('popupDiffDatePrinter'); if (typeof lastModifiedDate[datePrint] == 'function') { var d2 = adjustDate(lastModifiedDate, getTimeOffset()); txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true); } else { txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]); } var revlink = generalLink({url: mw.config.get('wgScript') + '?oldid='+revision.revid, text: label, title: label}); return simplePrintf('<tr><td>%s</td><td>%s</td></tr>', [ revlink, txt ]); } //</NOLITE> // ENDFILE: diffpreview.js // STARTFILE: links.js //<NOLITE> ///////////////////// // LINK GENERATION // ///////////////////// // titledDiffLink --> titledWikiLink --> generalLink // wikiLink --> titledWikiLink --> generalLink // editCounterLink --> generalLink // TODO Make these functions return Element objects, not just raw HTML strings. function titledDiffLink(l) { // article, text, title, from, to) { return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from, newWin: l.newWin, noPopup: l.noPopup, text: l.text, title: l.title, /* hack: no oldid here */ actionName: 'diff'}); } function wikiLink(l) { //{article:article, action:action, text:text, oldid, newid}) { if (! (typeof l.article == typeof {} && typeof l.action == typeof '' && typeof l.text==typeof '')) return null; if (typeof l.oldid == 'undefined') { l.oldid=null; } var savedOldid = l.oldid; if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { l.oldid=null; } var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc var oldidData=[l.oldid, safeDecodeURI(l.article)]; var revisionString = tprintf('revision %s of %s', oldidData); log('revisionString='+revisionString); switch (l.action) { case 'edit&section=new': hint = popupString('newSectionHint'); break; case 'edit&undo=': if (l.diff && l.diff != 'prev' && savedOldid ) { l.action += l.diff + '&undoafter=' + savedOldid; } else if (savedOldid) { l.action += savedOldid; } hint = popupString('undoHint'); break; case 'raw&ctype=text/css': hint=popupString('rawHint'); break; case 'revert': var p=parseParams(pg.current.link.href); l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=' + revertSummary(l.oldid, p.diff); if (p.diff=='prev') { l.action += '&direction=prev'; revisionString = tprintf('the revision prior to revision %s of %s', oldidData); } if (getValueOf('popupRevertSummaryPrompt')) { l.action += '&autosummaryprompt=true'; } if (getValueOf('popupMinorReverts')) { l.action += '&autominor=true'; } log('revisionString is now '+revisionString); break; case 'nullEdit': l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=null'; break; case 'historyfeed': l.action='history&feed=rss'; break; case 'markpatrolled': l.action='markpatrolled&rcid='+l.rcid; } if (hint) { if (l.oldid) { hint = simplePrintf(hint, [revisionString]); } else { hint = simplePrintf(hint, [safeDecodeURI(l.article)]); } } else { hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : ''; } return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin, title: hint, oldid: l.oldid, noPopup: l.noPopup, onclick: l.onclick}); } function revertSummary(oldid, diff) { var ret=''; if (diff == 'prev') { ret=getValueOf('popupQueriedRevertToPreviousSummary'); } else { ret = getValueOf('popupQueriedRevertSummary'); } return ret + '&autorv=' + oldid; } function titledWikiLink(l) { // possible properties of argument: // article, action, text, title, oldid, actionName, className, noPopup // oldid = null is fine here // article and action are mandatory args if (typeof l.article == 'undefined' || typeof l.action=='undefined') { errlog('got undefined article or action in titledWikiLink'); return null; } var base = pg.wiki.titlebase + l.article.urlString(); var url=base; if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; } // no need to add &action=view, and this confuses anchors if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; } if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; } var cssClass=pg.misc.defaultNavlinkClassname; if (typeof l.className!='undefined' && l.className) { cssClass=l.className; } return generalNavLink({url: url, newWin: l.newWin, title: (typeof l.title != 'undefined') ? l.title : null, text: (typeof l.text!='undefined')?l.text:null, className: cssClass, noPopup:l.noPopup, onclick:l.onclick}); } pg.fn.getLastContrib = function getLastContrib(wikipage, newWin) { getHistoryInfo(wikipage, function(x) { processLastContribInfo(x, {page: wikipage, newWin: newWin}); }); }; function processLastContribInfo(info, stuff) { if(!info.edits || !info.edits.length) { alert('Popups: an odd thing happened. Please retry.'); return; } if(!info.firstNewEditor) { alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length])); return; } var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+info.firstNewEditor.oldid; displayUrl(newUrl, stuff.newWin); } pg.fn.getDiffSinceMyEdit = function getDiffSinceMyEdit(wikipage, newWin) { getHistoryInfo(wikipage, function(x){ processDiffSinceMyEdit(x, {page: wikipage, newWin: newWin}); }); }; function processDiffSinceMyEdit(info, stuff) { if(!info.edits || !info.edits.length) { alert('Popups: something fishy happened. Please try again.'); return; } var friendlyName=stuff.page.split('_').join(' '); if(!info.myLastEdit) { alert(tprintf('Couldn\'t find an edit by %s\nin the last %s edits to\n%s', [info.userName, getValueOf('popupHistoryLimit'), friendlyName])); return; } if(info.myLastEdit.index === 0) { alert(tprintf("%s seems to be the last editor to the page %s", [info.userName, friendlyName])); return; } var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+ info.myLastEdit.oldid; displayUrl(newUrl, stuff.newWin); } function displayUrl(url, newWin){ if(newWin) { window.open(url); } else { document.location=url; } } pg.fn.purgePopups = function purgePopups() { processAllPopups(true); setupCache(); // deletes all cached items (not browser cached, though...) pg.option={}; abortAllDownloads(); }; function processAllPopups(nullify, banish) { for (var i=0; pg.current.links && i<pg.current.links.length; ++i) { if (!pg.current.links[i].navpopup) { continue; } if (nullify || banish) pg.current.links[i].navpopup.banish(); pg.current.links[i].simpleNoMore=false; if (nullify) pg.current.links[i].navpopup=null; } } pg.fn.disablePopups = function disablePopups(){ processAllPopups(false, true); setupTooltips(null, true); }; pg.fn.togglePreviews = function togglePreviews() { processAllPopups(true, true); pg.option.simplePopups=!pg.option.simplePopups; abortAllDownloads(); }; function magicWatchLink(l) { //Yuck!! Would require a thorough redesign to add this as a click event though ... l.onclick = simplePrintf( 'pg.fn.modifyWatchlist(\'%s\',\'%s\');return false;', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), this.id] ); return wikiLink(l); } pg.fn.modifyWatchlist = function modifyWatchlist(title, action) { var reqData = { 'action': 'watch', 'formatversion': 2, 'titles': title, 'uselang': mw.config.get('wgUserLanguage') }; if ( action === 'unwatch' ) reqData.unwatch = true; var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); // Load the Addedwatchtext or Removedwatchtext message and show it var mwTitle = mw.Title.newFromText( title ); var messageName; if ( mwTitle && mwTitle.getNamespaceId() > 0 && mwTitle.getNamespaceId() % 2 === 1 ) { messageName = action === 'watch' ? 'addedwatchtext-talk' : 'removedwatchtext-talk'; } else { messageName = action === 'watch' ? 'addedwatchtext' : 'removedwatchtext'; } $.when( api.postWithToken( 'watch', reqData ), mw.loader.using( [ 'mediawiki.api', 'mediawiki.jqueryMsg' ] ).then( function () { return api.loadMessagesIfMissing( [ messageName ] ); } ) ).done( function () { mw.notify( mw.message( messageName, title ).parseDom() ); } ); }; function magicHistoryLink(l) { // FIXME use onclick change href trick to sort this out instead of window.open var jsUrl='', title='', onClick=''; switch(l.id) { case 'lastContrib': onClick=simplePrintf('pg.fn.getLastContrib(\'%s\',%s)', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); title=popupString('lastContribHint'); break; case 'sinceMe': onClick=simplePrintf('pg.fn.getDiffSinceMyEdit(\'%s\',%s)', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); title=popupString('sinceMeHint'); break; } jsUrl = 'javascript:' + onClick; // jshint ignore:line onClick += ';return false;'; return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think title: title, text: l.text, noPopup: l.noPopup, onclick: onClick }); } function popupMenuLink(l) { var jsUrl=simplePrintf('javascript:pg.fn.%s()', [l.id]); // jshint ignore:line var title=popupString(simplePrintf('%sHint', [l.id])); var onClick=simplePrintf('pg.fn.%s();return false;', [l.id]); return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup, onclick: onClick}); } function specialLink(l) { // properties: article, specialpage, text, sep if (typeof l.specialpage=='undefined'||!l.specialpage) return null; var base = pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId]+':'+l.specialpage; if (typeof l.sep == 'undefined' || l.sep === null) l.sep='&target='; var article=l.article.urlString({keepSpaces: l.specialpage=='Search'}); var hint=popupString(l.specialpage+'Hint'); switch (l.specialpage) { case 'Log': switch (l.sep) { case '&user=': hint=popupString('userLogHint'); break; case '&type=block&page=': hint=popupString('blockLogHint'); break; case '&page=': hint=popupString('pageLogHint'); break; case '&type=protect&page=': hint=popupString('protectLogHint'); break; case '&type=delete&page=': hint=popupString('deleteLogHint'); break; default: log('Unknown log type, sep=' + l.sep); hint='Missing hint (FIXME)'; } break; case 'PrefixIndex': article += '/'; break; } if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]); else hint = safeDecodeURI(l.specialpage+':'+l.article) ; var url = base + l.sep + article; return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup}); } function generalLink(l) { // l.url, l.text, l.title, l.newWin, l.className, l.noPopup, l.onclick if (typeof l.url=='undefined') return null; // only quotation marks in the url can screw us up now... I think var url=l.url.split('"').join('%22'); var ret='<a href="' + url + '"'; if (typeof l.title!='undefined' && l.title) { ret += ' title="' + pg.escapeQuotesHTML(l.title) + '"'; } if (typeof l.onclick!='undefined' && l.onclick) { ret += ' onclick="' + pg.escapeQuotesHTML(l.onclick) + '"'; } if (l.noPopup) { ret += ' noPopup=1'; } var newWin; if (typeof l.newWin=='undefined' || l.newWin === null) { newWin=getValueOf('popupNewWindows'); } else { newWin=l.newWin; } if (newWin) { ret += ' target="_blank"'; } if (typeof l.className!='undefined'&&l.className) { ret+=' class="'+l.className+'"'; } ret += '>'; if (typeof l.text==typeof '') { ret+= l.text; } ret +='</a>'; return ret; } function appendParamsToLink(linkstr, params) { var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i')); if (sp.length<2) return null; var ret=sp.shift() + sp.shift(); ret += '&' + params + '"'; ret += sp.join(''); return ret; } function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional), alsoChangeLabel { if (x.newTarget) { log ('changeLinkTargetLink: newTarget=' + x.newTarget); } if (x.oldTarget !== decodeURIComponent( x.oldTarget ) ) { log ('This might be an input problem: ' + x.oldTarget ); } // FIXME: first character of page title as well as namespace should be case insensitive // eg [[category:X1]] and [[Category:X1]] are equivalent // this'll break if charAt(0) is nasty var cA = mw.util.escapeRegExp(x.oldTarget); var chs = cA.charAt(0).toUpperCase(); chs='['+chs + chs.toLowerCase()+']'; var currentArticleRegexBit=chs+cA.substring(1); currentArticleRegexBit=currentArticleRegexBit .split(RegExp('(?:[_ ]+|%20)', 'g')).join('(?:[_ ]+|%20)') .split('\\(').join('(?:%28|\\()') .split('\\)').join('(?:%29|\\))'); // why does this need to match encoded strings ? links in the document ? // leading and trailing space should be ignored, and anchor bits optional: currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*'; // e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s* // autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g var title=x.title || mw.config.get('wgPageName').split('_').join(' '); var lk=titledWikiLink({article: new Title(title), newWin:x.newWin, action: 'edit', text: x.text, title: x.hint, className: 'popup_change_title_link' }); var cmd=''; if (x.newTarget) { // escape '&' and other nasties var t = x.newTarget; var s = mw.util.escapeRegExp(x.newTarget); if (x.alsoChangeLabel) { cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~[[' + t + ']]~g;'; cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; } else { cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~[[' + t + '|$1]]~g;'; cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; } } else { cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;'; cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g'; } // Build query cmd = 'autoedit=' + encodeURIComponent ( cmd ); cmd += '&autoclick='+ encodeURIComponent( x.clickButton ) + '&actoken=' + encodeURIComponent( autoClickToken() ); cmd += ( x.minor === null ) ? '' : '&autominor='+ encodeURIComponent( x.minor ); cmd += ( x.watch === null ) ? '' : '&autowatch='+ encodeURIComponent( x.watch ); cmd += '&autosummary='+encodeURIComponent(x.summary); cmd += '&autoimpl='+encodeURIComponent( popupString('autoedit_version') ); return appendParamsToLink(lk, cmd); } function redirLink(redirMatch, article) { // NB redirMatch is in wikiText var ret=''; if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) { ret += '<hr />'; if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) { ret += popupString('Redirects to: (Fix '); log('redirLink: newTarget=' + redirMatch); ret += addPopupShortcut(changeLinkTargetLink({ newTarget: redirMatch, text: popupString('target'), hint: popupString('Fix this redirect, changing just the link target'), summary: simplePrintf(getValueOf('popupFixRedirsSummary'),[article.toString(), redirMatch]), oldTarget: article.toString(), clickButton: getValueOf('popupRedirAutoClick'), minor: true, watch: getValueOf('popupWatchRedirredPages') }), 'R'); ret += popupString(' or '); ret += addPopupShortcut(changeLinkTargetLink({ newTarget: redirMatch, text: popupString('target & label'), hint: popupString('Fix this redirect, changing the link target and label'), summary: simplePrintf(getValueOf('popupFixRedirsSummary'),[article.toString(), redirMatch]), oldTarget: article.toString(), clickButton: getValueOf('popupRedirAutoClick'), minor: true, watch: getValueOf('popupWatchRedirredPages'), alsoChangeLabel: true }), 'R'); ret += popupString(')'); } else ret += popupString('Redirects') + popupString(' to '); return ret; } else return '<br> ' + popupString('Redirects') + popupString(' to ') + titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view', /* FIXME: newWin */ text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')}); } function arinLink(l) { if (!saneLinkCheck(l)) { return null; } if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null; var uN=l.article.userName(); return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), newWin:l.newWin, title: tprintf('Look up %s in ARIN whois database', [uN]), text: l.text, noPopup:1}); } function toolDbName(cookieStyle) { var ret = mw.config.get('wgDBname'); if (!cookieStyle) { ret+= '_p'; } return ret; } function saneLinkCheck(l) { if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; } return true; } function editCounterLink(l) { if(!saneLinkCheck(l)) return null; if (! pg.wiki.wikimedia) return null; var uN=l.article.userName(); var tool=getValueOf('popupEditCounterTool'); var url; var defaultToolUrl='//tools.wmflabs.org/supercount/index.php?user=$1&project=$2.$3'; switch(tool) { case 'custom': url=simplePrintf(getValueOf('popupEditCounterUrl'), [ encodeURIComponent(uN), toolDbName() ]); break; case 'soxred': // no longer available case 'kate': // no longer available case 'interiot':// no longer available /* fall through */ case 'supercount': default: var theWiki=pg.wiki.hostname.split('.'); url=simplePrintf(defaultToolUrl, [ encodeURIComponent(uN), theWiki[0], theWiki[1] ]); } return generalNavLink({url:url, title: tprintf('editCounterLinkHint', [uN]), newWin:l.newWin, text: l.text, noPopup:1}); } function globalSearchLink(l) { if(!saneLinkCheck(l)) return null; var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search='; var article=l.article.urlString({keepSpaces:true}); return generalNavLink({url:base + article, newWin:l.newWin, title: tprintf('globalSearchHint', [safeDecodeURI(l.article)]), text: l.text, noPopup:1}); } function googleLink(l) { if(!saneLinkCheck(l)) return null; var base='https://www.google.com/search?q='; var article=l.article.urlString({keepSpaces:true}); return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin, title: tprintf('googleSearchHint', [safeDecodeURI(l.article)]), text: l.text, noPopup:1}); } function editorListLink(l) { if(!saneLinkCheck(l)) return null; var article= l.article.articleFromTalkPage() || l.article; var url='https://xtools.wmflabs.org/articleinfo/' + encodeURI( pg.wiki.hostname ) + '/' + article.urlString() + '?uselang=' + mw.config.get('wgUserLanguage'); return generalNavLink({url:url, title: tprintf('editorListHint', [article]), newWin:l.newWin, text: l.text, noPopup:1}); } function generalNavLink(l) { l.className = (l.className === null) ? 'popupNavLink' : l.className; return generalLink(l); } ////////////////////////////////////////////////// // magic history links // function getHistoryInfo(wikipage, whatNext) { log('getHistoryInfo'); getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory); } // FIXME eliminate pg.idNumber ... how? :-( function getHistory(wikipage, onComplete) { log('getHistory'); var url = pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&prop=revisions&titles=' + new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit'); log('getHistory: url='+url); return startDownload(url, pg.idNumber+'history', onComplete); } function processHistory(download) { var jsobj = getJsObj(download.data); try { var revisions = anyChild(jsobj.query.pages).revisions; var edits=[]; for (var i=0; i<revisions.length; ++i) { edits.push({ oldid: revisions[i].revid, editor: revisions[i].user }); } log('processed ' + edits.length + ' edits'); return finishProcessHistory( edits, mw.config.get('wgUserName') ); } catch (someError) { log('Something went wrong with JSON business'); return finishProcessHistory([]); } } function finishProcessHistory(edits, userName) { var histInfo={}; histInfo.edits=edits; histInfo.userName=userName; for (var i=0; i<edits.length; ++i) { if (typeof histInfo.myLastEdit === 'undefined' && userName && edits[i].editor==userName) { histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; } if (typeof histInfo.firstNewEditor === 'undefined' && edits[i].editor != edits[0].editor) { histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; } } //pg.misc.historyInfo=histInfo; return histInfo; } //</NOLITE> // ENDFILE: links.js // STARTFILE: options.js ////////////////////////////////////////////////// // options // check for existing value, else use default function defaultize(x) { if (pg.option[x]===null || typeof pg.option[x]=='undefined') { if (typeof window[x] != 'undefined' ) pg.option[x]=window[x]; else pg.option[x]=pg.optionDefault[x]; } } function newOption(x, def) { pg.optionDefault[x]=def; } function setDefault(x, def) { return newOption(x, def); } function getValueOf(varName) { defaultize(varName); return pg.option[varName]; } /*eslint-disable */ function useDefaultOptions() { // for testing for (var p in pg.optionDefault) { pg.option[p]=pg.optionDefault[p]; if (typeof window[p]!='undefined') { delete window[p]; } } } /*eslint-enable */ function setOptions() { // user-settable parameters and defaults var userIsSysop = false; if ( mw.config.get('wgUserGroups') ) { for ( var g = 0; g < mw.config.get('wgUserGroups').length; ++g ) { if ( mw.config.get('wgUserGroups')[g] == "sysop" ) userIsSysop = true; } } // Basic options newOption('popupDelay', 0.5); newOption('popupHideDelay', 0.5); newOption('simplePopups', false); newOption('popupStructure', 'shortmenus'); // see later - default for popupStructure is 'original' if simplePopups is true newOption('popupActionsMenu', true); newOption('popupSetupMenu', true); newOption('popupAdminLinks', userIsSysop); newOption('popupShortcutKeys', false); newOption('popupHistoricalLinks', true); newOption('popupOnlyArticleLinks', true); newOption('removeTitles', true); newOption('popupMaxWidth', 350); newOption('popupSimplifyMainLink', true); newOption('popupAppendRedirNavLinks', true); newOption('popupTocLinks', false); newOption('popupSubpopups', true); newOption('popupDragHandle', false /* 'popupTopLinks'*/); newOption('popupLazyPreviews', true); newOption('popupLazyDownloads', true); newOption('popupAllDabsStubs', false); newOption('popupDebugging', false); newOption('popupActiveNavlinks', true); newOption('popupModifier', false); // ctrl, shift, alt or meta newOption('popupModifierAction', 'enable'); // or 'disable' newOption('popupDraggable', true); newOption('popupReview', false); //<NOLITE> // images newOption('popupImages', true); newOption('imagePopupsForImages', true); newOption('popupNeverGetThumbs', false); //newOption('popupImagesToggleSize', true); newOption('popupThumbAction', 'imagepage'); //'sizetoggle'); newOption('popupImageSize', 60); newOption('popupImageSizeLarge', 200); // redirs, dabs, reversion newOption('popupFixRedirs', false); newOption('popupRedirAutoClick', 'wpDiff'); newOption('popupFixDabs', false); newOption('popupDabsAutoClick', 'wpDiff'); newOption('popupRevertSummaryPrompt', false); newOption('popupMinorReverts', false); newOption('popupRedlinkRemoval', false); newOption('popupRedlinkAutoClick', 'wpDiff'); newOption('popupWatchDisambiggedPages', null); newOption('popupWatchRedirredPages', null); newOption('popupDabWiktionary', 'last'); // navlinks newOption('popupNavLinks', true); newOption('popupNavLinkSeparator', ' &sdot; '); newOption('popupLastEditLink', true); newOption('popupEditCounterTool', 'supercount'); newOption('popupEditCounterUrl', ''); //</NOLITE> // previews etc newOption('popupPreviews', true); newOption('popupSummaryData', true); newOption('popupMaxPreviewSentences', 9); newOption('popupMaxPreviewCharacters', 900); newOption('popupLastModified', true); newOption('popupPreviewKillTemplates', true); newOption('popupPreviewRawTemplates', true); newOption('popupPreviewFirstParOnly', false); newOption('popupPreviewCutHeadings', false); newOption('popupPreviewButton', false); newOption('popupPreviewButtonEvent', 'click'); //<NOLITE> // diffs newOption('popupPreviewDiffs', true); newOption('popupDiffMaxLines', 100); newOption('popupDiffContextLines', 2); newOption('popupDiffContextCharacters', 40); newOption('popupDiffDates', true); newOption('popupDiffDatePrinter', 'toLocaleString'); // edit summaries. God, these are ugly. newOption('popupReviewedSummary', popupString('defaultpopupReviewedSummary') ); newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary') ); newOption('popupExtendedRevertSummary', popupString('defaultpopupExtendedRevertSummary') ); newOption('popupRevertSummary', popupString('defaultpopupRevertSummary') ); newOption('popupRevertToPreviousSummary', popupString('defaultpopupRevertToPreviousSummary') ); newOption('popupQueriedRevertSummary', popupString('defaultpopupQueriedRevertSummary') ); newOption('popupQueriedRevertToPreviousSummary', popupString('defaultpopupQueriedRevertToPreviousSummary') ); newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary') ); newOption('popupRedlinkSummary', popupString('defaultpopupRedlinkSummary') ); newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary') ); //</NOLITE> // misc newOption('popupHistoryLimit', 50); //<NOLITE> newOption('popupFilters', [popupFilterStubDetect, popupFilterDisambigDetect, popupFilterPageSize, popupFilterCountLinks, popupFilterCountImages, popupFilterCountCategories, popupFilterLastModified]); newOption('extraPopupFilters', []); newOption('popupOnEditSelection', 'cursor'); newOption('popupPreviewHistory', true); newOption('popupImageLinks', true); newOption('popupCategoryMembers', true); newOption('popupUserInfo', true); newOption('popupHistoryPreviewLimit', 25); newOption('popupContribsPreviewLimit',25); newOption('popupRevDelUrl', '//en.wikipedia.org/wiki/Wikipedia:Revision_deletion'); newOption('popupShowGender', true); //</NOLITE> // new windows newOption('popupNewWindows', false); newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true}); // regexps newOption('popupDabRegexp', '(\\{\\{\\s*disambig(?!uation needed)|disambig(uation|)\\s*\\}\\}|disamb\\s*\\}\\}|dab\\s*\\}\\})|\\{\\{\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|(road|ship)index)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page'); newOption('popupAnchorRegexp', 'anchors?'); //how to identify an anchors template newOption('popupStubRegexp', '(sect)?stub[}][}]|This .*-related article is a .*stub'); newOption('popupImageVarsRegexp', 'image|image_(?:file|skyline|name|flag|seal)|cover|badge|logo'); } // ENDFILE: options.js // STARTFILE: strings.js //<NOLITE> ////////////////////////////////////////////////// // Translatable strings ////////////////////////////////////////////////// // // See instructions at // https://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation pg.string = { ///////////////////////////////////// // summary data, searching etc. ///////////////////////////////////// 'article': 'article', 'category': 'category', 'categories': 'categories', 'image': 'image', 'images': 'images', 'stub': 'stub', 'section stub': 'section stub', 'Empty page': 'Empty page', 'kB': 'kB', 'bytes': 'bytes', 'day': 'day', 'days': 'days', 'hour': 'hour', 'hours': 'hours', 'minute': 'minute', 'minutes': 'minutes', 'second': 'second', 'seconds': 'seconds', 'week': 'week', 'weeks': 'weeks', 'search': 'search', 'SearchHint': 'Find English Wikipedia articles containing %s', 'web': 'web', 'global': 'global', 'globalSearchHint': 'Search across Wikipedias in different languages for %s', 'googleSearchHint': 'Google for %s', ///////////////////////////////////// // article-related actions and info // (some actions also apply to user pages) ///////////////////////////////////// 'actions': 'actions', ///// view articles and view talk 'popupsMenu': 'popups', 'togglePreviewsHint': 'Toggle preview generation in popups on this page', 'enable previews': 'enable previews', 'disable previews': 'disable previews', 'toggle previews': 'toggle previews', 'show preview': 'show preview', 'reset': 'reset', 'more...': 'more...', 'disable': 'disable popups', 'disablePopupsHint': 'Disable popups on this page. Reload page to re-enable.', 'historyfeedHint': 'RSS feed of recent changes to this page', 'purgePopupsHint': 'Reset popups, clearing all cached popup data.', 'PopupsHint': 'Reset popups, clearing all cached popup data.', 'spacebar': 'space', 'view': 'view', 'view article': 'view article', 'viewHint': 'Go to %s', 'talk': 'talk', 'talk page': 'talk page', 'this&nbsp;revision': 'this&nbsp;revision', 'revision %s of %s': 'revision %s of %s', 'Revision %s of %s': 'Revision %s of %s', 'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s', 'Toggle image size': 'Click to toggle image size', 'del': 'del', ///// delete, protect, move 'delete': 'delete', 'deleteHint': 'Delete %s', 'undeleteShort': 'un', 'UndeleteHint': 'Show the deletion history for %s', 'protect': 'protect', 'protectHint': 'Restrict editing rights to %s', 'unprotectShort': 'un', 'unprotectHint': 'Allow %s to be edited by anyone again', 'send thanks': 'send thanks', 'ThanksHint': 'Send a thank you notification to this user', 'move': 'move', 'move page': 'move page', 'MovepageHint': 'Change the title of %s', 'edit': 'edit', ///// edit articles and talk 'edit article': 'edit article', 'editHint': 'Change the content of %s', 'edit talk': 'edit talk', 'new': 'new', 'new topic': 'new topic', 'newSectionHint': 'Start a new section on %s', 'null edit': 'null edit', 'nullEditHint': 'Submit an edit to %s, making no changes ', 'hist': 'hist', ///// history, diffs, editors, related 'history': 'history', 'historyHint': 'List the changes made to %s', 'last': 'prev', // For labelling the previous revision in history pages; the key is "last" for backwards compatibility 'lastEdit': 'lastEdit', 'mark patrolled': 'mark patrolled', 'markpatrolledHint': 'Mark this edit as patrolled', 'Could not marked this edit as patrolled': 'Could not marked this edit as patrolled', 'show last edit': 'most recent edit', 'Show the last edit': 'Show the effects of the most recent change', 'lastContrib': 'lastContrib', 'last set of edits': 'latest edits', 'lastContribHint': 'Show the net effect of changes made by the last editor', 'cur': 'cur', 'diffCur': 'diffCur', 'Show changes since revision %s': 'Show changes since revision %s', '%s old': '%s old', // as in 4 weeks old 'oldEdit': 'oldEdit', 'purge': 'purge', 'purgeHint': 'Demand a fresh copy of %s', 'raw': 'source', 'rawHint': 'Download the source of %s', 'render': 'simple', 'renderHint': 'Show a plain HTML version of %s', 'Show the edit made to get revision': 'Show the edit made to get revision', 'sinceMe': 'sinceMe', 'changes since mine': 'diff my edit', 'sinceMeHint': 'Show changes since my last edit', 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s': 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s', 'eds': 'eds', 'editors': 'editors', 'editorListHint': 'List the users who have edited %s', 'related': 'related', 'relatedChanges': 'relatedChanges', 'related changes': 'related changes', 'RecentchangeslinkedHint': 'Show changes in articles related to %s', 'editOld': 'editOld', ///// edit old version, or revert 'rv': 'rv', 'revert': 'revert', 'revertHint': 'Revert to %s', 'defaultpopupReviewedSummary': 'Accepted by reviewing the [[Special:diff/%s/%s|difference]] between this version and previously accepted version using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRedlinkSummary': 'Removing link to empty page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupFixDabsSummary': 'Disambiguate [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupFixRedirsSummary': 'Redirect bypass from [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupExtendedRevertSummary': 'Revert to revision dated %s by %s, oldid %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRevertToPreviousSummary': 'Revert to the revision prior to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRevertSummary': 'Revert to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupQueriedRevertToPreviousSummary': 'Revert to the revision prior to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupQueriedRevertSummary': 'Revert to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRmDabLinkSummary': 'Remove link to dab page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'Redirects': 'Redirects', // as in Redirects to ... ' to ': ' to ', // as in Redirects to ... 'Bypass redirect': 'Bypass redirect', 'Fix this redirect': 'Fix this redirect', 'disambig': 'disambig', ///// add or remove dab etc. 'disambigHint': 'Disambiguate this link to [[%s]]', 'Click to disambiguate this link to:': 'Click to disambiguate this link to:', 'remove this link': 'remove this link', 'remove all links to this page from this article': 'remove all links to this page from this article', 'remove all links to this disambig page from this article': 'remove all links to this disambig page from this article', 'mainlink': 'mainlink', ///// links, watch, unwatch 'wikiLink': 'wikiLink', 'wikiLinks': 'wikiLinks', 'links here': 'links here', 'whatLinksHere': 'whatLinksHere', 'what links here': 'what links here', 'WhatlinkshereHint': 'List the pages that are hyperlinked to %s', 'unwatchShort': 'un', 'watchThingy': 'watch', // called watchThingy because {}.watch is a function 'watchHint': 'Add %s to my watchlist', 'unwatchHint': 'Remove %s from my watchlist', 'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits', '%s seems to be the last editor to the page %s': '%s seems to be the last editor to the page %s', 'rss': 'rss', ///////////////////////////////////// // diff previews ///////////////////////////////////// 'Diff truncated for performance reasons': 'Diff truncated for performance reasons', 'Old revision': 'Old revision', 'New revision': 'New revision', 'Something went wrong :-(': 'Something went wrong :-(', 'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent', 'Unknown date': 'Unknown date', ///////////////////////////////////// // other special previews ///////////////////////////////////// 'Empty category': 'Empty category', 'Category members (%s shown)': 'Category members (%s shown)', 'No image links found': 'No image links found', 'File links': 'File links', 'No image found': 'No image found', 'Image from Commons': 'Image from Commons', 'Description page': 'Description page', 'Alt text:': 'Alt text:', 'revdel':'Hidden revision', ///////////////////////////////////// // user-related actions and info ///////////////////////////////////// 'user': 'user', ///// user page, talk, email, space 'user&nbsp;page': 'user&nbsp;page', 'user talk': 'user talk', 'edit user talk': 'edit user talk', 'leave comment': 'leave comment', 'email': 'email', 'email user': 'email user', 'EmailuserHint': 'Send an email to %s', 'space': 'space', // short form for userSpace link 'PrefixIndexHint': 'Show pages in the userspace of %s', 'count': 'count', ///// contributions, log 'edit counter': 'edit counter', 'editCounterLinkHint': 'Count the contributions made by %s', 'contribs': 'contribs', 'contributions': 'contributions', 'deletedContribs': 'deleted contributions', 'DeletedcontributionsHint': 'List deleted edits made by %s', 'ContributionsHint': 'List the contributions made by %s', 'log': 'log', 'user log': 'user log', 'userLogHint': 'Show %s\'s user log', 'arin': 'ARIN lookup', ///// ARIN lookup, block user or IP 'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database', 'unblockShort': 'un', 'block': 'block', 'block user': 'block user', 'IpblocklistHint': 'Unblock %s', 'BlockipHint': 'Prevent %s from editing', 'block log': 'block log', 'blockLogHint': 'Show the block log for %s', 'protectLogHint': 'Show the protection log for %s', 'pageLogHint': 'Show the page log for %s', 'deleteLogHint': 'Show the deletion log for %s', 'Invalid %s %s': 'The option %s is invalid: %s', 'No backlinks found': 'No backlinks found', ' and more': ' and more', 'undo': 'undo', 'undoHint': 'undo this edit', 'Download preview data': 'Download preview data', 'Invalid or IP user': 'Invalid or IP user', 'Not a registered username': 'Not a registered username', 'BLOCKED': 'BLOCKED', 'Has blocks': 'Has blocks', ' edits since: ': ' edits since: ', 'last edit on ': 'last edit on ', ///////////////////////////////////// // Autoediting ///////////////////////////////////// 'Enter a non-empty edit summary or press cancel to abort': 'Enter a non-empty edit summary or press cancel to abort', 'Failed to get revision information, please edit manually.\n\n': 'Failed to get revision information, please edit manually.\n\n', 'The %s button has been automatically clicked. Please wait for the next page to load.': 'The %s button has been automatically clicked. Please wait for the next page to load.', 'Could not find button %s. Please check the settings in your javascript file.': 'Could not find button %s. Please check the settings in your javascript file.', ///////////////////////////////////// // Popups setup ///////////////////////////////////// 'Open full-size image': 'Open full-size image', 'zxy': 'zxy', 'autoedit_version': 'np20140416' }; function popupString(str) { if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; } if (pg.string[str]) { return pg.string[str]; } return str; } function tprintf(str,subs) { if (typeof subs != typeof []) { subs = [subs]; } return simplePrintf(popupString(str), subs); } //</NOLITE> // ENDFILE: strings.js // STARTFILE: run.js //////////////////////////////////////////////////////////////////// // Run things //////////////////////////////////////////////////////////////////// // For some reason popups requires a fully loaded page jQuery.ready(...) causes problems for some. // The old addOnloadHook did something similar to the below if (document.readyState=="complete") autoEdit(); //will setup popups else $( window ).on( 'load', autoEdit ); // Support for MediaWiki's live preview, VisualEditor's saves and Echo's flyout. ( function () { var once = true; function dynamicContentHandler( $content ) { // Try to detect the hook fired on initial page load and disregard // it, we already hook to onload (possibly to different parts of // page - it's configurable) and running twice might be bad. Ugly… if ( $content.attr( 'id' ) == 'mw-content-text' ) { if ( once ) { once = false; return; } } function registerHooksForVisibleNavpops () { for (var i=0; pg.current.links && i<pg.current.links.length; ++i) { var navpop = pg.current.links[i].navpopup; if (!navpop || !navpop.isVisible()) { continue; } Navpopup.tracker.addHook(posCheckerHook(navpop)); } } function doIt () { registerHooksForVisibleNavpops(); $content.each( function () { this.ranSetupTooltipsAlready = false; setupTooltips( this ); } ); } setupPopups( doIt ); } // This hook is also fired after page load. mw.hook( 'wikipage.content' ).add( dynamicContentHandler ); mw.hook( 'ext.echo.overlay.beforeShowingOverlay' ).add( function($overlay){ dynamicContentHandler( $overlay.find(".mw-echo-state") ); }); } )(); // Forked from [[User:Connel MacKenzie/mess-with-popups.js]] Previewmaker.prototype.firstBit = function() { try{ if (mw.config.get("wgNamespaceNumber") !== 0){ // dont't be givin' me no subsequent paragraphs, you hear me? /// first we "normalize" section headings, removing whitespace after, adding before var d = this.data; if (getValueOf('popupPreviewCutHeadings')) { this.data = this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); /// then we want to get rid of paragraph breaks whose text ends badly this.data = this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); this.data = this.data.replace(RegExp('^[\\s\\n]*'), ''); stuff = (RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); if (stuff) { d = stuff[0]; } if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } /// now put \n\n after sections so that bullets and numbered lists work d = d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); } // superfluous sentences are RIGHT OUT. // note: exactly 1 set of parens here needed to make the slice work d = d.parenSplit(RegExp('([!?.]+["' + "'" + ']*\\s)', 'g')); // leading space is bad, mmkay? d[0] = d[0].replace(RegExp('^\\s*'), ''); var notSentenceEnds = RegExp('([^.][a-z][.][a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|\\[[^\\]]*|\\s[A-Zvclm])$', 'i'); d = this.fixSentenceEnds(d, notSentenceEnds); var maxChars=getValueOf('popupMaxPreviewCharacters'); var n = getValueOf('popupMaxPreviewSentences'); var dd; do { dd = this.firstSentences(d, n); --n; } while (dd.length > maxChars && n > 0); this.data = dd; } else { //TODO: Limit this override to urls that start with http://*.wiktionary.org/ //TODO: extend the above section to also preview Wikipedia links var charsWikt = 0; var linesWikt = this.data.split('\n'); for (jWikt = 0; jWikt < linesWikt.length; jWikt++) { linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{[in]transitive}}/g, ''); linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{[un]countable}}/g, ''); linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{cattag\|(.*?)}}/g, ""); linesWikt[jWikt] = linesWikt[jWikt].replace(/[\{\}]/g, "'"); if (linesWikt[jWikt].search(/^[#]/) == -1) { if (linesWikt[jWikt].search(/^==[A-Z]/) == -1) { linesWikt[jWikt] = ''; } } charsWikt += linesWikt[jWikt].length; } if (charsWikt < 2) { linesWikt[0] = "No properly formatted content"; } var maxChars = getValueOf('popupMaxPreviewCharacters'); var n = getValueOf('popupMaxPreviewSentences'); var dd = ''; for (jWikt = 0; jWikt < linesWikt.length; jWikt++) { if (linesWikt[jWikt] !== '') { dd += linesWikt[jWikt] + '\n'; } if (dd.length < maxChars) { this.data = dd; } } } } catch (e) { console.log("error from mess with popups: ", e); } }; }); orsd53nf3vg9wb097lspoxfv57tbbij 88927 88926 2026-08-06T23:13:52Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-popups.js]] 88926 javascript text/javascript // {{documentation}} // _________________________________________________________________________________________ // | | // | === WARNING: GLOBAL GADGET FILE === | // | Changes to this page affect many users. | // | Please discuss changes on the [[Wiktionary:Grease Pit]] before editing. | // |_________________________________________________________________________________________| mw.loader.load('//en.wikipedia.org/w/index.php?action=raw&title=MediaWiki:Gadget-navpop.css&ctype=text/css', "text/css"); // Forked from [[:w:MediaWiki:Gadget-popups.js]] $(function () { ////////////////////////////////////////////////// // Globals // // Trying to shove as many of these as possible into the pg (popup globals) object var pg = { re: {}, // regexps ns: {}, // namespaces string: {}, // translatable strings wiki: {}, // local site info user: {}, // current user info misc: {}, // YUCK PHOOEY option: {}, // options, see newOption etc optionDefault: {}, // default option values flag: {}, // misc flags cache: {}, // page and image cache structures: {}, // navlink structures timer: {}, // all sorts of timers (too damn many) counter: {}, // .. and all sorts of counters current: {}, // state info fn: {}, // functions endoflist: null }; /* Bail if the gadget/script is being loaded twice */ if( window.pg ) { return; } /* Export to global context */ window.pg = pg; /// Local Variables: /// /// mode:c /// /// End: /// // ENDFILE: main.js // STARTFILE: actions.js function setupTooltips(container, remove, force, popData) { log('setupTooltips, container='+container+', remove='+remove); if (!container) { //<NOLITE> // the main initial call if (getValueOf('popupOnEditSelection') && document && document.editform && document.editform.wpTextbox1) { document.editform.wpTextbox1.onmouseup=doSelectionPopup; } //</NOLITE> // article/content is a structure-dependent thing container = defaultPopupsContainer(); } if (!remove && !force && container.ranSetupTooltipsAlready) { return; } container.ranSetupTooltipsAlready = !remove; var anchors; anchors=container.getElementsByTagName('A'); setupTooltipsLoop(anchors, 0, 250, 100, remove, popData); } function defaultPopupsContainer() { if (getValueOf('popupOnlyArticleLinks')) { return document.getElementById('mw_content') || document.getElementById('content') || document.getElementById('article') || document; } return document; } function setupTooltipsLoop(anchors,begin,howmany,sleep, remove, popData) { log(simplePrintf('setupTooltipsLoop(%s,%s,%s,%s,%s)', arguments)); var finish=begin+howmany; var loopend = Math.min(finish, anchors.length); var j=loopend - begin; log ('setupTooltips: anchors.length=' + anchors.length + ', begin=' + begin + ', howmany=' + howmany + ', loopend=' + loopend + ', remove=' + remove); var doTooltip= remove ? removeTooltip : addTooltip; // try a faster (?) loop construct if (j > 0) { do { var a=anchors[loopend - j]; if (typeof a==='undefined' || !a || !a.href) { log('got null anchor at index ' + loopend - j); continue; } doTooltip(a, popData); } while (--j); } if (finish < anchors.length) { setTimeout(function() { setupTooltipsLoop(anchors,finish,howmany,sleep,remove,popData);}, sleep); } else { if ( !remove && ! getValueOf('popupTocLinks')) { rmTocTooltips(); } pg.flag.finishedLoading=true; } } // eliminate popups from the TOC // This also kills any onclick stuff that used to be going on in the toc function rmTocTooltips() { var toc=document.getElementById('toc'); if (toc) { var tocLinks=toc.getElementsByTagName('A'); var tocLen = tocLinks.length; for (var j=0; j<tocLen; ++j) { removeTooltip(tocLinks[j], true); } } } function addTooltip(a, popData) { if ( !isPopupLink(a) ) { return; } a.onmouseover=mouseOverWikiLink; a.onmouseout= mouseOutWikiLink; a.onmousedown = killPopup; a.hasPopup = true; a.popData = popData; } function removeTooltip(a) { if ( !a.hasPopup ) { return; } a.onmouseover = null; a.onmouseout = null; if (a.originalTitle) { a.title = a.originalTitle; } a.hasPopup=false; } function removeTitle(a) { if (!a.originalTitle) { a.originalTitle=a.title; } a.title=''; } function restoreTitle(a) { if ( a.title || !a.originalTitle ) { return; } a.title = a.originalTitle; } function registerHooks(np) { var popupMaxWidth=getValueOf('popupMaxWidth'); if (typeof popupMaxWidth === 'number') { var setMaxWidth = function () { np.mainDiv.style.maxWidth = popupMaxWidth + 'px'; np.maxWidth = popupMaxWidth; }; np.addHook(setMaxWidth, 'unhide', 'before'); } //<NOLITE> np.addHook(addPopupShortcuts, 'unhide', 'after'); np.addHook(rmPopupShortcuts, 'hide', 'before'); //</NOLITE> } function removeModifierKeyHandler(a) { //remove listeners for modifier key if any that were added in mouseOverWikiLink document.removeEventListener('keydown', a.modifierKeyHandler, false); document.removeEventListener('keyup', a.modifierKeyHandler, false); } function mouseOverWikiLink(evt) { if (!evt && window.event) {evt=window.event;} // if the modifier is needed, listen for it, // we will remove the listener when we mouseout of this link or kill popup. if (getValueOf('popupModifier')) { // if popupModifierAction = enable, we should popup when the modifier is pressed // if popupModifierAction = disable, we should popup unless the modifier is pressed var action = getValueOf('popupModifierAction'); var key = action=='disable' ? 'keyup' : 'keydown'; var a = this; a.modifierKeyHandler = function(evt) { mouseOverWikiLink2(a, evt); }; document.addEventListener(key, a.modifierKeyHandler, false); } return mouseOverWikiLink2(this, evt); } /** * Gets the references list item that the provided footnote link targets. This * is typically a li element within the ol.references element inside the reflist. * @param {Element} a - A footnote link. * @returns {Element|boolean} The targeted element, or false if one can't be found. */ function footnoteTarget(a) { var aTitle=Title.fromAnchor(a); // We want ".3A" rather than "%3A" or "?" here, so use the anchor property directly var anch = aTitle.anchor; if ( ! /^(cite_note-|_note-|endnote)/.test(anch) ) { return false; } var lTitle=Title.fromURL(location.href); if ( lTitle.toString(true) !== aTitle.toString(true) ) { return false; } var el=document.getElementById(anch); while ( el && typeof el.nodeName === 'string') { var nt = el.nodeName.toLowerCase(); if ( nt === 'li' ) { return el; } else if ( nt === 'body' ) { return false; } else if ( el.parentNode ) { el=el.parentNode; } else { return false; } } return false; } function footnotePreview(x, navpop) { setPopupHTML('<hr />' + x.innerHTML, 'popupPreview', navpop.idNumber); } function modifierPressed(evt) { var mod=getValueOf('popupModifier'); if (!mod) { return false; } if (!evt && window.event) {evt=window.event;} return ( evt && mod && evt[mod.toLowerCase() + 'Key'] ); } // Checks if the correct modifier pressed/unpressed if needed function isCorrectModifier(a,evt) { if (!getValueOf('popupModifier')) { return true; } // if popupModifierAction = enable, we should popup when the modifier is pressed // if popupModifierAction = disable, we should popup unless the modifier is pressed var action = getValueOf('popupModifierAction'); return ( action == 'enable' && modifierPressed(evt) || action == 'disable' && !modifierPressed(evt) ); } function mouseOverWikiLink2(a, evt) { if (!isCorrectModifier(a,evt)) { return; } if ( getValueOf('removeTitles') ) { removeTitle(a); } if ( a==pg.current.link && a.navpopup && a.navpopup.isVisible() ) { return; } pg.current.link=a; if (getValueOf('simplePopups') && !pg.option.popupStructure) { // reset *default value* of popupStructure setDefault('popupStructure', 'original'); } var article=(new Title()).fromAnchor(a); // set global variable (ugh) to hold article (wikipage) pg.current.article = article; if (!a.navpopup) { a.navpopup=newNavpopup(a, article); pg.current.linksHash[a.href] = a.navpopup; pg.current.links.push(a); } if (a.navpopup.pending === null || a.navpopup.pending !== 0) { // either fresh popups or those with unfinshed business are redone from scratch simplePopupContent(a, article); } a.navpopup.showSoonIfStable(a.navpopup.delay); clearInterval(pg.timer.checkPopupPosition); pg.timer.checkPopupPosition=setInterval(checkPopupPosition, 600); if(getValueOf('simplePopups')) { if (getValueOf('popupPreviewButton') && !a.simpleNoMore) { var d=document.createElement('div'); d.className='popupPreviewButtonDiv'; var s=document.createElement('span'); d.appendChild(s); s.className='popupPreviewButton'; s['on' + getValueOf('popupPreviewButtonEvent')] = function() { a.simpleNoMore=true; d.style.display = "none"; nonsimplePopupContent(a,article); }; s.innerHTML=popupString('show preview'); setPopupHTML(d, 'popupPreview', a.navpopup.idNumber); } } if (a.navpopup.pending !== 0 ) { nonsimplePopupContent(a, article); } } // simplePopupContent: the content that do not require additional download // (it is shown even when simplePopups is true) function simplePopupContent(a, article) { /* FIXME hack */ a.navpopup.hasPopupMenu=false; a.navpopup.setInnerHTML(popupHTML(a)); fillEmptySpans({navpopup:a.navpopup}); if (getValueOf('popupDraggable')) { var dragHandle = getValueOf('popupDragHandle') || null; if (dragHandle && dragHandle != 'all') { dragHandle += a.navpopup.idNumber; } setTimeout(function(){a.navpopup.makeDraggable(dragHandle);}, 150); } //<NOLITE> if (getValueOf('popupRedlinkRemoval') && a.className=='new') { setPopupHTML('<br>'+popupRedlinkHTML(article), 'popupRedlink', a.navpopup.idNumber); } //</NOLITE> } function debugData(navpopup) { if(getValueOf('popupDebugging') && navpopup.idNumber) { setPopupHTML('idNumber='+navpopup.idNumber + ', pending=' + navpopup.pending, 'popupError', navpopup.idNumber); } } function newNavpopup(a, article) { var navpopup = new Navpopup(); navpopup.fuzz=5; navpopup.delay=getValueOf('popupDelay')*1000; // increment global counter now navpopup.idNumber = ++pg.idNumber; navpopup.parentAnchor = a; navpopup.parentPopup = (a.popData && a.popData.owner); navpopup.article = article; registerHooks(navpopup); return navpopup; } // Should we show nonsimple context? // If simplePopups is set to true, then we do not show nonsimple context, // but if a bottom "show preview" was clicked we do show nonsimple context function shouldShowNonSimple(a) { return !getValueOf('simplePopups') || a.simpleNoMore; } // Should we show nonsimple context govern by the option (e.g. popupUserInfo)? // If the user explicitly asked for nonsimple context by setting the option to true, // then we show it even in nonsimple mode. function shouldShow(a,option) { if (shouldShowNonSimple(a)) { return getValueOf(option); } else { return (typeof window[option] != 'undefined' ) && window[option]; } } function nonsimplePopupContent(a, article) { var diff=null, history=null; var params=parseParams(a.href); var oldid=(typeof params.oldid=='undefined' ? null : params.oldid); //<NOLITE> if(shouldShow(a,'popupPreviewDiffs')) { diff=params.diff; } if(shouldShow(a,'popupPreviewHistory')) { history=(params.action=='history'); } //</NOLITE> a.navpopup.pending=0; var referenceElement = footnoteTarget(a); if (referenceElement) { footnotePreview(referenceElement, a.navpopup); //<NOLITE> } else if ( diff || diff === 0 ) { loadDiff(article, oldid, diff, a.navpopup); } else if ( history ) { loadAPIPreview('history', article, a.navpopup); } else if ( shouldShowNonSimple(a) && pg.re.contribs.test(a.href) ) { loadAPIPreview('contribs', article, a.navpopup); } else if ( shouldShowNonSimple(a) && pg.re.backlinks.test(a.href) ) { loadAPIPreview('backlinks', article, a.navpopup); } else if ( // FIXME should be able to get all preview combinations with options article.namespaceId()==pg.nsImageId && ( shouldShow(a,'imagePopupsForImages') || ! anchorContainsImage(a) ) ) { loadAPIPreview('imagepagepreview', article, a.navpopup); loadImage(article, a.navpopup); //</NOLITE> } else { if (article.namespaceId() == pg.nsCategoryId && shouldShow(a,'popupCategoryMembers')) { loadAPIPreview('category', article, a.navpopup); } else if ((article.namespaceId() == pg.nsUserId || article.namespaceId() == pg.nsUsertalkId) && shouldShow(a,'popupUserInfo')) { loadAPIPreview('userinfo', article, a.navpopup); } if (shouldShowNonSimple(a)) startArticlePreview(article, oldid, a.navpopup); } } function pendingNavpopTask(navpop) { if (navpop && navpop.pending === null) { navpop.pending=0; } ++navpop.pending; debugData(navpop); } function completedNavpopTask(navpop) { if (navpop && navpop.pending) { --navpop.pending; } debugData(navpop); } function startArticlePreview(article, oldid, navpop) { navpop.redir=0; loadPreview(article, oldid, navpop); } function loadPreview(article, oldid, navpop) { if (!navpop.redir) { navpop.originalArticle=article; } article.oldid = oldid; loadAPIPreview('revision', article, navpop); } function loadPreviewFromRedir(redirMatch, navpop) { // redirMatch is a regex match var target = new Title().fromWikiText(redirMatch[2]); // overwrite (or add) anchor from original target // mediawiki does overwrite; eg [[User:Lupin/foo3#Done]] if ( navpop.article.anchor ) { target.anchor = navpop.article.anchor; } navpop.redir++; navpop.redirTarget=target; //<NOLITE> var warnRedir = redirLink(target, navpop.article); setPopupHTML(warnRedir, 'popupWarnRedir', navpop.idNumber); //</NOLITE> navpop.article=target; fillEmptySpans({redir: true, redirTarget: target, navpopup:navpop}); return loadPreview(target, null, navpop); } function insertPreview(download) { if (!download.owner) { return; } var redirMatch = pg.re.redirect.exec(download.data); if (download.owner.redir === 0 && redirMatch) { loadPreviewFromRedir(redirMatch, download.owner); return; } if (download.owner.visible || !getValueOf('popupLazyPreviews')) { insertPreviewNow(download); } else { var id=(download.owner.redir) ? 'PREVIEW_REDIR_HOOK' : 'PREVIEW_HOOK'; download.owner.addHook( function(){insertPreviewNow(download); return true;}, 'unhide', 'after', id ); } } function insertPreviewNow(download) { if (!download.owner) { return; } var wikiText=download.data; var navpop=download.owner; var art=navpop.redirTarget || navpop.originalArticle; //<NOLITE> makeFixDabs(wikiText, navpop); if (getValueOf('popupSummaryData')) { getPageInfo(wikiText, download); setPopupTrailer(getPageInfo(wikiText, download), navpop.idNumber); } var imagePage=''; if (art.namespaceId()==pg.nsImageId) { imagePage=art.toString(); } else { imagePage=getValidImageFromWikiText(wikiText); } if(imagePage) { loadImage(Title.fromWikiText(imagePage), navpop); } //</NOLITE> if (getValueOf('popupPreviews')) { insertArticlePreview(download, art, navpop); } } function insertArticlePreview(download, art, navpop) { if (download && typeof download.data == typeof ''){ if (art.namespaceId()==pg.nsTemplateId && getValueOf('popupPreviewRawTemplates')) { // FIXME compare/consolidate with diff escaping code for wikitext var h='<hr /><span style="font-family: monospace;">' + download.data.entify().split('\\n').join('<br />\\n') + '</span>'; setPopupHTML(h, 'popupPreview', navpop.idNumber); } else { var p=prepPreviewmaker(download.data, art, navpop); p.showPreview(); } } } function prepPreviewmaker(data, article, navpop) { // deal with tricksy anchors var d=anchorize(data, article.anchorString()); var urlBase=joinPath([pg.wiki.articlebase, article.urlString()]); var p=new Previewmaker(d, urlBase, navpop); return p; } // Try to imitate the way mediawiki generates HTML anchors from section titles function anchorize(d, anch) { if (!anch) { return d; } var anchRe=RegExp('(?:=+\\s*' + literalizeRegex(anch).replace(/[_ ]/g, '[_ ]') + '\\s*=+|\\{\\{\\s*'+getValueOf('popupAnchorRegexp')+'\\s*(?:\\|[^|}]*)*?\\s*'+literalizeRegex(anch)+'\\s*(?:\\|[^}]*)?}})'); var match=d.match(anchRe); if(match && match.length > 0 && match[0]) { return d.substring(d.indexOf(match[0])); } // now try to deal with == foo [[bar|baz]] boom == -> #foo_baz_boom var lines=d.split('\n'); for (var i=0; i<lines.length; ++i) { lines[i]=lines[i].replace(RegExp('[[]{2}([^|\\]]*?[|])?(.*?)[\\]]{2}', 'g'), '$2') .replace(/'''([^'])/g, '$1').replace(RegExp("''([^'])", 'g'), '$1'); if (lines[i].match(anchRe)) { return d.split('\n').slice(i).join('\n').replace(RegExp('^[^=]*'), ''); } } return d; } function killPopup() { removeModifierKeyHandler(this); if (getValueOf('popupShortcutKeys')) { rmPopupShortcuts(); } if (!pg) { return; } if (pg.current.link && pg.current.link.navpopup) { pg.current.link.navpopup.banish(); } pg.current.link=null; abortAllDownloads(); if (pg.timer.checkPopupPosition) { clearInterval(pg.timer.checkPopupPosition); pg.timer.checkPopupPosition=null; } return true; // preserve default action } // ENDFILE: actions.js // STARTFILE: domdrag.js /** @fileoverview The {@link Drag} object, which enables objects to be dragged around. <pre> ************************************************* dom-drag.js 09.25.2001 www.youngpup.net ************************************************** 10.28.2001 - fixed minor bug where events sometimes fired off the handle, not the root. ************************************************* Pared down, some hooks added by [[User:Lupin]] Copyright Aaron Boodman. Saying stupid things daily since March 2001. </pre> */ /** Creates a new Drag object. This is used to make various DOM elements draggable. @constructor */ function Drag () { /** Condition to determine whether or not to drag. This function should take one parameter, an Event. To disable this, set it to <code>null</code>. @type Function */ this.startCondition = null; /** Hook to be run when the drag finishes. This is passed the final coordinates of the dragged object (two integers, x and y). To disables this, set it to <code>null</code>. @type Function */ this.endHook = null; } /** Gets an event in a cross-browser manner. @param {Event} e @private */ Drag.prototype.fixE = function(e) { if (typeof e == 'undefined') { e = window.event; } if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; } if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; } return e; }; /** Initialises the Drag instance by telling it which object you want to be draggable, and what you want to drag it by. @param {DOMElement} o The "handle" by which <code>oRoot</code> is dragged. @param {DOMElement} oRoot The object which moves when <code>o</code> is dragged, or <code>o</code> if omitted. */ Drag.prototype.init = function(o, oRoot) { var dragObj = this; this.obj = o; o.onmousedown = function(e) { dragObj.start.apply( dragObj, [e]); }; o.dragging = false; o.popups_draggable = true; o.hmode = true; o.vmode = true; o.root = oRoot ? oRoot : o ; if (isNaN(parseInt(o.root.style.left, 10))) { o.root.style.left = "0px"; } if (isNaN(parseInt(o.root.style.top, 10))) { o.root.style.top = "0px"; } o.root.onthisStart = function(){}; o.root.onthisEnd = function(){}; o.root.onthis = function(){}; }; /** Starts the drag. @private @param {Event} e */ Drag.prototype.start = function(e) { var o = this.obj; // = this; e = this.fixE(e); if (this.startCondition && !this.startCondition(e)) { return; } var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10); o.root.onthisStart(x, y); o.lastMouseX = e.clientX; o.lastMouseY = e.clientY; var dragObj = this; o.onmousemoveDefault = document.onmousemove; o.dragging = true; document.onmousemove = function(e) { dragObj.drag.apply( dragObj, [e] ); }; document.onmouseup = function(e) { dragObj.end.apply( dragObj, [e] ); }; return false; }; /** Does the drag. @param {Event} e @private */ Drag.prototype.drag = function(e) { e = this.fixE(e); var o = this.obj; var ey = e.clientY; var ex = e.clientX; var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10 ); var nx, ny; nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1)); ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1)); this.obj.root.style[o.hmode ? "left" : "right"] = nx + "px"; this.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px"; this.obj.lastMouseX = ex; this.obj.lastMouseY = ey; this.obj.root.onthis(nx, ny); return false; }; /** Ends the drag. @private */ Drag.prototype.end = function() { document.onmousemove=this.obj.onmousemoveDefault; document.onmouseup = null; this.obj.dragging = false; if (this.endHook) { this.endHook( parseInt(this.obj.root.style[this.obj.hmode ? "left" : "right"], 10), parseInt(this.obj.root.style[this.obj.vmode ? "top" : "bottom"], 10)); } }; // ENDFILE: domdrag.js // STARTFILE: structures.js //<NOLITE> pg.structures.original={}; pg.structures.original.popupLayout=function () { return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupUserData', 'popupData', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; pg.structures.original.popupRedirSpans=function () { return ['popupRedir', 'popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks']; }; pg.structures.original.popupTitle=function (x) { log ('defaultstructure.popupTitle'); if (!getValueOf('popupNavLinks')) { return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params); } return ''; }; pg.structures.original.popupTopLinks=function (x) { log ('defaultstructure.popupTopLinks'); if (getValueOf('popupNavLinks')) { return navLinksHTML(x.article, x.hint, x.params); } return ''; }; pg.structures.original.popupImage=function(x) { log ('original.popupImage, x.article='+x.article+', x.navpop.idNumber='+x.navpop.idNumber); return imageHTML(x.article, x.navpop.idNumber); }; pg.structures.original.popupRedirTitle=pg.structures.original.popupTitle; pg.structures.original.popupRedirTopLinks=pg.structures.original.popupTopLinks; function copyStructure(oldStructure, newStructure) { pg.structures[newStructure]={}; for (var prop in pg.structures[oldStructure]) { pg.structures[newStructure][prop]=pg.structures[oldStructure][prop]; } } copyStructure('original', 'nostalgia'); pg.structures.nostalgia.popupTopLinks=function(x) { var str=''; str += '<b><<mainlink|shortcut= >></b>'; // user links // contribs - log - count - email - block // count only if applicable; block only if popupAdminLinks str += 'if(user){<br><<contribs|shortcut=c>>'; str+='if(wikimedia){*<<count|shortcut=#>>}'; str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>}}'; // editing links // talkpage -> edit|new - history - un|watch - article|edit // other page -> edit - history - un|watch - talk|edit|new var editstr='<<edit|shortcut=e>>'; var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'; var historystr='<<history|shortcut=h>>'; var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; str += '<br>if(talk){' + editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + '}else{' + // not a talk page editOldidStr + '*' + historystr + '*' + watchstr + '*' + '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; // misc links str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>'; str += 'if(admin){<br>}else{*}<<move|shortcut=m>>'; // admin links str += 'if(admin){*<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*' + '<<undelete|undeleteShort>>|<<delete|shortcut=d>>}'; return navlinkStringToHTML(str, x.article, x.params); }; pg.structures.nostalgia.popupRedirTopLinks=pg.structures.nostalgia.popupTopLinks; /** -- fancy -- **/ copyStructure('original', 'fancy'); pg.structures.fancy.popupTitle=function (x) { return navlinkStringToHTML('<font size=+0><<mainlink>></font>',x.article,x.params); }; pg.structures.fancy.popupTopLinks=function(x) { var hist='<<history|shortcut=h|hist>>|<<lastEdit|shortcut=/|last>>|<<editors|shortcut=E|eds>>'; var watch='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; var move='<<move|shortcut=m|move>>'; return navlinkStringToHTML('if(talk){' + '<<edit|shortcut=e>>|<<new|shortcut=+|+>>*' + hist + '*' + '<<article|shortcut=a>>|<<editArticle|edit>>' + '*' + watch + '*' + move + '}else{<<edit|shortcut=e>>*' + hist + '*<<talk|shortcut=t|>>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>' + '*' + watch + '*' + move+'}<br>', x.article, x.params); }; pg.structures.fancy.popupOtherLinks=function(x) { var admin='<<unprotect|unprotectShort>>|<<protect|shortcut=p>>*<<undelete|undeleteShort>>|<<delete|shortcut=d|del>>'; var user='<<contribs|shortcut=c>>if(wikimedia){|<<count|shortcut=#|#>>}'; user+='if(ipuser){|<<arin>>}else{*<<email|shortcut=E|'+ popupString('email')+'>>}if(admin){*<<block|shortcut=b>>}'; var normal='<<whatLinksHere|shortcut=l|links here>>*<<relatedChanges|shortcut=r|related>>'; return navlinkStringToHTML('<br>if(user){' + user + '*}if(admin){'+admin+'if(user){<br>}else{*}}' + normal, x.article, x.params); }; pg.structures.fancy.popupRedirTitle=pg.structures.fancy.popupTitle; pg.structures.fancy.popupRedirTopLinks=pg.structures.fancy.popupTopLinks; pg.structures.fancy.popupRedirOtherLinks=pg.structures.fancy.popupOtherLinks; /** -- fancy2 -- **/ // hack for [[User:MacGyverMagic]] copyStructure('fancy', 'fancy2'); pg.structures.fancy2.popupTopLinks=function(x) { // hack out the <br> at the end and put one at the beginning return '<br>'+pg.structures.fancy.popupTopLinks(x).replace(RegExp('<br>$','i'),''); }; pg.structures.fancy2.popupLayout=function () { // move toplinks to after the title return ['popupError', 'popupImage', 'popupTitle', 'popupUserData', 'popupData', 'popupTopLinks', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; /** -- menus -- **/ copyStructure('original', 'menus'); pg.structures.menus.popupLayout=function () { return ['popupError', 'popupImage', 'popupTopLinks', 'popupTitle', 'popupOtherLinks', 'popupRedir', ['popupWarnRedir', 'popupRedirTopLinks', 'popupRedirTitle', 'popupRedirData', 'popupRedirOtherLinks'], 'popupUserData', 'popupData', 'popupMiscTools', ['popupRedlink'], 'popupPrePreviewSep', 'popupPreview', 'popupSecondPreview', 'popupPreviewMore', 'popupPostPreview', 'popupFixDab']; }; pg.structures.menus.popupTopLinks = function (x, shorter) { // FIXME maybe this stuff should be cached var s=[]; var dropdiv='<div class="popup_drop">'; var enddiv='</div>'; var hist='<<history|shortcut=h>>'; if (!shorter) { hist = '<menurow>' + hist + '|<<historyfeed|rss>>|<<editors|shortcut=E>></menurow>'; } var lastedit='<<lastEdit|shortcut=/|show last edit>>'; var thank='if(diff){<<thank|send thanks>>}'; var jsHistory='<<lastContrib|last set of edits>><<sinceMe|changes since mine>>'; var linkshere='<<whatLinksHere|shortcut=l|what links here>>'; var related='<<relatedChanges|shortcut=r|related changes>>'; var search='<menurow><<search|shortcut=s>>if(wikimedia){|<<globalsearch|shortcut=g|global>>}' + '|<<google|shortcut=G|web>></menurow>'; var watch='<menurow><<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>></menurow>'; var protect='<menurow><<unprotect|unprotectShort>>|' + '<<protect|shortcut=p>>|<<protectlog|log>></menurow>'; var del='<menurow><<undelete|undeleteShort>>|<<delete|shortcut=d>>|' + '<<deletelog|log>></menurow>'; var move='<<move|shortcut=m|move page>>'; var nullPurge='<menurow><<nullEdit|shortcut=n|null edit>>|<<purge|shortcut=P>></menurow>'; var viewOptions='<menurow><<view|shortcut=v>>|<<render|shortcut=S>>|<<raw>></menurow>'; var editRow='if(oldid){' + '<menurow><<edit|shortcut=e>>|<<editOld|shortcut=e|this&nbsp;revision>></menurow>' + '<menurow><<revert|shortcut=v>>|<<undo>></menurow>' + '}else{<<edit|shortcut=e>>}'; var markPatrolled='if(rcid){<<markpatrolled|mark patrolled>>}'; var newTopic='if(talk){<<new|shortcut=+|new topic>>}'; var protectDelete='if(admin){' + protect + del + '}'; if (getValueOf('popupActionsMenu')) { s.push( '<<mainlink>>*' + dropdiv + menuTitle('actions')); } else { s.push( dropdiv + '<<mainlink>>'); } s.push( '<menu>'); s.push( editRow + markPatrolled + newTopic + hist + lastedit + thank ); if (!shorter) { s.push(jsHistory); } s.push( move + linkshere + related); if (!shorter) { s.push(nullPurge + search); } if (!shorter) { s.push(viewOptions); } s.push('<hr />' + watch + protectDelete); s.push('<hr />' + 'if(talk){<<article|shortcut=a|view article>><<editArticle|edit article>>}' + 'else{<<talk|shortcut=t|talk page>><<editTalk|edit talk>>' + '<<newTalk|shortcut=+|new topic>>}</menu>' + enddiv); // user menu starts here var email='<<email|shortcut=E|email user>>'; var contribs= 'if(wikimedia){<menurow>}<<contribs|shortcut=c|contributions>>if(wikimedia){</menurow>}' + 'if(admin){<menurow><<deletedContribs>></menurow>}'; s.push('if(user){*' + dropdiv + menuTitle('user')); s.push('<menu>'); s.push('<menurow><<userPage|shortcut=u|user&nbsp;page>>|<<userSpace|space>></menurow>'); s.push('<<userTalk|shortcut=t|user talk>><<editUserTalk|edit user talk>>' + '<<newUserTalk|shortcut=+|leave comment>>'); if(!shorter) { s.push( 'if(ipuser){<<arin>>}else{' + email + '}' ); } else { s.push( 'if(ipuser){}else{' + email + '}' ); } s.push('<hr />' + contribs + '<<userlog|shortcut=L|user log>>'); s.push('if(wikimedia){<<count|shortcut=#|edit counter>>}'); s.push('if(admin){<menurow><<unblock|unblockShort>>|<<block|shortcut=b|block user>></menurow>}'); s.push('<<blocklog|shortcut=B|block log>>'); s.push('</menu>' + enddiv + '}'); // popups menu starts here if (getValueOf('popupSetupMenu') && !x.navpop.hasPopupMenu /* FIXME: hack */) { x.navpop.hasPopupMenu=true; s.push('*' + dropdiv + menuTitle('popupsMenu') + '<menu>'); s.push('<<togglePreviews|toggle previews>>'); s.push('<<purgePopups|reset>>'); s.push('<<disablePopups|disable>>'); s.push('</menu>'+enddiv); } return navlinkStringToHTML(s.join(''), x.article, x.params); }; function menuTitle(s) { return '<a href="#" noPopup=1>' + popupString(s) + '</a>'; } pg.structures.menus.popupRedirTitle=pg.structures.menus.popupTitle; pg.structures.menus.popupRedirTopLinks=pg.structures.menus.popupTopLinks; copyStructure('menus', 'shortmenus'); pg.structures.shortmenus.popupTopLinks=function(x) { return pg.structures.menus.popupTopLinks(x,true); }; pg.structures.shortmenus.popupRedirTopLinks=pg.structures.shortmenus.popupTopLinks; //</NOLITE> pg.structures.lite={}; pg.structures.lite.popupLayout=function () { return ['popupTitle', 'popupPreview' ]; }; pg.structures.lite.popupTitle=function (x) { log (x.article + ': structures.lite.popupTitle'); //return navlinkStringToHTML('<b><<mainlink>></b>',x.article,x.params); return '<div><span class="popup_mainlink"><b>' + x.article.toString() + '</b></span></div>'; }; // ENDFILE: structures.js // STARTFILE: autoedit.js //<NOLITE> function substitute(data,cmdBody) { // alert('sub\nfrom: '+cmdBody.from+'\nto: '+cmdBody.to+'\nflags: '+cmdBody.flags); var fromRe=RegExp(cmdBody.from, cmdBody.flags); return data.replace(fromRe, cmdBody.to); } function execCmds(data, cmdList) { for (var i=0; i<cmdList.length; ++i) { data=cmdList[i].action(data, cmdList[i]); } return data; } function parseCmd(str) { // returns a list of commands if (!str.length) { return []; } var p=false; switch (str.charAt(0)) { case 's': p=parseSubstitute(str); break; default: return false; } if (p) { return [p].concat(parseCmd(p.remainder)); } return false; } function unEscape(str, sep) { return str.split('\\\\').join('\\').split('\\'+sep).join(sep).split('\\n').join('\n'); } function parseSubstitute(str) { // takes a string like s/a/b/flags;othercmds and parses it var from,to,flags,tmp; if (str.length<4) { return false; } var sep=str.charAt(1); str=str.substring(2); tmp=skipOver(str,sep); if (tmp) { from=tmp.segment; str=tmp.remainder; } else { return false; } tmp=skipOver(str,sep); if (tmp) { to=tmp.segment; str=tmp.remainder; } else { return false; } flags=''; if (str.length) { tmp=skipOver(str,';') || skipToEnd(str, ';'); if (tmp) {flags=tmp.segment; str=tmp.remainder; } } return {action: substitute, from: from, to: to, flags: flags, remainder: str}; } function skipOver(str,sep) { var endSegment=findNext(str,sep); if (endSegment<0) { return false; } var segment=unEscape(str.substring(0,endSegment), sep); return {segment: segment, remainder: str.substring(endSegment+1)}; } /*eslint-disable*/ function skipToEnd(str,sep) { return {segment: str, remainder: ''}; } /*eslint-enable */ function findNext(str, ch) { for (var i=0; i<str.length; ++i) { if (str.charAt(i)=='\\') { i+=2; } if (str.charAt(i)==ch) { return i; } } return -1; } function setCheckbox(param, box) { var val=mw.util.getParamValue(param); if (val) { switch (val) { case '1': case 'yes': case 'true': box.checked=true; break; case '0': case 'no': case 'false': box.checked=false; } } } function autoEdit() { setupPopups( function () { if (mw.util.getParamValue('autoimpl') !== popupString('autoedit_version') ) { return false; } if (mw.util.getParamValue('autowatchlist') && mw.util.getParamValue('actoken')===autoClickToken()) { pg.fn.modifyWatchlist(mw.util.getParamValue('title'), mw.util.getParamValue('action')); } if (!document.editform) { return false; } if (autoEdit.alreadyRan) { return false; } autoEdit.alreadyRan=true; var cmdString=mw.util.getParamValue('autoedit'); if (cmdString) { try { var editbox=document.editform.wpTextbox1; var cmdList=parseCmd(cmdString); var input=editbox.value; var output=execCmds(input, cmdList); editbox.value=output; } catch (dang) { return; } // wikEd user script compatibility if (typeof(wikEdUseWikEd) != 'undefined') { if (wikEdUseWikEd === true) { WikEdUpdateFrame(); } } } setCheckbox('autominor', document.editform.wpMinoredit); setCheckbox('autowatch', document.editform.wpWatchthis); var rvid = mw.util.getParamValue('autorv'); if (rvid) { var url=pg.wiki.apiwikibase + '?action=query&format=json&formatversion=2&prop=revisions&revids='+rvid; startDownload(url, null, autoEdit2); } else { autoEdit2(); } } ); } function autoEdit2(d) { var summary=mw.util.getParamValue('autosummary'); var summaryprompt=mw.util.getParamValue('autosummaryprompt'); var summarynotice=''; if (d && d.data && mw.util.getParamValue('autorv')) { var s = getRvSummary(summary, d.data); if (s === false) { summaryprompt=true; summarynotice=popupString('Failed to get revision information, please edit manually.\n\n'); summary = simplePrintf(summary, [mw.util.getParamValue('autorv'), '(unknown)', '(unknown)']); } else { summary = s; } } if (summaryprompt) { var txt= summarynotice + popupString('Enter a non-empty edit summary or press cancel to abort'); var response=prompt(txt, summary); if (response) { summary=response; } else { return; } } if (summary) { document.editform.wpSummary.value=summary; } // Attempt to avoid possible premature clicking of the save button // (maybe delays in updates to the DOM are to blame?? or a red herring) setTimeout(autoEdit3, 100); } function autoClickToken() { return mw.user.sessionId(); } function autoEdit3() { if( mw.util.getParamValue('actoken') != autoClickToken()) { return; } var btn=mw.util.getParamValue('autoclick'); if (btn) { if (document.editform && document.editform[btn]) { var button=document.editform[btn]; var msg=tprintf('The %s button has been automatically clicked. Please wait for the next page to load.', [ button.value ]); bannerMessage(msg); document.title='('+document.title+')'; button.click(); } else { alert(tprintf('Could not find button %s. Please check the settings in your javascript file.', [ btn ])); } } } function bannerMessage(s) { var headings=document.getElementsByTagName('h1'); if (headings) { var div=document.createElement('div'); div.innerHTML='<font size=+1><b>' + s + '</b></font>'; headings[0].parentNode.insertBefore(div, headings[0]); } } function getRvSummary(template, json) { try { var o=getJsObj(json); var edit = anyChild(o.query.pages).revisions[0]; var timestamp = edit.timestamp.split(/[A-Z]/g).join(' ').replace(/^ *| *$/g, ''); return simplePrintf(template, [edit.revid, timestamp, edit.userhidden ? '(hidden)' : edit.user ]); } catch (badness) { return false; } } //</NOLITE> // ENDFILE: autoedit.js // STARTFILE: downloader.js /** @fileoverview {@link Downloader}, a xmlhttprequest wrapper, and helper functions. */ /** Creates a new Downloader @constructor @class The Downloader class. Create a new instance of this class to download stuff. @param {String} url The url to download. This can be omitted and supplied later. */ function Downloader(url) { if (typeof XMLHttpRequest!='undefined') { this.http = new XMLHttpRequest(); } /** The url to download @type String */ this.url = url; /** A universally unique ID number @type integer */ this.id=null; /** Modification date, to be culled from the incoming headers @type Date @private */ this.lastModified = null; /** What to do when the download completes successfully @type Function @private */ this.callbackFunction = null; /** What to do on failure @type Function @private */ this.onFailure = null; /** Flag set on <code>abort</code> @type boolean */ this.aborted = false; /** HTTP method. See https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html for possibilities. @type String */ this.method='GET'; /** Async flag. @type boolean */ this.async=true; } new Downloader(); /** Submits the http request. */ Downloader.prototype.send = function (x) { if (!this.http) { return null; } return this.http.send(x); }; /** Aborts the download, setting the <code>aborted</code> field to true. */ Downloader.prototype.abort = function () { if (!this.http) { return null; } this.aborted=true; return this.http.abort(); }; /** Returns the downloaded data. */ Downloader.prototype.getData = function () {if (!this.http) { return null; } return this.http.responseText;}; /** Prepares the download. */ Downloader.prototype.setTarget = function () { if (!this.http) { return null; } this.http.open(this.method, this.url, this.async); this.http.setRequestHeader( 'Api-User-Agent', pg.misc.userAgent ); }; /** Gets the state of the download. */ Downloader.prototype.getReadyState=function () {if (!this.http) { return null; } return this.http.readyState;}; pg.misc.downloadsInProgress = { }; /** Starts the download. Note that setTarget {@link Downloader#setTarget} must be run first */ Downloader.prototype.start=function () { if (!this.http) { return; } pg.misc.downloadsInProgress[this.id] = this; this.http.send(null); }; /** Gets the 'Last-Modified' date from the download headers. Should be run after the download completes. Returns <code>null</code> on failure. @return {Date} */ Downloader.prototype.getLastModifiedDate=function () { if(!this.http) { return null; } var lastmod=null; try { lastmod=this.http.getResponseHeader('Last-Modified'); } catch (err) {} if (lastmod) { return new Date(lastmod); } return null; }; /** Sets the callback function. @param {Function} f callback function, called as <code>f(this)</code> on success */ Downloader.prototype.setCallback = function (f) { if(!this.http) { return; } this.http.onreadystatechange = f; }; Downloader.prototype.getStatus = function() { if (!this.http) { return null; } return this.http.status; }; ////////////////////////////////////////////////// // helper functions /** Creates a new {@link Downloader} and prepares it for action. @param {String} url The url to download @param {integer} id The ID of the {@link Downloader} object @param {Function} callback The callback function invoked on success @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser */ function newDownload(url, id, callback, onfailure) { var d=new Downloader(url); if (!d.http) { return 'ohdear'; } d.id=id; d.setTarget(); if (!onfailure) { onfailure=2; } var f = function () { if (d.getReadyState() == 4) { delete pg.misc.downloadsInProgress[this.id]; try { if ( d.getStatus() == 200 ) { d.data=d.getData(); d.lastModified=d.getLastModifiedDate(); callback(d); } else if (typeof onfailure == typeof 1) { if (onfailure > 0) { // retry newDownload(url, id, callback, onfailure - 1); } } else if (typeof onfailure === 'function') { onfailure(d,url,id,callback); } } catch (somerr) { /* ignore it */ } } }; d.setCallback(f); return d; } /** Simulates a download from cached data. The supplied data is put into a {@link Downloader} as if it had downloaded it. @param {String} url The url. @param {integer} id The ID. @param {Function} callback The callback, which is invoked immediately as <code>callback(d)</code>, where <code>d</code> is the new {@link Downloader}. @param {String} data The (cached) data. @param {Date} lastModified The (cached) last modified date. */ function fakeDownload(url, id, callback, data, lastModified, owner) { var d=newDownload(url,callback); d.owner=owner; d.id=id; d.data=data; d.lastModified=lastModified; return callback(d); } /** Starts a download. @param {String} url The url to download @param {integer} id The ID of the {@link Downloader} object @param {Function} callback The callback function invoked on success @return {String/Downloader} the {@link Downloader} object created, or 'ohdear' if an unsupported browser */ function startDownload(url, id, callback) { var d=newDownload(url, id, callback); if (typeof d == typeof '' ) { return d; } d.start(); return d; } /** Aborts all downloads which have been started. */ function abortAllDownloads() { for ( var x in pg.misc.downloadsInProgress ) { try { pg.misc.downloadsInProgress[x].aborted=true; pg.misc.downloadsInProgress[x].abort(); delete pg.misc.downloadsInProgress[x]; } catch (e) {} } } // ENDFILE: downloader.js // STARTFILE: livepreview.js // TODO: location is often not correct (eg relative links in previews) // NOTE: removed md5 and image and math parsing. was broken, lots of bytes. /** * InstaView - a Mediawiki to HTML converter in JavaScript * Version 0.6.1 * Copyright (C) Pedro Fayolle 2005-2006 * https://en.wikipedia.org/wiki/User:Pilaf * Distributed under the BSD license * * Changelog: * * 0.6.1 * - Fixed problem caused by \r characters * - Improved inline formatting parser * * 0.6 * - Changed name to InstaView * - Some major code reorganizations and factored out some common functions * - Handled conversion of relative links (i.e. [[/foo]]) * - Fixed misrendering of adjacent definition list items * - Fixed bug in table headings handling * - Changed date format in signatures to reflect Mediawiki's * - Fixed handling of [[:Image:...]] * - Updated MD5 function (hopefully it will work with UTF-8) * - Fixed bug in handling of links inside images * * To do: * - Better support for math tags * - Full support for <nowiki> * - Parser-based (as opposed to RegExp-based) inline wikicode handling (make it one-pass and bullet-proof) * - Support for templates (through AJAX) * - Support for coloured links (AJAX) */ var Insta = {}; function setupLivePreview() { // options Insta.conf = { baseUrl: '', user: {}, wiki: { lang: pg.wiki.lang, interwiki: pg.wiki.interwiki, default_thumb_width: 180 }, paths: { articles: pg.wiki.articlePath + '/', // Only used for Insta previews with images. (not in popups) math: '/math/', images: '//upload.wikimedia.org/wikipedia/en/', // FIXME getImageUrlStart(pg.wiki.hostname), images_fallback: '//upload.wikimedia.org/wikipedia/commons/', }, locale: { user: mw.config.get('wgFormattedNamespaces')[pg.nsUserId], image: mw.config.get('wgFormattedNamespaces')[pg.nsImageId], category: mw.config.get('wgFormattedNamespaces')[pg.nsCategoryId], // shouldn't be used in popup previews, i think months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] } }; // options with default values or backreferences Insta.conf.user.name = Insta.conf.user.name || 'Wikipedian'; Insta.conf.user.signature = '[['+Insta.conf.locale.user+':'+Insta.conf.user.name+'|'+Insta.conf.user.name+']]'; //Insta.conf.paths.images = '//upload.wikimedia.org/wikipedia/' + Insta.conf.wiki.lang + '/'; // define constants Insta.BLOCK_IMAGE = new RegExp('^\\[\\[(?:File|Image|'+Insta.conf.locale.image+ '):.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i'); } Insta.dump = function(from, to) { if (typeof from == 'string') { from = document.getElementById(from); } if (typeof to == 'string') { to = document.getElementById(to); } to.innerHTML = this.convert(from.value); }; Insta.convert = function(wiki) { var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode o = '', // output p = 0, // para flag $r; // result of passing a regexp to $() // some shorthands function remain() { return ll.length; } function sh() { return ll.shift(); } // shift function ps(s) { o += s; } // push // similar to C's printf, uses ? as placeholders, ?? to escape question marks function f() { var i=1, a=arguments, f=a[0], o='', c, p; for (; i<a.length; i++) { if ((p=f.indexOf('?'))+1) { // allow character escaping i -= c = f.charAt(p+1)=='?' ? 1 : 0; o += f.substring(0,p) + (c ? '?' : a[i]); f = f.substr(p+1+c); } else { break; } } return o+f; } function html_entities(s) { return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"); } // Wiki text parsing to html is a nightmare. // The below functions deliberately don't escape the ampersand since this would make it more difficult, // and we don't absolutely need to for how we need it. // This means that any unescaped ampersands in wikitext will remain unescaped and can cause invalid HTML. // Browsers should all be able to handle it though. // We also escape significant wikimarkup characters to prevent further matching on the processed text function htmlescape_text(s) { return s.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/:/g,"&#58;").replace(/\[/g,"&#91;").replace(/]/g,"&#93;"); } function htmlescape_attr(s) { return htmlescape_text(s).replace(/'/g,"&#39;").replace(/"/g,"&quot;"); } // return the first non matching character position between two strings function str_imatch(a, b) { for (var i=0, l=Math.min(a.length, b.length); i<l; i++) { if (a.charAt(i)!=b.charAt(i)) { break; } } return i; } // compare current line against a string or regexp // if passed a string it will compare only the first string.length characters // if passed a regexp the result is stored in $r function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)); } function $$(c) { return ll[0]==c; } // compare current line against a string function _(p) { return ll[0].charAt(p); } // return char at pos p function endl(s) { ps(s); sh(); } function parse_list() { var prev=''; while (remain() && $(/^([*#:;]+)(.*)$/)) { var l_match = $r; sh(); var ipos = str_imatch(prev, l_match[1]); // close uncontinued lists for (var prevPos=prev.length-1; prevPos >= ipos; prevPos--) { var pi = prev.charAt(prevPos); if (pi=='*') { ps('</ul>'); } else if (pi=='#') { ps('</ol>'); } // close a dl only if the new item is not a dl item (:, ; or empty) else if($.inArray(l_match[1].charAt(prevPos), ['','*','#'])) { ps('</dl>'); } } // open new lists for (var matchPos=ipos; matchPos<l_match[1].length; matchPos++) { var li = l_match[1].charAt(matchPos); if (li=='*') { ps('<ul>'); } else if (li=='#') { ps('<ol>'); } // open a new dl only if the prev item is not a dl item (:, ; or empty) else if ($.inArray(prev.charAt(matchPos), ['','*','#'])) { ps('<dl>'); } } switch (l_match[1].charAt(l_match[1].length-1)) { case '*': case '#': ps('<li>' + parse_inline_nowiki(l_match[2])); break; case ';': ps('<dt>'); var dt_match = l_match[2].match(/(.*?)(:.*?)$/); // handle ;dt :dd format if (dt_match) { ps(parse_inline_nowiki(dt_match[1])); ll.unshift(dt_match[2]); } else ps(parse_inline_nowiki(l_match[2])); break; case ':': ps('<dd>' + parse_inline_nowiki(l_match[2])); } prev=l_match[1]; } // close remaining lists for (var i=prev.length-1; i>=0; i--) { ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl'))); } } function parse_table() { endl(f('<table>', $(/^\{\|( .*)$/)? $r[1]: '')); for (;remain();) if ($('|')) switch (_(1)) { case '}': endl('</table>'); return; case '-': endl(f('<tr>', $(/\|-*(.*)/)[1])); break; default: parse_table_data(); } else if ($('!')) { parse_table_data(); } else { sh(); } } function parse_table_data() { var td_line, match_i; // 1: "|+", '|' or '+' // 2: ?? // 3: attributes ?? // TODO: finish commenting this regexp var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/); if (td_match[1] == '|+') ps('<caption'); else ps('<t' + ((td_match[1]=='|')?'d':'h')); if (typeof td_match[3] != 'undefined') { //ps(' ' + td_match[3]) match_i = 4; } else match_i = 2; ps('>'); if (td_match[1] != '|+') { // use || or !! as a cell separator depending on context // NOTE: when split() is passed a regexp make sure to use non-capturing brackets td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/); ps(parse_inline_nowiki(td_line.shift())); while (td_line.length) ll.unshift(td_match[1] + td_line.pop()); } else ps(td_match[match_i]); var tc = 0, td = []; while (remain()) { td.push(sh()); if ($('|')) { if (!tc) break; // we're at the outer-most level (no nested tables), skip to td parse else if (_(1)=='}') tc--; } else if (!tc && $('!')) break; else if ($('{|')) tc++; } if (td.length) ps(Insta.convert(td)); } function parse_pre() { ps('<pre>'); do { endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); } while (remain() && $(' ')); ps('</pre>'); } function parse_block_image() { ps(parse_image(sh())); } function parse_image(str) { //<NOLITE> // get what's in between "[[Image:" and "]]" var tag = str.substring(str.indexOf(':') + 1, str.length - 2); /* eslint-disable no-unused-vars */ var width; var attr = [], filename, caption = ''; var thumb=0, frame=0, center=0; var align=''; /* eslint-enable no-unused-vars */ if (tag.match(/\|/)) { // manage nested links var nesting = 0; var last_attr; for (var i = tag.length-1; i > 0; i--) { if (tag.charAt(i) == '|' && !nesting) { last_attr = tag.substr(i+1); tag = tag.substring(0, i); break; } else switch (tag.substr(i-1, 2)) { case ']]': nesting++; i--; break; case '[[': nesting--; i--; } } attr = tag.split(/\s*\|\s*/); attr.push(last_attr); filename = attr.shift(); var w_match; for (;attr.length; attr.shift()) { w_match = attr[0].match(/^(\d*)(?:[px]*\d*)?px$/); if (w_match) width = w_match[1]; else switch(attr[0]) { case 'thumb': case 'thumbnail': thumb=true; frame=true; break; case 'frame': frame=true; break; case 'none': case 'right': case 'left': center=false; align=attr[0]; break; case 'center': center=true; align='none'; break; default: if (attr.length == 1) caption = attr[0]; } } } else filename = tag; return ''; //</NOLITE> } function parse_inline_nowiki(str) { var start, lastend=0; var substart=0, nestlev=0, open, close, subloop; var html=''; while (-1 != (start = str.indexOf('<nowiki>', substart))) { html += parse_inline_wiki(str.substring(lastend, start)); start += 8; substart = start; subloop = true; do { open = str.indexOf('<nowiki>', substart); close = str.indexOf('</nowiki>', substart); if (close<=open || open==-1) { if (close==-1) { return html + html_entities(str.substr(start)); } substart = close+9; if (nestlev) { nestlev--; } else { lastend = substart; html += html_entities(str.substring(start, lastend-9)); subloop = false; } } else { substart = open+8; nestlev++; } } while (subloop); } return html + parse_inline_wiki(str.substr(lastend)); } function parse_inline_images(str) { //<NOLITE> var start, substart=0, nestlev=0; var loop, close, open, wiki, html; while (-1 != (start=str.indexOf('[[', substart))) { if(str.substr(start+2).match(RegExp('^(Image|File|' + Insta.conf.locale.image + '):','i'))) { loop=true; substart=start; do { substart+=2; close=str.indexOf(']]',substart); open=str.indexOf('[[',substart); if (close<=open||open==-1) { if (close==-1) return str; substart=close; if (nestlev) { nestlev--; } else { wiki=str.substring(start,close+2); html=parse_image(wiki); str=str.replace(wiki,html); substart=start+html.length; loop=false; } } else { substart=open; nestlev++; } } while (loop); } else break; } //</NOLITE> return str; } // the output of this function doesn't respect the FILO structure of HTML // but since most browsers can handle it I'll save myself the hassle function parse_inline_formatting(str) { var em,st,i,li,o=''; while ((i=str.indexOf("''",li))+1) { o += str.substring(li,i); li=i+2; if (str.charAt(i+2)=="'") { li++; st=!st; o+=st?'<strong>':'</strong>'; } else { em=!em; o+=em?'<em>':'</em>'; } } return o+str.substr(li); } function parse_inline_wiki(str) { str = parse_inline_images(str); str = parse_inline_formatting(str); // math str = str.replace(/<(?:)math>(.*?)<\/math>/ig, ''); // Build a Mediawiki-formatted date string var date = new Date(); var minutes = date.getUTCMinutes(); if (minutes < 10) minutes = '0' + minutes; date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), Insta.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear()); // text formatting return str. // signatures replace(/~{5}(?!~)/g, date). replace(/~{4}(?!~)/g, Insta.conf.user.name+' '+date). replace(/~{3}(?!~)/g, Insta.conf.user.name). // [[:Category:...]], [[:Image:...]], etc... replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):[^|]*?)\\]\\](\\w*)','gi'), function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2));}). // remove straight category and interwiki tags replace(RegExp('\\[\\[(?:'+Insta.conf.locale.category+'|'+Insta.conf.wiki.interwiki+'):.*?\\]\\]','gi'),''). // [[:Category:...|Links]], [[:Image:...|Links]], etc... replace(RegExp('\\[\\[:((?:'+Insta.conf.locale.category+'|Image|File|'+Insta.conf.locale.image+'|'+Insta.conf.wiki.interwiki+'):.*?)\\|([^\\]]+?)\\]\\](\\w*)','gi'), function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3));}). // [[/Relative links]] replace(/\[\[(\/[^|]*?)\]\]/g, function($0,$1){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($1)); }). // [[/Replaced|Relative links]] replace(/\[\[(\/.*?)\|(.+?)\]\]/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.baseUrl + htmlescape_attr($1), htmlescape_text($2)); }). // [[Common links]] replace(/\[\[([^[|]*?)\]\](\w*)/g, function($0,$1,$2){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($1) + htmlescape_text($2)); }). // [[Replaced|Links]] replace(/\[\[([^[]*?)\|([^\]]+?)\]\](\w*)/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1), htmlescape_text($2) + htmlescape_text($3)); }). // [[Stripped:Namespace|Namespace]] replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, function($0,$1,$2,$3){return f("<a href='?'>?</a>", Insta.conf.paths.articles + htmlescape_attr($1) + htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($2)); }). // External links replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, function($0,$1,$2,$3,$4){return f("<a class='external' href='?:?'>?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($4)); }). replace(/\[http:\/\/(.*?)\]/g, function($0,$1){return f("<a class='external' href='http://?'>[#]</a>", htmlescape_attr($1)); }). replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, function($0,$1,$2,$3){return f("<a class='external' href='?:?'>?:?</a>", htmlescape_attr($1), htmlescape_attr($2) + htmlescape_attr($3), htmlescape_text($1), htmlescape_text($2) + htmlescape_text($3)); }). replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*[^.,!?;: $])/g, function($0,$1,$2,$3,$4){return f("?<a class='external' href='?:?'>?:?</a>", htmlescape_text($1), htmlescape_attr($2), htmlescape_attr($3) + htmlescape_attr($4), htmlescape_text($2), htmlescape_text($3) + htmlescape_text($4)); }). replace('__NOTOC__',''). replace('__NOEDITSECTION__',''); } // begin parsing for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) { p=0; endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3])); } else if ($(/^[*#:;]/)) { p=0; parse_list(); } else if ($(' ')) { p=0; parse_pre(); } else if ($('{|')) { p=0; parse_table(); } else if ($(/^----+$/)) { p=0; endl('<hr />'); } else if ($(Insta.BLOCK_IMAGE)) { p=0; parse_block_image(); } else { // handle paragraphs if ($$('')) { p = (remain()>1 && ll[1]===('')); if (p) endl('<p><br>'); } else { if(!p) { ps('<p>'); p=1; } ps(parse_inline_nowiki(ll[0]) + ' '); } sh(); } return o; }; function wiki2html(txt,baseurl) { Insta.conf.baseUrl=baseurl; return Insta.convert(txt); } // ENDFILE: livepreview.js // STARTFILE: pageinfo.js //<NOLITE> function popupFilterPageSize(data) { return formatBytes(data.length); } function popupFilterCountLinks(data) { var num=countLinks(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('wikiLinks'):popupString('wikiLink')); } function popupFilterCountImages(data) { var num=countImages(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('images'):popupString('image')); } function popupFilterCountCategories(data) { var num=countCategories(data); return String(num) + '&nbsp;' + ((num!=1)?popupString('categories'):popupString('category')); } function popupFilterLastModified(data,download) { var lastmod=download.lastModified; var now=new Date(); var age=now-lastmod; if (lastmod && getValueOf('popupLastModified')) { return (tprintf('%s old', [formatAge(age)])).replace(RegExp(' ','g'), '&nbsp;'); } return ''; } function formatAge(age) { // coerce into a number var a=0+age, aa=a; var seclen = 1000; var minlen = 60*seclen; var hourlen = 60*minlen; var daylen = 24*hourlen; var weeklen = 7*daylen; var numweeks = (a-a%weeklen)/weeklen; a = a-numweeks*weeklen; var sweeks = addunit(numweeks, 'week'); var numdays = (a-a%daylen)/daylen; a = a-numdays*daylen; var sdays = addunit(numdays, 'day'); var numhours = (a-a%hourlen)/hourlen; a = a-numhours*hourlen; var shours = addunit(numhours,'hour'); var nummins = (a-a%minlen)/minlen; a = a-nummins*minlen; var smins = addunit(nummins, 'minute'); var numsecs = (a-a%seclen)/seclen; a = a-numsecs*seclen; var ssecs = addunit(numsecs, 'second'); if (aa > 4*weeklen) { return sweeks; } if (aa > weeklen) { return sweeks + ' ' + sdays; } if (aa > daylen) { return sdays + ' ' + shours; } if (aa > 6*hourlen) { return shours; } if (aa > hourlen) { return shours + ' ' + smins; } if (aa > 10*minlen) { return smins; } if (aa > minlen) { return smins + ' ' + ssecs; } return ssecs; } function addunit(num,str) { return '' + num + ' ' + ((num!=1) ? popupString(str+'s') : popupString(str)) ;} function runPopupFilters(list, data, download) { var ret=[]; for (var i=0; i<list.length; ++i) { if (list[i] && typeof list[i] == 'function') { var s=list[i](data, download, download.owner.article); if (s) { ret.push(s); } } } return ret; } function getPageInfo(data, download) { if (!data || data.length === 0) { return popupString('Empty page'); } var popupFilters=getValueOf('popupFilters') || []; var extraPopupFilters = getValueOf('extraPopupFilters') || []; var pageInfoArray = runPopupFilters(popupFilters.concat(extraPopupFilters), data, download); var pageInfo=pageInfoArray.join(', '); if (pageInfo !== '' ) { pageInfo = upcaseFirst(pageInfo); } return pageInfo; } // this could be improved! function countLinks(wikiText) { return wikiText.split('[[').length - 1; } // if N = # matches, n = # brackets, then // String.parenSplit(regex) intersperses the N+1 split elements // with Nn other elements. So total length is // L= N+1 + Nn = N(n+1)+1. So N=(L-1)/(n+1). function countImages(wikiText) { return (wikiText.parenSplit(pg.re.image).length - 1) / (pg.re.imageBracketCount + 1); } function countCategories(wikiText) { return (wikiText.parenSplit(pg.re.category).length - 1) / (pg.re.categoryBracketCount + 1); } function popupFilterStubDetect(data, download, article) { var counts=stubCount(data, article); if (counts.real) { return popupString('stub'); } if (counts.sect) { return popupString('section stub'); } return ''; } function popupFilterDisambigDetect(data, download, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return ''; } return (isDisambig(data, article)) ? popupString('disambig') : ''; } function formatBytes(num) { return (num > 949) ? (Math.round(num/100)/10+popupString('kB')) : (num +'&nbsp;' + popupString('bytes')) ; } //</NOLITE> // ENDFILE: pageinfo.js // STARTFILE: titles.js /** @fileoverview Defines the {@link Title} class, and associated crufty functions. <code>Title</code> deals with article titles and their various forms. {@link Stringwrapper} is the parent class of <code>Title</code>, which exists simply to make things a little neater. */ /** Creates a new Stringwrapper. @constructor @class the Stringwrapper class. This base class is not really useful on its own; it just wraps various common string operations. */ function Stringwrapper() { /** Wrapper for this.toString().indexOf() @param {String} x @type integer */ this.indexOf=function(x){return this.toString().indexOf(x);}; /** Returns this.value. @type String */ this.toString=function(){return this.value;}; /** Wrapper for {@link String#parenSplit} applied to this.toString() @param {RegExp} x @type Array */ this.parenSplit=function(x){return this.toString().parenSplit(x);}; /** Wrapper for this.toString().substring() @param {String} x @param {String} y (optional) @type String */ this.substring=function(x,y){ if (typeof y=='undefined') { return this.toString().substring(x); } return this.toString().substring(x,y); }; /** Wrapper for this.toString().split() @param {String} x @type Array */ this.split=function(x){return this.toString().split(x);}; /** Wrapper for this.toString().replace() @param {String} x @param {String} y @type String */ this.replace=function(x,y){ return this.toString().replace(x,y); }; } /** Creates a new <code>Title</code>. @constructor @class The Title class. Holds article titles and converts them into various forms. Also deals with anchors, by which we mean the bits of the article URL after a # character, representing locations within an article. @param {String} value The initial value to assign to the article. This must be the canonical title (see {@link Title#value}. Omit this in the constructor and use another function to set the title if this is unavailable. */ function Title(val) { /** The canonical article title. This must be in UTF-8 with no entities, escaping or nasties. Also, underscores should be replaced with spaces. @type String @private */ this.value=null; /** The canonical form of the anchor. This should be exactly as it appears in the URL, i.e. with the .C3.0A bits in. @type String */ this.anchor=''; this.setUtf(val); } Title.prototype=new Stringwrapper(); /** Returns the canonical representation of the article title, optionally without anchor. @param {boolean} omitAnchor @fixme Decide specs for anchor @return String The article title and the anchor. */ Title.prototype.toString=function(omitAnchor) { return this.value + ( (!omitAnchor && this.anchor) ? '#' + this.anchorString() : '' ); }; Title.prototype.anchorString=function() { if (!this.anchor) { return ''; } var split=this.anchor.parenSplit(/((?:[.][0-9A-F]{2})+)/); var len=split.length; for (var j=1; j<len; j+=2) { // FIXME s/decodeURI/decodeURIComponent/g ? split[j]=decodeURIComponent(split[j].split('.').join('%')).split('_').join(' '); } return split.join(''); }; Title.prototype.urlAnchor=function() { var split=this.anchor.parenSplit('/((?:[%][0-9A-F]{2})+)/'); var len=split.length; for (var j=1; j<len; j+=2) { split[j]=split[j].split('%').join('.'); } return split.join(''); }; Title.prototype.anchorFromUtf=function(str) { this.anchor=encodeURIComponent(str.split(' ').join('_')) .split('%3A').join(':').split("'").join('%27').split('%').join('.'); }; Title.fromURL=function(h) { return new Title().fromURL(h); }; Title.prototype.fromURL=function(h) { if (typeof h != 'string') { this.value=null; return this; } // NOTE : playing with decodeURI, encodeURI, escape, unescape, // we seem to be able to replicate the IE borked encoding // IE doesn't do this new-fangled utf-8 thing. // and it's worse than that. // IE seems to treat the query string differently to the rest of the url // the query is treated as bona-fide utf8, but the first bit of the url is pissed around with // we fix up & for all browsers, just in case. var splitted=h.split('?'); splitted[0]=splitted[0].split('&').join('%26'); h=splitted.join('?'); var contribs=pg.re.contribs.exec(h); if (contribs) { if (contribs[1]=='title=') { contribs[3]=contribs[3].split('+').join(' '); } var u=new Title(contribs[3]); this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + u.stripNamespace())); return this; } var email=pg.re.email.exec(h); if (email) { this.setUtf(this.decodeNasties(mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(email[3]).stripNamespace())); return this; } var backlinks=pg.re.backlinks.exec(h); if (backlinks) { this.setUtf(this.decodeNasties(new Title(backlinks[3]))); return this; } //A dummy title object for a Special:Diff link. var specialdiff=pg.re.specialdiff.exec(h); if (specialdiff) { this.setUtf(this.decodeNasties(new Title(mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Diff'))); return this; } // no more special cases to check -- // hopefully it's not a disguised user-related or specially treated special page var m=pg.re.main.exec(h); if(m === null) { this.value=null; } else { var fromBotInterface = /[?](.+[&])?title=/.test(h); if (fromBotInterface) { m[2]=m[2].split('+').join('_'); } var extracted = m[2] + (m[3] ? '#' + m[3] : ''); if (pg.flag.isSafari && /%25[0-9A-Fa-f]{2}/.test(extracted)) { // Fix Safari issue // Safari sometimes encodes % as %25 in UTF-8 encoded strings like %E5%A3 -> %25E5%25A3. this.setUtf(decodeURIComponent(unescape(extracted))); } else { this.setUtf(this.decodeNasties(extracted)); } } return this; }; Title.prototype.decodeNasties=function(txt) { var ret= this.decodeEscapes(decodeURI(txt)); ret = ret.replace(/[_ ]*$/, ''); return ret; }; Title.prototype.decodeEscapes=function(txt) { var split=txt.parenSplit(/((?:[%][0-9A-Fa-f]{2})+)/); var len=split.length; for (var i=1; i<len; i=i+2) { // FIXME is decodeURIComponent better? split[i]=unescape(split[i]); } return split.join(''); }; Title.fromAnchor=function(a) { return new Title().fromAnchor(a); }; Title.prototype.fromAnchor=function(a) { if (!a) { this.value=null; return this; } return this.fromURL(a.href); }; Title.fromWikiText=function(txt) { return new Title().fromWikiText(txt); }; Title.prototype.fromWikiText=function(txt) { // FIXME - testing needed txt=myDecodeURI(txt); this.setUtf(txt); return this; }; Title.prototype.hintValue=function(){ if(!this.value) { return ''; } return safeDecodeURI(this.value); }; //<NOLITE> Title.prototype.toUserName=function(withNs) { if (this.namespaceId() != pg.nsUserId && this.namespaceId() != pg.nsUsertalkId) { this.value=null; return; } this.value = (withNs ? mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' : '') + this.stripNamespace().split('/')[0]; }; Title.prototype.userName=function(withNs) { var t=(new Title(this.value)); t.toUserName(withNs); if (t.value) { return t; } return null; }; Title.prototype.toTalkPage=function() { // convert article to a talk page, or if we can't, return null // In other words: return null if this ALREADY IS a talk page // and return the corresponding talk page otherwise // // Per https://www.mediawiki.org/wiki/Manual:Namespace#Subject_and_talk_namespaces // * All discussion namespaces have odd-integer indices // * The discussion namespace index for a specific namespace with index n is n + 1 if (this.value === null) { return null; } var namespaceId = this.namespaceId(); if (namespaceId>=0 && namespaceId % 2 === 0) //non-special and subject namespace { var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId+1]; if (typeof localizedNamespace!=='undefined') { if (localizedNamespace === '') { this.value = this.stripNamespace(); } else { this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace(); } return this.value; } } this.value=null; return null; }; //</NOLITE> // Return canonical, localized namespace Title.prototype.namespace=function() { return mw.config.get('wgFormattedNamespaces')[this.namespaceId()]; }; Title.prototype.namespaceId=function() { var n=this.value.indexOf(':'); if (n<0) { return 0; } //mainspace var namespaceId = mw.config.get('wgNamespaceIds')[this.value.substring(0,n).split(' ').join('_').toLowerCase()]; if (typeof namespaceId=='undefined') return 0; //mainspace return namespaceId; }; //<NOLITE> Title.prototype.talkPage=function() { var t=new Title(this.value); t.toTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.isTalkPage=function() { if (this.talkPage()===null) { return true; } return false; }; Title.prototype.toArticleFromTalkPage=function() { //largely copy/paste from toTalkPage above. if (this.value === null) { return null; } var namespaceId = this.namespaceId(); if (namespaceId >= 0 && namespaceId % 2 == 1) //non-special and talk namespace { var localizedNamespace = mw.config.get('wgFormattedNamespaces')[namespaceId-1]; if (typeof localizedNamespace!=='undefined') { if (localizedNamespace === '') { this.value = this.stripNamespace(); } else { this.value = localizedNamespace.split(' ').join('_') + ':' + this.stripNamespace(); } return this.value; } } this.value=null; return null; }; Title.prototype.articleFromTalkPage=function() { var t=new Title(this.value); t.toArticleFromTalkPage(); if (t.value) { return t; } return null; }; Title.prototype.articleFromTalkOrArticle=function() { var t=new Title(this.value); if ( t.toArticleFromTalkPage() ) { return t; } return this; }; Title.prototype.isIpUser=function() { return pg.re.ipUser.test(this.userName()); }; //</NOLITE> Title.prototype.stripNamespace=function(){ // returns a string, not a Title var n=this.value.indexOf(':'); if (n<0) { return this.value; } var namespaceId = this.namespaceId(); if (namespaceId === pg.nsMainspaceId) return this.value; return this.value.substring(n+1); }; Title.prototype.setUtf=function(value){ if (!value) { this.value=''; return; } var anch=value.indexOf('#'); if(anch < 0) { this.value=value.split('_').join(' '); this.anchor=''; return; } this.value=value.substring(0,anch).split('_').join(' '); this.anchor=value.substring(anch+1); this.ns=null; // wait until namespace() is called }; Title.prototype.setUrl=function(urlfrag) { var anch=urlfrag.indexOf('#'); this.value=safeDecodeURI(urlfrag.substring(0,anch)); this.anchor=this.value.substring(anch+1); }; Title.prototype.append=function(x){ this.setUtf(this.value + x); }; Title.prototype.urlString=function(x) { if(!x) { x={}; } var v=this.toString(true); if (!x.omitAnchor && this.anchor) { v+= '#' + this.urlAnchor(); } if (!x.keepSpaces) { v=v.split(' ').join('_'); } return encodeURI(v).split('&').join('%26').split('?').join('%3F').split('+').join('%2B'); }; Title.prototype.removeAnchor=function() { return new Title(this.toString(true)); }; Title.prototype.toUrl=function() { return pg.wiki.titlebase + this.urlString(); }; function parseParams(url) { var specialDiff = pg.re.specialdiff.exec(url); if (specialDiff) { var split= specialDiff[1].split('/'); if (split.length==1) return {oldid:split[0], diff: 'prev'}; else if (split.length==2) return {oldid: split[0], diff: split[1]}; } var ret={}; if (url.indexOf('?')==-1) { return ret; } url = url.split('#')[0]; var s=url.split('?').slice(1).join(); var t=s.split('&'); for (var i=0; i<t.length; ++i) { var z=t[i].split('='); z.push(null); ret[z[0]]=z[1]; } //Diff revision with no oldid is interpreted as a diff to the previous revision by MediaWiki if (ret.diff && typeof(ret.oldid)==='undefined') { ret.oldid = "prev"; } //Documentation seems to say something different, but oldid can also accept prev/next, and Echo is emitting such URLs. Simple fixup during parameter decoding: if (ret.oldid && (ret.oldid==='prev' || ret.oldid==='next' || ret.oldid==='cur')) { var helper = ret.diff; ret.diff = ret.oldid; ret.oldid = helper; } return ret; } // (a) myDecodeURI (first standard decodeURI, then pg.re.urlNoPopup) // (b) change spaces to underscores // (c) encodeURI (just the straight one, no pg.re.urlNoPopup) function myDecodeURI (str) { var ret; // FIXME decodeURIComponent?? try { ret=decodeURI(str.toString()); } catch (summat) { return str; } for (var i=0; i<pg.misc.decodeExtras.length; ++i) { var from=pg.misc.decodeExtras[i].from; var to=pg.misc.decodeExtras[i].to; ret=ret.split(from).join(to); } return ret; } function safeDecodeURI(str) { var ret=myDecodeURI(str); return ret || str; } /////////// // TESTS // /////////// //<NOLITE> function isDisambig(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } return ! article.isTalkPage() && pg.re.disambig.test(data); } function stubCount(data, article) { if (!getValueOf('popupAllDabsStubs') && article.namespace()) { return false; } var sectStub=0; var realStub=0; if (pg.re.stub.test(data)) { var s=data.parenSplit(pg.re.stub); for (var i=1; i<s.length; i=i+2) { if (s[i]) { ++sectStub; } else { ++realStub; } } } return { real: realStub, sect: sectStub }; } function isValidImageName(str){ // extend as needed... return ( str.indexOf('{') == -1 ); } function isInStrippableNamespace(article) { // Does the namespace allow subpages // Note, would be better if we had access to wgNamespacesWithSubpages return ( article.namespaceId() !== 0 ); } function isInMainNamespace(article) { return article.namespaceId() === 0; } function anchorContainsImage(a) { // iterate over children of anchor a // see if any are images if (a === null) { return false; } var kids=a.childNodes; for (var i=0; i<kids.length; ++i) { if (kids[i].nodeName=='IMG') { return true; } } return false; } //</NOLITE> function isPopupLink(a) { // NB for performance reasons, TOC links generally return true // they should be stripped out later if (!markNopopupSpanLinks.done) { markNopopupSpanLinks(); } if (a.inNopopupSpan) { return false; } // FIXME is this faster inline? if (a.onmousedown || a.getAttribute('nopopup')) { return false; } var h=a.href; if (h === document.location.href+'#') { return false; } if (!pg.re.basenames.test(h)) { return false; } if (!pg.re.urlNoPopup.test(h)) { return true; } return ( (pg.re.email.test(h) || pg.re.contribs.test(h) || pg.re.backlinks.test(h) || pg.re.specialdiff.test(h)) && h.indexOf('&limit=') == -1 ); } function markNopopupSpanLinks() { if( !getValueOf('popupOnlyArticleLinks')) fixVectorMenuPopups(); var s = $('.nopopups').toArray(); for (var i=0; i<s.length; ++i) { var as=s[i].getElementsByTagName('a'); for (var j=0; j<as.length; ++j) { as[j].inNopopupSpan=true; } } markNopopupSpanLinks.done=true; } function fixVectorMenuPopups() { $('div.vectorMenu h3:first a:first').prop('inNopopupSpan', true); } // ENDFILE: titles.js // STARTFILE: getpage.js ////////////////////////////////////////////////// // Wiki-specific downloading // // Schematic for a getWiki call // // getPageWithCaching // | // false | true // getPage<-[findPictureInCache]->-onComplete(a fake download) // \. // (async)->addPageToCache(download)->-onComplete(download) // check cache to see if page exists function getPageWithCaching(url, onComplete, owner) { log('getPageWithCaching, url='+url); var i=findInPageCache(url); var d; if (i > -1) { d=fakeDownload(url, owner.idNumber, onComplete, pg.cache.pages[i].data, pg.cache.pages[i].lastModified, owner); } else { d=getPage(url, onComplete, owner); if (d && owner && owner.addDownload) { owner.addDownload(d); d.owner=owner; } } } function getPage(url, onComplete, owner) { log('getPage'); var callback= function (d) { if (!d.aborted) {addPageToCache(d); onComplete(d);} }; return startDownload(url, owner.idNumber, callback); } function findInPageCache(url) { for (var i=0; i<pg.cache.pages.length; ++i) { if (url==pg.cache.pages[i].url) { return i; } } return -1; } function addPageToCache(download) { log('addPageToCache '+download.url); var page = {url: download.url, data: download.data, lastModified: download.lastModified}; return pg.cache.pages.push(page); } // ENDFILE: getpage.js // STARTFILE: parensplit.js ////////////////////////////////////////////////// // parenSplit // String.prototype.parenSplit should do what ECMAscript says String.prototype.split does, // interspersing paren matches (regex capturing groups) between the split elements. // i.e. 'abc'.split(/(b)/)) should return ['a','b','c'], not ['a','c'] if (String('abc'.split(/(b)/))!='a,b,c') { // broken String.split, e.g. konq, IE < 10 String.prototype.parenSplit=function (re) { re=nonGlobalRegex(re); var s=this; var m=re.exec(s); var ret=[]; while (m && s) { // without the following loop, we have // 'ab'.parenSplit(/a|(b)/) != 'ab'.split(/a|(b)/) for(var i=0; i<m.length; ++i) { if (typeof m[i]=='undefined') m[i]=''; } ret.push(s.substring(0,m.index)); ret = ret.concat(m.slice(1)); s=s.substring(m.index + m[0].length); m=re.exec(s); } ret.push(s); return ret; }; } else { String.prototype.parenSplit=function (re) { return this.split(re); }; String.prototype.parenSplit.isNative=true; } function nonGlobalRegex(re) { var s=re.toString(); var flags=''; for (var j=s.length; s.charAt(j) != '/'; --j) { if (s.charAt(j) != 'g') { flags += s.charAt(j); } } var t=s.substring(1,j); return RegExp(t,flags); } // ENDFILE: parensplit.js // STARTFILE: tools.js // IE madness with encoding // ======================== // // suppose throughout that the page is in utf8, like wikipedia // // if a is an anchor DOM element and a.href should consist of // // http://host.name.here/wiki/foo?bar=baz // // then IE gives foo as "latin1-encoded" utf8; we have foo = decode_utf8(decodeURI(foo_ie)) // but IE gives bar=baz correctly as plain utf8 // // --------------------------------- // // IE's xmlhttp doesn't understand utf8 urls. Have to use encodeURI here. // // --------------------------------- // // summat else // Source: http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/utf8.htm //<NOLITE> function getJsObj(json) { try { var json_ret = JSON.parse(json); if( json_ret.warnings ) { for( var w=0; w < json_ret.warnings.length; w++ ) { if( json_ret.warnings[w]['*'] ) { log( json_ret.warnings[w]['*'] ); } else { log( json_ret.warnings[w]['warnings'] ); } } } else if ( json_ret.error ) { errlog( json_ret.error.code + ': ' + json_ret.error.info ); } return json_ret; } catch (someError) { errlog('Something went wrong with getJsObj, json='+json); return 1; } } function anyChild(obj) { for (var p in obj) { return obj[p]; } return null; } //</NOLITE> function upcaseFirst(str) { if (typeof str != typeof '' || str === '') return ''; return str.charAt(0).toUpperCase() + str.substring(1); } function findInArray(arr, foo) { if (!arr || !arr.length) { return -1; } var len=arr.length; for (var i=0; i<len; ++i) { if (arr[i]==foo) { return i; } } return -1; } /* eslint-disable no-unused-vars */ function nextOne (array, value) { // NB if the array has two consecutive entries equal // then this will loop on successive calls var i=findInArray(array, value); if (i<0) { return null; } return array[i+1]; } /* eslint-enable no-unused-vars */ function literalizeRegex(str){ return mw.util.escapeRegExp(str); } String.prototype.entify=function() { //var shy='&shy;'; return this.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;'/*+shy*/).split('"').join('&quot;'); }; // Array filter function function removeNulls(val) { return val !== null; } function joinPath(list) { return list.filter(removeNulls).join('/'); } function simplePrintf(str, subs) { if (!str || !subs) { return str; } var ret=[]; var s=str.parenSplit(/(%s|\$[0-9]+)/); var i=0; do { ret.push(s.shift()); if ( !s.length ) { break; } var cmd=s.shift(); if (cmd == '%s') { if ( i < subs.length ) { ret.push(subs[i]); } else { ret.push(cmd); } ++i; } else { var j=parseInt( cmd.replace('$', ''), 10 ) - 1; if ( j > -1 && j < subs.length ) { ret.push(subs[j]); } else { ret.push(cmd); } } } while (s.length > 0); return ret.join(''); } /* eslint-disable no-unused-vars */ function isString(x) { return (typeof x === 'string' || x instanceof String); } function isNumber(x) { return (typeof x === 'number' || x instanceof Number); } function isRegExp(x) { return x instanceof RegExp; } function isArray (x) { return x instanceof Array; } function isObject(x) { return x instanceof Object; } function isFunction(x) { return !isRegExp(x) && (typeof x === 'function' || x instanceof Function); } /* eslint-enable no-unused-vars */ function repeatString(s,mult) { var ret=''; for (var i=0; i<mult; ++i) { ret += s; } return ret; } function zeroFill(s, min) { min = min || 2; var t=s.toString(); return repeatString('0', min - t.length) + t; } function map(f, o) { if (isArray(o)) { return map_array(f,o); } return map_object(f,o); } function map_array(f,o) { var ret=[]; for (var i=0; i<o.length; ++i) { ret.push(f(o[i])); } return ret; } function map_object(f,o) { var ret={}; for (var i in o) { ret[o]=f(o[i]); } return ret; } pg.escapeQuotesHTML = function ( text ) { return text .replace(/&/g, "&amp;") .replace(/"/g, "&quot;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;"); }; // ENDFILE: tools.js // STARTFILE: dab.js //<NOLITE> ////////////////////////////////////////////////// // Dab-fixing code // function retargetDab(newTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) { log('retargetDab: newTarget='+newTarget + ' oldTarget=' + oldTarget); return changeLinkTargetLink( {newTarget: newTarget, text: newTarget.split(' ').join('&nbsp;'), hint: tprintf('disambigHint', [newTarget]), summary: simplePrintf( getValueOf('popupFixDabsSummary'), [friendlyCurrentArticleName, newTarget ]), clickButton: getValueOf('popupDabsAutoClick'), minor: true, oldTarget: oldTarget, watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit}); } function listLinks(wikitext, oldTarget, titleToEdit) { // mediawiki strips trailing spaces, so we do the same // testcase: https://en.wikipedia.org/w/index.php?title=Radial&oldid=97365633 var reg=RegExp('\\[\\[([^|]*?) *(\\||\\]\\])', 'gi'); var ret=[]; var splitted=wikitext.parenSplit(reg); // ^[a-z]+ should match interwiki links, hopefully (case-insensitive) // and ^[a-z]* should match those and [[:Category...]] style links too var omitRegex=RegExp('^[a-z]*:|^[Ss]pecial:|^[Ii]mage|^[Cc]ategory'); var friendlyCurrentArticleName= oldTarget.toString(); var wikPos = getValueOf('popupDabWiktionary'); for (var i=1; i<splitted.length; i=i+3) { if (typeof splitted[i] == typeof 'string' && splitted[i].length>0 && !omitRegex.test(splitted[i])) { ret.push( retargetDab(splitted[i], oldTarget, friendlyCurrentArticleName, titleToEdit) ); } /* if */ } /* for loop */ ret = rmDupesFromSortedList(ret.sort()); if (wikPos) { var wikTarget='wiktionary:' + friendlyCurrentArticleName.replace( RegExp('^(.+)\\s+[(][^)]+[)]\\s*$'), '$1' ); var meth; if (wikPos.toLowerCase() == 'first') { meth = 'unshift'; } else { meth = 'push'; } ret[meth]( retargetDab(wikTarget, oldTarget, friendlyCurrentArticleName, titleToEdit) ); } ret.push(changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join('&nbsp;'), hint: popupString("remove all links to this disambig page from this article"), clickButton: getValueOf('popupDabsAutoClick'), oldTarget: oldTarget, summary: simplePrintf(getValueOf('popupRmDabLinkSummary'), [friendlyCurrentArticleName]), watch: getValueOf('popupWatchDisambiggedPages'), title: titleToEdit })); return ret; } function rmDupesFromSortedList(list) { var ret=[]; for (var i=0; i<list.length; ++i) { if (ret.length === 0 || list[i]!=ret[ret.length-1]) { ret.push(list[i]); } } return ret; } function makeFixDab(data, navpop) { // grab title from parent popup if there is one; default exists in changeLinkTargetLink var titleToEdit=(navpop.parentPopup && navpop.parentPopup.article.toString()); var list=listLinks(data, navpop.originalArticle, titleToEdit); if (list.length === 0) { log('listLinks returned empty list'); return null; } var html='<hr />' + popupString('Click to disambiguate this link to:') + '<br>'; html+=list.join(', '); return html; } function makeFixDabs(wikiText, navpop) { if (getValueOf('popupFixDabs') && isDisambig(wikiText, navpop.article) && Title.fromURL(location.href).namespaceId() != pg.nsSpecialId && navpop.article.talkPage() ) { setPopupHTML(makeFixDab(wikiText, navpop), 'popupFixDab', navpop.idNumber); } } function popupRedlinkHTML(article) { return changeLinkTargetLink( { newTarget: null, text: popupString('remove this link').split(' ').join('&nbsp;'), hint: popupString("remove all links to this page from this article"), clickButton: getValueOf('popupRedlinkAutoClick'), oldTarget: article.toString(), summary: simplePrintf(getValueOf('popupRedlinkSummary'), [article.toString()])}); } //</NOLITE> // ENDFILE: dab.js // STARTFILE: htmloutput.js // this has to use a timer loop as we don't know if the DOM element exists when we want to set the text function setPopupHTML (str, elementId, popupId, onSuccess, append) { if (typeof popupId === 'undefined') { //console.error('popupId is not defined in setPopupHTML, html='+str.substring(0,100)); popupId = pg.idNumber; } var popupElement=document.getElementById(elementId+popupId); if (popupElement) { if (!append) { popupElement.innerHTML=''; } if (isString(str)) { popupElement.innerHTML+=str; } else { popupElement.appendChild(str); } if (onSuccess) { onSuccess(); } setTimeout(checkPopupPosition, 100); return true; } else { // call this function again in a little while... setTimeout(function(){ setPopupHTML(str,elementId,popupId,onSuccess); }, 600); } return null; } //<NOLITE> function setPopupTrailer(str,id) {return setPopupHTML(str, 'popupData', id);} //</NOLITE> // args.navpopup is mandatory // optional: args.redir, args.redirTarget // FIXME: ye gods, this is ugly stuff function fillEmptySpans(args) { // if redir is present and true then redirTarget is mandatory var redir=true; var rcid; if (typeof args != 'object' || typeof args.redir == 'undefined' || !args.redir) { redir=false; } var a=args.navpopup.parentAnchor; var article, hint=null, oldid=null, params={}; if (redir && typeof args.redirTarget == typeof {}) { article=args.redirTarget; //hint=article.hintValue(); } else { article=(new Title()).fromAnchor(a); hint=a.originalTitle || article.hintValue(); params=parseParams(a.href); oldid=(getValueOf('popupHistoricalLinks')) ? params.oldid : null; rcid=params.rcid; } var x={ article:article, hint: hint, oldid: oldid, rcid: rcid, navpop:args.navpopup, params:params }; var structure=pg.structures[getValueOf('popupStructure')]; if (typeof structure != 'object') { setPopupHTML('popupError', 'Unknown structure (this should never happen): '+ pg.option.popupStructure, args.navpopup.idNumber); return; } var spans=flatten(pg.misc.layout); var numspans = spans.length; var redirs=pg.misc.redirSpans; for (var i=0; i<numspans; ++i) { var found = redirs && (redirs.indexOf( spans[i] ) !== -1); //log('redir='+redir+', found='+found+', spans[i]='+spans[i]); if ( (found && !redir) || (!found && redir) ) { //log('skipping this set of the loop'); continue; } var structurefn=structure[spans[i]]; var setfn = setPopupHTML; if (getValueOf('popupActiveNavlinks') && (spans[i].indexOf('popupTopLinks')===0 || spans[i].indexOf('popupRedirTopLinks')===0) ) { setfn = setPopupTipsAndHTML; } switch (typeof structurefn) { case 'function': log('running '+spans[i]+'({article:'+x.article+', hint:'+x.hint+', oldid: '+x.oldid+'})'); setfn(structurefn(x), spans[i], args.navpopup.idNumber); break; case 'string': setfn(structurefn, spans[i], args.navpopup.idNumber); break; default: errlog('unknown thing with label '+spans[i] + ' (span index was ' + i + ')'); break; } } } // flatten an array function flatten(list, start) { var ret=[]; if (typeof start == 'undefined') { start=0; } for (var i=start; i<list.length; ++i) { if (typeof list[i] == typeof []) { return ret.concat(flatten(list[i])).concat(flatten(list, i+1)); } else { ret.push(list[i]); } } return ret; } // Generate html for whole popup function popupHTML (a) { getValueOf('popupStructure'); var structure=pg.structures[pg.option.popupStructure]; if (typeof structure != 'object') { //return 'Unknown structure: '+pg.option.popupStructure; // override user choice pg.option.popupStructure=pg.optionDefault.popupStructure; return popupHTML(a); } if (typeof structure.popupLayout != 'function') { return 'Bad layout'; } pg.misc.layout=structure.popupLayout(); if (typeof structure.popupRedirSpans === 'function') { pg.misc.redirSpans=structure.popupRedirSpans(); } else { pg.misc.redirSpans=[]; } return makeEmptySpans(pg.misc.layout, a.navpopup); } function makeEmptySpans (list, navpop) { var ret=''; for (var i=0; i<list.length; ++i) { if (typeof list[i] == typeof '') { ret += emptySpanHTML(list[i], navpop.idNumber, 'div'); } else if (typeof list[i] == typeof [] && list[i].length > 0 ) { ret = ret.parenSplit(RegExp('(</[^>]*?>$)')).join(makeEmptySpans(list[i], navpop)); } else if (typeof list[i] == typeof {} && list[i].nodeType ) { ret += emptySpanHTML(list[i].name, navpop.idNumber, list[i].nodeType); } } return ret; } function emptySpanHTML(name, id, tag, classname) { tag = tag || 'span'; if (!classname) { classname = emptySpanHTML.classAliases[name]; } classname = classname || name; if (name == getValueOf('popupDragHandle')) { classname += ' popupDragHandle'; } return simplePrintf('<%s id="%s" class="%s"></%s>', [tag, name + id, classname, tag]); } emptySpanHTML.classAliases={ 'popupSecondPreview': 'popupPreview' }; // generate html for popup image // <a id="popupImageLinkn"><img id="popupImagen"> // where n=idNumber function imageHTML(article, idNumber) { return simplePrintf('<a id="popupImageLink$1">' + '<img align="right" valign="top" id="popupImg$1" style="display: none;"></img>' + '</a>', [ idNumber ]); } function popTipsSoonFn(id, when, popData) { if (!when) { when=250; } var popTips=function(){ setupTooltips(document.getElementById(id), false, true, popData); }; return function() { setTimeout( popTips, when, popData ); }; } function setPopupTipsAndHTML(html, divname, idnumber, popData) { setPopupHTML(html, divname, idnumber, getValueOf('popupSubpopups') ? popTipsSoonFn(divname + idnumber, null, popData) : null); } // ENDFILE: htmloutput.js // STARTFILE: mouseout.js ////////////////////////////////////////////////// // fuzzy checks function fuzzyCursorOffMenus(x,y, fuzz, parent) { if (!parent) { return null; } var uls=parent.getElementsByTagName('ul'); for (var i=0; i<uls.length; ++i) { if (uls[i].className=='popup_menu') { if (uls[i].offsetWidth > 0) return false; } // else {document.title+='.';} } return true; } function checkPopupPosition () { // stop the popup running off the right of the screen // FIXME avoid pg.current.link if (pg.current.link && pg.current.link.navpopup) pg.current.link.navpopup.limitHorizontalPosition(); } function mouseOutWikiLink () { //console ('mouseOutWikiLink'); var a=this; removeModifierKeyHandler(a); if (a.navpopup === null || typeof a.navpopup === 'undefined') return; if ( ! a.navpopup.isVisible() ) { a.navpopup.banish(); return; } restoreTitle(a); Navpopup.tracker.addHook(posCheckerHook(a.navpopup)); } function posCheckerHook(navpop) { return function() { if (!navpop.isVisible()) { return true; /* remove this hook */ } if (Navpopup.tracker.dirty) { return false; } var x=Navpopup.tracker.x, y=Navpopup.tracker.y; var mouseOverNavpop = navpop.isWithin(x,y,navpop.fuzz, navpop.mainDiv) || !fuzzyCursorOffMenus(x,y,navpop.fuzz, navpop.mainDiv); // FIXME it'd be prettier to do this internal to the Navpopup objects var t=getValueOf('popupHideDelay'); if (t) { t = t * 1000; } if (!t) { if(!mouseOverNavpop) { if(navpop.parentAnchor) { restoreTitle( navpop.parentAnchor ); } navpop.banish(); return true; /* remove this hook */ } return false; } // we have a hide delay set var d=+(new Date()); if ( !navpop.mouseLeavingTime ) { navpop.mouseLeavingTime = d; return false; } if ( mouseOverNavpop ) { navpop.mouseLeavingTime=null; return false; } if (d - navpop.mouseLeavingTime > t) { navpop.mouseLeavingTime=null; navpop.banish(); return true; /* remove this hook */ } return false; }; } function runStopPopupTimer(navpop) { // at this point, we should have left the link but remain within the popup // so we call this function again until we leave the popup. if (!navpop.stopPopupTimer) { navpop.stopPopupTimer=setInterval(posCheckerHook(navpop), 500); navpop.addHook(function(){clearInterval(navpop.stopPopupTimer);}, 'hide', 'before'); } } // ENDFILE: mouseout.js // STARTFILE: previewmaker.js /** @fileoverview Defines the {@link Previewmaker} object, which generates short previews from wiki markup. */ /** Creates a new Previewmaker @constructor @class The Previewmaker class. Use an instance of this to generate short previews from Wikitext. @param {String} wikiText The Wikitext source of the page we wish to preview. @param {String} baseUrl The url we should prepend when creating relative urls. @param {Navpopup} owner The navpop associated to this preview generator */ function Previewmaker(wikiText, baseUrl, owner) { /** The wikitext which is manipulated to generate the preview. */ this.originalData=wikiText; this.baseUrl=baseUrl; this.owner=owner; this.maxCharacters=getValueOf('popupMaxPreviewCharacters'); this.maxSentences=getValueOf('popupMaxPreviewSentences'); this.setData(); } Previewmaker.prototype.setData=function() { var maxSize=Math.max(10000, 2*this.maxCharacters); this.data=this.originalData.substring(0,maxSize); }; /** Remove HTML comments @private */ Previewmaker.prototype.killComments = function () { // this also kills one trailing newline, eg [[diamyo]] this.data=this.data.replace(RegExp('^<!--[^$]*?-->\\n|\\n<!--[^$]*?-->(?=\\n)|<!--[^$]*?-->', 'g'), ''); }; /** @private */ Previewmaker.prototype.killDivs = function () { // say goodbye, divs (can be nested, so use * not *?) this.data=this.data.replace(RegExp('< *div[^>]* *>[\\s\\S]*?< */ *div *>', 'gi'), ''); }; /** @private */ Previewmaker.prototype.killGalleries = function () { this.data=this.data.replace(RegExp('< *gallery[^>]* *>[\\s\\S]*?< */ *gallery *>', 'gi'), ''); }; /** @private */ Previewmaker.prototype.kill = function(opening, closing, subopening, subclosing, repl) { var oldk=this.data; var k=this.killStuff(this.data, opening, closing, subopening, subclosing, repl); while (k.length < oldk.length) { oldk=k; k=this.killStuff(k, opening, closing, subopening, subclosing, repl); } this.data=k; }; /** @private */ Previewmaker.prototype.killStuff = function (txt, opening, closing, subopening, subclosing, repl) { var op=this.makeRegexp(opening); var cl=this.makeRegexp(closing, '^'); var sb=subopening ? this.makeRegexp(subopening, '^') : null; var sc=subclosing ? this.makeRegexp(subclosing, '^') : cl; if (!op || !cl) { alert('Navigation Popups error: op or cl is null! something is wrong.'); return; } if (!op.test(txt)) { return txt; } var ret=''; var opResult = op.exec(txt); ret = txt.substring(0,opResult.index); txt=txt.substring(opResult.index+opResult[0].length); var depth = 1; while (txt.length > 0) { var removal=0; if (depth==1 && cl.test(txt)) { depth--; removal=cl.exec(txt)[0].length; } else if (depth > 1 && sc.test(txt)) { depth--; removal=sc.exec(txt)[0].length; }else if (sb && sb.test(txt)) { depth++; removal=sb.exec(txt)[0].length; } if ( !removal ) { removal = 1; } txt=txt.substring(removal); if (depth === 0) { break; } } return ret + (repl || '') + txt; }; /** @private */ Previewmaker.prototype.makeRegexp = function (x, prefix, suffix) { prefix = prefix || ''; suffix = suffix || ''; var reStr=''; var flags=''; if (isString(x)) { reStr=prefix + literalizeRegex(x) + suffix; } else if (isRegExp(x)) { var s=x.toString().substring(1); var sp=s.split('/'); flags=sp[sp.length-1]; sp[sp.length-1]=''; s=sp.join('/'); s=s.substring(0,s.length-1); reStr= prefix + s + suffix; } else { log ('makeRegexp failed'); } log ('makeRegexp: got reStr=' + reStr + ', flags=' + flags); return RegExp(reStr, flags); }; /** @private */ Previewmaker.prototype.killBoxTemplates = function () { // taxobox removal... in fact, there's a saudiprincebox_begin, so let's be more general // also, have float_begin, ... float_end this.kill(RegExp('[{][{][^{}\\s|]*?(float|box)[_ ](begin|start)', 'i'), /[}][}]\s*/, '{{'); // infoboxes etc // from [[User:Zyxw/popups.js]]: kill frames too this.kill(RegExp('[{][{][^{}\\s|]*?(infobox|elementbox|frame)[_ ]', 'i'), /[}][}]\s*/, '{{'); }; /** @private */ Previewmaker.prototype.killTemplates = function () { // the plus sign is to avoid transcluding [[Template:', ']] this.kill('{'+'{', '}'+'}', '{', '}', ' '); }; /** @private */ Previewmaker.prototype.killTables = function () { // tables are bad, too // this can be slow, but it's an inprovement over a browser hang // torture test: [[Comparison_of_Intel_Central_Processing_Units]] this.kill('{|', /[|]}\s*/, '{|'); this.kill(/<table.*?>/i, /<\/table.*?>/i, /<table.*?>/i); // remove lines starting with a pipe for the hell of it (?) this.data=this.data.replace(RegExp('^[|].*$', 'mg'), ''); }; /** @private */ Previewmaker.prototype.killImages = function () { var forbiddenNamespaceAliases = []; jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) { if (_namespaceId!=pg.nsImageId && _namespaceId!=pg.nsCategoryId) return; forbiddenNamespaceAliases.push(_localizedNamespaceLc.split(' ').join('[ _]')); //todo: escape regexp fragments! }); // images and categories are a nono this.kill(RegExp('[[][[]\\s*(' + forbiddenNamespaceAliases.join('|') + ')\\s*:', 'i'), /\]\]\s*/, '[', ']'); }; /** @private */ Previewmaker.prototype.killHTML = function () { // kill <ref ...>...</ref> this.kill(/<ref\b[^/>]*?>/i, /<\/ref>/i); // let's also delete entire lines starting with <. it's worth a try. this.data=this.data.replace(RegExp('(^|\\n) *<.*', 'g'), '\n'); // and those pesky html tags, but not <nowiki> or <blockquote> var splitted=this.data.parenSplit(/(<[\w\W]*?(?:>|$|(?=<)))/); var len=splitted.length; for (var i=1; i<len; i=i+2) { switch (splitted[i]) { case '<nowiki>': case '</nowiki>': case '<blockquote>': case '</blockquote>': break; default: splitted[i]=''; } } this.data=splitted.join(''); }; /** @private */ Previewmaker.prototype.killChunks = function() { // heuristics alert // chunks of italic text? you crazy, man? var italicChunkRegex=new RegExp ("((^|\\n)\\s*:*\\s*''[^']([^']|'''|'[^']){20}(.|\\n[^\\n])*''[.!?\\s]*\\n)+", 'g'); // keep stuff separated, though, so stick in \n (fixes [[Union Jack]]? this.data=this.data.replace(italicChunkRegex, '\n'); }; /** @private */ Previewmaker.prototype.mopup = function () { // we simply *can't* be doing with horizontal rules right now this.data=this.data.replace(RegExp('^-{4,}','mg'),''); // no indented lines this.data=this.data.replace(RegExp('(^|\\n) *:[^\\n]*','g'), ''); // replace __TOC__, __NOTOC__ and whatever else there is // this'll probably do this.data=this.data.replace(RegExp('^__[A-Z_]*__ *$', 'gmi'),''); }; /** @private */ Previewmaker.prototype.firstBit = function () { // dont't be givin' me no subsequent paragraphs, you hear me? /// first we "normalize" section headings, removing whitespace after, adding before var d=this.data; if (getValueOf('popupPreviewCutHeadings')) { this.data=this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); /// then we want to get rid of paragraph breaks whose text ends badly this.data=this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); this.data=this.data.replace(RegExp('^[\\s\\n]*'), ''); var stuff=(RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); if (stuff) { d = stuff[0]; } if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } /// now put \n\n after sections so that bullets and numbered lists work d=d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); } // Split sentences. Superfluous sentences are RIGHT OUT. // note: exactly 1 set of parens here needed to make the slice work d = d.parenSplit(RegExp('([!?.]+["'+"'"+']*\\s)','g')); // leading space is bad, mmkay? d[0]=d[0].replace(RegExp('^\\s*'), ''); var notSentenceEnds=RegExp('([^.][a-z][.] *[a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|op|cit|\\[[^\\]]*|\\s[A-Zvclm])$', 'i'); d = this.fixSentenceEnds(d, notSentenceEnds); this.fullLength=d.join('').length; var n=this.maxSentences; var dd=this.firstSentences(d,n); do { dd=this.firstSentences(d,n); --n; } while ( dd.length > this.maxCharacters && n !== 0 ); this.data = dd; }; /** @private */ Previewmaker.prototype.fixSentenceEnds = function(strs, reg) { // take an array of strings, strs // join strs[i] to strs[i+1] & strs[i+2] if strs[i] matches regex reg for (var i=0; i<strs.length-2; ++i) { if (reg.test(strs[i])) { var a=[]; for (var j=0; j<strs.length; ++j) { if (j<i) a[j]=strs[j]; if (j==i) a[i]=strs[i]+strs[i+1]+strs[i+2]; if (j>i+2) a[j-2]=strs[j]; } return this.fixSentenceEnds(a,reg); } } return strs; }; /** @private */ Previewmaker.prototype.firstSentences = function(strs, howmany) { var t=strs.slice(0, 2*howmany); return t.join(''); }; /** @private */ Previewmaker.prototype.killBadWhitespace = function() { // also cleans up isolated '''', eg [[Suntory Sungoliath]] this.data=this.data.replace(RegExp('^ *\'+ *$', 'gm'), ''); }; /** Runs the various methods to generate the preview. The preview is stored in the <code>html</html> field. @private */ Previewmaker.prototype.makePreview = function() { if (this.owner.article.namespaceId()!=pg.nsTemplateId && this.owner.article.namespaceId()!=pg.nsImageId ) { this.killComments(); this.killDivs(); this.killGalleries(); this.killBoxTemplates(); if (getValueOf('popupPreviewKillTemplates')) { this.killTemplates(); } else { this.killMultilineTemplates(); } this.killTables(); this.killImages(); this.killHTML(); this.killChunks(); this.mopup(); this.firstBit(); this.killBadWhitespace(); } else { this.killHTML(); } this.html=wiki2html(this.data, this.baseUrl); // needs livepreview this.fixHTML(); this.stripLongTemplates(); }; /** @private */ Previewmaker.prototype.esWiki2HtmlPart = function(data) { var reLinks = /(?:\[\[([^|\]]*)(?:\|([^|\]]*))*]]([a-z]*))/gi; //match a wikilink reLinks.lastIndex = 0; //reset regex var match; var result = ""; var postfixIndex = 0; while ((match = reLinks.exec(data))) //match all wikilinks { //FIXME: the way that link is built here isn't perfect. It is clickable, but popups preview won't recognize it in some cases. result += pg.escapeQuotesHTML(data.substring(postfixIndex, match.index)) + '<a href="'+Insta.conf.paths.articles+pg.escapeQuotesHTML(match[1])+'">'+pg.escapeQuotesHTML((match[2]?match[2]:match[1])+match[3])+"</a>"; postfixIndex = reLinks.lastIndex; } //append the rest result += pg.escapeQuotesHTML(data.substring(postfixIndex)); return result; }; Previewmaker.prototype.editSummaryPreview=function() { var reAes = /\/\* *(.*?) *\*\//g; //match the first section marker reAes.lastIndex = 0; //reset regex var match; match = reAes.exec(this.data); if (match) { //we have a section link. Split it, process it, combine it. var prefix = this.data.substring(0,match.index-1); var section = match[1]; var postfix = this.data.substring(reAes.lastIndex); var start = "<span class='autocomment'>"; var end = "</span>"; if (prefix.length>0) start = this.esWiki2HtmlPart(prefix) + " " + start + "- "; if (postfix.length>0) end = ": " + end + this.esWiki2HtmlPart(postfix); var t=new Title().fromURL(this.baseUrl); t.anchorFromUtf(section); var sectionLink = Insta.conf.paths.articles + pg.escapeQuotesHTML(t.toString(true)) + '#' + pg.escapeQuotesHTML(t.anchor); return start + '<a href="'+sectionLink+'">&rarr;</a> '+pg.escapeQuotesHTML(section) + end; } //else there's no section link, htmlify the whole thing. return this.esWiki2HtmlPart(this.data); }; //<NOLITE> /** Test function for debugging preview problems one step at a time. */ /*eslint-disable */ function previewSteps(txt) { try { txt=txt || document.editform.wpTextbox1.value; } catch (err) { if (pg.cache.pages.length > 0) { txt=pg.cache.pages[pg.cache.pages.length-1].data; } else { alert('provide text or use an edit page'); } } txt=txt.substring(0,10000); var base=pg.wiki.articlebase + Title.fromURL(document.location.href).urlString(); var p=new Previewmaker(txt, base, pg.current.link.navpopup); if (this.owner.article.namespaceId() != pg.nsTemplateId) { p.killComments(); if (!confirm('done killComments(). Continue?\n---\n' + p.data)) { return; } p.killDivs(); if (!confirm('done killDivs(). Continue?\n---\n' + p.data)) { return; } p.killGalleries(); if (!confirm('done killGalleries(). Continue?\n---\n' + p.data)) { return; } p.killBoxTemplates(); if (!confirm('done killBoxTemplates(). Continue?\n---\n' + p.data)) { return; } if (getValueOf('popupPreviewKillTemplates')) { p.killTemplates(); if (!confirm('done killTemplates(). Continue?\n---\n' + p.data)) { return; } } else { p.killMultilineTemplates(); if (!confirm('done killMultilineTemplates(). Continue?\n---\n' + p.data)) { return; } } p.killTables(); if (!confirm('done killTables(). Continue?\n---\n' + p.data)) { return; } p.killImages(); if (!confirm('done killImages(). Continue?\n---\n' + p.data)) { return; } p.killHTML(); if (!confirm('done killHTML(). Continue?\n---\n' + p.data)) { return; } p.killChunks(); if (!confirm('done killChunks(). Continue?\n---\n' + p.data)) { return; } p.mopup(); if (!confirm('done mopup(). Continue?\n---\n' + p.data)) { return; } p.firstBit(); if (!confirm('done firstBit(). Continue?\n---\n' + p.data)) { return; } p.killBadWhitespace(); if (!confirm('done killBadWhitespace(). Continue?\n---\n' + p.data)) { return; } } p.html=wiki2html(p.data, base); // needs livepreview p.fixHTML(); if (!confirm('done fixHTML(). Continue?\n---\n' + p.html)) { return; } p.stripLongTemplates(); if (!confirm('done stripLongTemplates(). Continue?\n---\n' + p.html)) { return; } alert('finished preview - end result follows.\n---\n' + p.html); } /*eslint-enable */ //</NOLITE> /** Works around livepreview bugs. @private */ Previewmaker.prototype.fixHTML = function() { if(!this.html) return; var ret = this.html; // fix question marks in wiki links // maybe this'll break some stuff :-( ret=ret.replace(RegExp('(<a href="' + pg.wiki.articlePath + '/[^"]*)[?](.*?")', 'g'), '$1%3F$2'); ret=ret.replace(RegExp('(<a href=\'' + pg.wiki.articlePath + '/[^\']*)[?](.*?\')', 'g'), '$1%3F$2'); // FIXME fix up % too this.html=ret; }; /** Generates the preview and displays it in the current popup. Does nothing if the generated preview is invalid or consists of whitespace only. Also activates wikilinks in the preview for subpopups if the popupSubpopups option is true. */ Previewmaker.prototype.showPreview = function () { this.makePreview(); if (typeof this.html != typeof '') return; if (RegExp('^\\s*$').test(this.html)) return; setPopupHTML('<hr />', 'popupPrePreviewSep', this.owner.idNumber); setPopupTipsAndHTML(this.html, 'popupPreview', this.owner.idNumber, { owner: this.owner }); var more = (this.fullLength > this.data.length) ? this.moreLink() : ''; setPopupHTML(more, 'popupPreviewMore', this.owner.idNumber); }; /** @private */ Previewmaker.prototype.moreLink=function() { var a=document.createElement('a'); a.className='popupMoreLink'; a.innerHTML=popupString('more...'); var savedThis=this; a.onclick=function() { savedThis.maxCharacters+=2000; savedThis.maxSentences+=20; savedThis.setData(); savedThis.showPreview(); }; return a; }; /** @private */ Previewmaker.prototype.stripLongTemplates = function() { // operates on the HTML! this.html=this.html.replace(RegExp('^.{0,1000}[{][{][^}]*?(<(p|br)( /)?>\\s*){2,}([^{}]*?[}][}])?', 'gi'), ''); this.html=this.html.split('\n').join(' '); // workaround for <pre> templates this.html=this.html.replace(RegExp('[{][{][^}]*<pre>[^}]*[}][}]','gi'), ''); }; /** @private */ Previewmaker.prototype.killMultilineTemplates = function() { this.kill('{{{', '}}}'); this.kill(RegExp('\\s*[{][{][^{}]*\\n'), '}}', '{{'); }; // ENDFILE: previewmaker.js // STARTFILE: querypreview.js function loadAPIPreview(queryType, article, navpop) { var art=new Title(article).urlString(); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&'; var htmlGenerator=function(/*a, d*/){alert('invalid html generator');}; var usernameart = ''; switch (queryType) { case 'history': url += 'titles=' + art + '&prop=revisions&rvlimit=' + getValueOf('popupHistoryPreviewLimit'); htmlGenerator=APIhistoryPreviewHTML; break; case 'category': url += 'list=categorymembers&cmtitle=' + art; htmlGenerator=APIcategoryPreviewHTML; break; case 'userinfo': var username = new Title( article ).userName(); usernameart = encodeURIComponent( username ); if (pg.re.ipUser.test(username)) { url += 'list=blocks&bkprop=range|restrictions&bkip=' + usernameart; } else { url += 'list=users|usercontribs&usprop=blockinfo|groups|editcount|registration|gender&ususers=' + usernameart + "&meta=globaluserinfo&guiprop=groups|unattached&guiuser="+ usernameart + "&uclimit=1&ucprop=timestamp&ucuser=" + usernameart; } htmlGenerator=APIuserInfoPreviewHTML; break; case 'contribs': usernameart = encodeURIComponent( new Title( article ).userName() ); url += 'list=usercontribs&ucuser=' + usernameart + '&uclimit=' + getValueOf('popupContribsPreviewLimit'); htmlGenerator=APIcontribsPreviewHTML; break; case 'imagepagepreview': var trail=''; if (getValueOf('popupImageLinks')) { trail = '&list=imageusage&iutitle=' + art; } url += 'titles=' + art + '&prop=revisions|imageinfo&rvprop=content' + trail; htmlGenerator=APIimagepagePreviewHTML; break; case 'backlinks': url += 'list=backlinks&bltitle=' + art; htmlGenerator=APIbacklinksPreviewHTML; break; case 'revision': if (article.oldid) { url += 'revids=' + article.oldid; } else { url += 'titles=' + article.removeAnchor().urlString(); } url += '&prop=revisions|pageprops|info|images|categories&rvprop=ids|timestamp|flags|comment|user|content&cllimit=max&imlimit=max'; htmlGenerator=APIrevisionPreviewHTML; break; } pendingNavpopTask(navpop); var callback=function(d){ log( "callback of API functions was hit" ); showAPIPreview(queryType, htmlGenerator(article,d,navpop), navpop.idNumber, navpop, d); }; var go = function(){ getPageWithCaching(url, callback, navpop); return true; }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_'+queryType+'_QUERY_DATA'); } } function linkList(list) { list.sort(function(x,y) { return (x==y ? 0 : (x<y ? -1 : 1)); }); var buf=[]; for (var i=0; i<list.length; ++i) { buf.push(wikiLink({article: new Title(list[i]), text: list[i].split(' ').join('&nbsp;'), action: 'view'})); } return buf.join(', '); } function getTimeOffset() { var tz = mw.user.options.get('timecorrection'); if(tz) { if( tz.indexOf('|') > -1 ) { // New format return parseInt(tz.split('|')[1],10); } else if ( tz.indexOf(':') > -1 ) { // Old format return( parseInt(tz,10)*60 + parseInt(tz.split(':')[1],10) ); } } return 0; } /* * Creates a HTML table that's shown in the history and user-contribs popups. * @param {Object[]} h - a list of revisions, returned from the API * @param {boolean} reallyContribs - true only if we're displaying user contributions */ function editPreviewTable(article, h, reallyContribs, timeOffset) { var html=['<table>']; var day=null; var curart=article; var page=null; var makeFirstColumnLinks; if(reallyContribs) { // We're showing user contributions, so make (diff | hist) links makeFirstColumnLinks = function(currentRevision) { var result = '('; result += '<a href="' + pg.wiki.titlebase + new Title(currentRevision.title).urlString() + '&diff=prev' + '&oldid=' + currentRevision.revid + '">' + popupString('diff') + '</a>'; result += '&nbsp;|&nbsp;'; result += '<a href="' + pg.wiki.titlebase + new Title(currentRevision.title).urlString() + '&action=history">' + popupString('hist') + '</a>'; result += ')'; return result; }; } else { // It's a regular history page, so make (cur | last) links var firstRevid = h[0].revid; makeFirstColumnLinks = function(currentRevision) { var result = '('; result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&diff=' + firstRevid + '&oldid=' + currentRevision.revid + '">' + popupString('cur') + '</a>'; result += '&nbsp;|&nbsp;'; result += '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&diff=prev&oldid=' + currentRevision.revid + '">' + popupString('last') + '</a>'; result += ')'; return result; }; } for (var i=0; i<h.length; ++i) { if (reallyContribs) { page = h[i].title; curart = new Title(page); } var minor = h[i].minor ? '<b>m </b>' : ''; var editDate = adjustDate(getDateFromTimestamp(h[i].timestamp), timeOffset); var thisDay = dayFormat(editDate); var thisTime = timeFormat(editDate); if (thisDay == day) { thisDay = ''; } else { day = thisDay; } if (thisDay) { html.push( '<tr><td colspan=3><span class="popup_history_date">' + thisDay+'</span></td></tr>' ); } html.push('<tr class="popup_history_row_' + ( (i%2) ? 'odd' : 'even') + '">'); html.push('<td>' + makeFirstColumnLinks(h[i]) + '</td>'); html.push('<td>' + '<a href="' + pg.wiki.titlebase + new Title(curart).urlString() + '&oldid=' + h[i].revid + '">' + thisTime + '</a></td>'); var col3url='', col3txt=''; if (!reallyContribs) { var user=h[i].user; if( !h[i].userhidden ) { if( pg.re.ipUser.test(user) ) { col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId] + ':Contributions&target=' + new Title(user).urlString(); } else { col3url=pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsUserId] + ':' + new Title(user).urlString(); } col3txt=pg.escapeQuotesHTML(user); } else { col3url=getValueOf('popupRevDelUrl'); col3txt=pg.escapeQuotesHTML( popupString('revdel')); } } else { col3url=pg.wiki.titlebase + curart.urlString(); col3txt=pg.escapeQuotesHTML(page); } html.push('<td>' + (reallyContribs ? minor : '') + '<a href="' + col3url + '">' + col3txt + '</a></td>'); var comment=''; var c=h[i].comment || h[i].content; if (c) { comment=new Previewmaker(c, new Title(curart).toUrl()).editSummaryPreview(); } else if ( h[i].commenthidden ) { comment=popupString('revdel'); } html.push('<td>' + (!reallyContribs ? minor : '') + comment + '</td>'); html.push('</tr>'); html=[html.join('')]; } html.push('</table>'); return html.join(''); } function getDateFromTimestamp(t) { var s=t.split(/[^0-9]/); switch(s.length) { case 0: return null; case 1: return new Date(s[0]); case 2: return new Date(s[0], s[1]-1); case 3: return new Date(s[0], s[1]-1, s[2]); case 4: return new Date(s[0], s[1]-1, s[2], s[3]); case 5: return new Date(s[0], s[1]-1, s[2], s[3], s[4]); case 6: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5]); default: return new Date(s[0], s[1]-1, s[2], s[3], s[4], s[5], s[6]); } } function adjustDate(d, offset) { // offset is in minutes var o=offset * 60 * 1000; return new Date( +d + o); } function dayFormat(editDate, utc) { if (utc) { return map(zeroFill, [editDate.getUTCFullYear(), editDate.getUTCMonth()+1, editDate.getUTCDate()]).join('-'); } return map(zeroFill, [editDate.getFullYear(), editDate.getMonth()+1, editDate.getDate()]).join('-'); } function timeFormat(editDate, utc) { if (utc) { return map(zeroFill, [editDate.getUTCHours(), editDate.getUTCMinutes(), editDate.getUTCSeconds()]).join(':'); } return map(zeroFill, [editDate.getHours(), editDate.getMinutes(), editDate.getSeconds()]).join(':'); } function showAPIPreview(queryType, html, id, navpop, download) { // DJ: done var target='popupPreview'; completedNavpopTask(navpop); switch (queryType) { case 'imagelinks': case 'category': target='popupPostPreview'; break; case 'userinfo': target='popupUserData'; break; case 'revision': insertPreview(download); return; } setPopupTipsAndHTML(html, target, id); } function APIrevisionPreviewHTML(article, download) { try{ var jsObj=getJsObj(download.data); var page=anyChild(jsObj.query.pages); if( page.missing ) { // TODO we need to fix this proper later on download.owner = null; return; } var content = ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; if( typeof content === 'string' ) { download.data = content; download.lastModified = new Date(page.revisions[0].timestamp); } } catch(someError) { return 'Revision preview failed :('; } } function APIbacklinksPreviewHTML(article, download/*, navpop*/ ) { try { var jsObj=getJsObj(download.data); var list=jsObj.query.backlinks; var html=[]; if (!list) { return popupString('No backlinks found'); } for ( var i=0; i < list.length; i++ ) { var t=new Title(list[i].title); html.push('<a href="' + pg.wiki.titlebase + t.urlString() + '">' + t + '</a>'); } html=html.join(', '); if (jsObj['continue'] && jsObj['continue'].blcontinue) { html += popupString(' and more'); } return html; } catch (someError) { return 'backlinksPreviewHTML went wonky'; } } pg.fn.APIsharedImagePagePreviewHTML = function APIsharedImagePagePreviewHTML(obj) { log( "APIsharedImagePagePreviewHTML" ); var popupid = obj.requestid; if( obj.query && obj.query.pages ) { var page=anyChild(obj.query.pages ); var content = ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; if( typeof content === 'string' ) { /* Not entirely safe, but the best we can do */ var p=new Previewmaker(content, pg.current.link.navpopup.article, pg.current.link.navpopup); p.makePreview(); setPopupHTML( p.html, "popupSecondPreview", popupid ); } } }; function APIimagepagePreviewHTML(article, download, navpop) { try { var jsObj=getJsObj(download.data); var page=anyChild(jsObj.query.pages); var content= ( page && page.revisions && page.revisions[0].contentmodel === 'wikitext' ) ? page.revisions[0].content : null; var ret=''; var alt=''; try{alt=navpop.parentAnchor.childNodes[0].alt;} catch(e){} if (alt) { ret = ret + '<hr /><b>' + popupString('Alt text:') + '</b> ' + pg.escapeQuotesHTML(alt); } if (typeof content === 'string') { var p=prepPreviewmaker(content, article, navpop); p.makePreview(); if (p.html) { ret += '<hr />' + p.html; } if (getValueOf('popupSummaryData')) { var info=getPageInfo(content, download); log(info); setPopupTrailer(info, navpop.idNumber); } } if (page && page.imagerepository == "shared" ) { var art=new Title(article); var encart = encodeURIComponent( "File:" + art.stripNamespace() ); var shared_url = pg.wiki.apicommonsbase + '?format=json&formatversion=2' + '&callback=pg.fn.APIsharedImagePagePreviewHTML' + '&requestid=' + navpop.idNumber + '&action=query&prop=revisions&rvprop=content&titles=' + encart; ret = ret +'<hr />' + popupString( 'Image from Commons') + ': <a href="' + pg.wiki.commonsbase + '?title=' + encart + '">' + popupString( 'Description page') + '</a>'; mw.loader.load( shared_url ); } showAPIPreview('imagelinks', APIimagelinksPreviewHTML(article,download), navpop.idNumber, download); return ret; } catch (someError) { return 'API imagepage preview failed :('; } } function APIimagelinksPreviewHTML(article, download) { try { var jsobj=getJsObj(download.data); var list=jsobj.query.imageusage; if (list) { var ret=[]; for (var i=0; i < list.length; i++) { ret.push(list[i].title); } if (ret.length === 0) { return popupString('No image links found'); } return '<h2>' + popupString('File links') + '</h2>' + linkList(ret); } else { return popupString('No image links found'); } } catch(someError) { return 'Image links preview generation failed :('; } } function APIcategoryPreviewHTML(article, download) { try{ var jsobj=getJsObj(download.data); var list=jsobj.query.categorymembers; var ret=[]; for (var p=0; p < list.length; p++) { ret.push(list[p].title); } if (ret.length === 0) { return popupString('Empty category'); } ret = '<h2>' + tprintf('Category members (%s shown)', [ret.length]) + '</h2>' +linkList(ret); if (jsobj['continue'] && jsobj['continue'].cmcontinue) { ret += popupString(' and more'); } return ret; } catch(someError) { return 'Category preview failed :('; } } function APIuserInfoPreviewHTML(article, download) { var ret=[]; var queryobj = {}; try{ queryobj=getJsObj(download.data).query; } catch(someError) { return 'Userinfo preview failed :('; } var user=anyChild(queryobj.users); if (user) { var globaluserinfo=queryobj.globaluserinfo; if (user.invalid === '') { ret.push( popupString( 'Invalid user') ); } else if (user.missing === '') { ret.push( popupString( 'Not a registered username') ); } if( user.blockedby ) { if( user.blockpartial ) { ret.push('<b>' + popupString('Has blocks') + '</b>'); } else { ret.push('<b>' + popupString('BLOCKED') + '</b>'); } } if( globaluserinfo && ( 'locked' in globaluserinfo || 'hidden' in globaluserinfo ) ) { var lockedSulAccountIsAttachedToThis = true; for( var i=0; globaluserinfo.unattached && i < globaluserinfo.unattached.length; i++) { if ( globaluserinfo.unattached[i].wiki === mw.config.get('wgDBname') ) { lockedSulAccountIsAttachedToThis=false; break; } } if (lockedSulAccountIsAttachedToThis) { if ( 'locked' in globaluserinfo ) ret.push('<b><i>' + popupString('LOCKED') + '</i></b>'); if ( 'hidden' in globaluserinfo ) ret.push('<b><i>' + popupString('HIDDEN') + '</i></b>'); } } if( getValueOf('popupShowGender') && user.gender ) { switch( user.gender ) { case "male": ret.push( popupString( "\u2642" ) ); break; case "female": ret.push( popupString( "\u2640" ) ); break; } } if( user.groups ) { for( var j=0; j < user.groups.length; j++) { var currentGroup = user.groups[j]; if( ["*", "user", "autoconfirmed", "extendedconfirmed"].indexOf( currentGroup ) === -1 ) { ret.push( pg.escapeQuotesHTML(user.groups[j]) ); } } } if( globaluserinfo && globaluserinfo.groups ) { for( var k=0; k < globaluserinfo.groups.length; k++) { ret.push( '<i>'+pg.escapeQuotesHTML(globaluserinfo.groups[k])+'</i>' ); } } if( user.registration ) ret.push( pg.escapeQuotesHTML((user.editcount?user.editcount:'0') + popupString(' edits since: ') + (user.registration?dayFormat(getDateFromTimestamp(user.registration)):'')) ); } if (queryobj.usercontribs && queryobj.usercontribs.length) { ret.push( popupString('last edit on ') + dayFormat(getDateFromTimestamp(queryobj.usercontribs[0].timestamp)) ); } if (queryobj.blocks) { ret.push( popupString( 'IP user') ); //we only request list=blocks for IPs for (var l=0; l<queryobj.blocks.length; l++) { console.log(queryobj); var rbstr = queryobj.blocks[l].rangestart === queryobj.blocks[l].rangeend ? 'BLOCK' : 'RANGEBLOCK'; rbstr = (!Array.isArray(queryobj.blocks[l].restrictions) ? 'Has ' + rbstr.toLowerCase() + 's' : rbstr + 'ED'); ret.push('<b>' + popupString(rbstr) + '</b>' ); } } ret = '<hr />' + ret.join( ', ' ); return ret; } function APIcontribsPreviewHTML(article, download, navpop) { return APIhistoryPreviewHTML(article, download, navpop, true); } function APIhistoryPreviewHTML(article, download, navpop, reallyContribs) { try { var jsobj=getJsObj(download.data); var edits = []; if( reallyContribs ) { edits=jsobj.query.usercontribs; } else { edits=anyChild(jsobj.query.pages).revisions; } var ret=editPreviewTable(article, edits, reallyContribs, getTimeOffset()); return ret; } catch (someError) { return 'History preview failed :-('; } } //</NOLITE> // ENDFILE: querypreview.js // STARTFILE: debug.js //////////////////////////////////////////////////////////////////// // Debugging functions //////////////////////////////////////////////////////////////////// function setupDebugging() { //<NOLITE> if (window.popupDebug) { // popupDebug is set from .version window.log=function(x) { //if(gMsg!='')gMsg += '\n'; gMsg+=time() + ' ' + x; }; window.console.log(x); }; window.errlog=function(x) { window.console.error(x); }; log('Initializing logger'); } else { //</NOLITE> window.log = function() {}; window.errlog = function() {}; //<NOLITE> } //</NOLITE> } // ENDFILE: debug.js // STARTFILE: images.js // load image of type Title. function loadImage(image, navpop) { if (typeof image.stripNamespace != 'function') { alert('loadImages bad'); } // API call to retrieve image info. if ( !getValueOf('popupImages') ) return; if ( !isValidImageName(image) ) return false; var art=image.urlString(); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query'; url += '&prop=imageinfo&iiprop=url|mime&iiurlwidth=' + getValueOf('popupImageSizeLarge'); url += '&titles=' + art; pendingNavpopTask(navpop); var callback=function(d){ popupsInsertImage(navpop.idNumber, navpop, d); }; var go = function(){ getPageWithCaching(url, callback, navpop); return true; }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'after', 'DOWNLOAD_IMAGE_QUERY_DATA'); } } function popupsInsertImage(id, navpop, download) { log( "popupsInsertImage"); var imageinfo; try { var jsObj=getJsObj(download.data); var imagepage=anyChild(jsObj.query.pages); if (typeof imagepage.imageinfo === 'undefined') return; imageinfo = imagepage.imageinfo[0]; } catch (someError) { log( "popupsInsertImage failed :(" ); return; } var popupImage = document.getElementById("popupImg"+id); if (!popupImage) { log( "could not find insertion point for image"); return; } popupImage.width=getValueOf('popupImageSize'); popupImage.style.display='inline'; // Set the source for the image. if( imageinfo.thumburl ) popupImage.src=imageinfo.thumburl; else if( imageinfo.mime.indexOf("image") === 0 ){ popupImage.src=imageinfo.url; log( "a thumb could not be found, using original image" ); } else log( "fullsize imagethumb, but not sure if it's an image"); var a=document.getElementById("popupImageLink"+id); if (a === null) { return null; } // Determine the action of the surrouding imagelink. switch (getValueOf('popupThumbAction')) { case 'imagepage': if (pg.current.article.namespaceId()!=pg.nsImageId) { a.href=imageinfo.descriptionurl; // FIXME: unreliable pg.idNumber popTipsSoonFn('popupImage' + id)(); break; } /* falls through */ case 'sizetoggle': a.onclick=toggleSize; a.title=popupString('Toggle image size'); return; case 'linkfull': a.href = imageinfo.url; a.title=popupString('Open full-size image'); return; } } // Toggles the image between inline small and navpop fullwidth. // It's the same image, no actual sizechange occurs, only display width. function toggleSize() { var imgContainer=this; if (!imgContainer) { alert('imgContainer is null :/'); return; } var img=imgContainer.firstChild; if (!img) { alert('img is null :/'); return; } if (!img.style.width || img.style.width==='') { img.style.width='100%'; } else { img.style.width=''; } } // Returns one title of an image from wikiText. function getValidImageFromWikiText(wikiText) { // nb in pg.re.image we're interested in the second bracketed expression // this may change if the regex changes :-( //var match=pg.re.image.exec(wikiText); var matched=null; var match; // strip html comments, used by evil bots :-( var t = removeMatchesUnless(wikiText, RegExp('(<!--[\\s\\S]*?-->)'), 1, RegExp('^<!--[^[]*popup', 'i')); while ( ( match = pg.re.image.exec(t) ) ) { // now find a sane image name - exclude templates by seeking { var m = match[2] || match[6]; if ( isValidImageName(m) ) { matched=m; break; } } pg.re.image.lastIndex=0; if (!matched) { return null; } return mw.config.get('wgFormattedNamespaces')[pg.nsImageId]+':'+upcaseFirst(matched); } function removeMatchesUnless(str, re1, parencount, re2) { var split=str.parenSplit(re1); var c=parencount + 1; for (var i=0; i<split.length; ++i) { if ( i%c === 0 || re2.test(split[i]) ) { continue; } split[i]=''; } return split.join(''); } //</NOLITE> // ENDFILE: images.js // STARTFILE: namespaces.js // Set up namespaces and other non-strings.js localization // (currently that means redirs too) function setNamespaces() { pg.nsSpecialId = -1; pg.nsMainspaceId = 0; pg.nsImageId = 6; pg.nsUserId = 2; pg.nsUsertalkId = 3; pg.nsCategoryId = 14; pg.nsTemplateId = 10; } function setRedirs() { var r='redirect'; var R='REDIRECT'; var redirLists={ //<NOLITE> 'ar': [ R, 'تحويل' ], 'be': [ r, 'перанакіраваньне' ], 'bg': [ r, 'пренасочване', 'виж' ], 'bs': [ r, 'Preusmjeri', 'preusmjeri', 'PREUSMJERI' ], 'cs': [ R, 'PŘESMĚRUJ' ], 'cy': [ r, 'ail-cyfeirio' ], 'de': [ R, 'WEITERLEITUNG' ], 'el': [ R, 'ΑΝΑΚΑΤΕΥΘΥΝΣΗ'], 'eo': [ R, 'ALIDIREKTU', 'ALIDIREKTI' ], 'es': [ R, 'REDIRECCIÓN' ], 'et': [ r, 'suuna' ], 'ga': [ r, 'athsheoladh' ], 'gl': [ r, 'REDIRECCIÓN', 'REDIRECIONAMENTO'], 'he': [ R, 'הפניה' ], 'hu': [ R, 'ÁTIRÁNYÍTÁS' ], 'is': [ r, 'tilvísun', 'TILVÍSUN' ], 'it': [ R, 'RINVIA', 'Rinvia'], 'ja': [ R, '転送' ], 'mk': [ r, 'пренасочување', 'види' ], 'nds': [ r, 'wiederleiden' ], 'nl': [ R, 'DOORVERWIJZING' ], 'nn': [ r, 'omdiriger' ], 'pl': [ R, 'PATRZ', 'PRZEKIERUJ', 'TAM' ], 'pt': [ R, 'redir' ], 'ru': [ R, 'ПЕРЕНАПРАВЛЕНИЕ', 'ПЕРЕНАПР' ], 'sk': [ r, 'presmeruj' ], 'sr': [ r, 'Преусмери', 'преусмери', 'ПРЕУСМЕРИ', 'Preusmeri', 'preusmeri', 'PREUSMERI' ], 'tt': [ R, 'yünältü', 'перенаправление', 'перенапр' ], 'uk': [ R, 'ПЕРЕНАПРАВЛЕННЯ', 'ПЕРЕНАПР' ], 'vi': [ r, 'đổi' ], 'zh': [ R, '重定向'] // no comma //</NOLITE> }; var redirList=redirLists[ pg.wiki.lang ] || [r, R]; // Mediawiki is very tolerant about what comes after the #redirect at the start pg.re.redirect=RegExp('^\\s*[#](' + redirList.join('|') + ').*?\\[{2}([^\\|\\]]*)(|[^\\]]*)?\\]{2}\\s*(.*)', 'i'); } function setInterwiki() { if (pg.wiki.wikimedia) { // From https://meta.wikimedia.org/wiki/List_of_Wikipedias pg.wiki.interwiki='aa|ab|ace|af|ak|als|am|an|ang|ar|arc|arz|as|ast|av|ay|az|ba|bar|bat-smg|bcl|be|be-x-old|bg|bh|bi|bjn|bm|bn|bo|bpy|br|bs|bug|bxr|ca|cbk-zam|cdo|ce|ceb|ch|cho|chr|chy|ckb|co|cr|crh|cs|csb|cu|cv|cy|da|de|diq|dsb|dv|dz|ee|el|eml|en|eo|es|et|eu|ext|fa|ff|fi|fiu-vro|fj|fo|fr|frp|frr|fur|fy|ga|gag|gan|gd|gl|glk|gn|got|gu|gv|ha|hak|haw|he|hi|hif|ho|hr|hsb|ht|hu|hy|hz|ia|id|ie|ig|ii|ik|ilo|io|is|it|iu|ja|jbo|jv|ka|kaa|kab|kbd|kg|ki|kj|kk|kl|km|kn|ko|koi|kr|krc|ks|ksh|ku|kv|kw|ky|la|lad|lb|lbe|lg|li|lij|lmo|ln|lo|lt|ltg|lv|map-bms|mdf|mg|mh|mhr|mi|mk|ml|mn|mo|mr|mrj|ms|mt|mus|mwl|my|myv|mzn|na|nah|nap|nds|nds-nl|ne|new|ng|nl|nn|no|nov|nrm|nv|ny|oc|om|or|os|pa|pag|pam|pap|pcd|pdc|pfl|pi|pih|pl|pms|pnb|pnt|ps|pt|qu|rm|rmy|rn|ro|roa-rup|roa-tara|ru|rue|rw|sa|sah|sc|scn|sco|sd|se|sg|sh|si|simple|sk|sl|sm|sn|so|sq|sr|srn|ss|st|stq|su|sv|sw|szl|ta|te|tet|tg|th|ti|tk|tl|tn|to|tpi|tr|ts|tt|tum|tw|ty|udm|ug|uk|ur|uz|ve|vec|vi|vls|vo|wa|war|wo|wuu|xal|xh|yi|yo|za|zea|zh|zh-classical|zh-min-nan|zh-yue|zu'; pg.re.interwiki=RegExp('^'+pg.wiki.interwiki+':'); } else { pg.wiki.interwiki=null; pg.re.interwiki=RegExp('^$'); } } // return a regexp pattern matching all variants to write the given namespace function nsRe(namespaceId) { var imageNamespaceVariants = []; jQuery.each(mw.config.get('wgNamespaceIds'), function(_localizedNamespaceLc, _namespaceId) { if (_namespaceId!=namespaceId) return; _localizedNamespaceLc = upcaseFirst(_localizedNamespaceLc); imageNamespaceVariants.push(mw.util.escapeRegExp(_localizedNamespaceLc).split(' ').join('[ _]')); imageNamespaceVariants.push(mw.util.escapeRegExp(encodeURI(_localizedNamespaceLc))); }); return '(?:' + imageNamespaceVariants.join('|') + ')'; } function nsReImage() { return nsRe(pg.nsImageId); } // ENDFILE: namespaces.js // STARTFILE: selpop.js //<NOLITE> function getEditboxSelection() { // see http://www.webgurusforum.com/8/12/0 var editbox; try { editbox=document.editform.wpTextbox1; } catch (dang) { return; } // IE, Opera if (document.selection) { return document.selection.createRange().text; } // Mozilla var selStart = editbox.selectionStart; var selEnd = editbox.selectionEnd; return (editbox.value).substring(selStart, selEnd); } function doSelectionPopup() { // popup if the selection looks like [[foo|anything afterwards at all // or [[foo|bar]]text without ']]' // or [[foo|bar]] var sel=getEditboxSelection(); var open=sel.indexOf('[['); var pipe=sel.indexOf('|'); var close=sel.indexOf(']]'); if (open == -1 || ( pipe == -1 && close == -1) ) { return; } if (pipe != -1 && open > pipe || close != -1 && open > close) { return; } if (getValueOf('popupOnEditSelection')=='boxpreview') { return doSeparateSelectionPopup(sel); } var article=new Title(sel.substring(open+2, (pipe < 0) ? close : pipe)).urlString(); if (close > 0 && sel.substring(close+2).indexOf('[[') >= 0) { return; } var a=document.createElement('a'); a.href=pg.wiki.titlebase + article; mouseOverWikiLink2(a); if (a.navpopup) { a.navpopup.addHook(function(){runStopPopupTimer(a.navpopup);}, 'unhide', 'after'); } } function doSeparateSelectionPopup(str) { var div=document.getElementById('selectionPreview'); if (!div) { div = document.createElement('div'); div.id='selectionPreview'; try { var box=document.editform.wpTextbox1; box.parentNode.insertBefore(div, box); } catch (error) { return; } } div.innerHTML=wiki2html(str); div.ranSetupTooltipsAlready = false; popTipsSoonFn('selectionPreview')(); } //</NOLITE> // ENDFILE: selpop.js // STARTFILE: navpopup.js /** @fileoverview Defines two classes: {@link Navpopup} and {@link Mousetracker}. <code>Navpopup</code> describes popups: when they appear, where, what they look like and so on. <code>Mousetracker</code> "captures" the mouse using <code>document.onmousemove</code>. */ /** Creates a new Mousetracker. @constructor @class The Mousetracker class. This monitors mouse movements and manages associated hooks. */ function Mousetracker() { /** Interval to regularly run the hooks anyway, in milliseconds. @type Integer */ this.loopDelay=400; /** Timer for the loop. @type Timer */ this.timer=null; /** Flag - are we switched on? @type Boolean */ this.active=false; /** Flag - are we probably inaccurate, i.e. not reflecting the actual mouse position? */ this.dirty=true; /** Array of hook functions. @private @type Array */ this.hooks=[]; } /** Adds a hook, to be called when we get events. @param {Function} f A function which is called as <code>f(x,y)</code>. It should return <code>true</code> when it wants to be removed, and <code>false</code> otherwise. */ Mousetracker.prototype.addHook = function (f) { this.hooks.push(f); }; /** Runs hooks, passing them the x and y coords of the mouse. Hook functions that return true are passed to {@link Mousetracker#removeHooks} for removal. @private */ Mousetracker.prototype.runHooks = function () { if (!this.hooks || !this.hooks.length) { return; } //log('Mousetracker.runHooks; we got some hooks to run'); var remove=false; var removeObj={}; // this method gets called a LOT - // pre-cache some variables var x=this.x, y=this.y, len = this.hooks.length; for (var i=0; i<len; ++i) { //~ run the hook function, and remove it if it returns true if (this.hooks[i](x, y)===true) { remove=true; removeObj[i]=true; } } if (remove) { this.removeHooks(removeObj); } }; /** Removes hooks. @private @param {Object} removeObj An object whose keys are the index numbers of functions for removal, with values that evaluate to true */ Mousetracker.prototype.removeHooks = function(removeObj) { var newHooks=[]; var len = this.hooks.length; for (var i=0; i<len; ++i) { if (! removeObj[i]) { newHooks.push(this.hooks[i]); } } this.hooks=newHooks; }; /** Event handler for mouse wiggles. We simply grab the event, set x and y and run the hooks. This makes the cpu all hot and bothered :-( @private @param {Event} e Mousemove event */ Mousetracker.prototype.track=function (e) { //~ Apparently this is needed in IE. e = e || window.event; var x, y; if (e) { if (e.pageX) { x=e.pageX; y=e.pageY; } else if (typeof e.clientX!='undefined') { var left, top, docElt = document.documentElement; if (docElt) { left=docElt.scrollLeft; } left = left || document.body.scrollLeft || document.scrollLeft || 0; if (docElt) { top=docElt.scrollTop; } top = top || document.body.scrollTop || document.scrollTop || 0; x=e.clientX + left; y=e.clientY + top; } else { return; } this.setPosition(x,y); } }; /** Sets the x and y coordinates stored and takes appropriate action, running hooks as appropriate. @param {Integer} x, y Screen coordinates to set */ Mousetracker.prototype.setPosition=function(x,y) { this.x = x; this.y = y; if (this.dirty || this.hooks.length === 0) { this.dirty=false; return; } if (typeof this.lastHook_x != 'number') { this.lastHook_x = -100; this.lastHook_y=-100; } var diff = (this.lastHook_x - x)*(this.lastHook_y - y); diff = (diff >= 0) ? diff : -diff; if ( diff > 1 ) { this.lastHook_x=x; this.lastHook_y=y; if (this.dirty) { this.dirty = false; } else { this.runHooks(); } } }; /** Sets things in motion, unless they are already that is, registering an event handler on <code>document.onmousemove</code>. A half-hearted attempt is made to preserve the old event handler if there is one. */ Mousetracker.prototype.enable = function () { if (this.active) { return; } this.active=true; //~ Save the current handler for mousemove events. This isn't too //~ robust, of course. this.savedHandler=document.onmousemove; //~ Gotta save @tt{this} again for the closure, and use apply for //~ the member function. var savedThis=this; document.onmousemove=function (e) {savedThis.track.apply(savedThis, [e]);}; if (this.loopDelay) { this.timer = setInterval(function() { //log('loop delay in mousetracker is working'); savedThis.runHooks();}, this.loopDelay); } }; /** Disables the tracker, removing the event handler. */ Mousetracker.prototype.disable = function () { if (!this.active) { return; } if (typeof this.savedHandler === 'function') { document.onmousemove=this.savedHandler; } else { delete document.onmousemove; } if (this.timer) { clearInterval(this.timer); } this.active=false; }; /** Creates a new Navpopup. Gets a UID for the popup and @param init Contructor object. If <code>init.draggable</code> is true or absent, the popup becomes draggable. @constructor @class The Navpopup class. This generates popup hints, and does some management of them. */ function Navpopup(/*init*/) { //alert('new Navpopup(init)'); /** UID for each Navpopup instance. Read-only. @type integer */ this.uid=Navpopup.uid++; /** Read-only flag for current visibility of the popup. @type boolean @private */ this.visible=false; /** Flag to be set when we want to cancel a previous request to show the popup in a little while. @private @type boolean */ this.noshow=false; /** Categorised list of hooks. @see #runHooks @see #addHook @private @type Object */ this.hooks={ 'create': [], 'unhide': [], 'hide': [] }; /** list of unique IDs of hook functions, to avoid duplicates @private */ this.hookIds={}; /** List of downloads associated with the popup. @private @type Array */ this.downloads=[]; /** Number of uncompleted downloads. @type integer */ this.pending=null; /** Tolerance in pixels when detecting whether the mouse has left the popup. @type integer */ this.fuzz=5; /** Flag to toggle running {@link #limitHorizontalPosition} to regulate the popup's position. @type boolean */ this.constrained=true; /** The popup width in pixels. @private @type integer */ this.width=0; /** The popup width in pixels. @private @type integer */ this.height=0; /** The main content DIV element. @type HTMLDivElement */ this.mainDiv=null; this.createMainDiv(); // if (!init || typeof init.popups_draggable=='undefined' || init.popups_draggable) { // this.makeDraggable(true); // } } /** A UID for each Navpopup. This constructor property is just a counter. @type integer @private */ Navpopup.uid=0; /** Retrieves the {@link #visible} attribute, indicating whether the popup is currently visible. @type boolean */ Navpopup.prototype.isVisible=function() { return this.visible; }; /** Repositions popup using CSS style. @private @param {integer} x x-coordinate (px) @param {integer} y y-coordinate (px) @param {boolean} noLimitHor Don't call {@link #limitHorizontalPosition} */ Navpopup.prototype.reposition= function (x,y, noLimitHor) { log ('reposition('+x+','+y+','+noLimitHor+')'); if (typeof x != 'undefined' && x !== null) { this.left=x; } if (typeof y != 'undefined' && y !== null) { this.top=y; } if (typeof this.left != 'undefined' && typeof this.top != 'undefined') { this.mainDiv.style.left=this.left + 'px'; this.mainDiv.style.top=this.top + 'px'; } if (!noLimitHor) { this.limitHorizontalPosition(); } //console.log('navpop'+this.uid+' - (left,top)=(' + this.left + ',' + this.top + '), css=(' //+ this.mainDiv.style.left + ',' + this.mainDiv.style.top + ')'); }; /** Prevents popups from being in silly locations. Hopefully. Should not be run if {@link #constrained} is true. @private */ Navpopup.prototype.limitHorizontalPosition=function() { if (!this.constrained || this.tooWide) { return; } this.updateDimensions(); var x=this.left; var w=this.width; var cWidth=document.body.clientWidth; // log('limitHorizontalPosition: x='+x+ // ', this.left=' + this.left + // ', this.width=' + this.width + // ', cWidth=' + cWidth); if ( (x+w) >= cWidth || ( x > 0 && this.maxWidth && this.width < this.maxWidth && this.height > this.width && x > cWidth - this.maxWidth ) ) { // This is a very nasty hack. There has to be a better way! // We find the "natural" width of the div by positioning it at the far left // then reset it so that it should be flush right (well, nearly) this.mainDiv.style.left='-10000px'; this.mainDiv.style.width = this.maxWidth + 'px'; var naturalWidth=parseInt(this.mainDiv.offsetWidth, 10); var newLeft=cWidth - naturalWidth - 1; if (newLeft < 0) { newLeft = 0; this.tooWide=true; } // still unstable for really wide popups? log ('limitHorizontalPosition: moving to ('+newLeft + ','+ this.top+');' + ' naturalWidth=' + naturalWidth + ', clientWidth=' + cWidth); this.reposition(newLeft, null, true); } }; /** Counter indicating the z-order of the "highest" popup. We start the z-index at 1000 so that popups are above everything else on the screen. @private @type integer */ Navpopup.highest=1000; /** Brings popup to the top of the z-order. We increment the {@link #highest} property of the contructor here. @private */ Navpopup.prototype.raise = function () { this.mainDiv.style.zIndex=Navpopup.highest + 1; ++Navpopup.highest; }; /** Shows the popup provided {@link #noshow} is not true. Updates the position, brings the popup to the top of the z-order and unhides it. */ Navpopup.prototype.show = function () { //document.title+='s'; if (this.noshow) { return; } //document.title+='t'; this.reposition(); this.raise(); this.unhide(); }; /** Checks to see if the mouse pointer has stabilised (checking every <code>time</code>/2 milliseconds) and runs the {@link #show} method if it has. @param {integer} time The minimum time (ms) before the popup may be shown. */ Navpopup.prototype.showSoonIfStable = function (time) { log ('showSoonIfStable, time='+time); if (this.visible) { return; } this.noshow = false; //~ initialize these variables so that we never run @tt{show} after //~ just half the time this.stable_x = -10000; this.stable_y = -10000; var stableShow = function() { log('stableShow called'); var new_x = Navpopup.tracker.x, new_y = Navpopup.tracker.y; var dx = savedThis.stable_x - new_x, dy = savedThis.stable_y - new_y; var fuzz2 = 0; // savedThis.fuzz * savedThis.fuzz; //document.title += '[' + [savedThis.stable_x,new_x, savedThis.stable_y,new_y, dx, dy, fuzz2].join(',') + '] '; if ( dx * dx <= fuzz2 && dy * dy <= fuzz2 ) { log ('mouse is stable'); clearInterval(savedThis.showSoonStableTimer); savedThis.reposition.apply(savedThis, [new_x + 2, new_y + 2]); savedThis.show.apply(savedThis, []); savedThis.limitHorizontalPosition.apply(savedThis, []); return; } savedThis.stable_x = new_x; savedThis.stable_y = new_y; }; var savedThis = this; this.showSoonStableTimer = setInterval(stableShow, time/2); }; /** Sets the {@link #noshow} flag and hides the popup. This should be called when the mouse leaves the link before (or after) it's actually been displayed. */ Navpopup.prototype.banish = function () { log ('banish called'); // hide and prevent showing with showSoon in the future this.noshow=true; if (this.showSoonStableTimer) { log('clearing showSoonStableTimer'); clearInterval(this.showSoonStableTimer); } this.hide(); }; /** Runs hooks added with {@link #addHook}. @private @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' @param {String} when Controls exactly when the hook is run: either 'before' or 'after' */ Navpopup.prototype.runHooks = function (key, when) { if (!this.hooks[key]) { return; } var keyHooks=this.hooks[key]; var len=keyHooks.length; for (var i=0; i< len; ++i) { if (keyHooks[i] && keyHooks[i].when == when) { if (keyHooks[i].hook.apply(this, [])) { // remove the hook if (keyHooks[i].hookId) { delete this.hookIds[keyHooks[i].hookId]; } keyHooks[i]=null; } } } }; /** Adds a hook to the popup. Hook functions are run with <code>this</code> set to refer to the Navpopup instance, and no arguments. @param {Function} hook The hook function. Functions that return true are deleted. @param {String} key Key name of the {@link #hooks} array - one of 'create', 'unhide', 'hide' @param {String} when Controls exactly when the hook is run: either 'before' or 'after' @param {String} uid A truthy string identifying the hook function; if it matches another hook in this position, it won't be added again. */ Navpopup.prototype.addHook = function ( hook, key, when, uid ) { when = when || 'after'; if (!this.hooks[key]) { return; } // if uid is specified, don't add duplicates var hookId=null; if (uid) { hookId=[key,when,uid].join('|'); if (this.hookIds[hookId]) { return; } this.hookIds[hookId]=true; } this.hooks[key].push( {hook: hook, when: when, hookId: hookId} ); }; /** Creates the main DIV element, which contains all the actual popup content. Runs hooks with key 'create'. @private */ Navpopup.prototype.createMainDiv = function () { if (this.mainDiv) { return; } this.runHooks('create', 'before'); var mainDiv=document.createElement('div'); var savedThis=this; mainDiv.onclick=function(e) {savedThis.onclickHandler(e);}; mainDiv.className=(this.className) ? this.className : 'navpopup_maindiv'; mainDiv.id=mainDiv.className + this.uid; mainDiv.style.position='absolute'; mainDiv.style.minWidth = '350px'; mainDiv.style.display='none'; mainDiv.className='navpopup'; // easy access to javascript object through DOM functions mainDiv.navpopup=this; this.mainDiv=mainDiv; document.body.appendChild(mainDiv); this.runHooks('create', 'after'); }; /** Calls the {@link #raise} method. @private */ Navpopup.prototype.onclickHandler=function(/*e*/) { this.raise(); }; /** Makes the popup draggable, using a {@link Drag} object. @private */ Navpopup.prototype.makeDraggable=function(handleName) { if (!this.mainDiv) { this.createMainDiv(); } var drag=new Drag(); if (!handleName) { drag.startCondition=function(e) { try { if (!e.shiftKey) { return false; } } catch (err) { return false; } return true; }; } var dragHandle; if (handleName) dragHandle = document.getElementById(handleName); if (!dragHandle) dragHandle = this.mainDiv; var np=this; drag.endHook=function(x,y) { Navpopup.tracker.dirty=true; np.reposition(x,y); }; drag.init(dragHandle,this.mainDiv); }; /** Hides the popup using CSS. Runs hooks with key 'hide'. Sets {@link #visible} appropriately. {@link #banish} should be called externally instead of this method. @private */ Navpopup.prototype.hide = function () { this.runHooks('hide', 'before'); this.abortDownloads(); if (typeof this.visible != 'undefined' && this.visible) { this.mainDiv.style.display='none'; this.visible=false; } this.runHooks('hide', 'after'); }; /** Shows the popup using CSS. Runs hooks with key 'unhide'. Sets {@link #visible} appropriately. {@link #show} should be called externally instead of this method. @private */ Navpopup.prototype.unhide = function () { this.runHooks('unhide', 'before'); if (typeof this.visible != 'undefined' && !this.visible) { this.mainDiv.style.display='inline'; this.visible=true; } this.runHooks('unhide', 'after'); }; /** Sets the <code>innerHTML</code> attribute of the main div containing the popup content. @param {String} html The HTML to set. */ Navpopup.prototype.setInnerHTML = function (html) { this.mainDiv.innerHTML = html; }; /** Updates the {@link #width} and {@link #height} attributes with the CSS properties. @private */ Navpopup.prototype.updateDimensions = function () { this.width=parseInt(this.mainDiv.offsetWidth, 10); this.height=parseInt(this.mainDiv.offsetHeight, 10); }; /** Checks if the point (x,y) is within {@link #fuzz} of the {@link #mainDiv}. @param {integer} x x-coordinate (px) @param {integer} y y-coordinate (px) @type boolean */ Navpopup.prototype.isWithin = function(x,y) { //~ If we're not even visible, no point should be considered as //~ being within the popup. if (!this.visible) { return false; } this.updateDimensions(); var fuzz=this.fuzz || 0; //~ Use a simple box metric here. return (x+fuzz >= this.left && x-fuzz <= this.left + this.width && y+fuzz >= this.top && y-fuzz <= this.top + this.height); }; /** Adds a download to {@link #downloads}. @param {Downloader} download */ Navpopup.prototype.addDownload=function(download) { if (!download) { return; } this.downloads.push(download); }; /** Aborts the downloads listed in {@link #downloads}. @see Downloader#abort */ Navpopup.prototype.abortDownloads=function() { for(var i=0; i<this.downloads.length; ++i) { var d=this.downloads[i]; if (d && d.abort) { d.abort(); } } this.downloads=[]; }; /** A {@link Mousetracker} instance which is a property of the constructor (pseudo-global). */ Navpopup.tracker=new Mousetracker(); // ENDFILE: navpopup.js // STARTFILE: diff.js //<NOLITE> /* * Javascript Diff Algorithm * By John Resig (http://ejohn.org/) and [[:en:User:Lupin]] * * More Info: * http://ejohn.org/projects/javascript-diff-algorithm/ */ function delFmt(x) { if (!x.length) { return ''; } return "<del class='popupDiff'>" + x.join('') +"</del>"; } function insFmt(x) { if (!x.length) { return ''; } return "<ins class='popupDiff'>" + x.join('') +"</ins>"; } function countCrossings(a, b, i, eject) { // count the crossings on the edge starting at b[i] if (!b[i].row && b[i].row !== 0) { return -1; } var count=0; for (var j=0; j<a.length; ++j) { if (!a[j].row && a[j].row !== 0) { continue; } if ( (j-b[i].row)*(i-a[j].row) > 0) { if(eject) { return true; } count++; } } return count; } function shortenDiffString(str, context) { var re=RegExp('(<del[\\s\\S]*?</del>|<ins[\\s\\S]*?</ins>)'); var splitted=str.parenSplit(re); var ret=['']; for (var i=0; i<splitted.length; i+=2) { if (splitted[i].length < 2*context) { ret[ret.length-1] += splitted[i]; if (i+1<splitted.length) { ret[ret.length-1] += splitted[i+1]; } continue; } else { if (i > 0) { ret[ret.length-1] += splitted[i].substring(0,context); } if (i+1 < splitted.length) { ret.push(splitted[i].substring(splitted[i].length-context) + splitted[i+1]); } } } while (ret.length > 0 && !ret[0]) { ret = ret.slice(1); } return ret; } function diffString( o, n, simpleSplit ) { var splitRe=RegExp('([[]{2}|[\\]]{2}|[{]{2,3}|[}]{2,3}|[|]|=|<|>|[*:]+|\\s|\\b)'); // We need to split the strings o and n first, and entify() the parts // individually, so that the HTML entities are never cut apart. (AxelBoldt) var out, i, oSplitted, nSplitted; if (simpleSplit) { oSplitted=o.split(/\b/); nSplitted=n.split(/\b/); } else { oSplitted=o.parenSplit(splitRe); nSplitted=n.parenSplit(splitRe); } for (i=0; i<oSplitted.length; ++i) {oSplitted[i]=oSplitted[i].entify();} for (i=0; i<nSplitted.length; ++i) {nSplitted[i]=nSplitted[i].entify();} out = diff (oSplitted, nSplitted); var str = ""; var acc=[]; // accumulator for prettier output // crossing pairings -- eg 'A B' vs 'B A' -- cause problems, so let's iron them out // this doesn't always do things optimally but it should be fast enough var maxOutputPair=0; for (i=0; i<out.n.length; ++i) { if ( out.n[i].paired ) { if( maxOutputPair > out.n[i].row ) { // tangle - delete pairing out.o[ out.n[i].row ]=out.o[ out.n[i].row ].text; out.n[i]=out.n[i].text; } if (maxOutputPair < out.n[i].row) { maxOutputPair = out.n[i].row; } } } // output the stuff preceding the first paired old line for (i=0; i<out.o.length && !out.o[i].paired; ++i) { acc.push( out.o[i] ); } str += delFmt(acc); acc=[]; // main loop for ( i = 0; i < out.n.length; ++i ) { // output unpaired new "lines" while ( i < out.n.length && !out.n[i].paired ) { acc.push( out.n[i++] ); } str += insFmt(acc); acc=[]; if ( i < out.n.length ) { // this new "line" is paired with the (out.n[i].row)th old "line" str += out.n[i].text; // output unpaired old rows starting after this new line's partner var m = out.n[i].row + 1; while ( m < out.o.length && !out.o[m].paired ) { acc.push ( out.o[m++] ); } str += delFmt(acc); acc=[]; } } return str; } // see http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object // FIXME: use obj.hasOwnProperty instead of this kludge! var jsReservedProperties=RegExp('^(constructor|prototype|__((define|lookup)[GS]etter)__' + '|eval|hasOwnProperty|propertyIsEnumerable' + '|to(Source|String|LocaleString)|(un)?watch|valueOf)$'); function diffBugAlert(word) { if (!diffBugAlert.list[word]) { diffBugAlert.list[word]=1; alert('Bad word: '+word+'\n\nPlease report this bug.'); } } diffBugAlert.list={}; function makeDiffHashtable(src) { var ret={}; for ( var i = 0; i < src.length; i++ ) { if ( jsReservedProperties.test(src[i]) ) { src[i] += '<!-- -->'; } if ( !ret[ src[i] ] ) { ret[ src[i] ] = []; } try { ret[ src[i] ].push( i ); } catch (err) { diffBugAlert(src[i]); } } return ret; } function diff( o, n ) { // pass 1: make hashtable ns with new rows as keys var ns = makeDiffHashtable(n); // pass 2: make hashtable os with old rows as keys var os = makeDiffHashtable(o); // pass 3: pair unique new rows and matching unique old rows var i; for ( i in ns ) { if ( ns[i].length == 1 && os[i] && os[i].length == 1 ) { n[ ns[i][0] ] = { text: n[ ns[i][0] ], row: os[i][0], paired: true }; o[ os[i][0] ] = { text: o[ os[i][0] ], row: ns[i][0], paired: true }; } } // pass 4: pair matching rows immediately following paired rows (not necessarily unique) for ( i = 0; i < n.length - 1; i++ ) { if ( n[i].paired && ! n[i+1].paired && n[i].row + 1 < o.length && ! o[ n[i].row + 1 ].paired && n[i+1] == o[ n[i].row + 1 ] ) { n[i+1] = { text: n[i+1], row: n[i].row + 1, paired: true }; o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1, paired: true }; } } // pass 5: pair matching rows immediately preceding paired rows (not necessarily unique) for ( i = n.length - 1; i > 0; i-- ) { if ( n[i].paired && ! n[i-1].paired && n[i].row > 0 && ! o[ n[i].row - 1 ].paired && n[i-1] == o[ n[i].row - 1 ] ) { n[i-1] = { text: n[i-1], row: n[i].row - 1, paired: true }; o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1, paired: true }; } } return { o: o, n: n }; } //</NOLITE> // ENDFILE: diff.js // STARTFILE: init.js function setSiteInfo() { if (window.popupLocalDebug) { pg.wiki.hostname = 'en.wikipedia.org'; } else { pg.wiki.hostname = location.hostname; // use in preference to location.hostname for flexibility (?) } pg.wiki.wikimedia=RegExp('(wiki([pm]edia|source|books|news|quote|versity)|wiktionary|mediawiki)[.]org').test(pg.wiki.hostname); pg.wiki.wikia=RegExp('[.]wikia[.]com$', 'i').test(pg.wiki.hostname); pg.wiki.isLocal=RegExp('^localhost').test(pg.wiki.hostname); pg.wiki.commons=( pg.wiki.wikimedia && pg.wiki.hostname != 'commons.wikimedia.org') ? 'commons.wikimedia.org' : null; pg.wiki.lang = mw.config.get('wgContentLanguage'); var port = location.port ? ':' + location.port : ''; pg.wiki.sitebase = pg.wiki.hostname + port; } function setUserInfo() { var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'query', list: 'users', ususers: mw.config.get('wgUserName'), usprop: 'rights' }; pg.user.canReview = false; if (getValueOf('popupReview')) { api.get(params).done(function(data){ var rights = data.query.users[0].rights; pg.user.canReview = rights.indexOf('review') !== -1; // TODO: Should it be a getValueOf('ReviewRight') ? }); } } function setTitleBase() { var protocol = ( window.popupLocalDebug ? 'http:' : location.protocol ); pg.wiki.articlePath = mw.config.get('wgArticlePath').replace(/\/\$1/, ""); // as in http://some.thing.com/wiki/Article pg.wiki.botInterfacePath = mw.config.get('wgScript'); pg.wiki.APIPath = mw.config.get('wgScriptPath') +"/api.php"; // default mediawiki setting is paths like http://some.thing.com/articlePath/index.php?title=foo var titletail = pg.wiki.botInterfacePath + '?title='; //var titletail2 = joinPath([pg.wiki.botInterfacePath, 'wiki.phtml?title=']); // other sites may need to add code here to set titletail depending on how their urls work pg.wiki.titlebase = protocol + '//' + pg.wiki.sitebase + titletail; //pg.wiki.titlebase2 = protocol + '//' + joinPath([pg.wiki.sitebase, titletail2]); pg.wiki.wikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.botInterfacePath; pg.wiki.apiwikibase = protocol + '//' + pg.wiki.sitebase + pg.wiki.APIPath; pg.wiki.articlebase = protocol + '//' + pg.wiki.sitebase + pg.wiki.articlePath; pg.wiki.commonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.botInterfacePath; pg.wiki.apicommonsbase = protocol + '//' + pg.wiki.commons + pg.wiki.APIPath; pg.re.basenames = RegExp( '^(' + map( literalizeRegex, [ pg.wiki.titlebase, //pg.wiki.titlebase2, pg.wiki.articlebase ]).join('|') + ')' ); } ////////////////////////////////////////////////// // Global regexps function setMainRegex() { var reStart='[^:]*://'; var preTitles = literalizeRegex( mw.config.get('wgScriptPath') ) + '/(?:index[.]php|wiki[.]phtml)[?]title='; preTitles += '|' + literalizeRegex( pg.wiki.articlePath + '/' ); var reEnd='(' + preTitles + ')([^&?#]*)[^#]*(?:#(.+))?'; pg.re.main = RegExp(reStart + literalizeRegex(pg.wiki.sitebase) + reEnd); } function setRegexps() { // TODO: We shoud use an api call to get the aliases for special pages, now it does not work for non-English wikipedias: // E.g., https://ru.wikipedia.org/w/api.php?action=query&meta=siteinfo&siprop=specialpagealiases&formatversion=2 setMainRegex(); var sp=nsRe(pg.nsSpecialId); pg.re.urlNoPopup=RegExp('((title=|/)' + sp + '(?:%3A|:)|section=[0-9]|^#$)') ; pg.re.contribs =RegExp('(title=|/)' + sp + '(?:%3A|:)Contributions' + '(&target=|/|/' + nsRe(pg.nsUserId)+':)(.*)') ; pg.re.email =RegExp('(title=|/)' + sp + '(?:%3A|:)EmailUser' + '(&target=|/|/(?:' + nsRe(pg.nsUserId)+':)?)(.*)') ; pg.re.backlinks =RegExp('(title=|/)' + sp + '(?:%3A|:)WhatLinksHere' + '(&target=|/)([^&]*)'); pg.re.specialdiff=RegExp('/' + sp + '(?:%3A|:)Diff/([^?#]*)'); //<NOLITE> var im=nsReImage(); // note: tries to get images in infobox templates too, e.g. movie pages, album pages etc // (^|\[\[)image: *([^|\]]*[^|\] ]) * // (^|\[\[)image: *([^|\]]*[^|\] ])([^0-9\]]*([0-9]+) *px)? // $4 = 120 as in 120px pg.re.image = RegExp('(^|\\[\\[)' + im + ': *([^|\\]]*[^|\\] ])' + '([^0-9\\]]*([0-9]+) *px)?|(?:\\n *[|]?|[|]) *' + '(' + getValueOf('popupImageVarsRegexp') + ')' + ' *= *(?:\\[\\[ *)?(?:' + im + ':)?' + '([^|]*?)(?:\\]\\])? *[|]? *\\n', 'img') ; pg.re.imageBracketCount = 6; pg.re.category = RegExp('\\[\\[' +nsRe(pg.nsCategoryId) + ': *([^|\\]]*[^|\\] ]) *', 'i'); pg.re.categoryBracketCount = 1; pg.re.ipUser=RegExp('^' + // IPv6 '(?::(?::|(?::[0-9A-Fa-f]{1,4}){1,7})|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){0,6}::|[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4}){7})' + // IPv4 '|(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}' + '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$'); pg.re.stub= RegExp(getValueOf('popupStubRegexp'), 'im'); pg.re.disambig=RegExp(getValueOf('popupDabRegexp'), 'im'); //</NOLITE> // FIXME replace with general parameter parsing function, this is daft pg.re.oldid=RegExp('[?&]oldid=([^&]*)'); pg.re.diff=RegExp('[?&]diff=([^&]*)'); } ////////////////////////////////////////////////// // miscellany function setupCache() { // page caching pg.cache.pages = []; } function setMisc() { pg.current.link=null; pg.current.links=[]; pg.current.linksHash={}; setupCache(); pg.timer.checkPopupPosition=null; pg.counter.loop=0; // ids change with each popup: popupImage0, popupImage1 etc pg.idNumber=0; // for myDecodeURI pg.misc.decodeExtras = [ {from: '%2C', to: ',' }, {from: '_', to: ' ' }, {from: '%24', to: '$'}, {from: '%26', to: '&' } // no , ]; pg.misc.userAgent = 'Navigation popups/1.0 (' + mw.config.get( 'wgServerName' ) +')'; } // We need a callback since this might end up asynchronous because of // the mw.loader.using() call. function setupPopups( callback ) { if ( setupPopups.completed ) { if ( typeof callback === 'function' ) { callback(); } return; } // These dependencies are also enforced from the gadget, // but not everyone loads this as a gadget, so double check mw.loader.using( ['mediawiki.util', 'mediawiki.user', 'user.options'] ).then( function() { // NB translatable strings should be set up first (strings.js) // basics setupDebugging(); setSiteInfo(); setTitleBase(); setOptions(); // see options.js setUserInfo(); // namespaces etc setNamespaces(); setInterwiki(); // regexps setRegexps(); setRedirs(); // other stuff setMisc(); setupLivePreview(); // main deal here setupTooltips(); log('In setupPopups(), just called setupTooltips()'); Navpopup.tracker.enable(); setupPopups.completed = true; if ( typeof callback === 'function' ) { callback(); } }); } // ENDFILE: init.js // STARTFILE: navlinks.js //<NOLITE> ////////////////////////////////////////////////// // navlinks... let the fun begin // function defaultNavlinkSpec() { var str=''; str += '<b><<mainlink|shortcut= >></b>'; if (getValueOf('popupLastEditLink')) { str += '*<<lastEdit|shortcut=/>>|<<lastContrib>>|<<sinceMe>>if(oldid){|<<oldEdit>>|<<diffCur>>}'; } // user links // contribs - log - count - email - block // count only if applicable; block only if popupAdminLinks str += 'if(user){<br><<contribs|shortcut=c>>*<<userlog|shortcut=L|log>>'; str+='if(ipuser){*<<arin>>}if(wikimedia){*<<count|shortcut=#>>}'; str+='if(ipuser){}else{*<<email|shortcut=E>>}if(admin){*<<block|shortcut=b>>|<<blocklog|log>>}}'; // editing links // talkpage -> edit|new - history - un|watch - article|edit // other page -> edit - history - un|watch - talk|edit|new var editstr='<<edit|shortcut=e>>'; var editOldidStr='if(oldid){<<editOld|shortcut=e>>|<<revert|shortcut=v|rv>>|<<edit|cur>>}else{' + editstr + '}'; var historystr='<<history|shortcut=h>>|<<editors|shortcut=E|>>'; var watchstr='<<unwatch|unwatchShort>>|<<watch|shortcut=w|watchThingy>>'; str+='<br>if(talk){' + editOldidStr+'|<<new|shortcut=+>>' + '*' + historystr+'*'+watchstr + '*' + '<b><<article|shortcut=a>></b>|<<editArticle|edit>>' + '}else{' + // not a talk page editOldidStr + '*' + historystr + '*' + watchstr + '*' + '<b><<talk|shortcut=t>></b>|<<editTalk|edit>>|<<newTalk|shortcut=+|new>>}'; // misc links str += '<br><<whatLinksHere|shortcut=l>>*<<relatedChanges|shortcut=r>>*<<move|shortcut=m>>'; // admin links str += 'if(admin){<br><<unprotect|unprotectShort>>|<<protect|shortcut=p>>|<<protectlog|log>>*' + '<<undelete|undeleteShort>>|<<delete|shortcut=d>>|<<deletelog|log>>}'; return str; } function navLinksHTML (article, hint, params) { //oldid, rcid) { var str = '<span class="popupNavLinks">' + defaultNavlinkSpec() + '</span>'; // BAM return navlinkStringToHTML(str, article, params); } function expandConditionalNavlinkString(s,article,z,recursionCount) { var oldid=z.oldid, rcid=z.rcid, diff=z.diff; // nested conditionals (up to 10 deep) are ok, hopefully! (work from the inside out) if (typeof recursionCount!=typeof 0) { recursionCount=0; } var conditionalSplitRegex=RegExp( //(1 if \\( (2 2) \\) {(3 3)} (4 else {(5 5)} 4)1) '(;?\\s*if\\s*\\(\\s*([\\w]*)\\s*\\)\\s*\\{([^{}]*)\\}(\\s*else\\s*\\{([^{}]*?)\\}|))', 'i'); var splitted=s.parenSplit(conditionalSplitRegex); // $1: whole conditional // $2: test condition // $3: true expansion // $4: else clause (possibly empty) // $5: false expansion (possibly null) var numParens=5; var ret = splitted[0]; for (var i=1; i<splitted.length; i=i+numParens+1) { var testString=splitted[i+2-1]; var trueString=splitted[i+3-1]; var falseString=splitted[i+5-1]; if (typeof falseString=='undefined' || !falseString) { falseString=''; } var testResult=null; switch (testString) { case 'user': testResult=(article.userName())?true:false; break; case 'talk': testResult=(article.talkPage())?false:true; // talkPage converts _articles_ to talkPages break; case 'admin': testResult=getValueOf('popupAdminLinks')?true:false; break; case 'oldid': testResult=(typeof oldid != 'undefined' && oldid)?true:false; break; case 'rcid': testResult=(typeof rcid != 'undefined' && rcid)?true:false; break; case 'ipuser': testResult=(article.isIpUser())?true:false; break; case 'mainspace_en': testResult=isInMainNamespace(article) && pg.wiki.hostname=='en.wikipedia.org'; break; case 'wikimedia': testResult=(pg.wiki.wikimedia) ? true : false; break; case 'diff': testResult=(typeof diff != 'undefined' && diff)?true:false; break; } switch(testResult) { case null: ret+=splitted[i]; break; case true: ret+=trueString; break; case false: ret+=falseString; break; } // append non-conditional string ret += splitted[i+numParens]; } if (conditionalSplitRegex.test(ret) && recursionCount < 10) { return expandConditionalNavlinkString(ret,article,z,recursionCount+1); } return ret; } function navlinkStringToArray(s, article, params) { s=expandConditionalNavlinkString(s,article,params); var splitted=s.parenSplit(RegExp('<<(.*?)>>')); var ret=[]; for (var i=0; i<splitted.length; ++i) { if (i%2) { // i odd, so s is a tag var t=new navlinkTag(); var ss=splitted[i].split('|'); t.id=ss[0]; for (var j=1; j<ss.length; ++j) { var sss=ss[j].split('='); if (sss.length>1) { t[sss[0]]=sss[1]; } else { // no assignment (no "="), so treat this as a title (overwriting the last one) t.text=popupString(sss[0]); } } t.article=article; var oldid=params.oldid, rcid=params.rcid, diff=params.diff; if (typeof oldid !== 'undefined' && oldid !== null) { t.oldid=oldid; } if (typeof rcid !== 'undefined' && rcid !== null) { t.rcid=rcid; } if (typeof diff !== 'undefined' && diff !== null) { t.diff=diff; } if (!t.text && t.id !== 'mainlink') { t.text=popupString(t.id); } ret.push(t); } else { // plain HTML ret.push(splitted[i]); } } return ret; } function navlinkSubstituteHTML(s) { return s.split('*').join(getValueOf('popupNavLinkSeparator')) .split('<menurow>').join('<li class="popup_menu_row">') .split('</menurow>').join('</li>') .split('<menu>').join('<ul class="popup_menu">') .split('</menu>').join('</ul>'); } function navlinkDepth(magic,s) { return s.split('<' + magic + '>').length - s.split('</' + magic + '>').length; } // navlinkString: * becomes the separator // <<foo|bar=baz|fubar>> becomes a foo-link with attribute bar='baz' // and visible text 'fubar' // if(test){...} and if(test){...}else{...} work too (nested ok) function navlinkStringToHTML(s,article,params) { //limitAlert(navlinkStringToHTML, 5, 'navlinkStringToHTML\n' + article + '\n' + (typeof article)); var p=navlinkStringToArray(s,article,params); var html=''; var menudepth = 0; // nested menus not currently allowed, but doesn't do any harm to code for it var menurowdepth = 0; for (var i=0; i<p.length; ++i) { if (typeof p[i] == typeof '') { html+=navlinkSubstituteHTML(p[i]); menudepth += navlinkDepth('menu', p[i]); menurowdepth += navlinkDepth('menurow', p[i]); // if (menudepth === 0) { // tagType='span'; // } else if (menurowdepth === 0) { // tagType='li'; // } else { // tagType = null; // } } else if (typeof p[i].type != 'undefined' && p[i].type=='navlinkTag') { if (menudepth > 0 && menurowdepth === 0) { html += '<li class="popup_menu_item">' + p[i].html() + '</li>'; } else { html+=p[i].html(); } } } return html; } function navlinkTag() { this.type='navlinkTag'; } navlinkTag.prototype.html=function () { this.getNewWin(); this.getPrintFunction(); var html=''; var opening, closing; var tagType='span'; if (!tagType) { opening = ''; closing = ''; } else { opening = '<' + tagType + ' class="popup_' + this.id + '">'; closing = '</' + tagType + '>'; } if (typeof this.print!='function') { errlog ('Oh dear - invalid print function for a navlinkTag, id='+this.id); } else { html=this.print(this); if (typeof html != typeof '') {html='';} else if (typeof this.shortcut!='undefined') html=addPopupShortcut(html, this.shortcut); } return opening + html + closing; }; navlinkTag.prototype.getNewWin=function() { getValueOf('popupLinksNewWindow'); if (typeof pg.option.popupLinksNewWindow[this.id] === 'undefined') { this.newWin=null; } this.newWin=pg.option.popupLinksNewWindow[this.id]; }; navlinkTag.prototype.getPrintFunction=function() { //think about this some more // this.id and this.article should already be defined if (typeof this.id!=typeof '' || typeof this.article!=typeof {} ) { return; } this.noPopup=1; switch (this.id) { case 'contribs': case 'history': case 'whatLinksHere': case 'userPage': case 'monobook': case 'userTalk': case 'talk': case 'article': case 'lastEdit': this.noPopup=null; } switch (this.id) { case 'email': case 'contribs': case 'block': case 'unblock': case 'userlog': case 'userSpace': case 'deletedContribs': this.article=this.article.userName(); } switch (this.id) { case 'userTalk': case 'newUserTalk': case 'editUserTalk': case 'userPage': case 'monobook': case 'editMonobook': case 'blocklog': this.article=this.article.userName(true); /* fall through */ case 'pagelog': case 'deletelog': case 'protectlog': delete this.oldid; } if (this.id=='editMonobook' || this.id=='monobook') { this.article.append('/monobook.js'); } if (this.id != 'mainlink') { // FIXME anchor handling should be done differently with Title object this.article=this.article.removeAnchor(); // if (typeof this.text=='undefined') this.text=popupString(this.id); } switch (this.id) { case 'undelete': this.print=specialLink; this.specialpage='Undelete'; this.sep='/'; break; case 'whatLinksHere': this.print=specialLink; this.specialpage='Whatlinkshere'; break; case 'relatedChanges': this.print=specialLink; this.specialpage='Recentchangeslinked'; break; case 'move': this.print=specialLink; this.specialpage='Movepage'; break; case 'contribs': this.print=specialLink; this.specialpage='Contributions'; break; case 'deletedContribs':this.print=specialLink; this.specialpage='Deletedcontributions'; break; case 'email': this.print=specialLink; this.specialpage='EmailUser'; this.sep='/'; break; case 'block': this.print=specialLink; this.specialpage='Blockip'; this.sep='&ip='; break; case 'unblock': this.print=specialLink; this.specialpage='Ipblocklist'; this.sep='&action=unblock&ip='; break; case 'userlog': this.print=specialLink; this.specialpage='Log'; this.sep='&user='; break; case 'blocklog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=block&page='; break; case 'pagelog': this.print=specialLink; this.specialpage='Log'; this.sep='&page='; break; case 'protectlog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=protect&page='; break; case 'deletelog': this.print=specialLink; this.specialpage='Log'; this.sep='&type=delete&page='; break; case 'userSpace': this.print=specialLink; this.specialpage='PrefixIndex'; this.sep='&namespace=2&prefix='; break; case 'search': this.print=specialLink; this.specialpage='Search'; this.sep='&fulltext=Search&search='; break; case 'thank': this.print=specialLink; this.specialpage='Thanks'; this.sep='/'; this.article.value = this.diff; break; case 'unwatch': case 'watch': this.print=magicWatchLink; this.action=this.id+'&autowatchlist=1&autoimpl=' + popupString('autoedit_version') + '&actoken='+autoClickToken(); break; case 'history': case 'historyfeed': case 'unprotect': case 'protect': this.print=wikiLink; this.action=this.id; break; case 'delete': this.print=wikiLink; this.action='delete'; if (this.article.namespaceId()==pg.nsImageId) { var img=this.article.stripNamespace(); this.action+='&image='+img; } break; case 'markpatrolled': case 'edit': // editOld should keep the oldid, but edit should not. delete this.oldid; /* fall through */ case 'view': case 'purge': case 'render': this.print=wikiLink; this.action=this.id; break; case 'raw': this.print=wikiLink; this.action='raw'; break; case 'new': this.print=wikiLink; this.action='edit&section=new'; break; case 'mainlink': if (typeof this.text=='undefined') { this.text=this.article.toString().entify(); } if (getValueOf('popupSimplifyMainLink') && isInStrippableNamespace(this.article)) { // only show the /subpage part of the title text var s=this.text.split('/'); this.text=s[s.length-1]; if (this.text==='' && s.length > 1) { this.text=s[s.length-2]; } } this.print=titledWikiLink; if (typeof this.title==='undefined' && pg.current.link && typeof pg.current.link.href !== 'undefined') { this.title=safeDecodeURI((pg.current.link.originalTitle)?pg.current.link.originalTitle:this.article); if (typeof this.oldid !== 'undefined' && this.oldid) { this.title=tprintf('Revision %s of %s', [this.oldid, this.title]); } } this.action='view'; break; case 'userPage': case 'article': case 'monobook': case 'editMonobook': case 'editArticle': delete this.oldid; //alert(this.id+'\n'+this.article + '\n'+ typeof this.article); this.article=this.article.articleFromTalkOrArticle(); //alert(this.id+'\n'+this.article + '\n'+ typeof this.article); this.print=wikiLink; if (this.id.indexOf('edit')===0) { this.action='edit'; } else { this.action='view';} break; case 'userTalk': case 'talk': this.article=this.article.talkPage(); delete this.oldid; this.print=wikiLink; this.action='view'; break; case 'arin': this.print=arinLink; break; case 'count': this.print=editCounterLink; break; case 'google': this.print=googleLink; break; case 'editors': this.print=editorListLink; break; case 'globalsearch': this.print=globalSearchLink; break; case 'lastEdit': this.print=titledDiffLink; this.title=popupString('Show the last edit'); this.from='prev'; this.to='cur'; break; case 'oldEdit': this.print=titledDiffLink; this.title=popupString('Show the edit made to get revision') + ' ' + this.oldid; this.from='prev'; this.to=this.oldid; break; case 'editOld': this.print=wikiLink; this.action='edit'; break; case 'undo': this.print=wikiLink; this.action='edit&undo='; break; case 'revert': this.print=wikiLink; this.action='revert'; break; case 'nullEdit': this.print=wikiLink; this.action='nullEdit'; break; case 'diffCur': this.print=titledDiffLink; this.title=tprintf('Show changes since revision %s', [this.oldid]); this.from=this.oldid; this.to='cur'; break; case 'editUserTalk': case 'editTalk': delete this.oldid; this.article=this.article.talkPage(); this.action='edit'; this.print=wikiLink; break; case 'newUserTalk': case 'newTalk': this.article=this.article.talkPage(); this.action='edit&section=new'; this.print=wikiLink; break; case 'lastContrib': case 'sinceMe': this.print=magicHistoryLink; break; case 'togglePreviews': this.text=popupString(pg.option.simplePopups ? 'enable previews' : 'disable previews'); /* fall through */ case 'disablePopups': case 'purgePopups': this.print=popupMenuLink; break; default: this.print=function () {return 'Unknown navlink type: '+this.id+'';}; } }; // // end navlinks ////////////////////////////////////////////////// //</NOLITE> // ENDFILE: navlinks.js // STARTFILE: shortcutkeys.js //<NOLITE> function popupHandleKeypress(evt) { var keyCode = window.event ? window.event.keyCode : ( evt.keyCode ? evt.keyCode : evt.which); if (!keyCode || !pg.current.link || !pg.current.link.navpopup) { return; } if (keyCode==27) { // escape killPopup(); return false; // swallow keypress } var letter=String.fromCharCode(keyCode); var links=pg.current.link.navpopup.mainDiv.getElementsByTagName('A'); var startLink=0; var i,j; if (popupHandleKeypress.lastPopupLinkSelected) { for (i=0; i<links.length; ++i) { if (links[i]==popupHandleKeypress.lastPopupLinkSelected) { startLink=i; } } } for (j=0; j<links.length; ++j) { i=(startLink + j + 1) % links.length; if (links[i].getAttribute('popupkey')==letter) { if (evt && evt.preventDefault) evt.preventDefault(); links[i].focus(); popupHandleKeypress.lastPopupLinkSelected=links[i]; return false; // swallow keypress } } // pass keypress on if (document.oldPopupOnkeypress) { return document.oldPopupOnkeypress(evt); } return true; } function addPopupShortcuts() { if (document.onkeypress!=popupHandleKeypress) { document.oldPopupOnkeypress=document.onkeypress; } document.onkeypress=popupHandleKeypress; } function rmPopupShortcuts() { popupHandleKeypress.lastPopupLinkSelected=null; try { if (document.oldPopupOnkeypress && document.oldPopupOnkeypress==popupHandleKeypress) { // panic document.onkeypress=null; //function () {}; return; } document.onkeypress=document.oldPopupOnkeypress; } catch (nasties) { /* IE goes here */ } } function addLinkProperty(html, property) { // take "<a href=...>...</a> and add a property // not sophisticated at all, easily broken var i=html.indexOf('>'); if (i<0) { return html; } return html.substring(0,i) + ' ' + property + html.substring(i); } function addPopupShortcut(html, key) { if (!getValueOf('popupShortcutKeys')) { return html; } var ret= addLinkProperty(html, 'popupkey="'+key+'"'); if (key==' ') { key=popupString('spacebar'); } return ret.replace(RegExp('^(.*?)(title=")(.*?)(".*)$', 'i'),'$1$2$3 ['+key+']$4'); } //</NOLITE> // ENDFILE: shortcutkeys.js // STARTFILE: diffpreview.js //<NOLITE> //lets jump through hoops to find the rev ids we need to retrieve function loadDiff(article, oldid, diff, navpop) { navpop.diffData={ oldRev: {}, newRev: {} }; mw.loader.using( 'mediawiki.api' ).then( function() { var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'compare', prop: 'ids|title' }; if(article.title){ params.fromtitle = article.title; } switch (diff) { case 'cur': switch ( oldid ) { case null: case '': case 'prev': // this can only work if we have the title // cur -> prev params.torelative = 'prev'; break; default: params.fromrev = oldid; params.torelative = 'cur'; break; } break; case 'prev': if( oldid ) { params.fromrev = oldid; } else { params.fromtitle; } params.torelative = 'prev'; break; case 'next': params.fromrev = oldid || 0; params.torelative = 'next'; break; default: params.fromrev = oldid || 0; params.torev = diff || 0; break; } api.get( params ).then( function( data ) { navpop.diffData.oldRev.revid = data.compare.fromrevid; navpop.diffData.newRev.revid = data.compare.torevid; addReviewLink(navpop, 'popupMiscTools'); var go = function() { pendingNavpopTask(navpop); var url=pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&'; url += 'revids=' + navpop.diffData.oldRev.revid + '|' + navpop.diffData.newRev.revid; url += '&prop=revisions&rvprop=ids|timestamp|content'; getPageWithCaching(url, doneDiff, navpop); return true; // remove hook once run }; if (navpop.visible || !getValueOf('popupLazyDownloads')) { go(); } else { navpop.addHook(go, 'unhide', 'before', 'DOWNLOAD_DIFFS'); } } ); } ); } // Put a "mark patrolled" link to an element target // TODO: Allow patrol a revision, as well as a diff function addReviewLink (navpop, target) { if (! pg.user.canReview) return; // If 'newRev' is older than 'oldRev' than it could be confusing, so we do not show the review link. if (navpop.diffData.newRev.revid <= navpop.diffData.oldRev.revid) return; var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); var params = { action: 'query', prop: 'info|flagged', revids: navpop.diffData.oldRev.revid, formatversion : 2 }; api.get (params).then(function(data){ var stable_revid = data.query.pages[0].flagged && data.query.pages[0].flagged.stable_revid || 0; // The diff can be reviewed if the old version is the last reviewed version // TODO: Other possible conditions that we may want to implement instead of this one: // * old version is patrolled and the new version is not patrolled // * old version is patrolled and the new version is more recent than the last reviewed version if (stable_revid == navpop.diffData.oldRev.revid) { var a = document.createElement('a'); a.innerHTML = popupString('mark patrolled'); a.title=popupString('markpatrolledHint'); a.onclick = function() { var params = { action: 'review', revid: navpop.diffData.newRev.revid, comment: tprintf('defaultpopupReviewedSummary', [navpop.diffData.oldRev.revid, navpop.diffData.newRev.revid]) }; api.postWithToken('csrf',params).done(function(){ a.style.display = "none"; // TODO: Update current page and other already constructed popups } ).fail(function(){ alert(popupString('Could not marked this edit as patrolled')); }); }; setPopupHTML(a, target, navpop.idNumber,null,true); } }); } function doneDiff(download) { if (!download.owner || !download.owner.diffData) { return; } var navpop=download.owner; completedNavpopTask(navpop); var pages, revisions=[]; try{ // Process the downloads pages = getJsObj(download.data).query.pages; for(var i=0; i < pages.length; i++ ) { revisions = revisions.concat(pages[i].revisions); } for(i=0; i< revisions.length; i++){ if(revisions[i].revid == navpop.diffData.oldRev.revid) { navpop.diffData.oldRev.revision = revisions[i]; } else if (revisions[i].revid == navpop.diffData.newRev.revid) { navpop.diffData.newRev.revision = revisions[i]; } } } catch(someError) { errlog( 'Could not get diff' ); } insertDiff(navpop); } function rmBoringLines(a,b,context) { if (typeof context == 'undefined') { context=2; } // this is fairly slow... i think it's quicker than doing a word-based diff from the off, though var aa=[], aaa=[]; var bb=[], bbb=[]; var i, j; // first, gather all disconnected nodes in a and all crossing nodes in a and b for (i=0; i<a.length; ++i ) { if(!a[i].paired) { aa[i]=1; } else if (countCrossings(b,a,i, true)) { aa[i]=1; bb[ a[i].row ] = 1; } } // pick up remaining disconnected nodes in b for (i=0; i<b.length; ++i ) { if (bb[i]==1) { continue; } if(!b[i].paired) { bb[i]=1; } } // another pass to gather context: we want the neighbours of included nodes which are not yet included // we have to add in partners of these nodes, but we don't want to add context for *those* nodes in the next pass for (i=0; i<b.length; ++i) { if ( bb[i] == 1 ) { for (j=Math.max(0,i-context); j < Math.min(b.length, i+context); ++j) { if ( !bb[j] ) { bb[j] = 1; aa[ b[j].row ] = 0.5; } } } } for (i=0; i<a.length; ++i) { if ( aa[i] == 1 ) { for (j=Math.max(0,i-context); j < Math.min(a.length, i+context); ++j) { if ( !aa[j] ) { aa[j] = 1; bb[ a[j].row ] = 0.5; } } } } for (i=0; i<bb.length; ++i) { if (bb[i] > 0) { // it's a row we need if (b[i].paired) { bbb.push(b[i].text); } // joined; partner should be in aa else { bbb.push(b[i]); } } } for (i=0; i<aa.length; ++i) { if (aa[i] > 0) { // it's a row we need if (a[i].paired) { aaa.push(a[i].text); } // joined; partner should be in aa else { aaa.push(a[i]); } } } return { a: aaa, b: bbb}; } function stripOuterCommonLines(a,b,context) { var i=0; while (i<a.length && i < b.length && a[i]==b[i]) { ++i; } var j=a.length-1; var k=b.length-1; while ( j>=0 && k>=0 && a[j]==b[k] ) { --j; --k; } return { a: a.slice(Math.max(0,i - 1 - context), Math.min(a.length+1, j + context+1)), b: b.slice(Math.max(0,i - 1 - context), Math.min(b.length+1, k + context+1)) }; } function insertDiff(navpop) { // for speed reasons, we first do a line-based diff, discard stuff that seems boring, then do a word-based diff // FIXME: sometimes this gives misleading diffs as distant chunks are squashed together var oldlines = navpop.diffData.oldRev.revision.content.split('\n'); var newlines = navpop.diffData.newRev.revision.content.split('\n'); var inner=stripOuterCommonLines(oldlines,newlines,getValueOf('popupDiffContextLines')); oldlines=inner.a; newlines=inner.b; var truncated=false; getValueOf('popupDiffMaxLines'); if (oldlines.length > pg.option.popupDiffMaxLines || newlines.length > pg.option.popupDiffMaxLines) { // truncate truncated=true; inner=stripOuterCommonLines(oldlines.slice(0,pg.option.popupDiffMaxLines), newlines.slice(0,pg.option.popupDiffMaxLines), pg.option.popupDiffContextLines); oldlines=inner.a; newlines=inner.b; } var lineDiff=diff(oldlines, newlines); var lines2=rmBoringLines(lineDiff.o, lineDiff.n); var oldlines2=lines2.a; var newlines2=lines2.b; var simpleSplit = !String.prototype.parenSplit.isNative; var html='<hr />'; if (getValueOf('popupDiffDates')) { html += diffDatesTable(navpop); html += '<hr />'; } html += shortenDiffString( diffString(oldlines2.join('\n'), newlines2.join('\n'), simpleSplit), getValueOf('popupDiffContextCharacters') ).join('<hr />'); setPopupTipsAndHTML(html.split('\n').join('<br>') + (truncated ? '<hr /><b>'+popupString('Diff truncated for performance reasons')+'</b>' : '') , 'popupPreview', navpop.idNumber); } function diffDatesTable( navpop ) { var html='<table class="popup_diff_dates">'; html += diffDatesTableRow( navpop.diffData.newRev.revision, tprintf('New revision')); html += diffDatesTableRow( navpop.diffData.oldRev.revision, tprintf('Old revision')); html += '</table>'; return html; } function diffDatesTableRow( revision, label ) { var txt=''; var lastModifiedDate = new Date(revision.timestamp); var datePrint=getValueOf('popupDiffDatePrinter'); if (typeof lastModifiedDate[datePrint] == 'function') { var d2 = adjustDate(lastModifiedDate, getTimeOffset()); txt = dayFormat(d2, true) + ' ' + timeFormat(d2, true); } else { txt = tprintf('Invalid %s %s', ['popupDiffDatePrinter', datePrint]); } var revlink = generalLink({url: mw.config.get('wgScript') + '?oldid='+revision.revid, text: label, title: label}); return simplePrintf('<tr><td>%s</td><td>%s</td></tr>', [ revlink, txt ]); } //</NOLITE> // ENDFILE: diffpreview.js // STARTFILE: links.js //<NOLITE> ///////////////////// // LINK GENERATION // ///////////////////// // titledDiffLink --> titledWikiLink --> generalLink // wikiLink --> titledWikiLink --> generalLink // editCounterLink --> generalLink // TODO Make these functions return Element objects, not just raw HTML strings. function titledDiffLink(l) { // article, text, title, from, to) { return titledWikiLink({article: l.article, action: l.to + '&oldid=' + l.from, newWin: l.newWin, noPopup: l.noPopup, text: l.text, title: l.title, /* hack: no oldid here */ actionName: 'diff'}); } function wikiLink(l) { //{article:article, action:action, text:text, oldid, newid}) { if (! (typeof l.article == typeof {} && typeof l.action == typeof '' && typeof l.text==typeof '')) return null; if (typeof l.oldid == 'undefined') { l.oldid=null; } var savedOldid = l.oldid; if (!/^(edit|view|revert|render)$|^raw/.test(l.action)) { l.oldid=null; } var hint=popupString(l.action + 'Hint'); // revertHint etc etc etc var oldidData=[l.oldid, safeDecodeURI(l.article)]; var revisionString = tprintf('revision %s of %s', oldidData); log('revisionString='+revisionString); switch (l.action) { case 'edit&section=new': hint = popupString('newSectionHint'); break; case 'edit&undo=': if (l.diff && l.diff != 'prev' && savedOldid ) { l.action += l.diff + '&undoafter=' + savedOldid; } else if (savedOldid) { l.action += savedOldid; } hint = popupString('undoHint'); break; case 'raw&ctype=text/css': hint=popupString('rawHint'); break; case 'revert': var p=parseParams(pg.current.link.href); l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=' + revertSummary(l.oldid, p.diff); if (p.diff=='prev') { l.action += '&direction=prev'; revisionString = tprintf('the revision prior to revision %s of %s', oldidData); } if (getValueOf('popupRevertSummaryPrompt')) { l.action += '&autosummaryprompt=true'; } if (getValueOf('popupMinorReverts')) { l.action += '&autominor=true'; } log('revisionString is now '+revisionString); break; case 'nullEdit': l.action='edit&autoclick=wpSave&actoken=' + autoClickToken() + '&autoimpl=' + popupString('autoedit_version') + '&autosummary=null'; break; case 'historyfeed': l.action='history&feed=rss'; break; case 'markpatrolled': l.action='markpatrolled&rcid='+l.rcid; } if (hint) { if (l.oldid) { hint = simplePrintf(hint, [revisionString]); } else { hint = simplePrintf(hint, [safeDecodeURI(l.article)]); } } else { hint = safeDecodeURI(l.article + '&action=' + l.action) + (l.oldid) ? '&oldid='+l.oldid : ''; } return titledWikiLink({article: l.article, action: l.action, text: l.text, newWin:l.newWin, title: hint, oldid: l.oldid, noPopup: l.noPopup, onclick: l.onclick}); } function revertSummary(oldid, diff) { var ret=''; if (diff == 'prev') { ret=getValueOf('popupQueriedRevertToPreviousSummary'); } else { ret = getValueOf('popupQueriedRevertSummary'); } return ret + '&autorv=' + oldid; } function titledWikiLink(l) { // possible properties of argument: // article, action, text, title, oldid, actionName, className, noPopup // oldid = null is fine here // article and action are mandatory args if (typeof l.article == 'undefined' || typeof l.action=='undefined') { errlog('got undefined article or action in titledWikiLink'); return null; } var base = pg.wiki.titlebase + l.article.urlString(); var url=base; if (typeof l.actionName=='undefined' || !l.actionName) { l.actionName='action'; } // no need to add &action=view, and this confuses anchors if (l.action != 'view') { url = base + '&' + l.actionName + '=' + l.action; } if (typeof l.oldid!='undefined' && l.oldid) { url+='&oldid='+l.oldid; } var cssClass=pg.misc.defaultNavlinkClassname; if (typeof l.className!='undefined' && l.className) { cssClass=l.className; } return generalNavLink({url: url, newWin: l.newWin, title: (typeof l.title != 'undefined') ? l.title : null, text: (typeof l.text!='undefined')?l.text:null, className: cssClass, noPopup:l.noPopup, onclick:l.onclick}); } pg.fn.getLastContrib = function getLastContrib(wikipage, newWin) { getHistoryInfo(wikipage, function(x) { processLastContribInfo(x, {page: wikipage, newWin: newWin}); }); }; function processLastContribInfo(info, stuff) { if(!info.edits || !info.edits.length) { alert('Popups: an odd thing happened. Please retry.'); return; } if(!info.firstNewEditor) { alert(tprintf('Only found one editor: %s made %s edits', [info.edits[0].editor,info.edits.length])); return; } var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+info.firstNewEditor.oldid; displayUrl(newUrl, stuff.newWin); } pg.fn.getDiffSinceMyEdit = function getDiffSinceMyEdit(wikipage, newWin) { getHistoryInfo(wikipage, function(x){ processDiffSinceMyEdit(x, {page: wikipage, newWin: newWin}); }); }; function processDiffSinceMyEdit(info, stuff) { if(!info.edits || !info.edits.length) { alert('Popups: something fishy happened. Please try again.'); return; } var friendlyName=stuff.page.split('_').join(' '); if(!info.myLastEdit) { alert(tprintf('Couldn\'t find an edit by %s\nin the last %s edits to\n%s', [info.userName, getValueOf('popupHistoryLimit'), friendlyName])); return; } if(info.myLastEdit.index === 0) { alert(tprintf("%s seems to be the last editor to the page %s", [info.userName, friendlyName])); return; } var newUrl=pg.wiki.titlebase + new Title(stuff.page).urlString() + '&diff=cur&oldid='+ info.myLastEdit.oldid; displayUrl(newUrl, stuff.newWin); } function displayUrl(url, newWin){ if(newWin) { window.open(url); } else { document.location=url; } } pg.fn.purgePopups = function purgePopups() { processAllPopups(true); setupCache(); // deletes all cached items (not browser cached, though...) pg.option={}; abortAllDownloads(); }; function processAllPopups(nullify, banish) { for (var i=0; pg.current.links && i<pg.current.links.length; ++i) { if (!pg.current.links[i].navpopup) { continue; } if (nullify || banish) pg.current.links[i].navpopup.banish(); pg.current.links[i].simpleNoMore=false; if (nullify) pg.current.links[i].navpopup=null; } } pg.fn.disablePopups = function disablePopups(){ processAllPopups(false, true); setupTooltips(null, true); }; pg.fn.togglePreviews = function togglePreviews() { processAllPopups(true, true); pg.option.simplePopups=!pg.option.simplePopups; abortAllDownloads(); }; function magicWatchLink(l) { //Yuck!! Would require a thorough redesign to add this as a click event though ... l.onclick = simplePrintf( 'pg.fn.modifyWatchlist(\'%s\',\'%s\');return false;', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), this.id] ); return wikiLink(l); } pg.fn.modifyWatchlist = function modifyWatchlist(title, action) { var reqData = { 'action': 'watch', 'formatversion': 2, 'titles': title, 'uselang': mw.config.get('wgUserLanguage') }; if ( action === 'unwatch' ) reqData.unwatch = true; var api = new mw.Api( { ajax: { headers: { 'Api-User-Agent': pg.misc.userAgent } } } ); // Load the Addedwatchtext or Removedwatchtext message and show it var mwTitle = mw.Title.newFromText( title ); var messageName; if ( mwTitle && mwTitle.getNamespaceId() > 0 && mwTitle.getNamespaceId() % 2 === 1 ) { messageName = action === 'watch' ? 'addedwatchtext-talk' : 'removedwatchtext-talk'; } else { messageName = action === 'watch' ? 'addedwatchtext' : 'removedwatchtext'; } $.when( api.postWithToken( 'watch', reqData ), mw.loader.using( [ 'mediawiki.api', 'mediawiki.jqueryMsg' ] ).then( function () { return api.loadMessagesIfMissing( [ messageName ] ); } ) ).done( function () { mw.notify( mw.message( messageName, title ).parseDom() ); } ); }; function magicHistoryLink(l) { // FIXME use onclick change href trick to sort this out instead of window.open var jsUrl='', title='', onClick=''; switch(l.id) { case 'lastContrib': onClick=simplePrintf('pg.fn.getLastContrib(\'%s\',%s)', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); title=popupString('lastContribHint'); break; case 'sinceMe': onClick=simplePrintf('pg.fn.getDiffSinceMyEdit(\'%s\',%s)', [l.article.toString(true).split("\\").join("\\\\").split("'").join("\\'"), l.newWin]); title=popupString('sinceMeHint'); break; } jsUrl = 'javascript:' + onClick; // jshint ignore:line onClick += ';return false;'; return generalNavLink({url: jsUrl, newWin: false, // can't have new windows with JS links, I think title: title, text: l.text, noPopup: l.noPopup, onclick: onClick }); } function popupMenuLink(l) { var jsUrl=simplePrintf('javascript:pg.fn.%s()', [l.id]); // jshint ignore:line var title=popupString(simplePrintf('%sHint', [l.id])); var onClick=simplePrintf('pg.fn.%s();return false;', [l.id]); return generalNavLink({url: jsUrl, newWin:false, title:title, text:l.text, noPopup:l.noPopup, onclick: onClick}); } function specialLink(l) { // properties: article, specialpage, text, sep if (typeof l.specialpage=='undefined'||!l.specialpage) return null; var base = pg.wiki.titlebase + mw.config.get('wgFormattedNamespaces')[pg.nsSpecialId]+':'+l.specialpage; if (typeof l.sep == 'undefined' || l.sep === null) l.sep='&target='; var article=l.article.urlString({keepSpaces: l.specialpage=='Search'}); var hint=popupString(l.specialpage+'Hint'); switch (l.specialpage) { case 'Log': switch (l.sep) { case '&user=': hint=popupString('userLogHint'); break; case '&type=block&page=': hint=popupString('blockLogHint'); break; case '&page=': hint=popupString('pageLogHint'); break; case '&type=protect&page=': hint=popupString('protectLogHint'); break; case '&type=delete&page=': hint=popupString('deleteLogHint'); break; default: log('Unknown log type, sep=' + l.sep); hint='Missing hint (FIXME)'; } break; case 'PrefixIndex': article += '/'; break; } if (hint) hint = simplePrintf(hint, [safeDecodeURI(l.article)]); else hint = safeDecodeURI(l.specialpage+':'+l.article) ; var url = base + l.sep + article; return generalNavLink({url: url, title: hint, text: l.text, newWin:l.newWin, noPopup:l.noPopup}); } function generalLink(l) { // l.url, l.text, l.title, l.newWin, l.className, l.noPopup, l.onclick if (typeof l.url=='undefined') return null; // only quotation marks in the url can screw us up now... I think var url=l.url.split('"').join('%22'); var ret='<a href="' + url + '"'; if (typeof l.title!='undefined' && l.title) { ret += ' title="' + pg.escapeQuotesHTML(l.title) + '"'; } if (typeof l.onclick!='undefined' && l.onclick) { ret += ' onclick="' + pg.escapeQuotesHTML(l.onclick) + '"'; } if (l.noPopup) { ret += ' noPopup=1'; } var newWin; if (typeof l.newWin=='undefined' || l.newWin === null) { newWin=getValueOf('popupNewWindows'); } else { newWin=l.newWin; } if (newWin) { ret += ' target="_blank"'; } if (typeof l.className!='undefined'&&l.className) { ret+=' class="'+l.className+'"'; } ret += '>'; if (typeof l.text==typeof '') { ret+= l.text; } ret +='</a>'; return ret; } function appendParamsToLink(linkstr, params) { var sp=linkstr.parenSplit(RegExp('(href="[^"]+?)"', 'i')); if (sp.length<2) return null; var ret=sp.shift() + sp.shift(); ret += '&' + params + '"'; ret += sp.join(''); return ret; } function changeLinkTargetLink(x) { // newTarget, text, hint, summary, clickButton, minor, title (optional), alsoChangeLabel { if (x.newTarget) { log ('changeLinkTargetLink: newTarget=' + x.newTarget); } if (x.oldTarget !== decodeURIComponent( x.oldTarget ) ) { log ('This might be an input problem: ' + x.oldTarget ); } // FIXME: first character of page title as well as namespace should be case insensitive // eg [[category:X1]] and [[Category:X1]] are equivalent // this'll break if charAt(0) is nasty var cA = mw.util.escapeRegExp(x.oldTarget); var chs = cA.charAt(0).toUpperCase(); chs='['+chs + chs.toLowerCase()+']'; var currentArticleRegexBit=chs+cA.substring(1); currentArticleRegexBit=currentArticleRegexBit .split(RegExp('(?:[_ ]+|%20)', 'g')).join('(?:[_ ]+|%20)') .split('\\(').join('(?:%28|\\()') .split('\\)').join('(?:%29|\\))'); // why does this need to match encoded strings ? links in the document ? // leading and trailing space should be ignored, and anchor bits optional: currentArticleRegexBit = '\\s*(' + currentArticleRegexBit + '(?:#[^\\[\\|]*)?)\\s*'; // e.g. Computer (archaic) -> \s*([Cc]omputer[_ ](?:%2528|\()archaic(?:%2528|\)))\s* // autoedit=s~\[\[([Cc]ad)\]\]~[[Computer-aided%20design|$1]]~g;s~\[\[([Cc]AD)[|]~[[Computer-aided%20design|~g var title=x.title || mw.config.get('wgPageName').split('_').join(' '); var lk=titledWikiLink({article: new Title(title), newWin:x.newWin, action: 'edit', text: x.text, title: x.hint, className: 'popup_change_title_link' }); var cmd=''; if (x.newTarget) { // escape '&' and other nasties var t = x.newTarget; var s = mw.util.escapeRegExp(x.newTarget); if (x.alsoChangeLabel) { cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~[[' + t + ']]~g;'; cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; } else { cmd += 's~\\[\\[' + currentArticleRegexBit + '\\]\\]~[[' + t + '|$1]]~g;'; cmd += 's~\\[\\[' + currentArticleRegexBit + '[|]~[[' + t + '|~g;'; cmd += 's~\\[\\[' + s + '\\|' + s + '\\]\\]~[[' + t + ']]~g'; } } else { cmd += 's~\\[\\['+currentArticleRegexBit+'\\]\\]~$1~g;'; cmd += 's~\\[\\['+currentArticleRegexBit+'[|](.*?)\\]\\]~$2~g'; } // Build query cmd = 'autoedit=' + encodeURIComponent ( cmd ); cmd += '&autoclick='+ encodeURIComponent( x.clickButton ) + '&actoken=' + encodeURIComponent( autoClickToken() ); cmd += ( x.minor === null ) ? '' : '&autominor='+ encodeURIComponent( x.minor ); cmd += ( x.watch === null ) ? '' : '&autowatch='+ encodeURIComponent( x.watch ); cmd += '&autosummary='+encodeURIComponent(x.summary); cmd += '&autoimpl='+encodeURIComponent( popupString('autoedit_version') ); return appendParamsToLink(lk, cmd); } function redirLink(redirMatch, article) { // NB redirMatch is in wikiText var ret=''; if (getValueOf('popupAppendRedirNavLinks') && getValueOf('popupNavLinks')) { ret += '<hr />'; if (getValueOf('popupFixRedirs') && typeof autoEdit != 'undefined' && autoEdit) { ret += popupString('Redirects to: (Fix '); log('redirLink: newTarget=' + redirMatch); ret += addPopupShortcut(changeLinkTargetLink({ newTarget: redirMatch, text: popupString('target'), hint: popupString('Fix this redirect, changing just the link target'), summary: simplePrintf(getValueOf('popupFixRedirsSummary'),[article.toString(), redirMatch]), oldTarget: article.toString(), clickButton: getValueOf('popupRedirAutoClick'), minor: true, watch: getValueOf('popupWatchRedirredPages') }), 'R'); ret += popupString(' or '); ret += addPopupShortcut(changeLinkTargetLink({ newTarget: redirMatch, text: popupString('target & label'), hint: popupString('Fix this redirect, changing the link target and label'), summary: simplePrintf(getValueOf('popupFixRedirsSummary'),[article.toString(), redirMatch]), oldTarget: article.toString(), clickButton: getValueOf('popupRedirAutoClick'), minor: true, watch: getValueOf('popupWatchRedirredPages'), alsoChangeLabel: true }), 'R'); ret += popupString(')'); } else ret += popupString('Redirects') + popupString(' to '); return ret; } else return '<br> ' + popupString('Redirects') + popupString(' to ') + titledWikiLink({article: new Title().fromWikiText(redirMatch), action: 'view', /* FIXME: newWin */ text: safeDecodeURI(redirMatch), title: popupString('Bypass redirect')}); } function arinLink(l) { if (!saneLinkCheck(l)) { return null; } if ( ! l.article.isIpUser() || ! pg.wiki.wikimedia) return null; var uN=l.article.userName(); return generalNavLink({url:'http://ws.arin.net/cgi-bin/whois.pl?queryinput=' + encodeURIComponent(uN), newWin:l.newWin, title: tprintf('Look up %s in ARIN whois database', [uN]), text: l.text, noPopup:1}); } function toolDbName(cookieStyle) { var ret = mw.config.get('wgDBname'); if (!cookieStyle) { ret+= '_p'; } return ret; } function saneLinkCheck(l) { if (typeof l.article != typeof {} || typeof l.text != typeof '') { return false; } return true; } function editCounterLink(l) { if(!saneLinkCheck(l)) return null; if (! pg.wiki.wikimedia) return null; var uN=l.article.userName(); var tool=getValueOf('popupEditCounterTool'); var url; var defaultToolUrl='//tools.wmflabs.org/supercount/index.php?user=$1&project=$2.$3'; switch(tool) { case 'custom': url=simplePrintf(getValueOf('popupEditCounterUrl'), [ encodeURIComponent(uN), toolDbName() ]); break; case 'soxred': // no longer available case 'kate': // no longer available case 'interiot':// no longer available /* fall through */ case 'supercount': default: var theWiki=pg.wiki.hostname.split('.'); url=simplePrintf(defaultToolUrl, [ encodeURIComponent(uN), theWiki[0], theWiki[1] ]); } return generalNavLink({url:url, title: tprintf('editCounterLinkHint', [uN]), newWin:l.newWin, text: l.text, noPopup:1}); } function globalSearchLink(l) { if(!saneLinkCheck(l)) return null; var base='http://vs.aka-online.de/cgi-bin/globalwpsearch.pl?timeout=120&search='; var article=l.article.urlString({keepSpaces:true}); return generalNavLink({url:base + article, newWin:l.newWin, title: tprintf('globalSearchHint', [safeDecodeURI(l.article)]), text: l.text, noPopup:1}); } function googleLink(l) { if(!saneLinkCheck(l)) return null; var base='https://www.google.com/search?q='; var article=l.article.urlString({keepSpaces:true}); return generalNavLink({url:base + '%22' + article + '%22', newWin:l.newWin, title: tprintf('googleSearchHint', [safeDecodeURI(l.article)]), text: l.text, noPopup:1}); } function editorListLink(l) { if(!saneLinkCheck(l)) return null; var article= l.article.articleFromTalkPage() || l.article; var url='https://xtools.wmflabs.org/articleinfo/' + encodeURI( pg.wiki.hostname ) + '/' + article.urlString() + '?uselang=' + mw.config.get('wgUserLanguage'); return generalNavLink({url:url, title: tprintf('editorListHint', [article]), newWin:l.newWin, text: l.text, noPopup:1}); } function generalNavLink(l) { l.className = (l.className === null) ? 'popupNavLink' : l.className; return generalLink(l); } ////////////////////////////////////////////////// // magic history links // function getHistoryInfo(wikipage, whatNext) { log('getHistoryInfo'); getHistory(wikipage, whatNext ? function(d){whatNext(processHistory(d));} : processHistory); } // FIXME eliminate pg.idNumber ... how? :-( function getHistory(wikipage, onComplete) { log('getHistory'); var url = pg.wiki.apiwikibase + '?format=json&formatversion=2&action=query&prop=revisions&titles=' + new Title(wikipage).urlString() + '&rvlimit=' + getValueOf('popupHistoryLimit'); log('getHistory: url='+url); return startDownload(url, pg.idNumber+'history', onComplete); } function processHistory(download) { var jsobj = getJsObj(download.data); try { var revisions = anyChild(jsobj.query.pages).revisions; var edits=[]; for (var i=0; i<revisions.length; ++i) { edits.push({ oldid: revisions[i].revid, editor: revisions[i].user }); } log('processed ' + edits.length + ' edits'); return finishProcessHistory( edits, mw.config.get('wgUserName') ); } catch (someError) { log('Something went wrong with JSON business'); return finishProcessHistory([]); } } function finishProcessHistory(edits, userName) { var histInfo={}; histInfo.edits=edits; histInfo.userName=userName; for (var i=0; i<edits.length; ++i) { if (typeof histInfo.myLastEdit === 'undefined' && userName && edits[i].editor==userName) { histInfo.myLastEdit={index: i, oldid: edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; } if (typeof histInfo.firstNewEditor === 'undefined' && edits[i].editor != edits[0].editor) { histInfo.firstNewEditor={index:i, oldid:edits[i].oldid, previd: (i === 0 ? null : edits[i-1].oldid)}; } } //pg.misc.historyInfo=histInfo; return histInfo; } //</NOLITE> // ENDFILE: links.js // STARTFILE: options.js ////////////////////////////////////////////////// // options // check for existing value, else use default function defaultize(x) { if (pg.option[x]===null || typeof pg.option[x]=='undefined') { if (typeof window[x] != 'undefined' ) pg.option[x]=window[x]; else pg.option[x]=pg.optionDefault[x]; } } function newOption(x, def) { pg.optionDefault[x]=def; } function setDefault(x, def) { return newOption(x, def); } function getValueOf(varName) { defaultize(varName); return pg.option[varName]; } /*eslint-disable */ function useDefaultOptions() { // for testing for (var p in pg.optionDefault) { pg.option[p]=pg.optionDefault[p]; if (typeof window[p]!='undefined') { delete window[p]; } } } /*eslint-enable */ function setOptions() { // user-settable parameters and defaults var userIsSysop = false; if ( mw.config.get('wgUserGroups') ) { for ( var g = 0; g < mw.config.get('wgUserGroups').length; ++g ) { if ( mw.config.get('wgUserGroups')[g] == "sysop" ) userIsSysop = true; } } // Basic options newOption('popupDelay', 0.5); newOption('popupHideDelay', 0.5); newOption('simplePopups', false); newOption('popupStructure', 'shortmenus'); // see later - default for popupStructure is 'original' if simplePopups is true newOption('popupActionsMenu', true); newOption('popupSetupMenu', true); newOption('popupAdminLinks', userIsSysop); newOption('popupShortcutKeys', false); newOption('popupHistoricalLinks', true); newOption('popupOnlyArticleLinks', true); newOption('removeTitles', true); newOption('popupMaxWidth', 350); newOption('popupSimplifyMainLink', true); newOption('popupAppendRedirNavLinks', true); newOption('popupTocLinks', false); newOption('popupSubpopups', true); newOption('popupDragHandle', false /* 'popupTopLinks'*/); newOption('popupLazyPreviews', true); newOption('popupLazyDownloads', true); newOption('popupAllDabsStubs', false); newOption('popupDebugging', false); newOption('popupActiveNavlinks', true); newOption('popupModifier', false); // ctrl, shift, alt or meta newOption('popupModifierAction', 'enable'); // or 'disable' newOption('popupDraggable', true); newOption('popupReview', false); //<NOLITE> // images newOption('popupImages', true); newOption('imagePopupsForImages', true); newOption('popupNeverGetThumbs', false); //newOption('popupImagesToggleSize', true); newOption('popupThumbAction', 'imagepage'); //'sizetoggle'); newOption('popupImageSize', 60); newOption('popupImageSizeLarge', 200); // redirs, dabs, reversion newOption('popupFixRedirs', false); newOption('popupRedirAutoClick', 'wpDiff'); newOption('popupFixDabs', false); newOption('popupDabsAutoClick', 'wpDiff'); newOption('popupRevertSummaryPrompt', false); newOption('popupMinorReverts', false); newOption('popupRedlinkRemoval', false); newOption('popupRedlinkAutoClick', 'wpDiff'); newOption('popupWatchDisambiggedPages', null); newOption('popupWatchRedirredPages', null); newOption('popupDabWiktionary', 'last'); // navlinks newOption('popupNavLinks', true); newOption('popupNavLinkSeparator', ' &sdot; '); newOption('popupLastEditLink', true); newOption('popupEditCounterTool', 'supercount'); newOption('popupEditCounterUrl', ''); //</NOLITE> // previews etc newOption('popupPreviews', true); newOption('popupSummaryData', true); newOption('popupMaxPreviewSentences', 9); newOption('popupMaxPreviewCharacters', 900); newOption('popupLastModified', true); newOption('popupPreviewKillTemplates', true); newOption('popupPreviewRawTemplates', true); newOption('popupPreviewFirstParOnly', false); newOption('popupPreviewCutHeadings', false); newOption('popupPreviewButton', false); newOption('popupPreviewButtonEvent', 'click'); //<NOLITE> // diffs newOption('popupPreviewDiffs', true); newOption('popupDiffMaxLines', 100); newOption('popupDiffContextLines', 2); newOption('popupDiffContextCharacters', 40); newOption('popupDiffDates', true); newOption('popupDiffDatePrinter', 'toLocaleString'); // edit summaries. God, these are ugly. newOption('popupReviewedSummary', popupString('defaultpopupReviewedSummary') ); newOption('popupFixDabsSummary', popupString('defaultpopupFixDabsSummary') ); newOption('popupExtendedRevertSummary', popupString('defaultpopupExtendedRevertSummary') ); newOption('popupRevertSummary', popupString('defaultpopupRevertSummary') ); newOption('popupRevertToPreviousSummary', popupString('defaultpopupRevertToPreviousSummary') ); newOption('popupQueriedRevertSummary', popupString('defaultpopupQueriedRevertSummary') ); newOption('popupQueriedRevertToPreviousSummary', popupString('defaultpopupQueriedRevertToPreviousSummary') ); newOption('popupFixRedirsSummary', popupString('defaultpopupFixRedirsSummary') ); newOption('popupRedlinkSummary', popupString('defaultpopupRedlinkSummary') ); newOption('popupRmDabLinkSummary', popupString('defaultpopupRmDabLinkSummary') ); //</NOLITE> // misc newOption('popupHistoryLimit', 50); //<NOLITE> newOption('popupFilters', [popupFilterStubDetect, popupFilterDisambigDetect, popupFilterPageSize, popupFilterCountLinks, popupFilterCountImages, popupFilterCountCategories, popupFilterLastModified]); newOption('extraPopupFilters', []); newOption('popupOnEditSelection', 'cursor'); newOption('popupPreviewHistory', true); newOption('popupImageLinks', true); newOption('popupCategoryMembers', true); newOption('popupUserInfo', true); newOption('popupHistoryPreviewLimit', 25); newOption('popupContribsPreviewLimit',25); newOption('popupRevDelUrl', '//en.wikipedia.org/wiki/Wikipedia:Revision_deletion'); newOption('popupShowGender', true); //</NOLITE> // new windows newOption('popupNewWindows', false); newOption('popupLinksNewWindow', {'lastContrib': true, 'sinceMe': true}); // regexps newOption('popupDabRegexp', '(\\{\\{\\s*disambig(?!uation needed)|disambig(uation|)\\s*\\}\\}|disamb\\s*\\}\\}|dab\\s*\\}\\})|\\{\\{\\s*(((geo|hn|road?|school|number)dis)|[234][lc][acw]|(road|ship)index)(\\s*[|][^}]*)?\\s*[}][}]|is a .*disambiguation.*page'); newOption('popupAnchorRegexp', 'anchors?'); //how to identify an anchors template newOption('popupStubRegexp', '(sect)?stub[}][}]|This .*-related article is a .*stub'); newOption('popupImageVarsRegexp', 'image|image_(?:file|skyline|name|flag|seal)|cover|badge|logo'); } // ENDFILE: options.js // STARTFILE: strings.js //<NOLITE> ////////////////////////////////////////////////// // Translatable strings ////////////////////////////////////////////////// // // See instructions at // https://en.wikipedia.org/wiki/Wikipedia:Tools/Navigation_popups/Translation pg.string = { ///////////////////////////////////// // summary data, searching etc. ///////////////////////////////////// 'article': 'article', 'category': 'category', 'categories': 'categories', 'image': 'image', 'images': 'images', 'stub': 'stub', 'section stub': 'section stub', 'Empty page': 'Empty page', 'kB': 'kB', 'bytes': 'bytes', 'day': 'day', 'days': 'days', 'hour': 'hour', 'hours': 'hours', 'minute': 'minute', 'minutes': 'minutes', 'second': 'second', 'seconds': 'seconds', 'week': 'week', 'weeks': 'weeks', 'search': 'search', 'SearchHint': 'Find English Wikipedia articles containing %s', 'web': 'web', 'global': 'global', 'globalSearchHint': 'Search across Wikipedias in different languages for %s', 'googleSearchHint': 'Google for %s', ///////////////////////////////////// // article-related actions and info // (some actions also apply to user pages) ///////////////////////////////////// 'actions': 'actions', ///// view articles and view talk 'popupsMenu': 'popups', 'togglePreviewsHint': 'Toggle preview generation in popups on this page', 'enable previews': 'enable previews', 'disable previews': 'disable previews', 'toggle previews': 'toggle previews', 'show preview': 'show preview', 'reset': 'reset', 'more...': 'more...', 'disable': 'disable popups', 'disablePopupsHint': 'Disable popups on this page. Reload page to re-enable.', 'historyfeedHint': 'RSS feed of recent changes to this page', 'purgePopupsHint': 'Reset popups, clearing all cached popup data.', 'PopupsHint': 'Reset popups, clearing all cached popup data.', 'spacebar': 'space', 'view': 'view', 'view article': 'view article', 'viewHint': 'Go to %s', 'talk': 'talk', 'talk page': 'talk page', 'this&nbsp;revision': 'this&nbsp;revision', 'revision %s of %s': 'revision %s of %s', 'Revision %s of %s': 'Revision %s of %s', 'the revision prior to revision %s of %s': 'the revision prior to revision %s of %s', 'Toggle image size': 'Click to toggle image size', 'del': 'del', ///// delete, protect, move 'delete': 'delete', 'deleteHint': 'Delete %s', 'undeleteShort': 'un', 'UndeleteHint': 'Show the deletion history for %s', 'protect': 'protect', 'protectHint': 'Restrict editing rights to %s', 'unprotectShort': 'un', 'unprotectHint': 'Allow %s to be edited by anyone again', 'send thanks': 'send thanks', 'ThanksHint': 'Send a thank you notification to this user', 'move': 'move', 'move page': 'move page', 'MovepageHint': 'Change the title of %s', 'edit': 'edit', ///// edit articles and talk 'edit article': 'edit article', 'editHint': 'Change the content of %s', 'edit talk': 'edit talk', 'new': 'new', 'new topic': 'new topic', 'newSectionHint': 'Start a new section on %s', 'null edit': 'null edit', 'nullEditHint': 'Submit an edit to %s, making no changes ', 'hist': 'hist', ///// history, diffs, editors, related 'history': 'history', 'historyHint': 'List the changes made to %s', 'last': 'prev', // For labelling the previous revision in history pages; the key is "last" for backwards compatibility 'lastEdit': 'lastEdit', 'mark patrolled': 'mark patrolled', 'markpatrolledHint': 'Mark this edit as patrolled', 'Could not marked this edit as patrolled': 'Could not marked this edit as patrolled', 'show last edit': 'most recent edit', 'Show the last edit': 'Show the effects of the most recent change', 'lastContrib': 'lastContrib', 'last set of edits': 'latest edits', 'lastContribHint': 'Show the net effect of changes made by the last editor', 'cur': 'cur', 'diffCur': 'diffCur', 'Show changes since revision %s': 'Show changes since revision %s', '%s old': '%s old', // as in 4 weeks old 'oldEdit': 'oldEdit', 'purge': 'purge', 'purgeHint': 'Demand a fresh copy of %s', 'raw': 'source', 'rawHint': 'Download the source of %s', 'render': 'simple', 'renderHint': 'Show a plain HTML version of %s', 'Show the edit made to get revision': 'Show the edit made to get revision', 'sinceMe': 'sinceMe', 'changes since mine': 'diff my edit', 'sinceMeHint': 'Show changes since my last edit', 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s': 'Couldn\'t find an edit by %s\nin the last %s edits to\n%s', 'eds': 'eds', 'editors': 'editors', 'editorListHint': 'List the users who have edited %s', 'related': 'related', 'relatedChanges': 'relatedChanges', 'related changes': 'related changes', 'RecentchangeslinkedHint': 'Show changes in articles related to %s', 'editOld': 'editOld', ///// edit old version, or revert 'rv': 'rv', 'revert': 'revert', 'revertHint': 'Revert to %s', 'defaultpopupReviewedSummary': 'Accepted by reviewing the [[Special:diff/%s/%s|difference]] between this version and previously accepted version using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRedlinkSummary': 'Removing link to empty page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupFixDabsSummary': 'Disambiguate [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupFixRedirsSummary': 'Redirect bypass from [[%s]] to [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupExtendedRevertSummary': 'Revert to revision dated %s by %s, oldid %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRevertToPreviousSummary': 'Revert to the revision prior to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRevertSummary': 'Revert to revision %s using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupQueriedRevertToPreviousSummary': 'Revert to the revision prior to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupQueriedRevertSummary': 'Revert to revision $1 dated $2 by $3 using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'defaultpopupRmDabLinkSummary': 'Remove link to dab page [[%s]] using [[:en:Wikipedia:Tools/Navigation_popups|popups]]', 'Redirects': 'Redirects', // as in Redirects to ... ' to ': ' to ', // as in Redirects to ... 'Bypass redirect': 'Bypass redirect', 'Fix this redirect': 'Fix this redirect', 'disambig': 'disambig', ///// add or remove dab etc. 'disambigHint': 'Disambiguate this link to [[%s]]', 'Click to disambiguate this link to:': 'Click to disambiguate this link to:', 'remove this link': 'remove this link', 'remove all links to this page from this article': 'remove all links to this page from this article', 'remove all links to this disambig page from this article': 'remove all links to this disambig page from this article', 'mainlink': 'mainlink', ///// links, watch, unwatch 'wikiLink': 'wikiLink', 'wikiLinks': 'wikiLinks', 'links here': 'links here', 'whatLinksHere': 'whatLinksHere', 'what links here': 'what links here', 'WhatlinkshereHint': 'List the pages that are hyperlinked to %s', 'unwatchShort': 'un', 'watchThingy': 'watch', // called watchThingy because {}.watch is a function 'watchHint': 'Add %s to my watchlist', 'unwatchHint': 'Remove %s from my watchlist', 'Only found one editor: %s made %s edits': 'Only found one editor: %s made %s edits', '%s seems to be the last editor to the page %s': '%s seems to be the last editor to the page %s', 'rss': 'rss', ///////////////////////////////////// // diff previews ///////////////////////////////////// 'Diff truncated for performance reasons': 'Diff truncated for performance reasons', 'Old revision': 'Old revision', 'New revision': 'New revision', 'Something went wrong :-(': 'Something went wrong :-(', 'Empty revision, maybe non-existent': 'Empty revision, maybe non-existent', 'Unknown date': 'Unknown date', ///////////////////////////////////// // other special previews ///////////////////////////////////// 'Empty category': 'Empty category', 'Category members (%s shown)': 'Category members (%s shown)', 'No image links found': 'No image links found', 'File links': 'File links', 'No image found': 'No image found', 'Image from Commons': 'Image from Commons', 'Description page': 'Description page', 'Alt text:': 'Alt text:', 'revdel':'Hidden revision', ///////////////////////////////////// // user-related actions and info ///////////////////////////////////// 'user': 'user', ///// user page, talk, email, space 'user&nbsp;page': 'user&nbsp;page', 'user talk': 'user talk', 'edit user talk': 'edit user talk', 'leave comment': 'leave comment', 'email': 'email', 'email user': 'email user', 'EmailuserHint': 'Send an email to %s', 'space': 'space', // short form for userSpace link 'PrefixIndexHint': 'Show pages in the userspace of %s', 'count': 'count', ///// contributions, log 'edit counter': 'edit counter', 'editCounterLinkHint': 'Count the contributions made by %s', 'contribs': 'contribs', 'contributions': 'contributions', 'deletedContribs': 'deleted contributions', 'DeletedcontributionsHint': 'List deleted edits made by %s', 'ContributionsHint': 'List the contributions made by %s', 'log': 'log', 'user log': 'user log', 'userLogHint': 'Show %s\'s user log', 'arin': 'ARIN lookup', ///// ARIN lookup, block user or IP 'Look up %s in ARIN whois database': 'Look up %s in the ARIN whois database', 'unblockShort': 'un', 'block': 'block', 'block user': 'block user', 'IpblocklistHint': 'Unblock %s', 'BlockipHint': 'Prevent %s from editing', 'block log': 'block log', 'blockLogHint': 'Show the block log for %s', 'protectLogHint': 'Show the protection log for %s', 'pageLogHint': 'Show the page log for %s', 'deleteLogHint': 'Show the deletion log for %s', 'Invalid %s %s': 'The option %s is invalid: %s', 'No backlinks found': 'No backlinks found', ' and more': ' and more', 'undo': 'undo', 'undoHint': 'undo this edit', 'Download preview data': 'Download preview data', 'Invalid or IP user': 'Invalid or IP user', 'Not a registered username': 'Not a registered username', 'BLOCKED': 'BLOCKED', 'Has blocks': 'Has blocks', ' edits since: ': ' edits since: ', 'last edit on ': 'last edit on ', ///////////////////////////////////// // Autoediting ///////////////////////////////////// 'Enter a non-empty edit summary or press cancel to abort': 'Enter a non-empty edit summary or press cancel to abort', 'Failed to get revision information, please edit manually.\n\n': 'Failed to get revision information, please edit manually.\n\n', 'The %s button has been automatically clicked. Please wait for the next page to load.': 'The %s button has been automatically clicked. Please wait for the next page to load.', 'Could not find button %s. Please check the settings in your javascript file.': 'Could not find button %s. Please check the settings in your javascript file.', ///////////////////////////////////// // Popups setup ///////////////////////////////////// 'Open full-size image': 'Open full-size image', 'zxy': 'zxy', 'autoedit_version': 'np20140416' }; function popupString(str) { if (typeof popupStrings != 'undefined' && popupStrings && popupStrings[str]) { return popupStrings[str]; } if (pg.string[str]) { return pg.string[str]; } return str; } function tprintf(str,subs) { if (typeof subs != typeof []) { subs = [subs]; } return simplePrintf(popupString(str), subs); } //</NOLITE> // ENDFILE: strings.js // STARTFILE: run.js //////////////////////////////////////////////////////////////////// // Run things //////////////////////////////////////////////////////////////////// // For some reason popups requires a fully loaded page jQuery.ready(...) causes problems for some. // The old addOnloadHook did something similar to the below if (document.readyState=="complete") autoEdit(); //will setup popups else $( window ).on( 'load', autoEdit ); // Support for MediaWiki's live preview, VisualEditor's saves and Echo's flyout. ( function () { var once = true; function dynamicContentHandler( $content ) { // Try to detect the hook fired on initial page load and disregard // it, we already hook to onload (possibly to different parts of // page - it's configurable) and running twice might be bad. Ugly… if ( $content.attr( 'id' ) == 'mw-content-text' ) { if ( once ) { once = false; return; } } function registerHooksForVisibleNavpops () { for (var i=0; pg.current.links && i<pg.current.links.length; ++i) { var navpop = pg.current.links[i].navpopup; if (!navpop || !navpop.isVisible()) { continue; } Navpopup.tracker.addHook(posCheckerHook(navpop)); } } function doIt () { registerHooksForVisibleNavpops(); $content.each( function () { this.ranSetupTooltipsAlready = false; setupTooltips( this ); } ); } setupPopups( doIt ); } // This hook is also fired after page load. mw.hook( 'wikipage.content' ).add( dynamicContentHandler ); mw.hook( 'ext.echo.overlay.beforeShowingOverlay' ).add( function($overlay){ dynamicContentHandler( $overlay.find(".mw-echo-state") ); }); } )(); // Forked from [[User:Connel MacKenzie/mess-with-popups.js]] Previewmaker.prototype.firstBit = function() { try{ if (mw.config.get("wgNamespaceNumber") !== 0){ // dont't be givin' me no subsequent paragraphs, you hear me? /// first we "normalize" section headings, removing whitespace after, adding before var d = this.data; if (getValueOf('popupPreviewCutHeadings')) { this.data = this.data.replace(RegExp('\\s*(==+[^=]*==+)\\s*', 'g'), '\n\n$1 '); /// then we want to get rid of paragraph breaks whose text ends badly this.data = this.data.replace(RegExp('([:;]) *\\n{2,}', 'g'), '$1\n'); this.data = this.data.replace(RegExp('^[\\s\\n]*'), ''); stuff = (RegExp('^([^\\n]|\\n[^\\n\\s])*')).exec(this.data); if (stuff) { d = stuff[0]; } if (!getValueOf('popupPreviewFirstParOnly')) { d = this.data; } /// now put \n\n after sections so that bullets and numbered lists work d = d.replace(RegExp('(==+[^=]*==+)\\s*', 'g'), '$1\n\n'); } // superfluous sentences are RIGHT OUT. // note: exactly 1 set of parens here needed to make the slice work d = d.parenSplit(RegExp('([!?.]+["' + "'" + ']*\\s)', 'g')); // leading space is bad, mmkay? d[0] = d[0].replace(RegExp('^\\s*'), ''); var notSentenceEnds = RegExp('([^.][a-z][.][a-z]|etc|sic|Dr|Mr|Mrs|Ms|St|no|\\[[^\\]]*|\\s[A-Zvclm])$', 'i'); d = this.fixSentenceEnds(d, notSentenceEnds); var maxChars=getValueOf('popupMaxPreviewCharacters'); var n = getValueOf('popupMaxPreviewSentences'); var dd; do { dd = this.firstSentences(d, n); --n; } while (dd.length > maxChars && n > 0); this.data = dd; } else { //TODO: Limit this override to urls that start with http://*.wiktionary.org/ //TODO: extend the above section to also preview Wikipedia links var charsWikt = 0; var linesWikt = this.data.split('\n'); for (jWikt = 0; jWikt < linesWikt.length; jWikt++) { linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{[in]transitive}}/g, ''); linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{[un]countable}}/g, ''); linesWikt[jWikt] = linesWikt[jWikt].replace(/\{\{cattag\|(.*?)}}/g, ""); linesWikt[jWikt] = linesWikt[jWikt].replace(/[\{\}]/g, "'"); if (linesWikt[jWikt].search(/^[#]/) == -1) { if (linesWikt[jWikt].search(/^==[A-Z]/) == -1) { linesWikt[jWikt] = ''; } } charsWikt += linesWikt[jWikt].length; } if (charsWikt < 2) { linesWikt[0] = "No properly formatted content"; } var maxChars = getValueOf('popupMaxPreviewCharacters'); var n = getValueOf('popupMaxPreviewSentences'); var dd = ''; for (jWikt = 0; jWikt < linesWikt.length; jWikt++) { if (linesWikt[jWikt] !== '') { dd += linesWikt[jWikt] + '\n'; } if (dd.length < maxChars) { this.data = dd; } } } } catch (e) { console.log("error from mess with popups: ", e); } }; }); orsd53nf3vg9wb097lspoxfv57tbbij MediaWiki:Gadget-PagePreviews.js 8 17963 88928 2026-06-20T23:36:13Z en>Ioaxxere 0 Prefix page-preview CSS class; update constants 88928 javascript text/javascript // Page Previews for Wiktionary, by [[User:Ioaxxere]] // <nowiki> // Generated using: [[MediaWiki:Gadget-PagePreviews.js/ConstGeneration]] const INTERWIKI_PREFIXES = new Map([["aa","aa"],["ab","ab"],["abstract","abstract"],["acc",0],["ace","ace"],["acronym",0],["advisory",0],["ady","ady"],["af","af"],["ak","ak"],["als","als"],["alt","alt"],["am","am"],["ami","ami"],["an","an"],["ang","ang"],["ann","ann"],["anp","anp"],["antwiki",0],["appropedia",0],["aquariumwiki",0],["ar","ar"],["arbcom-zh",0],["arborwiki",0],["arc","arc"],["arxiv",0],["ary","ary"],["arz","arz"],["as","as"],["ast","ast"],["atj","atj"],["av","av"],["avk","avk"],["awa","awa"],["ay","ay"],["az","az"],["azb","azb"],["b",0],["ba","ba"],["ban","ban"],["bar","bar"],["bat-smg","bat-smg"],["battlestarwiki",0],["bbc","bbc"],["bcl","bcl"],["bcnbio",0],["bdr","bdr"],["be","be"],["be-tarask","be-tarask"],["be-x-old","be-tarask"],["beacha",0],["betawiki",0],["betawikiversity",0],["bew","bew"],["bg","bg"],["bh","bh"],["bi","bi"],["bibcode",0],["bibliowiki",0],["bjn","bjn"],["blk","blk"],["bm","bm"],["bn","bn"],["bo","bo"],["botwiki",0],["boxrec",0],["bpy","bpy"],["br","br"],["bs","bs"],["btm","btm"],["bug","bug"],["bugzilla",0],["bulba",0],["bxr","bxr"],["c",0],["c2",0],["ca","ca"],["cache",0],["cbk-zam","cbk-zam"],["ccorg",0],["cdo","cdo"],["ce","ce"],["ceb","ceb"],["centralwikia",0],["ch","ch"],["chapter",0],["cho","cho"],["choralwiki",0],["chr","chr"],["chy","chy"],["citizendium",0],["ckb","ckb"],["cmn","zh"],["co","co"],["commons",0],["communitywiki",0],["comune",0],["cr","cr"],["creativecommons",0],["creativecommonswiki",0],["crh","crh"],["cs","cs"],["csb","csb"],["cu","cu"],["cv","cv"],["cy","cy"],["cz","cs"],["d",0],["da","da"],["dag","dag"],["dbdump",0],["dcdatabase",0],["dcw",0],["de","de"],["debian",0],["devmo",0],["dga","dga"],["dico",0],["dicoado",0],["dict",0],["dictionary",0],["diffblog",0],["din","din"],["diq","diq"],["discord",0],["disinfopedia",0],["dk","da"],["dmoz",0],["dmozs",0],["doi",0],["donate",0],["doom_wiki",0],["download",0],["dpd",0],["dpla",0],["drae",0],["dsb","dsb"],["dtp","dtp"],["dty","dty"],["dv","dv"],["dz","dz"],["ee","ee"],["egl","eml"],["el","el"],["elibre",0],["emacswiki",0],["eml","eml"],["en","en"],["en-simple","simple"],["encyc",0],["englyphwiki",0],["enkol",0],["eo","eo"],["epo","eo"],["es","es"],["esolang",0],["et","et"],["etherpad",0],["etherpadbackup",0],["ethnologue",0],["ethnologuefamily",0],["eu","eu"],["exkcd",0],["exotica",0],["ext","ext"],["f",0],["fa","fa"],["fandom",0],["fanimutationwiki",0],["fat","fat"],["fedora",0],["ff","ff"],["fi","fi"],["finalfantasy",0],["finnix",0],["fiu-vro","fiu-vro"],["fj","fj"],["flickrphoto",0],["flickruser",0],["fo","fo"],["foldoc",0],["fon","fon"],["foundation",0],["foundationsite",0],["fr","fr"],["freebsdman",0],["freedomdefined",0],["freenode",0],["freesoft",0],["frp","frp"],["frr","frr"],["fur","fur"],["fy","fy"],["ga","ga"],["gag","gag"],["gan","gan"],["gcr","gcr"],["gd","gd"],["gentoo",0],["genwiki",0],["gerrit",0],["git",0],["github",0],["gitiles",0],["gitlab",0],["gl","gl"],["glk","glk"],["globalcontribs",0],["glottolog",0],["glottopedia",0],["gn","gn"],["gom","gom"],["google",0],["googledefine",0],["googlegroups",0],["gor","gor"],["got","got"],["gpe","gpe"],["gs",0],["gsw","als"],["gu","gu"],["guc","guc"],["gucprefix",0],["guildwarswiki",0],["gur","gur"],["gutenberg",0],["gutenbergwiki",0],["guw","guw"],["gv","gv"],["ha","ha"],["hackerspaces",0],["hak","hak"],["hammondwiki",0],["haw","haw"],["hdl",0],["he","he"],["heraldik",0],["hi","hi"],["hif","hif"],["ho","ho"],["horizonlabs",0],["hr","hr"],["hrfwiki",0],["hrwiki",0],["hsb","hsb"],["ht","ht"],["hu","hu"],["hy","hy"],["hyw","hyw"],["hz","hz"],["ia","ia"],["iarchive",0],["iba","iba"],["id","id"],["ie","ie"],["ig","ig"],["igl","igl"],["ii","ii"],["ik","ik"],["ilo","ilo"],["imdbcompany",0],["imdbname",0],["imdbtitle",0],["incubator",0],["infosphere",0],["inh","inh"],["io","io"],["irc",0],["ircrc",0],["ircs",0],["is","is"],["isni",0],["iso639-3",0],["issn",0],["it","it"],["iu","iu"],["ja","ja"],["jaglyphwiki",0],["jam","jam"],["jbo","jbo"],["jira",0],["jp","ja"],["jstor",0],["jv","jv"],["ka","ka"],["kaa","kaa"],["kab","kab"],["kai","kai"],["kaj","kaj"],["kamelo",0],["karlsruhe",0],["kbd","kbd"],["kbp","kbp"],["kcg","kcg"],["kg","kg"],["kge","kge"],["ki","ki"],["kj","kj"],["kk","kk"],["kl","kl"],["km","km"],["kn","kn"],["knc","knc"],["ko","ko"],["koi","koi"],["kr","kr"],["krc","krc"],["ks","ks"],["ksh","ksh"],["ku","ku"],["kus","kus"],["kv","kv"],["kw","kw"],["ky","ky"],["la","la"],["labsconsole",0],["lad","lad"],["lb","lb"],["lbe","lbe"],["lexemes",0],["lez","lez"],["lfn","lfn"],["lg","lg"],["li","li"],["liberachat",0],["libreplanet",0],["lij","lij"],["lingualibre",0],["linguistlist",0],["listarchive",0],["lld","lld"],["lmo","lmo"],["ln","ln"],["lo","lo"],["localwiki",0],["lofc",0],["lojban",0],["lokalhistoriewiki",0],["lostpedia",0],["lrc","lrc"],["lt","lt"],["ltg","ltg"],["luxo",0],["lv","lv"],["lzh","zh-classical"],["m",0],["mad","mad"],["mag","mag"],["mai","mai"],["mail",0],["mailarchive",0],["map-bms","map-bms"],["mariowiki",0],["marveldatabase",0],["mdf","mdf"],["mdwiki",0],["meatball",0],["mediawikiwiki",0],["mediazilla",0],["memoryalpha",0],["meta",0],["metawiki",0],["metawikimedia",0],["metawikipedia",0],["mg","mg"],["mh","mh"],["mhr","mhr"],["mi","mi"],["min","min"],["mineralienatlas",0],["miraheze",0],["mixnmatch",0],["mk","mk"],["ml","ml"],["mn","mn"],["mni","mni"],["mnw","mnw"],["mo","mo"],["moinmoin",0],["mos","mos"],["mosapedia",0],["mozillawiki",0],["mozillazinekb",0],["mr","mr"],["mrj","mrj"],["ms","ms"],["mt","mt"],["mus","mus"],["mw",0],["mwl","mwl"],["mwod",0],["mwot",0],["my","my"],["myv","myv"],["mzn","mzn"],["n",0],["na","na"],["nah","nah"],["nan","zh-min-nan"],["nap","nap"],["nara",0],["nb","no"],["nds","nds"],["nds-nl","nds-nl"],["ne","ne"],["new","new"],["ng","ng"],["nia","nia"],["nl","nl"],["nlab",0],["nn","nn"],["no","no"],["nost","nostalgia"],["nostalgia","nostalgia"],["nov","nov"],["nqo","nqo"],["nr","nr"],["nrm","nrm"],["nso","nso"],["nup","nup"],["nv","nv"],["ny","ny"],["oc","oc"],["oclc",0],["oeis",0],["oewiki",0],["oldwikisource",0],["olo","olo"],["olpc",0],["om","om"],["openlibrary",0],["openstreetmap",0],["openwetware",0],["or","or"],["organicdesign",0],["orthodoxwiki",0],["os","os"],["osmwiki",0],["otrs",0],["otrswiki",0],["outreach",0],["outreachwiki",0],["owasp",0],["pa","pa"],["pag","pag"],["pam","pam"],["pap","pap"],["paws",0],["pcd","pcd"],["pcm","pcm"],["pdc","pdc"],["petscan",0],["pfl","pfl"],["phab",0],["phabricator",0],["pi","pi"],["pih","pih"],["pl","pl"],["planetmath",0],["pmid",0],["pms","pms"],["pnb","pnb"],["pnt","pnt"],["pokewiki",0],["pokéwiki",0],["policy",0],["ppl","ppl"],["proofwiki",0],["ps","ps"],["pt","pt"],["pwn","pwn"],["pyrev",0],["pythoninfo",0],["q",0],["qu","qu"],["quality",0],["quarry",0],["rcirc",0],["regiowiki",0],["rev",0],["revo",0],["rfc",0],["rheinneckar",0],["rki","rki"],["rm","rm"],["rmy","rmy"],["rn","rn"],["ro","ro"],["roa-rup","roa-rup"],["roa-tara","roa-tara"],["rodovid",0],["rsk","rsk"],["rt",0],["ru","ru"],["rue","rue"],["rup","roa-rup"],["rw","rw"],["s",0],["sa","sa"],["sah","sah"],["sat","sat"],["sc","sc"],["scholar",0],["schoolswp",0],["schoolwiki",0],["scn","scn"],["sco","sco"],["scores",0],["scoutwiki",0],["sd","sd"],["se","se"],["securewikidc",0],["semantic-mw",0],["senseislibrary",0],["sep11",0],["sg","sg"],["sgs","bat-smg"],["sh","sh"],["sharemap",0],["shi","shi"],["shn","shn"],["shoutwiki",0],["shy","shy"],["si","si"],["silcode",0],["simple","simple"],["sk","sk"],["skr","skr"],["sl","sl"],["slashdot",0],["sm","sm"],["smn","smn"],["sn","sn"],["so","so"],["sourceforge",0],["spamcheck",0],["spcom",0],["species",0],["sq","sq"],["sr","sr"],["srn","srn"],["ss","ss"],["st","st"],["stats",0],["stewardry",0],["stq","stq"],["strategy",0],["strategywiki",0],["su","su"],["sulutil",0],["sv","sv"],["svn",0],["sw","sw"],["swtrain",0],["syl","syl"],["szl","szl"],["szy","szy"],["ta","ta"],["tardis",0],["tay","tay"],["tclerswiki",0],["tcy","tcy"],["tdd","tdd"],["te","te"],["tenwiki","ten"],["test2wiki","test2"],["testcommons",0],["testwiki","test"],["testwikidata",0],["tet","tet"],["tfwiki",0],["tg","tg"],["th","th"],["thelemapedia",0],["theopedia",0],["ti","ti"],["ticket",0],["tig","tig"],["tk","tk"],["tl","tl"],["tly","tly"],["tmbw",0],["tn","tn"],["to","to"],["tok","tok"],["tolkiengateway",0],["toolforge",0],["toolhub",0],["toollabs",0],["tools",0],["tpi","tpi"],["tr","tr"],["translatewiki",0],["trv","trv"],["ts","ts"],["tswiki",0],["tt","tt"],["tum","tum"],["tviv",0],["tw","tw"],["twiki",0],["twl",0],["ty","ty"],["tyv","tyv"],["tyvawiki",0],["udm","udm"],["ug","ug"],["uk","uk"],["umap",0],["uncyclopedia",0],["unihan",0],["ur","ur"],["urbandict",0],["usability",0],["usemod",0],["utrs",0],["uz","uz"],["v",0],["ve","ve"],["vec","vec"],["vep","vep"],["vi","vi"],["viaf",0],["vikidia",0],["vlos",0],["vls","vls"],["vo","vo"],["votewiki",0],["voy",0],["vro","fiu-vro"],["vrts",0],["vrtwiki",0],["w","en"],["wa","wa"],["war","war"],["wcna",0],["weirdgloop",0],["werelate",0],["wg","wg-en"],["wikia",0],["wikiapiary",0],["wikiasite",0],["wikibooks",0],["wikicities",0],["wikicity",0],["wikiconference",0],["wikidata",0],["wikiedudashboard",0],["wikifunctions",0],["wikifur",0],["wikihow",0],["wikiindex",0],["wikilivres",0],["wikilivresru",0],["wikimania",0],["wikimedia",0],["wikinews",0],["wikinfo",0],["wikinvest",0],["wikipapers",0],["wikipedia",0],["wikipediawikipedia",0],["wikiquote",0],["wikiskripta",0],["wikisophia",0],["wikisource",0],["wikisp",0],["wikispecies",0],["wikispore",0],["wikispot",0],["wikitech",0],["wikiti",0],["wikitrek",0],["wikiversity",0],["wikivoyage",0],["wikiwikiweb",0],["wikt",0],["wiktionary",0],["wm2005",0],["wm2006",0],["wm2007",0],["wm2008",0],["wm2009",0],["wm2010",0],["wm2011",0],["wm2012",0],["wm2013",0],["wm2014",0],["wm2015",0],["wm2016",0],["wm2017",0],["wm2018",0],["wmam",0],["wmania",0],["wmar",0],["wmat",0],["wmau",0],["wmbd",0],["wmbe",0],["wmbr",0],["wmca",0],["wmch",0],["wmcl",0],["wmcn",0],["wmco",0],["wmcz",0],["wmcz_docs",0],["wmcz_old",0],["wmdc",0],["wmde",0],["wmdeblog",0],["wmdk",0],["wmdoc",0],["wmec",0],["wmee",0],["wmes",0],["wmet",0],["wmf",0],["wmfblog",0],["wmfdashboard",0],["wmfi",0],["wmfr",0],["wmge",0],["wmhi",0],["wmhk",0],["wmhu",0],["wmid",0],["wmil",0],["wmin",0],["wmit",0],["wmke",0],["wmmk",0],["wmmx",0],["wmnl",0],["wmno",0],["wmnoc",0],["wmnoch",0],["wmnyc",0],["wmpa-us",0],["wmph",0],["wmpl",0],["wmplsite",0],["wmpt",0],["wmpunjabi",0],["wmromd",0],["wmrs",0],["wmru",0],["wmse",0],["wmsk",0],["wmteam",0],["wmtr",0],["wmtw",0],["wmua",0],["wmuk",0],["wmve",0],["wmza",0],["wo","wo"],["wookieepedia",0],["wowwiki",0],["wplibrary",0],["wurmpedia",0],["wuu","wuu"],["xal","xal"],["xh","xh"],["xkcd",0],["xmf","xmf"],["xtools",0],["yi","yi"],["yo","yo"],["yue","zh-yue"],["za","za"],["zea","zea"],["zgh","zgh"],["zh","zh"],["zh-classical","zh-classical"],["zh-cn","zh"],["zh-min-nan","zh-min-nan"],["zh-tw","zh"],["zh-yue","zh-yue"],["zu","zu"],["zum",0]]); const WP_LANGUAGES = new Map([["ab","Abkhazian"],["ace","Acehnese"],["ady","Adyghe"],["af","Afrikaans"],["als","Alemannic"],["alt","Southern Altai"],["am","Amharic"],["ami","Amis"],["an","Aragonese"],["ang","Old English"],["ann","Obolo"],["anp","Angika"],["ar","Arabic"],["arc","Aramaic"],["ary","Moroccan Arabic"],["arz","Egyptian Arabic"],["as","Assamese"],["ast","Asturian"],["atj","Atikamekw"],["av","Avaric"],["avk","Kotava"],["awa","Awadhi"],["ay","Aymara"],["az","Azerbaijani"],["azb","South Azerbaijani"],["ba","Bashkir"],["ban","Balinese"],["bar","Bavarian"],["bat-smg","Samogitian"],["bbc","Batak Toba"],["bcl","Central Bikol"],["bdr","West Coast Bajau"],["be","Belarusian"],["be-tarask","Belarusian (Taraškievica orthography)"],["bew","Betawi"],["bg","Bulgarian"],["bh","Bhojpuri"],["bi","Bislama"],["bjn","Banjar"],["blk","Pa'O"],["bm","Bambara"],["bn","Bangla"],["bo","Tibetan"],["bpy","Bishnupriya"],["br","Breton"],["bs","Bosnian"],["btm","Batak Mandailing"],["bug","Buginese"],["bxr","Russia Buriat"],["ca","Catalan"],["cbk-zam","Chavacano"],["cdo","Mindong"],["ce","Chechen"],["ceb","Cebuano"],["ch","Chamorro"],["chr","Cherokee"],["chy","Cheyenne"],["ckb","Central Kurdish"],["co","Corsican"],["crh","Crimean Tatar"],["cs","Czech"],["csb","Kashubian"],["cu","Church Slavic"],["cv","Chuvash"],["cy","Welsh"],["da","Danish"],["dag","Dagbani"],["de","German"],["dga","Southern Dagaare"],["din","Dinka"],["diq","Dimli"],["dsb","Lower Sorbian"],["dtp","Central Dusun"],["dty","Doteli"],["dv","Divehi"],["dz","Dzongkha"],["ee","Ewe"],["el","Greek"],["eml","Emiliano-Romagnolo"],["en","English"],["eo","Esperanto"],["es","Spanish"],["et","Estonian"],["eu","Basque"],["ext","Extremaduran"],["fa","Persian"],["fat","Fanti"],["ff","Fula"],["fi","Finnish"],["fiu-vro","Võro"],["fj","Fijian"],["fo","Faroese"],["fon","Fon"],["fr","French"],["frp","Arpitan"],["frr","Northern Frisian"],["fur","Friulian"],["fy","Western Frisian"],["ga","Irish"],["gag","Gagauz"],["gan","Gan"],["gcr","Guianan Creole"],["gd","Scottish Gaelic"],["gl","Galician"],["glk","Gilaki"],["gn","Guarani"],["gom","Goan Konkani"],["gor","Gorontalo"],["got","Gothic"],["gpe","Ghanaian Pidgin"],["gu","Gujarati"],["guc","Wayuu"],["gur","Frafra"],["guw","Gun"],["gv","Manx"],["ha","Hausa"],["hak","Hakka Chinese"],["haw","Hawaiian"],["he","Hebrew"],["hi","Hindi"],["hif","Fiji Hindi"],["hr","Croatian"],["hsb","Upper Sorbian"],["ht","Haitian Creole"],["hu","Hungarian"],["hy","Armenian"],["hyw","Western Armenian"],["ia","Interlingua"],["iba","Iban"],["id","Indonesian"],["ie","Interlingue"],["ig","Igbo"],["igl","Igala"],["ik","Inupiaq"],["ilo","Iloko"],["inh","Ingush"],["io","Ido"],["is","Icelandic"],["it","Italian"],["iu","Inuktitut"],["ja","Japanese"],["jam","Jamaican Creole English"],["jbo","Lojban"],["jv","Javanese"],["ka","Georgian"],["kaa","Kara-Kalpak"],["kab","Kabyle"],["kai","Karekare"],["kaj","Jju"],["kbd","Kabardian"],["kbp","Kabiye"],["kcg","Tyap"],["kg","Kongo"],["kge","Komering"],["ki","Kikuyu"],["kk","Kazakh"],["km","Khmer"],["kn","Kannada"],["knc","Central Kanuri"],["ko","Korean"],["koi","Komi-Permyak"],["krc","Karachay-Balkar"],["ks","Kashmiri"],["ksh","Colognian"],["ku","Kurdish"],["kus","Kusaal"],["kv","Komi"],["kw","Cornish"],["ky","Kyrgyz"],["la","Latin"],["lad","Ladino"],["lb","Luxembourgish"],["lbe","Lak"],["lez","Lezghian"],["lfn","Lingua Franca Nova"],["lg","Ganda"],["li","Limburgish"],["lij","Ligurian"],["lld","Ladin"],["lmo","Lombard"],["ln","Lingala"],["lo","Lao"],["lt","Lithuanian"],["ltg","Latgalian"],["lv","Latvian"],["mad","Madurese"],["mag","Magahi"],["mai","Maithili"],["map-bms","Banyumasan"],["mdf","Moksha"],["mg","Malagasy"],["mhr","Eastern Mari"],["mi","Māori"],["min","Minangkabau"],["mk","Macedonian"],["ml","Malayalam"],["mn","Mongolian"],["mni","Manipuri"],["mnw","Mon"],["mos","Mossi"],["mr","Marathi"],["mrj","Western Mari"],["ms","Malay"],["mt","Maltese"],["mwl","Mirandese"],["my","Burmese"],["myv","Erzya"],["mzn","Mazanderani"],["nah","Nahuatl"],["nap","Neapolitan"],["nds","Low German"],["nds-nl","Low Saxon"],["ne","Nepali"],["new","Newari"],["nia","Nias"],["nl","Dutch"],["nn","Norwegian Nynorsk"],["no","Norwegian"],["nov","Novial"],["nqo","N’Ko"],["nr","South Ndebele"],["nrm","Norman"],["nso","Northern Sotho"],["nup","Nupe"],["nv","Navajo"],["ny","Nyanja"],["oc","Occitan"],["olo","Livvi-Karelian"],["om","Oromo"],["or","Odia"],["os","Ossetic"],["pa","Punjabi"],["pag","Pangasinan"],["pam","Pampanga"],["pap","Papiamento"],["pcd","Picard"],["pcm","Nigerian Pidgin"],["pdc","Pennsylvania German"],["pfl","Palatine German"],["pi","Pali"],["pl","Polish"],["pms","Piedmontese"],["pnb","Western Punjabi"],["pnt","Pontic"],["ppl","Nawat"],["ps","Pashto"],["pt","Portuguese"],["pwn","Paiwan"],["qu","Quechua"],["rki","Arakanese"],["rm","Romansh"],["rmy","Vlax Romani"],["rn","Rundi"],["ro","Romanian"],["roa-rup","Aromanian"],["roa-tara","Tarantino"],["rsk","Pannonian Rusyn"],["ru","Russian"],["rue","Rusyn"],["rw","Kinyarwanda"],["sa","Sanskrit"],["sah","Yakut"],["sat","Santali"],["sc","Sardinian"],["scn","Sicilian"],["sco","Scots"],["sd","Sindhi"],["se","Northern Sami"],["sg","Sango"],["sh","Serbo-Croatian"],["shi","Tachelhit"],["shn","Shan"],["si","Sinhala"],["simple","Simple English"],["sk","Slovak"],["skr","Saraiki"],["sl","Slovenian"],["sm","Samoan"],["smn","Inari Sami"],["sn","Shona"],["so","Somali"],["sq","Albanian"],["sr","Serbian"],["srn","Sranan Tongo"],["ss","Swati"],["st","Southern Sotho"],["stq","Saterland Frisian"],["su","Sundanese"],["sv","Swedish"],["sw","Swahili"],["syl","Sylheti"],["szl","Silesian"],["szy","Sakizaya"],["ta","Tamil"],["tay","Atayal"],["tcy","Tulu"],["tdd","Tai Nuea"],["te","Telugu"],["tet","Tetum"],["tg","Tajik"],["th","Thai"],["ti","Tigrinya"],["tig","Tigre"],["tk","Turkmen"],["tl","Tagalog"],["tly","Talysh"],["tn","Tswana"],["to","Tongan"],["tok","Toki Pona"],["tpi","Tok Pisin"],["tr","Turkish"],["trv","Taroko"],["ts","Tsonga"],["tt","Tatar"],["tum","Tumbuka"],["tw","Twi"],["ty","Tahitian"],["tyv","Tuvinian"],["udm","Udmurt"],["ug","Uyghur"],["uk","Ukrainian"],["ur","Urdu"],["uz","Uzbek"],["ve","Venda"],["vec","Venetian"],["vep","Veps"],["vi","Vietnamese"],["vls","West Flemish"],["vo","Volapük"],["wa","Walloon"],["war","Waray"],["wo","Wolof"],["wuu","Wu"],["xal","Kalmyk"],["xh","Xhosa"],["xmf","Mingrelian"],["yi","Yiddish"],["yo","Yoruba"],["za","Zhuang"],["zea","Zeelandic"],["zgh","Standard Moroccan Tamazight"],["zh","Chinese"],["zh-classical","Literary Chinese"],["zh-min-nan","Minnan"],["zh-yue","Cantonese"],["zu","Zulu"]]); const appendixWithSlash = ["Adûni", "Afrihili", "Arabic_roots", "Belter_Creole", "Bibliography", "Black_Speech", "Bolak", "Communicationssprache", "Dothraki", "Eloi", "Gestures", "Glosa", "Goa'uld", "High_Valyrian", "Idiom_Neutral", "Interlingue", "Interslavic", "Klingon", "Kotava", "Láadan", "Lapine", "Lingua_Franca_Nova", "Lojban", "Mandalorian", "Medefaidrin", "Minecraft", "Mundolinco", "Na'vi", "Neo", "Novial", "Noxilo", "Protologisms/Long_words", "Quenya", "Romanova", "Sindarin", "Snowclones", "Talossan", "Toki_Pona", "Unas"]; const appendixNoSlash = ["Boldface", "Capital_letter", "Italics", "Lowercase_letter", "Possessive", "Repetition", "Small_caps", "Strikethrough", "Subscript", "Superscript", "Underline", "Uppercase_letter"]; const animationSpeed = 0.2; // seconds mw.util.addCSS(` .wikt-page-preview ol { margin: 0 0.5em 0 1.5em; padding: 0; } .wikt-page-preview dl { margin-bottom: 0; } .wikt-page-preview p { margin: 0; } /* popupContainer has the opacity animation, while popup gets translated. */ .popup-fade-in-up, .popup-fade-in-down { animation: popup-fade-in ${animationSpeed}s ease forwards; } .popup-fade-out-up, .popup-fade-out-down { animation: popup-fade-out ${animationSpeed}s ease forwards; } .popup-fade-in-up > div { animation: popup-move-in-up ${animationSpeed}s ease forwards; } .popup-fade-in-down > div { animation: popup-move-in-down ${animationSpeed}s ease forwards; } .popup-fade-out-up > div { animation: popup-move-out-up ${animationSpeed}s ease forwards; } .popup-fade-out-down > div { animation: popup-move-out-down ${animationSpeed}s ease forwards; } @keyframes popup-move-in-up { 0% { transform: translate(0, 20px); } } @keyframes popup-move-in-down { 0% { transform: translate(0, -20px); } } @keyframes popup-move-out-up { 100% { transform: translate(0, -20px); } } @keyframes popup-move-out-down { 100% { transform: translate(0, 20px); } } @keyframes popup-fade-out { 100% { opacity: 0; } } @keyframes popup-fade-in { 0% { opacity: 0; } } .ring-loader { margin: auto; width: 24px; height: 24px; border-radius: 50%; border-top: 5px solid var(--wikt-palette-black); border-bottom: 5px solid var(--wikt-palette-black); border-left: 5px solid transparent; border-right: 5px solid transparent; animation: spin 1.2s linear infinite; } @keyframes spin { 100% { transform: rotate(360deg); } } .preview-headerlink, .preview-headerlink:visited { color: inherit; font-weight: bold; } /* Hack: get the speaker icon on Wikipedia articles without having to load Phonos. */ .ext-phonos .oo-ui-buttonElement-button:after { content: "🔊"; } .ext-phonos * { display: inline !important; padding: 0 !important; margin: 0 !important; } `); const definitionIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M15 2a7.65 7.65 0 00-5 2 7.65 7.65 0 00-5-2H1v15h4a7.65 7.65 0 015 2 7.65 7.65 0 015-2h4V2zm2.5 13.5H14a4.38 4.38 0 00-3 1V5s1-1.5 4-1.5h2.5z"></path></g></svg>`; const glossaryIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M12.43 14.34A5 5 0 0110 15a5 5 0 113.95-2L17 16.09V3a2 2 0 00-2-2H5a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 001.45-.63z"></path><circle cx="10" cy="10" r="3"></circle></g></svg>`; const articleIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V3a2 2 0 00-2-2zm0 3h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"></path></g></svg>`; const bibliographyIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M3 2h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H3c0 0 .5-.5.5-1V3c0-.5-.5-1-.5-1zM4 6h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H4c0 0 .5-.5.5-1V7c0-.5-.5-1-.5-1zM3 10h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H3c0 0 .5-.5.5-1v-1c0-.5-.5-1-.5-1zM4 14h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H4c0 0 .5-.5.5-1v-1c0-.5-.5-1-.5-1z"/></g></svg>`; const loader = document.createElement("div"); loader.className = "ring-loader"; const popupContainer = document.createElement("div"); const popup = document.createElement("div"); const popupContent = document.createElement("div"); popupContainer.style = `display: none; position: absolute; filter: drop-shadow(0px 30px 30px rgba(0, 0, 0, 0.15)) drop-shadow(0px 0px 0.75px var(--wikt-palette-dullblue)); z-index: 801`; popupContainer.className = "wikt-page-preview"; popup.style = "box-sizing: border-box; height: 100%; background: var(--wikt-palette-white)"; popupContent.style = "display: flex; flex-direction: column; border-radius: 2px; box-sizing: border-box; color: var(--wikt-palette-black); overflow: auto; height: 100%; overflow-wrap: break-word; scrollbar-width: thin"; document.body.append(popupContainer); popupContainer.append(popup); popup.append(popupContent); let popupTimer; let openLink; let mouseX, mouseY; let API_controller = new AbortController(); function closePopup() { if (!openLink) return; openLink = null; API_controller.abort(); API_controller = new AbortController(); if (popupContainer.classList.contains("popup-fade-in-up")) { popupContainer.classList.remove("popup-fade-in-up"); popupContainer.classList.add("popup-fade-out-down"); } else { popupContainer.classList.remove("popup-fade-in-down"); popupContainer.classList.add("popup-fade-out-up"); } // After the animation has completed, reset the popup to its initial state. setTimeout(() => { popupContainer.style.display = "none"; popupContainer.classList.remove("popup-fade-out-down", "popup-fade-out-up"); }, animationSpeed * 1000); } popup.addEventListener("pointerenter", () => { clearTimeout(popupTimer); }); popup.addEventListener("pointerleave", () => { clearTimeout(popupTimer); popupTimer = setTimeout(closePopup, 300); }); function processLink(link) { let linkTitle = decodeURIComponent(link.pathname.split("/wiki/")[1]); let titlePrefix = linkTitle.includes(":") ? linkTitle.toLowerCase().split(":")[0] : ""; let resolvedTitle = linkTitle; let API_domain = link.origin; let linkAnchor = decodeURIComponent(link.hash.slice(1) || ""); let isWPlink = link.href.match(/^https:\/\/[^.]+.wikipedia.org\/wiki\//); let isPreviewLink = Boolean(link.closest(".wikt-page-preview")); let isGlossary = /^Appendix:.*[Gg]lossary$/.test(linkTitle); // Start with various checks to determine whether a link should be processed. if (link.matches(`nav a, .cancelLink a, .mw-widget-titleOptionWidget a, .new, .preview-headerlink, .external, [href$="#"]`)) { return; } else if (isGlossary) { // Links to glossary *must* have an anchor. if (!linkAnchor) return; } else if (linkTitle.startsWith("Appendix:Bibliography/")) { // Bibliography subpages must have an anchor starting with `bib-`. if (!linkAnchor || !linkAnchor.startsWith("bib-")) return; } else if (!isWPlink) { // Other Wiktionary pages must not have a lowercase-starting anchor (filters out some unhelpful links). if (/^[a-z]/.test(linkAnchor)) return; } if (link.href.startsWith("https://en.wiktionary.org/wiki/")) { // Filter out all interwiki prefixes. if (INTERWIKI_PREFIXES.has(titlePrefix)) return; let {namespace, title} = new mw.Title(linkTitle); if (namespace === 0) { // Mainspace if (title.endsWith("/translations")) return; } else if (namespace === 100) { // Appendix space if (!appendixWithSlash.some(lang => title.startsWith(lang + "/")) && !appendixNoSlash.includes(title) && !isGlossary) return; } else if (namespace !== 118) { // Reconstruction space return; } } else if (isWPlink) { // Filter out invalid interwiki prefixes. if (INTERWIKI_PREFIXES.get(titlePrefix) === 0) return; // Get the resolved title if it's a language interwiki. if (INTERWIKI_PREFIXES.has(titlePrefix)) { API_domain = `https://${INTERWIKI_PREFIXES.get(titlePrefix)}.wikipedia.org`; resolvedTitle = linkTitle.substring(linkTitle.indexOf(":") + 1); // If the resolved title contains another interwiki, return. let resolvedTitlePrefix = resolvedTitle.includes(":") ? resolvedTitle.toLowerCase().split(":")[0] : ""; // same as titlePrefix if (INTERWIKI_PREFIXES.has(resolvedTitlePrefix)) return; } } else { return; } link.addEventListener("pointerover", event => { [mouseX, mouseY] = [event.clientX, event.clientY]; clearTimeout(popupTimer); // Ignore links which are already open. if (link === openLink) return; if (!isPreviewLink) closePopup(); // Fetch popup text immediately on hover to reduce delay. let responsePromise = fetch(`${API_domain}/api/rest_v1/page/html/${encodeURIComponent(resolvedTitle)}`, { headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}, signal: API_controller.signal }).then(r => r.text()).catch(() => { /* fetch was aborted */ }); popupTimer = setTimeout(() => { popupContainer.style.display = ""; popupContent.innerHTML = ""; popupContent.append(loader); popupContent.style.padding = "14px 16px 8px"; // Disable link hovering until animation has completed. popupContent.style.pointerEvents = "none"; setTimeout(() => popupContent.style.pointerEvents = "", animationSpeed * 1000); // Adapt the popup for large, standard, and small size preference in Vector 2022. let sizeSetting = 0; if (document.documentElement.matches(".vector-feature-custom-font-size-clientpref-1")) sizeSetting = 1; else if (document.documentElement.matches(".vector-feature-custom-font-size-clientpref-2")) sizeSetting = 2; let width = [320, 340, 360][sizeSetting]; let height = [210, 225, 240][sizeSetting]; let triangleSize = [9, 10, 11][sizeSetting]; popupContainer.style.fontSize = ["14px", "15px", "17px"][sizeSetting]; popupContainer.style.lineHeight = ["21px", "22px", "24px"][sizeSetting]; popupContainer.style.width = width + "px"; popupContainer.style.height = height + "px"; if (isPreviewLink) { // Trigger fade-in-down animation. popupContainer.classList.remove("popup-fade-in-up", "popup-fade-in-down"); void popupContainer.offsetLeft; // force reflow popupContainer.classList.add("popup-fade-in-down"); } else { openLink = link; // Get list of rects (lines) of the target element, then find the one whose midpoint is closest to mouseY. // This ensures that the code can correctly handle multi-line links. let linkBlock = [...event.target.getClientRects()].reduce((prev, next) => Math.abs((next.top + next.bottom) / 2 - mouseY) < Math.abs((prev.top + prev.bottom) / 2 - mouseY) ? next : prev); // Horizontal position. Choose left or right depending on the side of the screen the mouse is in. let leftPosition = mouseX - 30; if (mouseX > document.documentElement.clientWidth / 2) leftPosition = mouseX - width + 30; // Ensure that the popup is at least 5px away from the side of the screen. leftPosition = Math.max(5, Math.min(leftPosition, document.documentElement.clientWidth - width - 5)); popupContainer.style.left = leftPosition + document.documentElement.scrollLeft + "px"; // Vertical position. Prioritize fade-in-down unless there would be less than 10px of room above. if (linkBlock.top > height + 10 || linkBlock.top > document.documentElement.clientHeight - linkBlock.bottom) { popupContainer.style.top = linkBlock.top + document.documentElement.scrollTop - height + "px"; popupContainer.classList.add("popup-fade-in-down"); popup.style.padding = `0 0 ${triangleSize}px`; // Create a triangle on the bottom. popup.style.clipPath = `polygon(0 0, 100% 0, 100% calc(100% - ${triangleSize}px), ${mouseX - leftPosition + triangleSize}px calc(100% - ${triangleSize}px), ${mouseX - leftPosition}px 100%, ${mouseX - leftPosition - triangleSize}px calc(100% - ${triangleSize}px), 0 calc(100% - ${triangleSize}px))`; } else { popupContainer.style.top = linkBlock.bottom + document.documentElement.scrollTop + "px"; popupContainer.classList.add("popup-fade-in-up"); popup.style.padding = `${triangleSize}px 0 0`; // Create a triangle on top. popup.style.clipPath = `polygon(0 ${triangleSize}px, ${mouseX - leftPosition - triangleSize}px ${triangleSize}px, ${mouseX - leftPosition}px 0, ${mouseX - leftPosition + triangleSize}px ${triangleSize}px, 100% ${triangleSize}px, 100% 100%, 0 100%)`; } } responsePromise.then(response => { if (!response) return; // if the fetch was aborted popupContent.innerHTML = ""; let responseDocument = new DOMParser().parseFromString(response, "text/html"); // Convert to absolute URLs. responseDocument.querySelectorAll("a[href]").forEach(link => link.setAttribute("href", link.href)); let anchoredElement = responseDocument.getElementById(linkAnchor); let popupHeader = document.createElement("div"); popupHeader.style = "font-size: 90%; color: var(--wikt-palette-deepblue)"; popupContent.append(popupHeader); let iconContainer = document.createElement("span"); iconContainer.style = "float: right; margin-left: 10px; height: 20px; color: var(--wikt-palette-black)"; popupHeader.append(iconContainer); let titleLink = document.createElement("a"); titleLink.href = link.href; titleLink.title = link.title; titleLink.className = "skin-invert-image preview-headerlink"; // Scrape entry content. if (isWPlink) { iconContainer.innerHTML = articleIcon; titleLink.textContent = linkTitle.replaceAll("_", " "); if (responseDocument.title) titleLink.innerHTML = responseDocument.title; // sometimes gives HTML text let WikipediaName = WP_LANGUAGES.get(API_domain.substr(8).split(".")[0]); popupHeader.append(WikipediaName + " Wikipedia article for ", titleLink); let articleContent = document.createElement("div"); articleContent.style.margin = "5px 0 0 10px"; let firstSection = responseDocument.querySelector("section"); if (firstSection && responseDocument.querySelector(`meta[property="mw:pageNamespace"][content="0"]`)) { firstSection.querySelectorAll("b").forEach(boldElem => boldElem.outerHTML = boldElem.innerHTML); firstSection.querySelectorAll(":scope > p, :scope > ul, :scope > ol").forEach(elem => articleContent.append(elem)); } if (articleContent.childElementCount) popupContent.append(articleContent); } else if (isGlossary) { iconContainer.innerHTML = glossaryIcon; titleLink.textContent = linkAnchor.replaceAll("_", " "); popupHeader.append("Glossary definition of ", titleLink); if (anchoredElement && anchoredElement.matches(".template-anchor")) { // Get succeeding `dd` elements. The HTML is <dt>...<span class="template-anchor"></span>...</dt><dd>...</dd><dd>...</dd> for (let elem = anchoredElement.parentElement.nextElementSibling; elem && elem.matches("dd"); elem = elem.nextElementSibling) { elem.style = "margin: 5px 0 0 15px"; popupContent.append(elem.cloneNode(true)); } } } else if (linkTitle.startsWith("Appendix:Bibliography/")) { iconContainer.innerHTML = bibliographyIcon; let language = linkTitle.slice(22).replaceAll("_", " "); // trim "Appendix:Bibliography/" prefix popupHeader.append(`${language} bibliography`); if (anchoredElement && anchoredElement.matches(".bibliography-id")) { let bibliographyCitation = document.createElement("div"); bibliographyCitation.style = "margin: 5px 0 0 15px"; bibliographyCitation.innerHTML = anchoredElement.innerHTML; popupContent.append(bibliographyCitation); } } else { const hasDefinitions = elem => Boolean(elem.querySelector("ol:not(.references), .ja-see, .zh-see")); iconContainer.innerHTML = definitionIcon; // Try to resolve the anchor element to #Chinese. if (!anchoredElement && ["Cantonese", "Gan", "Hakka", "Hokkien", "Literary_Chinese", "Mandarin", "Middle_Chinese", "Old_Chinese", "Wu", "Xiang"].includes(linkAnchor)) anchoredElement = responseDocument.querySelector("#Chinese"); // Try to guess the anchor target in the following order: English, Chinese, Translingual, [first h2 on page] // Always prioritize an L2 section which contains definitions. if (!linkAnchor) { let pageH2s = [...responseDocument.querySelectorAll("h2")]; if (pageH2s.some(h2 => hasDefinitions(h2.parentElement))) pageH2s = pageH2s.filter(h2 => hasDefinitions(h2.parentElement)); anchoredElement = pageH2s.find(h2 => h2.id === "English"); if (!anchoredElement) anchoredElement = pageH2s.find(h2 => h2.id === "Chinese"); if (!anchoredElement) anchoredElement = pageH2s.find(h2 => h2.id === "Translingual"); if (!anchoredElement) anchoredElement = pageH2s[0]; } let displayTitle = document.createElement("strong"); displayTitle.textContent = linkTitle.split("/").pop().replaceAll("_", " "); if (linkTitle.startsWith("Reconstruction:")) displayTitle.textContent = "*" + displayTitle.textContent; // Find localest section containing an h2. let languageSection = anchoredElement; while (languageSection && !languageSection.querySelector(":scope > h2")) languageSection = languageSection.parentElement.closest("section"); // Make sure that the entry is well-formed. if (languageSection) { let language = languageSection.querySelector(":scope > h2").textContent; let scrapeSection = anchoredElement.closest("section"); // Find localest section which contains any definitions. while (scrapeSection && !hasDefinitions(scrapeSection)) scrapeSection = scrapeSection.parentElement.closest("section"); if (scrapeSection) { let headwords = [...scrapeSection.querySelectorAll(".headword-line > strong")]; if (new Set(headwords.map(h => h.textContent)).size === 1) { // If there is a single unique headword, replace the display title with that. displayTitle = headwords[0]; if (displayTitle.querySelector("a > img")) displayTitle = displayTitle.querySelector("a > img").cloneNode(); } else if (new Set(headwords.map(h => h.cloneNode().outerHTML)).size === 1) { // If there is a single unique set of element attributes, use that with the display title. headwords[0].innerHTML = displayTitle.innerHTML; displayTitle = headwords[0]; } // Remove existing links in the headword. displayTitle.querySelectorAll("a").forEach(elem => elem.replaceWith(elem.textContent)); let ols = scrapeSection.querySelectorAll(":scope > ol:not(.references), section > ol:not(.references)"); if (anchoredElement.matches(".senseid")) { [...anchoredElement.parentElement.childNodes].forEach(child => { if (child !== anchoredElement) child.remove(); }); ols = [anchoredElement.closest("ol")]; } for (let ol of ols) { let POS_container = document.createElement("div"); POS_container.style.margin = "8px 0 5px 0"; let POS = document.createElement("span"); POS.style = "font-size: 110%; font-weight: bold"; POS.textContent = ol.closest("section").firstChild.textContent; POS_container.append(POS); let tlb = ol.closest("section").querySelector(".headword-line ~ .usage-label-term"); if (tlb) POS_container.append(document.createElement("br"), tlb); popupContent.append(POS_container, ol); } // {{ja-see}} and {{zh-see}} don't follow the normal format, so just insert them verbatim. for (let seeTemplate of scrapeSection.querySelectorAll(".ja-see, .zh-see")) popupContent.append(seeTemplate); } titleLink.append(displayTitle); popupHeader.append("Preview definitions of " + language + " ", titleLink); } else { titleLink.append(displayTitle); popupHeader.append("Preview definitions of ", titleLink); } } // Post-fetch error handling. if (popupContent.childElementCount > 1) { // Clean up HTML. popupContent.querySelectorAll("link, .previewonly, .maintenance-line, .mw-empty-elt, .reference, .Inline-Template, .vsHide").forEach(elem => elem.remove()); if (!isWPlink) popupContent.querySelectorAll("li > ul").forEach(elem => elem.remove()); // remove quotations for (let elem of popupContent.querySelectorAll("*")) elem.removeAttribute("id"); // avoid inadvertently repeating IDs within a page } else if (isWPlink) { // Display a message if the Wikipedia article was invalid or not in mainspace. let noArticle = document.createElement("div"); noArticle.style = "margin: 5px 0 0 15px; font-size: 90%"; noArticle.textContent = "(article content could not be previewed)"; popupContent.append(noArticle); } else if (linkAnchor && !anchoredElement) { // Display a message if the anchor is invalid. let noSectionFound = document.createElement("div"); noSectionFound.style = "margin: 10px 0 0 7.5px; font-size: 90%"; let strong = document.createElement("strong"); strong.textContent = linkAnchor.replaceAll("_", " "); noSectionFound.append("The ", strong, " section was not found on this page."); popupContent.append(noSectionFound); } else { // Display a message if no definitions were found in the section. let noDefinitionsFound = document.createElement("div"); noDefinitionsFound.style = "margin: 5px 0 0 15px; font-size: 90%"; noDefinitionsFound.textContent = "(no definitions found)"; popupContent.append(noDefinitionsFound); } // Reduce the padding if a scrollbar is present. The intended padding is 16px on each side. if (width - popupHeader.clientWidth > 32) popupContent.style.paddingRight = Math.max(4, 48 + popupHeader.clientWidth - width) + "px"; }); // (Hack?) make sure that `link pointerleave` doesn't cause the popup to immediately close. setTimeout(() => clearTimeout(popupTimer), 0); }, isPreviewLink ? 1200 : 400); }); link.addEventListener("pointerout", () => { clearTimeout(popupTimer); if (link === openLink) { popupTimer = setTimeout(closePopup, 300); } else { API_controller.abort(); API_controller = new AbortController(); } }); link.addEventListener("pointermove", event => [mouseX, mouseY] = [event.clientX, event.clientY]); link.addEventListener("click", () => clearTimeout(popupTimer)); } // Process all links. document.querySelectorAll("a").forEach(processLink); // Process links which are added to the DOM after the gadget has run. (new MutationObserver(events => events.flatMap(event => [...event.addedNodes]).forEach(node => { if (node instanceof HTMLAnchorElement) processLink(node); if (node instanceof HTMLElement) node.querySelectorAll("a").forEach(processLink); }))).observe(document.body, {childList: true, subtree: true}); // Dispatch hover events to support [[w:MediaWiki:Gadget-ReferenceTooltips.js]]. const linkEvent = ev => openLink && openLink.dispatchEvent(new Event(ev, {bubbles: true, cancelable: true})); // Note: for some reason an event listener on `popup` doesn't catch everything... popupContainer.addEventListener("pointerenter", () => setTimeout(() => linkEvent("mouseover"))); popupContainer.addEventListener("pointerleave", () => linkEvent("mouseout")); // Custom events popupContainer.addEventListener("pointerenter", () => linkEvent("linkPopupHover")); popupContainer.addEventListener("pointerleave", () => linkEvent("linkPopupUnhover")); // </nowiki> m7wjlrwv96nlex8o1osdzwat04davci 88929 88928 2026-08-06T23:15:37Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-PagePreviews.js]] 88928 javascript text/javascript // Page Previews for Wiktionary, by [[User:Ioaxxere]] // <nowiki> // Generated using: [[MediaWiki:Gadget-PagePreviews.js/ConstGeneration]] const INTERWIKI_PREFIXES = new Map([["aa","aa"],["ab","ab"],["abstract","abstract"],["acc",0],["ace","ace"],["acronym",0],["advisory",0],["ady","ady"],["af","af"],["ak","ak"],["als","als"],["alt","alt"],["am","am"],["ami","ami"],["an","an"],["ang","ang"],["ann","ann"],["anp","anp"],["antwiki",0],["appropedia",0],["aquariumwiki",0],["ar","ar"],["arbcom-zh",0],["arborwiki",0],["arc","arc"],["arxiv",0],["ary","ary"],["arz","arz"],["as","as"],["ast","ast"],["atj","atj"],["av","av"],["avk","avk"],["awa","awa"],["ay","ay"],["az","az"],["azb","azb"],["b",0],["ba","ba"],["ban","ban"],["bar","bar"],["bat-smg","bat-smg"],["battlestarwiki",0],["bbc","bbc"],["bcl","bcl"],["bcnbio",0],["bdr","bdr"],["be","be"],["be-tarask","be-tarask"],["be-x-old","be-tarask"],["beacha",0],["betawiki",0],["betawikiversity",0],["bew","bew"],["bg","bg"],["bh","bh"],["bi","bi"],["bibcode",0],["bibliowiki",0],["bjn","bjn"],["blk","blk"],["bm","bm"],["bn","bn"],["bo","bo"],["botwiki",0],["boxrec",0],["bpy","bpy"],["br","br"],["bs","bs"],["btm","btm"],["bug","bug"],["bugzilla",0],["bulba",0],["bxr","bxr"],["c",0],["c2",0],["ca","ca"],["cache",0],["cbk-zam","cbk-zam"],["ccorg",0],["cdo","cdo"],["ce","ce"],["ceb","ceb"],["centralwikia",0],["ch","ch"],["chapter",0],["cho","cho"],["choralwiki",0],["chr","chr"],["chy","chy"],["citizendium",0],["ckb","ckb"],["cmn","zh"],["co","co"],["commons",0],["communitywiki",0],["comune",0],["cr","cr"],["creativecommons",0],["creativecommonswiki",0],["crh","crh"],["cs","cs"],["csb","csb"],["cu","cu"],["cv","cv"],["cy","cy"],["cz","cs"],["d",0],["da","da"],["dag","dag"],["dbdump",0],["dcdatabase",0],["dcw",0],["de","de"],["debian",0],["devmo",0],["dga","dga"],["dico",0],["dicoado",0],["dict",0],["dictionary",0],["diffblog",0],["din","din"],["diq","diq"],["discord",0],["disinfopedia",0],["dk","da"],["dmoz",0],["dmozs",0],["doi",0],["donate",0],["doom_wiki",0],["download",0],["dpd",0],["dpla",0],["drae",0],["dsb","dsb"],["dtp","dtp"],["dty","dty"],["dv","dv"],["dz","dz"],["ee","ee"],["egl","eml"],["el","el"],["elibre",0],["emacswiki",0],["eml","eml"],["en","en"],["en-simple","simple"],["encyc",0],["englyphwiki",0],["enkol",0],["eo","eo"],["epo","eo"],["es","es"],["esolang",0],["et","et"],["etherpad",0],["etherpadbackup",0],["ethnologue",0],["ethnologuefamily",0],["eu","eu"],["exkcd",0],["exotica",0],["ext","ext"],["f",0],["fa","fa"],["fandom",0],["fanimutationwiki",0],["fat","fat"],["fedora",0],["ff","ff"],["fi","fi"],["finalfantasy",0],["finnix",0],["fiu-vro","fiu-vro"],["fj","fj"],["flickrphoto",0],["flickruser",0],["fo","fo"],["foldoc",0],["fon","fon"],["foundation",0],["foundationsite",0],["fr","fr"],["freebsdman",0],["freedomdefined",0],["freenode",0],["freesoft",0],["frp","frp"],["frr","frr"],["fur","fur"],["fy","fy"],["ga","ga"],["gag","gag"],["gan","gan"],["gcr","gcr"],["gd","gd"],["gentoo",0],["genwiki",0],["gerrit",0],["git",0],["github",0],["gitiles",0],["gitlab",0],["gl","gl"],["glk","glk"],["globalcontribs",0],["glottolog",0],["glottopedia",0],["gn","gn"],["gom","gom"],["google",0],["googledefine",0],["googlegroups",0],["gor","gor"],["got","got"],["gpe","gpe"],["gs",0],["gsw","als"],["gu","gu"],["guc","guc"],["gucprefix",0],["guildwarswiki",0],["gur","gur"],["gutenberg",0],["gutenbergwiki",0],["guw","guw"],["gv","gv"],["ha","ha"],["hackerspaces",0],["hak","hak"],["hammondwiki",0],["haw","haw"],["hdl",0],["he","he"],["heraldik",0],["hi","hi"],["hif","hif"],["ho","ho"],["horizonlabs",0],["hr","hr"],["hrfwiki",0],["hrwiki",0],["hsb","hsb"],["ht","ht"],["hu","hu"],["hy","hy"],["hyw","hyw"],["hz","hz"],["ia","ia"],["iarchive",0],["iba","iba"],["id","id"],["ie","ie"],["ig","ig"],["igl","igl"],["ii","ii"],["ik","ik"],["ilo","ilo"],["imdbcompany",0],["imdbname",0],["imdbtitle",0],["incubator",0],["infosphere",0],["inh","inh"],["io","io"],["irc",0],["ircrc",0],["ircs",0],["is","is"],["isni",0],["iso639-3",0],["issn",0],["it","it"],["iu","iu"],["ja","ja"],["jaglyphwiki",0],["jam","jam"],["jbo","jbo"],["jira",0],["jp","ja"],["jstor",0],["jv","jv"],["ka","ka"],["kaa","kaa"],["kab","kab"],["kai","kai"],["kaj","kaj"],["kamelo",0],["karlsruhe",0],["kbd","kbd"],["kbp","kbp"],["kcg","kcg"],["kg","kg"],["kge","kge"],["ki","ki"],["kj","kj"],["kk","kk"],["kl","kl"],["km","km"],["kn","kn"],["knc","knc"],["ko","ko"],["koi","koi"],["kr","kr"],["krc","krc"],["ks","ks"],["ksh","ksh"],["ku","ku"],["kus","kus"],["kv","kv"],["kw","kw"],["ky","ky"],["la","la"],["labsconsole",0],["lad","lad"],["lb","lb"],["lbe","lbe"],["lexemes",0],["lez","lez"],["lfn","lfn"],["lg","lg"],["li","li"],["liberachat",0],["libreplanet",0],["lij","lij"],["lingualibre",0],["linguistlist",0],["listarchive",0],["lld","lld"],["lmo","lmo"],["ln","ln"],["lo","lo"],["localwiki",0],["lofc",0],["lojban",0],["lokalhistoriewiki",0],["lostpedia",0],["lrc","lrc"],["lt","lt"],["ltg","ltg"],["luxo",0],["lv","lv"],["lzh","zh-classical"],["m",0],["mad","mad"],["mag","mag"],["mai","mai"],["mail",0],["mailarchive",0],["map-bms","map-bms"],["mariowiki",0],["marveldatabase",0],["mdf","mdf"],["mdwiki",0],["meatball",0],["mediawikiwiki",0],["mediazilla",0],["memoryalpha",0],["meta",0],["metawiki",0],["metawikimedia",0],["metawikipedia",0],["mg","mg"],["mh","mh"],["mhr","mhr"],["mi","mi"],["min","min"],["mineralienatlas",0],["miraheze",0],["mixnmatch",0],["mk","mk"],["ml","ml"],["mn","mn"],["mni","mni"],["mnw","mnw"],["mo","mo"],["moinmoin",0],["mos","mos"],["mosapedia",0],["mozillawiki",0],["mozillazinekb",0],["mr","mr"],["mrj","mrj"],["ms","ms"],["mt","mt"],["mus","mus"],["mw",0],["mwl","mwl"],["mwod",0],["mwot",0],["my","my"],["myv","myv"],["mzn","mzn"],["n",0],["na","na"],["nah","nah"],["nan","zh-min-nan"],["nap","nap"],["nara",0],["nb","no"],["nds","nds"],["nds-nl","nds-nl"],["ne","ne"],["new","new"],["ng","ng"],["nia","nia"],["nl","nl"],["nlab",0],["nn","nn"],["no","no"],["nost","nostalgia"],["nostalgia","nostalgia"],["nov","nov"],["nqo","nqo"],["nr","nr"],["nrm","nrm"],["nso","nso"],["nup","nup"],["nv","nv"],["ny","ny"],["oc","oc"],["oclc",0],["oeis",0],["oewiki",0],["oldwikisource",0],["olo","olo"],["olpc",0],["om","om"],["openlibrary",0],["openstreetmap",0],["openwetware",0],["or","or"],["organicdesign",0],["orthodoxwiki",0],["os","os"],["osmwiki",0],["otrs",0],["otrswiki",0],["outreach",0],["outreachwiki",0],["owasp",0],["pa","pa"],["pag","pag"],["pam","pam"],["pap","pap"],["paws",0],["pcd","pcd"],["pcm","pcm"],["pdc","pdc"],["petscan",0],["pfl","pfl"],["phab",0],["phabricator",0],["pi","pi"],["pih","pih"],["pl","pl"],["planetmath",0],["pmid",0],["pms","pms"],["pnb","pnb"],["pnt","pnt"],["pokewiki",0],["pokéwiki",0],["policy",0],["ppl","ppl"],["proofwiki",0],["ps","ps"],["pt","pt"],["pwn","pwn"],["pyrev",0],["pythoninfo",0],["q",0],["qu","qu"],["quality",0],["quarry",0],["rcirc",0],["regiowiki",0],["rev",0],["revo",0],["rfc",0],["rheinneckar",0],["rki","rki"],["rm","rm"],["rmy","rmy"],["rn","rn"],["ro","ro"],["roa-rup","roa-rup"],["roa-tara","roa-tara"],["rodovid",0],["rsk","rsk"],["rt",0],["ru","ru"],["rue","rue"],["rup","roa-rup"],["rw","rw"],["s",0],["sa","sa"],["sah","sah"],["sat","sat"],["sc","sc"],["scholar",0],["schoolswp",0],["schoolwiki",0],["scn","scn"],["sco","sco"],["scores",0],["scoutwiki",0],["sd","sd"],["se","se"],["securewikidc",0],["semantic-mw",0],["senseislibrary",0],["sep11",0],["sg","sg"],["sgs","bat-smg"],["sh","sh"],["sharemap",0],["shi","shi"],["shn","shn"],["shoutwiki",0],["shy","shy"],["si","si"],["silcode",0],["simple","simple"],["sk","sk"],["skr","skr"],["sl","sl"],["slashdot",0],["sm","sm"],["smn","smn"],["sn","sn"],["so","so"],["sourceforge",0],["spamcheck",0],["spcom",0],["species",0],["sq","sq"],["sr","sr"],["srn","srn"],["ss","ss"],["st","st"],["stats",0],["stewardry",0],["stq","stq"],["strategy",0],["strategywiki",0],["su","su"],["sulutil",0],["sv","sv"],["svn",0],["sw","sw"],["swtrain",0],["syl","syl"],["szl","szl"],["szy","szy"],["ta","ta"],["tardis",0],["tay","tay"],["tclerswiki",0],["tcy","tcy"],["tdd","tdd"],["te","te"],["tenwiki","ten"],["test2wiki","test2"],["testcommons",0],["testwiki","test"],["testwikidata",0],["tet","tet"],["tfwiki",0],["tg","tg"],["th","th"],["thelemapedia",0],["theopedia",0],["ti","ti"],["ticket",0],["tig","tig"],["tk","tk"],["tl","tl"],["tly","tly"],["tmbw",0],["tn","tn"],["to","to"],["tok","tok"],["tolkiengateway",0],["toolforge",0],["toolhub",0],["toollabs",0],["tools",0],["tpi","tpi"],["tr","tr"],["translatewiki",0],["trv","trv"],["ts","ts"],["tswiki",0],["tt","tt"],["tum","tum"],["tviv",0],["tw","tw"],["twiki",0],["twl",0],["ty","ty"],["tyv","tyv"],["tyvawiki",0],["udm","udm"],["ug","ug"],["uk","uk"],["umap",0],["uncyclopedia",0],["unihan",0],["ur","ur"],["urbandict",0],["usability",0],["usemod",0],["utrs",0],["uz","uz"],["v",0],["ve","ve"],["vec","vec"],["vep","vep"],["vi","vi"],["viaf",0],["vikidia",0],["vlos",0],["vls","vls"],["vo","vo"],["votewiki",0],["voy",0],["vro","fiu-vro"],["vrts",0],["vrtwiki",0],["w","en"],["wa","wa"],["war","war"],["wcna",0],["weirdgloop",0],["werelate",0],["wg","wg-en"],["wikia",0],["wikiapiary",0],["wikiasite",0],["wikibooks",0],["wikicities",0],["wikicity",0],["wikiconference",0],["wikidata",0],["wikiedudashboard",0],["wikifunctions",0],["wikifur",0],["wikihow",0],["wikiindex",0],["wikilivres",0],["wikilivresru",0],["wikimania",0],["wikimedia",0],["wikinews",0],["wikinfo",0],["wikinvest",0],["wikipapers",0],["wikipedia",0],["wikipediawikipedia",0],["wikiquote",0],["wikiskripta",0],["wikisophia",0],["wikisource",0],["wikisp",0],["wikispecies",0],["wikispore",0],["wikispot",0],["wikitech",0],["wikiti",0],["wikitrek",0],["wikiversity",0],["wikivoyage",0],["wikiwikiweb",0],["wikt",0],["wiktionary",0],["wm2005",0],["wm2006",0],["wm2007",0],["wm2008",0],["wm2009",0],["wm2010",0],["wm2011",0],["wm2012",0],["wm2013",0],["wm2014",0],["wm2015",0],["wm2016",0],["wm2017",0],["wm2018",0],["wmam",0],["wmania",0],["wmar",0],["wmat",0],["wmau",0],["wmbd",0],["wmbe",0],["wmbr",0],["wmca",0],["wmch",0],["wmcl",0],["wmcn",0],["wmco",0],["wmcz",0],["wmcz_docs",0],["wmcz_old",0],["wmdc",0],["wmde",0],["wmdeblog",0],["wmdk",0],["wmdoc",0],["wmec",0],["wmee",0],["wmes",0],["wmet",0],["wmf",0],["wmfblog",0],["wmfdashboard",0],["wmfi",0],["wmfr",0],["wmge",0],["wmhi",0],["wmhk",0],["wmhu",0],["wmid",0],["wmil",0],["wmin",0],["wmit",0],["wmke",0],["wmmk",0],["wmmx",0],["wmnl",0],["wmno",0],["wmnoc",0],["wmnoch",0],["wmnyc",0],["wmpa-us",0],["wmph",0],["wmpl",0],["wmplsite",0],["wmpt",0],["wmpunjabi",0],["wmromd",0],["wmrs",0],["wmru",0],["wmse",0],["wmsk",0],["wmteam",0],["wmtr",0],["wmtw",0],["wmua",0],["wmuk",0],["wmve",0],["wmza",0],["wo","wo"],["wookieepedia",0],["wowwiki",0],["wplibrary",0],["wurmpedia",0],["wuu","wuu"],["xal","xal"],["xh","xh"],["xkcd",0],["xmf","xmf"],["xtools",0],["yi","yi"],["yo","yo"],["yue","zh-yue"],["za","za"],["zea","zea"],["zgh","zgh"],["zh","zh"],["zh-classical","zh-classical"],["zh-cn","zh"],["zh-min-nan","zh-min-nan"],["zh-tw","zh"],["zh-yue","zh-yue"],["zu","zu"],["zum",0]]); const WP_LANGUAGES = new Map([["ab","Abkhazian"],["ace","Acehnese"],["ady","Adyghe"],["af","Afrikaans"],["als","Alemannic"],["alt","Southern Altai"],["am","Amharic"],["ami","Amis"],["an","Aragonese"],["ang","Old English"],["ann","Obolo"],["anp","Angika"],["ar","Arabic"],["arc","Aramaic"],["ary","Moroccan Arabic"],["arz","Egyptian Arabic"],["as","Assamese"],["ast","Asturian"],["atj","Atikamekw"],["av","Avaric"],["avk","Kotava"],["awa","Awadhi"],["ay","Aymara"],["az","Azerbaijani"],["azb","South Azerbaijani"],["ba","Bashkir"],["ban","Balinese"],["bar","Bavarian"],["bat-smg","Samogitian"],["bbc","Batak Toba"],["bcl","Central Bikol"],["bdr","West Coast Bajau"],["be","Belarusian"],["be-tarask","Belarusian (Taraškievica orthography)"],["bew","Betawi"],["bg","Bulgarian"],["bh","Bhojpuri"],["bi","Bislama"],["bjn","Banjar"],["blk","Pa'O"],["bm","Bambara"],["bn","Bangla"],["bo","Tibetan"],["bpy","Bishnupriya"],["br","Breton"],["bs","Bosnian"],["btm","Batak Mandailing"],["bug","Buginese"],["bxr","Russia Buriat"],["ca","Catalan"],["cbk-zam","Chavacano"],["cdo","Mindong"],["ce","Chechen"],["ceb","Cebuano"],["ch","Chamorro"],["chr","Cherokee"],["chy","Cheyenne"],["ckb","Central Kurdish"],["co","Corsican"],["crh","Crimean Tatar"],["cs","Czech"],["csb","Kashubian"],["cu","Church Slavic"],["cv","Chuvash"],["cy","Welsh"],["da","Danish"],["dag","Dagbani"],["de","German"],["dga","Southern Dagaare"],["din","Dinka"],["diq","Dimli"],["dsb","Lower Sorbian"],["dtp","Central Dusun"],["dty","Doteli"],["dv","Divehi"],["dz","Dzongkha"],["ee","Ewe"],["el","Greek"],["eml","Emiliano-Romagnolo"],["en","English"],["eo","Esperanto"],["es","Spanish"],["et","Estonian"],["eu","Basque"],["ext","Extremaduran"],["fa","Persian"],["fat","Fanti"],["ff","Fula"],["fi","Finnish"],["fiu-vro","Võro"],["fj","Fijian"],["fo","Faroese"],["fon","Fon"],["fr","French"],["frp","Arpitan"],["frr","Northern Frisian"],["fur","Friulian"],["fy","Western Frisian"],["ga","Irish"],["gag","Gagauz"],["gan","Gan"],["gcr","Guianan Creole"],["gd","Scottish Gaelic"],["gl","Galician"],["glk","Gilaki"],["gn","Guarani"],["gom","Goan Konkani"],["gor","Gorontalo"],["got","Gothic"],["gpe","Ghanaian Pidgin"],["gu","Gujarati"],["guc","Wayuu"],["gur","Frafra"],["guw","Gun"],["gv","Manx"],["ha","Hausa"],["hak","Hakka Chinese"],["haw","Hawaiian"],["he","Hebrew"],["hi","Hindi"],["hif","Fiji Hindi"],["hr","Croatian"],["hsb","Upper Sorbian"],["ht","Haitian Creole"],["hu","Hungarian"],["hy","Armenian"],["hyw","Western Armenian"],["ia","Interlingua"],["iba","Iban"],["id","Indonesian"],["ie","Interlingue"],["ig","Igbo"],["igl","Igala"],["ik","Inupiaq"],["ilo","Iloko"],["inh","Ingush"],["io","Ido"],["is","Icelandic"],["it","Italian"],["iu","Inuktitut"],["ja","Japanese"],["jam","Jamaican Creole English"],["jbo","Lojban"],["jv","Javanese"],["ka","Georgian"],["kaa","Kara-Kalpak"],["kab","Kabyle"],["kai","Karekare"],["kaj","Jju"],["kbd","Kabardian"],["kbp","Kabiye"],["kcg","Tyap"],["kg","Kongo"],["kge","Komering"],["ki","Kikuyu"],["kk","Kazakh"],["km","Khmer"],["kn","Kannada"],["knc","Central Kanuri"],["ko","Korean"],["koi","Komi-Permyak"],["krc","Karachay-Balkar"],["ks","Kashmiri"],["ksh","Colognian"],["ku","Kurdish"],["kus","Kusaal"],["kv","Komi"],["kw","Cornish"],["ky","Kyrgyz"],["la","Latin"],["lad","Ladino"],["lb","Luxembourgish"],["lbe","Lak"],["lez","Lezghian"],["lfn","Lingua Franca Nova"],["lg","Ganda"],["li","Limburgish"],["lij","Ligurian"],["lld","Ladin"],["lmo","Lombard"],["ln","Lingala"],["lo","Lao"],["lt","Lithuanian"],["ltg","Latgalian"],["lv","Latvian"],["mad","Madurese"],["mag","Magahi"],["mai","Maithili"],["map-bms","Banyumasan"],["mdf","Moksha"],["mg","Malagasy"],["mhr","Eastern Mari"],["mi","Māori"],["min","Minangkabau"],["mk","Macedonian"],["ml","Malayalam"],["mn","Mongolian"],["mni","Manipuri"],["mnw","Mon"],["mos","Mossi"],["mr","Marathi"],["mrj","Western Mari"],["ms","Malay"],["mt","Maltese"],["mwl","Mirandese"],["my","Burmese"],["myv","Erzya"],["mzn","Mazanderani"],["nah","Nahuatl"],["nap","Neapolitan"],["nds","Low German"],["nds-nl","Low Saxon"],["ne","Nepali"],["new","Newari"],["nia","Nias"],["nl","Dutch"],["nn","Norwegian Nynorsk"],["no","Norwegian"],["nov","Novial"],["nqo","N’Ko"],["nr","South Ndebele"],["nrm","Norman"],["nso","Northern Sotho"],["nup","Nupe"],["nv","Navajo"],["ny","Nyanja"],["oc","Occitan"],["olo","Livvi-Karelian"],["om","Oromo"],["or","Odia"],["os","Ossetic"],["pa","Punjabi"],["pag","Pangasinan"],["pam","Pampanga"],["pap","Papiamento"],["pcd","Picard"],["pcm","Nigerian Pidgin"],["pdc","Pennsylvania German"],["pfl","Palatine German"],["pi","Pali"],["pl","Polish"],["pms","Piedmontese"],["pnb","Western Punjabi"],["pnt","Pontic"],["ppl","Nawat"],["ps","Pashto"],["pt","Portuguese"],["pwn","Paiwan"],["qu","Quechua"],["rki","Arakanese"],["rm","Romansh"],["rmy","Vlax Romani"],["rn","Rundi"],["ro","Romanian"],["roa-rup","Aromanian"],["roa-tara","Tarantino"],["rsk","Pannonian Rusyn"],["ru","Russian"],["rue","Rusyn"],["rw","Kinyarwanda"],["sa","Sanskrit"],["sah","Yakut"],["sat","Santali"],["sc","Sardinian"],["scn","Sicilian"],["sco","Scots"],["sd","Sindhi"],["se","Northern Sami"],["sg","Sango"],["sh","Serbo-Croatian"],["shi","Tachelhit"],["shn","Shan"],["si","Sinhala"],["simple","Simple English"],["sk","Slovak"],["skr","Saraiki"],["sl","Slovenian"],["sm","Samoan"],["smn","Inari Sami"],["sn","Shona"],["so","Somali"],["sq","Albanian"],["sr","Serbian"],["srn","Sranan Tongo"],["ss","Swati"],["st","Southern Sotho"],["stq","Saterland Frisian"],["su","Sundanese"],["sv","Swedish"],["sw","Swahili"],["syl","Sylheti"],["szl","Silesian"],["szy","Sakizaya"],["ta","Tamil"],["tay","Atayal"],["tcy","Tulu"],["tdd","Tai Nuea"],["te","Telugu"],["tet","Tetum"],["tg","Tajik"],["th","Thai"],["ti","Tigrinya"],["tig","Tigre"],["tk","Turkmen"],["tl","Tagalog"],["tly","Talysh"],["tn","Tswana"],["to","Tongan"],["tok","Toki Pona"],["tpi","Tok Pisin"],["tr","Turkish"],["trv","Taroko"],["ts","Tsonga"],["tt","Tatar"],["tum","Tumbuka"],["tw","Twi"],["ty","Tahitian"],["tyv","Tuvinian"],["udm","Udmurt"],["ug","Uyghur"],["uk","Ukrainian"],["ur","Urdu"],["uz","Uzbek"],["ve","Venda"],["vec","Venetian"],["vep","Veps"],["vi","Vietnamese"],["vls","West Flemish"],["vo","Volapük"],["wa","Walloon"],["war","Waray"],["wo","Wolof"],["wuu","Wu"],["xal","Kalmyk"],["xh","Xhosa"],["xmf","Mingrelian"],["yi","Yiddish"],["yo","Yoruba"],["za","Zhuang"],["zea","Zeelandic"],["zgh","Standard Moroccan Tamazight"],["zh","Chinese"],["zh-classical","Literary Chinese"],["zh-min-nan","Minnan"],["zh-yue","Cantonese"],["zu","Zulu"]]); const appendixWithSlash = ["Adûni", "Afrihili", "Arabic_roots", "Belter_Creole", "Bibliography", "Black_Speech", "Bolak", "Communicationssprache", "Dothraki", "Eloi", "Gestures", "Glosa", "Goa'uld", "High_Valyrian", "Idiom_Neutral", "Interlingue", "Interslavic", "Klingon", "Kotava", "Láadan", "Lapine", "Lingua_Franca_Nova", "Lojban", "Mandalorian", "Medefaidrin", "Minecraft", "Mundolinco", "Na'vi", "Neo", "Novial", "Noxilo", "Protologisms/Long_words", "Quenya", "Romanova", "Sindarin", "Snowclones", "Talossan", "Toki_Pona", "Unas"]; const appendixNoSlash = ["Boldface", "Capital_letter", "Italics", "Lowercase_letter", "Possessive", "Repetition", "Small_caps", "Strikethrough", "Subscript", "Superscript", "Underline", "Uppercase_letter"]; const animationSpeed = 0.2; // seconds mw.util.addCSS(` .wikt-page-preview ol { margin: 0 0.5em 0 1.5em; padding: 0; } .wikt-page-preview dl { margin-bottom: 0; } .wikt-page-preview p { margin: 0; } /* popupContainer has the opacity animation, while popup gets translated. */ .popup-fade-in-up, .popup-fade-in-down { animation: popup-fade-in ${animationSpeed}s ease forwards; } .popup-fade-out-up, .popup-fade-out-down { animation: popup-fade-out ${animationSpeed}s ease forwards; } .popup-fade-in-up > div { animation: popup-move-in-up ${animationSpeed}s ease forwards; } .popup-fade-in-down > div { animation: popup-move-in-down ${animationSpeed}s ease forwards; } .popup-fade-out-up > div { animation: popup-move-out-up ${animationSpeed}s ease forwards; } .popup-fade-out-down > div { animation: popup-move-out-down ${animationSpeed}s ease forwards; } @keyframes popup-move-in-up { 0% { transform: translate(0, 20px); } } @keyframes popup-move-in-down { 0% { transform: translate(0, -20px); } } @keyframes popup-move-out-up { 100% { transform: translate(0, -20px); } } @keyframes popup-move-out-down { 100% { transform: translate(0, 20px); } } @keyframes popup-fade-out { 100% { opacity: 0; } } @keyframes popup-fade-in { 0% { opacity: 0; } } .ring-loader { margin: auto; width: 24px; height: 24px; border-radius: 50%; border-top: 5px solid var(--wikt-palette-black); border-bottom: 5px solid var(--wikt-palette-black); border-left: 5px solid transparent; border-right: 5px solid transparent; animation: spin 1.2s linear infinite; } @keyframes spin { 100% { transform: rotate(360deg); } } .preview-headerlink, .preview-headerlink:visited { color: inherit; font-weight: bold; } /* Hack: get the speaker icon on Wikipedia articles without having to load Phonos. */ .ext-phonos .oo-ui-buttonElement-button:after { content: "🔊"; } .ext-phonos * { display: inline !important; padding: 0 !important; margin: 0 !important; } `); const definitionIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M15 2a7.65 7.65 0 00-5 2 7.65 7.65 0 00-5-2H1v15h4a7.65 7.65 0 015 2 7.65 7.65 0 015-2h4V2zm2.5 13.5H14a4.38 4.38 0 00-3 1V5s1-1.5 4-1.5h2.5z"></path></g></svg>`; const glossaryIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M12.43 14.34A5 5 0 0110 15a5 5 0 113.95-2L17 16.09V3a2 2 0 00-2-2H5a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 001.45-.63z"></path><circle cx="10" cy="10" r="3"></circle></g></svg>`; const articleIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V3a2 2 0 00-2-2zm0 3h5v1H5zm0 2h5v1H5zm0 2h5v1H5zm10 7H5v-1h10zm0-2H5v-1h10zm0-2H5v-1h10zm0-2h-4V4h4z"></path></g></svg>`; const bibliographyIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M3 2h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H3c0 0 .5-.5.5-1V3c0-.5-.5-1-.5-1zM4 6h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H4c0 0 .5-.5.5-1V7c0-.5-.5-1-.5-1zM3 10h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H3c0 0 .5-.5.5-1v-1c0-.5-.5-1-.5-1zM4 14h12c.5 0 1 .5 1 1v1c0 .5-.5 1-1 1H4c0 0 .5-.5.5-1v-1c0-.5-.5-1-.5-1z"/></g></svg>`; const loader = document.createElement("div"); loader.className = "ring-loader"; const popupContainer = document.createElement("div"); const popup = document.createElement("div"); const popupContent = document.createElement("div"); popupContainer.style = `display: none; position: absolute; filter: drop-shadow(0px 30px 30px rgba(0, 0, 0, 0.15)) drop-shadow(0px 0px 0.75px var(--wikt-palette-dullblue)); z-index: 801`; popupContainer.className = "wikt-page-preview"; popup.style = "box-sizing: border-box; height: 100%; background: var(--wikt-palette-white)"; popupContent.style = "display: flex; flex-direction: column; border-radius: 2px; box-sizing: border-box; color: var(--wikt-palette-black); overflow: auto; height: 100%; overflow-wrap: break-word; scrollbar-width: thin"; document.body.append(popupContainer); popupContainer.append(popup); popup.append(popupContent); let popupTimer; let openLink; let mouseX, mouseY; let API_controller = new AbortController(); function closePopup() { if (!openLink) return; openLink = null; API_controller.abort(); API_controller = new AbortController(); if (popupContainer.classList.contains("popup-fade-in-up")) { popupContainer.classList.remove("popup-fade-in-up"); popupContainer.classList.add("popup-fade-out-down"); } else { popupContainer.classList.remove("popup-fade-in-down"); popupContainer.classList.add("popup-fade-out-up"); } // After the animation has completed, reset the popup to its initial state. setTimeout(() => { popupContainer.style.display = "none"; popupContainer.classList.remove("popup-fade-out-down", "popup-fade-out-up"); }, animationSpeed * 1000); } popup.addEventListener("pointerenter", () => { clearTimeout(popupTimer); }); popup.addEventListener("pointerleave", () => { clearTimeout(popupTimer); popupTimer = setTimeout(closePopup, 300); }); function processLink(link) { let linkTitle = decodeURIComponent(link.pathname.split("/wiki/")[1]); let titlePrefix = linkTitle.includes(":") ? linkTitle.toLowerCase().split(":")[0] : ""; let resolvedTitle = linkTitle; let API_domain = link.origin; let linkAnchor = decodeURIComponent(link.hash.slice(1) || ""); let isWPlink = link.href.match(/^https:\/\/[^.]+.wikipedia.org\/wiki\//); let isPreviewLink = Boolean(link.closest(".wikt-page-preview")); let isGlossary = /^Appendix:.*[Gg]lossary$/.test(linkTitle); // Start with various checks to determine whether a link should be processed. if (link.matches(`nav a, .cancelLink a, .mw-widget-titleOptionWidget a, .new, .preview-headerlink, .external, [href$="#"]`)) { return; } else if (isGlossary) { // Links to glossary *must* have an anchor. if (!linkAnchor) return; } else if (linkTitle.startsWith("Appendix:Bibliography/")) { // Bibliography subpages must have an anchor starting with `bib-`. if (!linkAnchor || !linkAnchor.startsWith("bib-")) return; } else if (!isWPlink) { // Other Wiktionary pages must not have a lowercase-starting anchor (filters out some unhelpful links). if (/^[a-z]/.test(linkAnchor)) return; } if (link.href.startsWith("https://en.wiktionary.org/wiki/")) { // Filter out all interwiki prefixes. if (INTERWIKI_PREFIXES.has(titlePrefix)) return; let {namespace, title} = new mw.Title(linkTitle); if (namespace === 0) { // Mainspace if (title.endsWith("/translations")) return; } else if (namespace === 100) { // Appendix space if (!appendixWithSlash.some(lang => title.startsWith(lang + "/")) && !appendixNoSlash.includes(title) && !isGlossary) return; } else if (namespace !== 118) { // Reconstruction space return; } } else if (isWPlink) { // Filter out invalid interwiki prefixes. if (INTERWIKI_PREFIXES.get(titlePrefix) === 0) return; // Get the resolved title if it's a language interwiki. if (INTERWIKI_PREFIXES.has(titlePrefix)) { API_domain = `https://${INTERWIKI_PREFIXES.get(titlePrefix)}.wikipedia.org`; resolvedTitle = linkTitle.substring(linkTitle.indexOf(":") + 1); // If the resolved title contains another interwiki, return. let resolvedTitlePrefix = resolvedTitle.includes(":") ? resolvedTitle.toLowerCase().split(":")[0] : ""; // same as titlePrefix if (INTERWIKI_PREFIXES.has(resolvedTitlePrefix)) return; } } else { return; } link.addEventListener("pointerover", event => { [mouseX, mouseY] = [event.clientX, event.clientY]; clearTimeout(popupTimer); // Ignore links which are already open. if (link === openLink) return; if (!isPreviewLink) closePopup(); // Fetch popup text immediately on hover to reduce delay. let responsePromise = fetch(`${API_domain}/api/rest_v1/page/html/${encodeURIComponent(resolvedTitle)}`, { headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}, signal: API_controller.signal }).then(r => r.text()).catch(() => { /* fetch was aborted */ }); popupTimer = setTimeout(() => { popupContainer.style.display = ""; popupContent.innerHTML = ""; popupContent.append(loader); popupContent.style.padding = "14px 16px 8px"; // Disable link hovering until animation has completed. popupContent.style.pointerEvents = "none"; setTimeout(() => popupContent.style.pointerEvents = "", animationSpeed * 1000); // Adapt the popup for large, standard, and small size preference in Vector 2022. let sizeSetting = 0; if (document.documentElement.matches(".vector-feature-custom-font-size-clientpref-1")) sizeSetting = 1; else if (document.documentElement.matches(".vector-feature-custom-font-size-clientpref-2")) sizeSetting = 2; let width = [320, 340, 360][sizeSetting]; let height = [210, 225, 240][sizeSetting]; let triangleSize = [9, 10, 11][sizeSetting]; popupContainer.style.fontSize = ["14px", "15px", "17px"][sizeSetting]; popupContainer.style.lineHeight = ["21px", "22px", "24px"][sizeSetting]; popupContainer.style.width = width + "px"; popupContainer.style.height = height + "px"; if (isPreviewLink) { // Trigger fade-in-down animation. popupContainer.classList.remove("popup-fade-in-up", "popup-fade-in-down"); void popupContainer.offsetLeft; // force reflow popupContainer.classList.add("popup-fade-in-down"); } else { openLink = link; // Get list of rects (lines) of the target element, then find the one whose midpoint is closest to mouseY. // This ensures that the code can correctly handle multi-line links. let linkBlock = [...event.target.getClientRects()].reduce((prev, next) => Math.abs((next.top + next.bottom) / 2 - mouseY) < Math.abs((prev.top + prev.bottom) / 2 - mouseY) ? next : prev); // Horizontal position. Choose left or right depending on the side of the screen the mouse is in. let leftPosition = mouseX - 30; if (mouseX > document.documentElement.clientWidth / 2) leftPosition = mouseX - width + 30; // Ensure that the popup is at least 5px away from the side of the screen. leftPosition = Math.max(5, Math.min(leftPosition, document.documentElement.clientWidth - width - 5)); popupContainer.style.left = leftPosition + document.documentElement.scrollLeft + "px"; // Vertical position. Prioritize fade-in-down unless there would be less than 10px of room above. if (linkBlock.top > height + 10 || linkBlock.top > document.documentElement.clientHeight - linkBlock.bottom) { popupContainer.style.top = linkBlock.top + document.documentElement.scrollTop - height + "px"; popupContainer.classList.add("popup-fade-in-down"); popup.style.padding = `0 0 ${triangleSize}px`; // Create a triangle on the bottom. popup.style.clipPath = `polygon(0 0, 100% 0, 100% calc(100% - ${triangleSize}px), ${mouseX - leftPosition + triangleSize}px calc(100% - ${triangleSize}px), ${mouseX - leftPosition}px 100%, ${mouseX - leftPosition - triangleSize}px calc(100% - ${triangleSize}px), 0 calc(100% - ${triangleSize}px))`; } else { popupContainer.style.top = linkBlock.bottom + document.documentElement.scrollTop + "px"; popupContainer.classList.add("popup-fade-in-up"); popup.style.padding = `${triangleSize}px 0 0`; // Create a triangle on top. popup.style.clipPath = `polygon(0 ${triangleSize}px, ${mouseX - leftPosition - triangleSize}px ${triangleSize}px, ${mouseX - leftPosition}px 0, ${mouseX - leftPosition + triangleSize}px ${triangleSize}px, 100% ${triangleSize}px, 100% 100%, 0 100%)`; } } responsePromise.then(response => { if (!response) return; // if the fetch was aborted popupContent.innerHTML = ""; let responseDocument = new DOMParser().parseFromString(response, "text/html"); // Convert to absolute URLs. responseDocument.querySelectorAll("a[href]").forEach(link => link.setAttribute("href", link.href)); let anchoredElement = responseDocument.getElementById(linkAnchor); let popupHeader = document.createElement("div"); popupHeader.style = "font-size: 90%; color: var(--wikt-palette-deepblue)"; popupContent.append(popupHeader); let iconContainer = document.createElement("span"); iconContainer.style = "float: right; margin-left: 10px; height: 20px; color: var(--wikt-palette-black)"; popupHeader.append(iconContainer); let titleLink = document.createElement("a"); titleLink.href = link.href; titleLink.title = link.title; titleLink.className = "skin-invert-image preview-headerlink"; // Scrape entry content. if (isWPlink) { iconContainer.innerHTML = articleIcon; titleLink.textContent = linkTitle.replaceAll("_", " "); if (responseDocument.title) titleLink.innerHTML = responseDocument.title; // sometimes gives HTML text let WikipediaName = WP_LANGUAGES.get(API_domain.substr(8).split(".")[0]); popupHeader.append(WikipediaName + " Wikipedia article for ", titleLink); let articleContent = document.createElement("div"); articleContent.style.margin = "5px 0 0 10px"; let firstSection = responseDocument.querySelector("section"); if (firstSection && responseDocument.querySelector(`meta[property="mw:pageNamespace"][content="0"]`)) { firstSection.querySelectorAll("b").forEach(boldElem => boldElem.outerHTML = boldElem.innerHTML); firstSection.querySelectorAll(":scope > p, :scope > ul, :scope > ol").forEach(elem => articleContent.append(elem)); } if (articleContent.childElementCount) popupContent.append(articleContent); } else if (isGlossary) { iconContainer.innerHTML = glossaryIcon; titleLink.textContent = linkAnchor.replaceAll("_", " "); popupHeader.append("Glossary definition of ", titleLink); if (anchoredElement && anchoredElement.matches(".template-anchor")) { // Get succeeding `dd` elements. The HTML is <dt>...<span class="template-anchor"></span>...</dt><dd>...</dd><dd>...</dd> for (let elem = anchoredElement.parentElement.nextElementSibling; elem && elem.matches("dd"); elem = elem.nextElementSibling) { elem.style = "margin: 5px 0 0 15px"; popupContent.append(elem.cloneNode(true)); } } } else if (linkTitle.startsWith("Appendix:Bibliography/")) { iconContainer.innerHTML = bibliographyIcon; let language = linkTitle.slice(22).replaceAll("_", " "); // trim "Appendix:Bibliography/" prefix popupHeader.append(`${language} bibliography`); if (anchoredElement && anchoredElement.matches(".bibliography-id")) { let bibliographyCitation = document.createElement("div"); bibliographyCitation.style = "margin: 5px 0 0 15px"; bibliographyCitation.innerHTML = anchoredElement.innerHTML; popupContent.append(bibliographyCitation); } } else { const hasDefinitions = elem => Boolean(elem.querySelector("ol:not(.references), .ja-see, .zh-see")); iconContainer.innerHTML = definitionIcon; // Try to resolve the anchor element to #Chinese. if (!anchoredElement && ["Cantonese", "Gan", "Hakka", "Hokkien", "Literary_Chinese", "Mandarin", "Middle_Chinese", "Old_Chinese", "Wu", "Xiang"].includes(linkAnchor)) anchoredElement = responseDocument.querySelector("#Chinese"); // Try to guess the anchor target in the following order: English, Chinese, Translingual, [first h2 on page] // Always prioritize an L2 section which contains definitions. if (!linkAnchor) { let pageH2s = [...responseDocument.querySelectorAll("h2")]; if (pageH2s.some(h2 => hasDefinitions(h2.parentElement))) pageH2s = pageH2s.filter(h2 => hasDefinitions(h2.parentElement)); anchoredElement = pageH2s.find(h2 => h2.id === "English"); if (!anchoredElement) anchoredElement = pageH2s.find(h2 => h2.id === "Chinese"); if (!anchoredElement) anchoredElement = pageH2s.find(h2 => h2.id === "Translingual"); if (!anchoredElement) anchoredElement = pageH2s[0]; } let displayTitle = document.createElement("strong"); displayTitle.textContent = linkTitle.split("/").pop().replaceAll("_", " "); if (linkTitle.startsWith("Reconstruction:")) displayTitle.textContent = "*" + displayTitle.textContent; // Find localest section containing an h2. let languageSection = anchoredElement; while (languageSection && !languageSection.querySelector(":scope > h2")) languageSection = languageSection.parentElement.closest("section"); // Make sure that the entry is well-formed. if (languageSection) { let language = languageSection.querySelector(":scope > h2").textContent; let scrapeSection = anchoredElement.closest("section"); // Find localest section which contains any definitions. while (scrapeSection && !hasDefinitions(scrapeSection)) scrapeSection = scrapeSection.parentElement.closest("section"); if (scrapeSection) { let headwords = [...scrapeSection.querySelectorAll(".headword-line > strong")]; if (new Set(headwords.map(h => h.textContent)).size === 1) { // If there is a single unique headword, replace the display title with that. displayTitle = headwords[0]; if (displayTitle.querySelector("a > img")) displayTitle = displayTitle.querySelector("a > img").cloneNode(); } else if (new Set(headwords.map(h => h.cloneNode().outerHTML)).size === 1) { // If there is a single unique set of element attributes, use that with the display title. headwords[0].innerHTML = displayTitle.innerHTML; displayTitle = headwords[0]; } // Remove existing links in the headword. displayTitle.querySelectorAll("a").forEach(elem => elem.replaceWith(elem.textContent)); let ols = scrapeSection.querySelectorAll(":scope > ol:not(.references), section > ol:not(.references)"); if (anchoredElement.matches(".senseid")) { [...anchoredElement.parentElement.childNodes].forEach(child => { if (child !== anchoredElement) child.remove(); }); ols = [anchoredElement.closest("ol")]; } for (let ol of ols) { let POS_container = document.createElement("div"); POS_container.style.margin = "8px 0 5px 0"; let POS = document.createElement("span"); POS.style = "font-size: 110%; font-weight: bold"; POS.textContent = ol.closest("section").firstChild.textContent; POS_container.append(POS); let tlb = ol.closest("section").querySelector(".headword-line ~ .usage-label-term"); if (tlb) POS_container.append(document.createElement("br"), tlb); popupContent.append(POS_container, ol); } // {{ja-see}} and {{zh-see}} don't follow the normal format, so just insert them verbatim. for (let seeTemplate of scrapeSection.querySelectorAll(".ja-see, .zh-see")) popupContent.append(seeTemplate); } titleLink.append(displayTitle); popupHeader.append("Preview definitions of " + language + " ", titleLink); } else { titleLink.append(displayTitle); popupHeader.append("Preview definitions of ", titleLink); } } // Post-fetch error handling. if (popupContent.childElementCount > 1) { // Clean up HTML. popupContent.querySelectorAll("link, .previewonly, .maintenance-line, .mw-empty-elt, .reference, .Inline-Template, .vsHide").forEach(elem => elem.remove()); if (!isWPlink) popupContent.querySelectorAll("li > ul").forEach(elem => elem.remove()); // remove quotations for (let elem of popupContent.querySelectorAll("*")) elem.removeAttribute("id"); // avoid inadvertently repeating IDs within a page } else if (isWPlink) { // Display a message if the Wikipedia article was invalid or not in mainspace. let noArticle = document.createElement("div"); noArticle.style = "margin: 5px 0 0 15px; font-size: 90%"; noArticle.textContent = "(article content could not be previewed)"; popupContent.append(noArticle); } else if (linkAnchor && !anchoredElement) { // Display a message if the anchor is invalid. let noSectionFound = document.createElement("div"); noSectionFound.style = "margin: 10px 0 0 7.5px; font-size: 90%"; let strong = document.createElement("strong"); strong.textContent = linkAnchor.replaceAll("_", " "); noSectionFound.append("The ", strong, " section was not found on this page."); popupContent.append(noSectionFound); } else { // Display a message if no definitions were found in the section. let noDefinitionsFound = document.createElement("div"); noDefinitionsFound.style = "margin: 5px 0 0 15px; font-size: 90%"; noDefinitionsFound.textContent = "(no definitions found)"; popupContent.append(noDefinitionsFound); } // Reduce the padding if a scrollbar is present. The intended padding is 16px on each side. if (width - popupHeader.clientWidth > 32) popupContent.style.paddingRight = Math.max(4, 48 + popupHeader.clientWidth - width) + "px"; }); // (Hack?) make sure that `link pointerleave` doesn't cause the popup to immediately close. setTimeout(() => clearTimeout(popupTimer), 0); }, isPreviewLink ? 1200 : 400); }); link.addEventListener("pointerout", () => { clearTimeout(popupTimer); if (link === openLink) { popupTimer = setTimeout(closePopup, 300); } else { API_controller.abort(); API_controller = new AbortController(); } }); link.addEventListener("pointermove", event => [mouseX, mouseY] = [event.clientX, event.clientY]); link.addEventListener("click", () => clearTimeout(popupTimer)); } // Process all links. document.querySelectorAll("a").forEach(processLink); // Process links which are added to the DOM after the gadget has run. (new MutationObserver(events => events.flatMap(event => [...event.addedNodes]).forEach(node => { if (node instanceof HTMLAnchorElement) processLink(node); if (node instanceof HTMLElement) node.querySelectorAll("a").forEach(processLink); }))).observe(document.body, {childList: true, subtree: true}); // Dispatch hover events to support [[w:MediaWiki:Gadget-ReferenceTooltips.js]]. const linkEvent = ev => openLink && openLink.dispatchEvent(new Event(ev, {bubbles: true, cancelable: true})); // Note: for some reason an event listener on `popup` doesn't catch everything... popupContainer.addEventListener("pointerenter", () => setTimeout(() => linkEvent("mouseover"))); popupContainer.addEventListener("pointerleave", () => linkEvent("mouseout")); // Custom events popupContainer.addEventListener("pointerenter", () => linkEvent("linkPopupHover")); popupContainer.addEventListener("pointerleave", () => linkEvent("linkPopupUnhover")); // </nowiki> m7wjlrwv96nlex8o1osdzwat04davci MediaWiki:Gadget-CommentsInLocalTime.js 8 17964 88930 2024-12-11T21:21:52Z en>Surjection 0 88930 javascript text/javascript // {{documentation}} // _________________________________________________________________________________________ // | | // | === WARNING: GLOBAL GADGET FILE === | // | Changes to this page affect many users. | // | Please discuss changes on the [[Wiktionary:Grease Pit]] before editing. | // |_________________________________________________________________________________________| // // // The content below are copied from https://en.wikipedia.org/w/index.php?title=User:Gary/comments_in_local_time.js&oldid=1103519446 // See [[w:User:Gary/comments_in_local_time.js]], [[w:Wikipedia:Comments in Local Time]] // ********************************************************************************************************************************* /** * COMMENTS IN LOCAL TIME * * Description: * Changes [[Coordinated Universal Time|UTC]]-based times and dates, * such as those used in signatures, to be relative to local time. * * Documentation: * [[Wikipedia:Comments in Local Time]] */ $(() => { /** * Given a number, add a leading zero if necessary, so that the final number * has two characters. * * @param {number} number Number * @returns {string} The number with a leading zero, if necessary. */ function addLeadingZero(number) { const numberArg = number; if (numberArg < 10) { return `0${numberArg}`; } return numberArg; } function convertMonthToNumber(month) { return new Date(`${month} 1, 2001`).getMonth(); } function getDates(time) { const [, oldHour, oldMinute, oldDay, oldMonth, oldYear] = time; // Today const today = new Date(); // Yesterday const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); // Tomorrow const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); // Set the date entered. const newTime = new Date(); newTime.setUTCFullYear(oldYear, convertMonthToNumber(oldMonth), oldDay); newTime.setUTCHours(oldHour); newTime.setUTCMinutes(oldMinute); return { time: newTime, today, tomorrow, yesterday }; } /** * Determine whether to use the singular or plural word, and use that. * * @param {string} term Original term * @param {number} count Count of items * @param {string} plural Pluralized term * @returns {string} The word to use */ function pluralize(term, count, plural = null) { let pluralArg = plural; // No unique pluralized word is found, so just use a general one. if (!pluralArg) { pluralArg = `${term}s`; } // There's only one item, so just use the singular word. if (count === 1) { return term; } // There are multiple items, so use the plural word. return pluralArg; } class CommentsInLocalTime { constructor() { this.language = ''; this.LocalComments = {}; /** * Settings */ this.settings(); this.language = this.setDefaultSetting( 'language', this.LocalComments.language ); // These values are also reflected in the documentation: // https://en.wikipedia.org/wiki/Wikipedia:Comments_in_Local_Time#Default_settings this.setDefaultSetting({ dateDifference: true, dateFormat: 'dmy', dayOfWeek: true, dropDays: 0, dropMonths: 0, timeFirst: true, twentyFourHours: false, }); } adjustTime(originalTimestamp, search) { const { time, today, tomorrow, yesterday } = getDates( originalTimestamp.match(search) ); // A string matching the date pattern was found, but it cannot be // converted to a Date object. Return it with no changes made. if (Number.isNaN(time)) { return [originalTimestamp, '']; } const date = this.determineDateText({ time, today, tomorrow, yesterday, }); const { ampm, hour } = this.getHour(time); const minute = addLeadingZero(time.getMinutes()); const finalTime = `${hour}:${minute}${ampm}`; // Determine the time offset. const utcValue = (-1 * time.getTimezoneOffset()) / 60; const utcOffset = utcValue >= 0 ? `+${utcValue}` : `−${Math.abs(utcValue.toFixed(1))}`; const utcPart = `(UTC${utcOffset})`; const returnDate = this.LocalComments.timeFirst ? `${finalTime}, ${date} ${utcPart}` : `${date}, ${finalTime} ${utcPart}`; return returnDate; } convertNumberToMonth(number) { return [ this.language.January, this.language.February, this.language.March, this.language.April, this.language.May, this.language.June, this.language.July, this.language.August, this.language.September, this.language.October, this.language.November, this.language.December, ][number]; } createDateText({ day, month, time, today, year }) { // Calculate day of week const dayNames = [ this.language.Sunday, this.language.Monday, this.language.Tuesday, this.language.Wednesday, this.language.Thursday, this.language.Friday, this.language.Saturday, ]; const dayOfTheWeek = dayNames[time.getDay()]; let descriptiveDifference = ''; let last = ''; // Create a relative descriptive difference if (this.LocalComments.dateDifference) { ({ descriptiveDifference, last } = this.createRelativeDate( today, time )); } const monthName = this.convertNumberToMonth(time.getMonth()); // Format the date according to user preferences let formattedDate = ''; switch (this.LocalComments.dateFormat.toLowerCase()) { case 'dmy': formattedDate = `${day} ${monthName} ${year}`; break; case 'mdy': formattedDate = `${monthName} ${day}, ${year}`; break; default: formattedDate = `${year}-${month}-${addLeadingZero(day)}`; } const formattedDayOfTheWeek = this.LocalComments.dayOfWeek ? `, ${last}${dayOfTheWeek}` : ''; return `${formattedDate}${formattedDayOfTheWeek}${descriptiveDifference}`; } /** * Create relative date data. * * @param {Date} today Today * @param {Date} time The timestamp from a comment * @returns {Object.<string, *>} Relative date data */ createRelativeDate(today, time) { /** * The time difference from today, in milliseconds. * * @type {number} */ const millisecondsAgo = today.getTime() - time.getTime(); /** * The number of days ago, that we will display. It's not necessarily the * total days ago. * * @type {number} */ let daysAgo = Math.abs(Math.round(millisecondsAgo / 1000 / 60 / 60 / 24)); const { differenceWord, last } = this.relativeText({ daysAgo, millisecondsAgo, }); // This method of computing the years and months is not exact. However, // it's better than the previous method that used 1 January + delta days. // That was usually quite off because it mapped the second delta month to // February, which has only 28 days. This method is usually not more than // one day off, except perhaps over very distant dates. /** * The number of months ago, that we will display. It's not necessarily * the total months ago. * * @type {number} */ let monthsAgo = Math.floor((daysAgo / 365) * 12); /** * The total amount of time ago, in months. * * @type {number} */ const totalMonthsAgo = monthsAgo; /** * The number of years ago that we will display. It's not necessarily the * total years ago. * * @type {number} */ let yearsAgo = Math.floor(totalMonthsAgo / 12); if (totalMonthsAgo < this.LocalComments.dropMonths) { yearsAgo = 0; } else if (this.LocalComments.dropMonths > 0) { monthsAgo = 0; } else { monthsAgo -= yearsAgo * 12; } if (daysAgo < this.LocalComments.dropDays) { monthsAgo = 0; yearsAgo = 0; } else if (this.LocalComments.dropDays > 0 && totalMonthsAgo >= 1) { daysAgo = 0; } else { daysAgo -= Math.floor((totalMonthsAgo * 365) / 12); } const descriptiveParts = []; // There is years text to add. if (yearsAgo > 0) { descriptiveParts.push( `${yearsAgo} ${pluralize( this.language.year, yearsAgo, this.language.years )}` ); } // There is months text to add. if (monthsAgo > 0) { descriptiveParts.push( `${monthsAgo} ${pluralize( this.language.month, monthsAgo, this.language.months )}` ); } // There is days text to add. if (daysAgo > 0) { descriptiveParts.push( `${daysAgo} ${pluralize( this.language.day, daysAgo, this.language.days )}` ); } return { descriptiveDifference: ` (${descriptiveParts.join( ', ' )} ${differenceWord})`, last, }; } determineDateText({ time, today, tomorrow, yesterday }) { // Set the date bits to output. const year = time.getFullYear(); const month = addLeadingZero(time.getMonth() + 1); const day = time.getDate(); // Return 'today' or 'yesterday' if that is the case if ( year === today.getFullYear() && month === addLeadingZero(today.getMonth() + 1) && day === today.getDate() ) { return this.language.Today; } if ( year === yesterday.getFullYear() && month === addLeadingZero(yesterday.getMonth() + 1) && day === yesterday.getDate() ) { return this.language.Yesterday; } if ( year === tomorrow.getFullYear() && month === addLeadingZero(tomorrow.getMonth() + 1) && day === tomorrow.getDate() ) { return this.language.Tomorrow; } return this.createDateText({ day, month, time, today, year }); } getHour(time) { let ampm; let hour = Number.parseInt(time.getHours(), 10); if (this.LocalComments.twentyFourHours) { ampm = ''; hour = addLeadingZero(hour); } else { // Output am or pm depending on the date. ampm = hour <= 11 ? ' am' : ' pm'; if (hour > 12) { hour -= 12; } else if (hour === 0) { hour = 12; } } return { ampm, hour }; } relativeText({ daysAgo, millisecondsAgo }) { let differenceWord = ''; let last = ''; // The date is in the past. if (millisecondsAgo >= 0) { differenceWord = this.language.ago; if (daysAgo <= 7) { last = `${this.language.last} `; } // The date is in the future. } else { differenceWord = this.language['from now']; if (daysAgo <= 7) { last = `${this.language.this} `; } } return { differenceWord, last }; } replaceText(node, search) { if (!node) { return; } // Check if this is a text node. if (node.nodeType === 3) { // Don't continue if this text node's parent tag is one of these. if (['CODE', 'PRE'].includes(node.parentNode.nodeName)) { return; } const value = node.nodeValue; const matches = value.match(search); if (matches) { // Only act on the first timestamp we found in this node. This is for // the rare occassion that there is more than one timestamp in the // same text node. const [match] = matches; const position = value.search(search); const stringLength = match.toString().length; // Grab the text content before and after the matching timestamp, // which we'll then wrap in their own SPAN nodes. const beforeMatch = value.slice(0, position); const afterMatch = value.slice(position + stringLength); const returnDate = this.adjustTime(match.toString(), search); // Create the code to display the new local comments content. const $span = $( `<span class="localcomments" style="font-size: 95%;" title="${match}">${returnDate}</span>` ); // Replace the existing text node in the page with our new local // comments node. $(node).replaceWith($span); // Replace the text content that appears before the timestamp. if (beforeMatch) { $span.before( `<span class="before-localcomments">${beforeMatch}</span>` ); } // Replace the text content that appears after the timestamp. if (afterMatch) { $span.after( `<span class="after-localcomments">${afterMatch}</span>` ); } } } else { const children = []; let child; [child] = node.childNodes; while (child) { children.push(child); child = child.nextSibling; } // Loop through children and run this func on it again, recursively. children.forEach((child2) => { this.replaceText(child2, search); }); } } run() { if ( ['', 'MediaWiki', 'Special'].includes( mw.config.get('wgCanonicalNamespace') ) ) { return; } // Check for disabled URLs. const isDisabledUrl = ['action=history'].some((disabledUrl) => document.location.href.includes(disabledUrl) ); if (isDisabledUrl) { return; } this.replaceText( document.querySelector('.mw-body-content .mw-parser-output'), /(\d{1,2}):(\d{2}), (\d{1,2}) ([A-Z][a-z]+) (\d{4}) \(UTC\)/ ); } setDefaultSetting(...args) { // There are no arguments. if (args.length === 0) { return false; } // The first arg is an object, so just set that data directly onto the // settings object. like {setting 1: true, setting 2: false} if (typeof args[0] === 'object') { const [settings] = args; // Loop through each setting. Object.keys(settings).forEach((name) => { const value = settings[name]; if (typeof this.LocalComments[name] === 'undefined') { this.LocalComments[name] = value; } }); return settings; } // The first arg is a string, so use the first arg as the settings key, // and the second arg as the value to set it to. const [name, setting] = args; if (typeof this.LocalComments[name] === 'undefined') { this.LocalComments[name] = setting; } return this.LocalComments[name]; } /** * Set the script's settings. * * @returns {undefined} */ settings() { // The user has set custom settings, so use those. if (window.LocalComments) { this.LocalComments = window.LocalComments; } /** * Language * * LOCALIZING THIS SCRIPT * To localize this script, change the terms below, * to the RIGHT of the colons, to the correct term used in that language. * * For example, in the French language, * * 'Today' : 'Today', * * would be * * 'Today' : "Aujourd'hui", */ this.LocalComments.language = { // Relative terms Today: 'Today', Yesterday: 'Yesterday', Tomorrow: 'Tomorrow', last: 'last', this: 'this', // Days of the week Sunday: 'Sunday', Monday: 'Monday', Tuesday: 'Tuesday', Wednesday: 'Wednesday', Thursday: 'Thursday', Friday: 'Friday', Saturday: 'Saturday', // Months of the year January: 'January', February: 'February', March: 'March', April: 'April', May: 'May', June: 'June', July: 'July', August: 'August', September: 'September', October: 'October', November: 'November', December: 'December', // Difference words ago: 'ago', 'from now': 'from now', // Date phrases year: 'year', years: 'years', month: 'month', months: 'months', day: 'day', days: 'days', }; } } // Check if we've already ran this script. if (window.commentsInLocalTimeWasRun) { return; } window.commentsInLocalTimeWasRun = true; const commentsInLocalTime = new CommentsInLocalTime(); commentsInLocalTime.run(); }); 13houlikxdhnop5vg42wvznssty7q8h 88931 88930 2026-08-06T23:15:47Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-CommentsInLocalTime.js]] 88930 javascript text/javascript // {{documentation}} // _________________________________________________________________________________________ // | | // | === WARNING: GLOBAL GADGET FILE === | // | Changes to this page affect many users. | // | Please discuss changes on the [[Wiktionary:Grease Pit]] before editing. | // |_________________________________________________________________________________________| // // // The content below are copied from https://en.wikipedia.org/w/index.php?title=User:Gary/comments_in_local_time.js&oldid=1103519446 // See [[w:User:Gary/comments_in_local_time.js]], [[w:Wikipedia:Comments in Local Time]] // ********************************************************************************************************************************* /** * COMMENTS IN LOCAL TIME * * Description: * Changes [[Coordinated Universal Time|UTC]]-based times and dates, * such as those used in signatures, to be relative to local time. * * Documentation: * [[Wikipedia:Comments in Local Time]] */ $(() => { /** * Given a number, add a leading zero if necessary, so that the final number * has two characters. * * @param {number} number Number * @returns {string} The number with a leading zero, if necessary. */ function addLeadingZero(number) { const numberArg = number; if (numberArg < 10) { return `0${numberArg}`; } return numberArg; } function convertMonthToNumber(month) { return new Date(`${month} 1, 2001`).getMonth(); } function getDates(time) { const [, oldHour, oldMinute, oldDay, oldMonth, oldYear] = time; // Today const today = new Date(); // Yesterday const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); // Tomorrow const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); // Set the date entered. const newTime = new Date(); newTime.setUTCFullYear(oldYear, convertMonthToNumber(oldMonth), oldDay); newTime.setUTCHours(oldHour); newTime.setUTCMinutes(oldMinute); return { time: newTime, today, tomorrow, yesterday }; } /** * Determine whether to use the singular or plural word, and use that. * * @param {string} term Original term * @param {number} count Count of items * @param {string} plural Pluralized term * @returns {string} The word to use */ function pluralize(term, count, plural = null) { let pluralArg = plural; // No unique pluralized word is found, so just use a general one. if (!pluralArg) { pluralArg = `${term}s`; } // There's only one item, so just use the singular word. if (count === 1) { return term; } // There are multiple items, so use the plural word. return pluralArg; } class CommentsInLocalTime { constructor() { this.language = ''; this.LocalComments = {}; /** * Settings */ this.settings(); this.language = this.setDefaultSetting( 'language', this.LocalComments.language ); // These values are also reflected in the documentation: // https://en.wikipedia.org/wiki/Wikipedia:Comments_in_Local_Time#Default_settings this.setDefaultSetting({ dateDifference: true, dateFormat: 'dmy', dayOfWeek: true, dropDays: 0, dropMonths: 0, timeFirst: true, twentyFourHours: false, }); } adjustTime(originalTimestamp, search) { const { time, today, tomorrow, yesterday } = getDates( originalTimestamp.match(search) ); // A string matching the date pattern was found, but it cannot be // converted to a Date object. Return it with no changes made. if (Number.isNaN(time)) { return [originalTimestamp, '']; } const date = this.determineDateText({ time, today, tomorrow, yesterday, }); const { ampm, hour } = this.getHour(time); const minute = addLeadingZero(time.getMinutes()); const finalTime = `${hour}:${minute}${ampm}`; // Determine the time offset. const utcValue = (-1 * time.getTimezoneOffset()) / 60; const utcOffset = utcValue >= 0 ? `+${utcValue}` : `−${Math.abs(utcValue.toFixed(1))}`; const utcPart = `(UTC${utcOffset})`; const returnDate = this.LocalComments.timeFirst ? `${finalTime}, ${date} ${utcPart}` : `${date}, ${finalTime} ${utcPart}`; return returnDate; } convertNumberToMonth(number) { return [ this.language.January, this.language.February, this.language.March, this.language.April, this.language.May, this.language.June, this.language.July, this.language.August, this.language.September, this.language.October, this.language.November, this.language.December, ][number]; } createDateText({ day, month, time, today, year }) { // Calculate day of week const dayNames = [ this.language.Sunday, this.language.Monday, this.language.Tuesday, this.language.Wednesday, this.language.Thursday, this.language.Friday, this.language.Saturday, ]; const dayOfTheWeek = dayNames[time.getDay()]; let descriptiveDifference = ''; let last = ''; // Create a relative descriptive difference if (this.LocalComments.dateDifference) { ({ descriptiveDifference, last } = this.createRelativeDate( today, time )); } const monthName = this.convertNumberToMonth(time.getMonth()); // Format the date according to user preferences let formattedDate = ''; switch (this.LocalComments.dateFormat.toLowerCase()) { case 'dmy': formattedDate = `${day} ${monthName} ${year}`; break; case 'mdy': formattedDate = `${monthName} ${day}, ${year}`; break; default: formattedDate = `${year}-${month}-${addLeadingZero(day)}`; } const formattedDayOfTheWeek = this.LocalComments.dayOfWeek ? `, ${last}${dayOfTheWeek}` : ''; return `${formattedDate}${formattedDayOfTheWeek}${descriptiveDifference}`; } /** * Create relative date data. * * @param {Date} today Today * @param {Date} time The timestamp from a comment * @returns {Object.<string, *>} Relative date data */ createRelativeDate(today, time) { /** * The time difference from today, in milliseconds. * * @type {number} */ const millisecondsAgo = today.getTime() - time.getTime(); /** * The number of days ago, that we will display. It's not necessarily the * total days ago. * * @type {number} */ let daysAgo = Math.abs(Math.round(millisecondsAgo / 1000 / 60 / 60 / 24)); const { differenceWord, last } = this.relativeText({ daysAgo, millisecondsAgo, }); // This method of computing the years and months is not exact. However, // it's better than the previous method that used 1 January + delta days. // That was usually quite off because it mapped the second delta month to // February, which has only 28 days. This method is usually not more than // one day off, except perhaps over very distant dates. /** * The number of months ago, that we will display. It's not necessarily * the total months ago. * * @type {number} */ let monthsAgo = Math.floor((daysAgo / 365) * 12); /** * The total amount of time ago, in months. * * @type {number} */ const totalMonthsAgo = monthsAgo; /** * The number of years ago that we will display. It's not necessarily the * total years ago. * * @type {number} */ let yearsAgo = Math.floor(totalMonthsAgo / 12); if (totalMonthsAgo < this.LocalComments.dropMonths) { yearsAgo = 0; } else if (this.LocalComments.dropMonths > 0) { monthsAgo = 0; } else { monthsAgo -= yearsAgo * 12; } if (daysAgo < this.LocalComments.dropDays) { monthsAgo = 0; yearsAgo = 0; } else if (this.LocalComments.dropDays > 0 && totalMonthsAgo >= 1) { daysAgo = 0; } else { daysAgo -= Math.floor((totalMonthsAgo * 365) / 12); } const descriptiveParts = []; // There is years text to add. if (yearsAgo > 0) { descriptiveParts.push( `${yearsAgo} ${pluralize( this.language.year, yearsAgo, this.language.years )}` ); } // There is months text to add. if (monthsAgo > 0) { descriptiveParts.push( `${monthsAgo} ${pluralize( this.language.month, monthsAgo, this.language.months )}` ); } // There is days text to add. if (daysAgo > 0) { descriptiveParts.push( `${daysAgo} ${pluralize( this.language.day, daysAgo, this.language.days )}` ); } return { descriptiveDifference: ` (${descriptiveParts.join( ', ' )} ${differenceWord})`, last, }; } determineDateText({ time, today, tomorrow, yesterday }) { // Set the date bits to output. const year = time.getFullYear(); const month = addLeadingZero(time.getMonth() + 1); const day = time.getDate(); // Return 'today' or 'yesterday' if that is the case if ( year === today.getFullYear() && month === addLeadingZero(today.getMonth() + 1) && day === today.getDate() ) { return this.language.Today; } if ( year === yesterday.getFullYear() && month === addLeadingZero(yesterday.getMonth() + 1) && day === yesterday.getDate() ) { return this.language.Yesterday; } if ( year === tomorrow.getFullYear() && month === addLeadingZero(tomorrow.getMonth() + 1) && day === tomorrow.getDate() ) { return this.language.Tomorrow; } return this.createDateText({ day, month, time, today, year }); } getHour(time) { let ampm; let hour = Number.parseInt(time.getHours(), 10); if (this.LocalComments.twentyFourHours) { ampm = ''; hour = addLeadingZero(hour); } else { // Output am or pm depending on the date. ampm = hour <= 11 ? ' am' : ' pm'; if (hour > 12) { hour -= 12; } else if (hour === 0) { hour = 12; } } return { ampm, hour }; } relativeText({ daysAgo, millisecondsAgo }) { let differenceWord = ''; let last = ''; // The date is in the past. if (millisecondsAgo >= 0) { differenceWord = this.language.ago; if (daysAgo <= 7) { last = `${this.language.last} `; } // The date is in the future. } else { differenceWord = this.language['from now']; if (daysAgo <= 7) { last = `${this.language.this} `; } } return { differenceWord, last }; } replaceText(node, search) { if (!node) { return; } // Check if this is a text node. if (node.nodeType === 3) { // Don't continue if this text node's parent tag is one of these. if (['CODE', 'PRE'].includes(node.parentNode.nodeName)) { return; } const value = node.nodeValue; const matches = value.match(search); if (matches) { // Only act on the first timestamp we found in this node. This is for // the rare occassion that there is more than one timestamp in the // same text node. const [match] = matches; const position = value.search(search); const stringLength = match.toString().length; // Grab the text content before and after the matching timestamp, // which we'll then wrap in their own SPAN nodes. const beforeMatch = value.slice(0, position); const afterMatch = value.slice(position + stringLength); const returnDate = this.adjustTime(match.toString(), search); // Create the code to display the new local comments content. const $span = $( `<span class="localcomments" style="font-size: 95%;" title="${match}">${returnDate}</span>` ); // Replace the existing text node in the page with our new local // comments node. $(node).replaceWith($span); // Replace the text content that appears before the timestamp. if (beforeMatch) { $span.before( `<span class="before-localcomments">${beforeMatch}</span>` ); } // Replace the text content that appears after the timestamp. if (afterMatch) { $span.after( `<span class="after-localcomments">${afterMatch}</span>` ); } } } else { const children = []; let child; [child] = node.childNodes; while (child) { children.push(child); child = child.nextSibling; } // Loop through children and run this func on it again, recursively. children.forEach((child2) => { this.replaceText(child2, search); }); } } run() { if ( ['', 'MediaWiki', 'Special'].includes( mw.config.get('wgCanonicalNamespace') ) ) { return; } // Check for disabled URLs. const isDisabledUrl = ['action=history'].some((disabledUrl) => document.location.href.includes(disabledUrl) ); if (isDisabledUrl) { return; } this.replaceText( document.querySelector('.mw-body-content .mw-parser-output'), /(\d{1,2}):(\d{2}), (\d{1,2}) ([A-Z][a-z]+) (\d{4}) \(UTC\)/ ); } setDefaultSetting(...args) { // There are no arguments. if (args.length === 0) { return false; } // The first arg is an object, so just set that data directly onto the // settings object. like {setting 1: true, setting 2: false} if (typeof args[0] === 'object') { const [settings] = args; // Loop through each setting. Object.keys(settings).forEach((name) => { const value = settings[name]; if (typeof this.LocalComments[name] === 'undefined') { this.LocalComments[name] = value; } }); return settings; } // The first arg is a string, so use the first arg as the settings key, // and the second arg as the value to set it to. const [name, setting] = args; if (typeof this.LocalComments[name] === 'undefined') { this.LocalComments[name] = setting; } return this.LocalComments[name]; } /** * Set the script's settings. * * @returns {undefined} */ settings() { // The user has set custom settings, so use those. if (window.LocalComments) { this.LocalComments = window.LocalComments; } /** * Language * * LOCALIZING THIS SCRIPT * To localize this script, change the terms below, * to the RIGHT of the colons, to the correct term used in that language. * * For example, in the French language, * * 'Today' : 'Today', * * would be * * 'Today' : "Aujourd'hui", */ this.LocalComments.language = { // Relative terms Today: 'Today', Yesterday: 'Yesterday', Tomorrow: 'Tomorrow', last: 'last', this: 'this', // Days of the week Sunday: 'Sunday', Monday: 'Monday', Tuesday: 'Tuesday', Wednesday: 'Wednesday', Thursday: 'Thursday', Friday: 'Friday', Saturday: 'Saturday', // Months of the year January: 'January', February: 'February', March: 'March', April: 'April', May: 'May', June: 'June', July: 'July', August: 'August', September: 'September', October: 'October', November: 'November', December: 'December', // Difference words ago: 'ago', 'from now': 'from now', // Date phrases year: 'year', years: 'years', month: 'month', months: 'months', day: 'day', days: 'days', }; } } // Check if we've already ran this script. if (window.commentsInLocalTimeWasRun) { return; } window.commentsInLocalTimeWasRun = true; const commentsInLocalTime = new CommentsInLocalTime(); commentsInLocalTime.run(); }); 13houlikxdhnop5vg42wvznssty7q8h MediaWiki:Gadget-UTCLiveClock.js 8 17965 88932 2025-09-14T14:51:15Z en>Surjection 0 allow override in case someone wants to 88932 javascript text/javascript // {{documentation}} window.UTCLiveClockLocation = window.UTCLiveClockLocation || 'outside'; // see [[mw:MediaWiki:Gadget-UTCLiveClock]] mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-UTCLiveClock.js&action=raw&ctype=text/javascript'); br5it9eznjp6c2wr62ib6dljeq06622 88933 88932 2026-08-06T23:15:57Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-UTCLiveClock.js]] 88932 javascript text/javascript // {{documentation}} window.UTCLiveClockLocation = window.UTCLiveClockLocation || 'outside'; // see [[mw:MediaWiki:Gadget-UTCLiveClock]] mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-UTCLiveClock.js&action=raw&ctype=text/javascript'); br5it9eznjp6c2wr62ib6dljeq06622 MediaWiki:Gadget-UTCLiveClock.css 8 17966 88934 2017-10-06T14:59:43Z en>Gamren 0 Created page with "/** * Explicitly set width of the UTC-clock list element, so that we can use a * hidden peer gadget to add space where the clock would go before it loads. */ .skin-vector #..." 88934 css text/css /** * Explicitly set width of the UTC-clock list element, so that we can use a * hidden peer gadget to add space where the clock would go before it loads. */ .skin-vector #utcdate { width: 6em; /* * The default margin-left is 0.75em, but set it again here explicitly, so * we can be sure of the exact width. */ margin-left: 0.75em; } .skin-monobook #utcdate { width: 6.279em; display: inline-block; /* We need this for the width property to work */ /* * The default margin-left is 1em, but set it again here explicitly, so * we can be sure of the exact width. */ margin-left: 1em; } a9b5uwepu2o3etikfxjo5stx2yqmdz4 88935 88934 2026-08-06T23:16:06Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-UTCLiveClock.css]] 88934 css text/css /** * Explicitly set width of the UTC-clock list element, so that we can use a * hidden peer gadget to add space where the clock would go before it loads. */ .skin-vector #utcdate { width: 6em; /* * The default margin-left is 0.75em, but set it again here explicitly, so * we can be sure of the exact width. */ margin-left: 0.75em; } .skin-monobook #utcdate { width: 6.279em; display: inline-block; /* We need this for the width property to work */ /* * The default margin-left is 1em, but set it again here explicitly, so * we can be sure of the exact width. */ margin-left: 1em; } a9b5uwepu2o3etikfxjo5stx2yqmdz4 MediaWiki:Gadget-WiktSidebarTranslation.js 8 17967 88936 2017-08-17T06:16:09Z en>Dixtosa 0 88936 javascript text/javascript $(function(){ $("#p-lang .interlanguage-link a").each(function(){ var langnameMatch = $(this).attr("title").match(/(.*) – (.*)/); var langname = $(this).attr("title"); //some wiktionaries like afrikaans have '' as their main page if (langnameMatch && langnameMatch.length >= 3) langname = langnameMatch[2]; $(this).text(langname) .attr("lang", "en");//this line breaks compact languages }); $("#p-lang .interlanguage-link").sort(function(lia, lib){ return $(lia).children().first().text() < $(lib).children().first().text() ? -1 : 1; }).appendTo("#p-lang>div>ul"); }); 0l3tsev12k2w1jgnrnjj728cjr5knji 88937 88936 2026-08-06T23:16:14Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-WiktSidebarTranslation.js]] 88936 javascript text/javascript $(function(){ $("#p-lang .interlanguage-link a").each(function(){ var langnameMatch = $(this).attr("title").match(/(.*) – (.*)/); var langname = $(this).attr("title"); //some wiktionaries like afrikaans have '' as their main page if (langnameMatch && langnameMatch.length >= 3) langname = langnameMatch[2]; $(this).text(langname) .attr("lang", "en");//this line breaks compact languages }); $("#p-lang .interlanguage-link").sort(function(lia, lib){ return $(lia).children().first().text() < $(lib).children().first().text() ? -1 : 1; }).appendTo("#p-lang>div>ul"); }); 0l3tsev12k2w1jgnrnjj728cjr5knji MediaWiki:Gadget-TreeDescs-pagestyles.css 8 17968 88938 2025-11-18T19:48:01Z en>Surjection 0 Surjection changed the content model of the page [[MediaWiki:Gadget-TreeDescs-pagestyles.css]] from "Sanitized CSS" to "CSS": gadgets cannot use sanitized CSS 88938 css text/css /* code forked from [[w:Template:Tree list/styles.css]] */ .treeview ul { padding: 0; margin: 0; } .treeview li li { margin: 0; list-style-type: none; list-style-image: none; background: url("https://upload.wikimedia.org/wikipedia/commons/f/f2/Treeview-grey-line.png") no-repeat 0 -2979.5px; /* @noflip */ padding: 0 0 0 21px; text-indent: 0.3em; } .treeview li li:last-child { background-position: 0 -5969.5px } /* first line here deals with new situation after RemexHTML switch, * where emptyline cause the first child to become the 2nd child. Such a mess */ .treeview li.emptyline > ul > .mw-empty-elt:first-child + .emptyline, .treeview li.emptyline > ul > li:first-child { background-position: 0 9px } /* additional code for Wiktionary */ .treeview li dd { margin: 0; } .treeview li dl { margin: 0; padding-left: 21px; } .treeview li dl:not(:last-child) { background: url("https://upload.wikimedia.org/wikipedia/commons/f/f2/Treeview-grey-line.png") no-repeat 0 -2px; /* @noflip */ padding-left: 21px; text-indent: 0.3em; } .treeview .desc-arr { color: var(--wikt-palette-grey-9, grey); } .treeview li li .desc-arr { vertical-align: top; } lz282qet5qzkmuxcslusjro6a7akd85 88939 88938 2026-08-06T23:16:52Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TreeDescs-pagestyles.css]] 88938 css text/css /* code forked from [[w:Template:Tree list/styles.css]] */ .treeview ul { padding: 0; margin: 0; } .treeview li li { margin: 0; list-style-type: none; list-style-image: none; background: url("https://upload.wikimedia.org/wikipedia/commons/f/f2/Treeview-grey-line.png") no-repeat 0 -2979.5px; /* @noflip */ padding: 0 0 0 21px; text-indent: 0.3em; } .treeview li li:last-child { background-position: 0 -5969.5px } /* first line here deals with new situation after RemexHTML switch, * where emptyline cause the first child to become the 2nd child. Such a mess */ .treeview li.emptyline > ul > .mw-empty-elt:first-child + .emptyline, .treeview li.emptyline > ul > li:first-child { background-position: 0 9px } /* additional code for Wiktionary */ .treeview li dd { margin: 0; } .treeview li dl { margin: 0; padding-left: 21px; } .treeview li dl:not(:last-child) { background: url("https://upload.wikimedia.org/wikipedia/commons/f/f2/Treeview-grey-line.png") no-repeat 0 -2px; /* @noflip */ padding-left: 21px; text-indent: 0.3em; } .treeview .desc-arr { color: var(--wikt-palette-grey-9, grey); } .treeview li li .desc-arr { vertical-align: top; } lz282qet5qzkmuxcslusjro6a7akd85 MediaWiki:Gadget-ShowIDs-pagestyles.css 8 17969 88940 2026-05-15T14:39:51Z en>Fenakhay 0 Remove duplication 88940 css text/css .senseid, .etymid, .senseid-displayed, .etymid-displayed { --id-border: var(--wikt-palette-blue-6); --id-background: var(--wikt-palette-blue-1); --id-background-target: var(--wikt-palette-blue-4); } .etymonid, .etymonid-displayed { --id-border: var(--wikt-palette-red-6); --id-background: var(--wikt-palette-red-1); --id-background-target: var(--wikt-palette-red-4); } .etymid, .etymonid { margin-left: 0; padding: 0 !important; display: inline; } .senseid-displayed, .etymid-displayed, .etymonid-displayed, .senseid::before, .etymid::before, .etymonid::before { border: 1px solid var(--id-border); background: var(--id-background); color: var(--wikt-palette-black); border-radius: 5px; font-size: 90%; margin-right: 0.1em; padding: 0.2em !important; content: attr(data-id); } .senseid-displayed:target, .etymid-displayed:target, .etymonid-displayed:target, .senseid:target .senseid-displayed, .etymid:target .etymid-displayed, .etymonid:target .etymonid-displayed, .senseid:target::before, .etymid:target::before, .etymonid:target::before { background: var(--id-background-target); font-weight: 600; } .senseid:not([data-id])::before, .etymid:not([data-id])::before, .etymonid:not([data-id])::before, .senseid[data-id=""]::before, .etymid[data-id=""]::before, .etymonid[data-id=""]::before { content: none !important; display: none !important; } 9c32gfnz5l4kzwwbspg704ebxwivhou 88941 88940 2026-08-06T23:17:01Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-ShowIDs-pagestyles.css]] 88940 css text/css .senseid, .etymid, .senseid-displayed, .etymid-displayed { --id-border: var(--wikt-palette-blue-6); --id-background: var(--wikt-palette-blue-1); --id-background-target: var(--wikt-palette-blue-4); } .etymonid, .etymonid-displayed { --id-border: var(--wikt-palette-red-6); --id-background: var(--wikt-palette-red-1); --id-background-target: var(--wikt-palette-red-4); } .etymid, .etymonid { margin-left: 0; padding: 0 !important; display: inline; } .senseid-displayed, .etymid-displayed, .etymonid-displayed, .senseid::before, .etymid::before, .etymonid::before { border: 1px solid var(--id-border); background: var(--id-background); color: var(--wikt-palette-black); border-radius: 5px; font-size: 90%; margin-right: 0.1em; padding: 0.2em !important; content: attr(data-id); } .senseid-displayed:target, .etymid-displayed:target, .etymonid-displayed:target, .senseid:target .senseid-displayed, .etymid:target .etymid-displayed, .etymonid:target .etymonid-displayed, .senseid:target::before, .etymid:target::before, .etymonid:target::before { background: var(--id-background-target); font-weight: 600; } .senseid:not([data-id])::before, .etymid:not([data-id])::before, .etymonid:not([data-id])::before, .senseid[data-id=""]::before, .etymid[data-id=""]::before, .etymonid[data-id=""]::before { content: none !important; display: none !important; } 9c32gfnz5l4kzwwbspg704ebxwivhou MediaWiki:Gadget-WiktGadgetPrefs.js 8 17970 88942 2025-09-14T16:29:49Z en>Ioaxxere 0 docs should encourage good style 88942 javascript text/javascript /* global mw */ // <nowiki> /*jshint shadow:true, undef:true, latedef:true, unused:true, esversion:3 */ /** * WiktGadgetPrefs -- developed by [[wikt:en:User:Surjection]] * * *********************************************************************** * Documentation for gadget authors: * Example usage (remember to add ext.gadget.WiktGadgetPrefs as a dependency): const preferences = mw.wiktGadgetPrefs.get("gadgetfoobar", { "label": { "en": "Foobar Gadget" } }, { "frobulate": { "type": "boolean", "default": false, "label": { "en": "Whether this gadget should frobulate" } } } ); const shouldFrobulate = preferences.frobulate; // strenum example const preferences = mw.wiktGadgetPrefs.get("gadgetfoobar", { "label": { "en": "Foobar Gadget" } }, { "frobulate": { "type": "strenum", "default": "yes", "label": { "en": "Whether this gadget should frobulate" }, "choices": [ "yes", "no", "maybe" ], "choiceLabels": { "en": { "yes": "Yes!", "no": "No!!", "maybe": "Maybe?" } } } } ); const shouldFrobulate = preferences.frobulate; *********************************************************************** * * Dependencies needed: mw.user, user.options */ (function() { "use strict"; /** * @typedef WiktGadgetOptions * - Represents gadget options. * @property {{[languageCode: string]: string}} [label] * - The label to display on the preferences page for this * gadget/namespace. The language code should be a MediaWiki * language code, e.g. "en" for English. */ /** * @typedef WiktGadgetPreference * - Represents a single preference. * @property {{"boolean"|"integer"|"string"|"strenum"|"object"}} type * - Must be one of the following: * - "boolean" for boolean values, either true or false. * - "integer" for an integer value. * - "string" for a string value. * - "strenum" for a string value that must be one of the options. * - "object" for an arbitrary JSON value, including null. * No type checks are done. * @property {any} default * - The default value for this preference if missing, or if * the value is invalid. * - The developer is responsible for ensuring that this value is * given, and that it meets the preconditions defined below. * @property {string[]} [choices] * - If the type is "strenum", then this must be an array of * allowed options. If the value is not in this list, the default * value will be returned. * @property {number} [minimum] * - If the type is "integer", this is the minimum allowed value. * @property {number} [maximum] * - If the type is "integer", this is the maximum allowed value. * @property {number} [maximumLength] * - If the type is "string", this is the maximum allowed length. * @property {{[languageCode: string]: string}} [label] * - The label to display on the preferences page for this * preference. The language code should be a MediaWiki * language code, e.g. "en" for English. * @property {{[languageCode: string]: {[choice: string]: string}}} [choiceLabels] * - The label to display on the preferences page for the choices * of this preference (if it is an enum type). The language code * should be a MediaWiki language code, e.g. "en" for English. */ var wiktGadgetPrefs__registeredPrefs = {}; var wiktGadgetPrefs__error = (Error ? function (message) { return new Error(message); } : function (message) { return message; }); var wiktGadgetPrefs__asciify = function (text) { return text.replace(/[^A-Za-z0-9-]/g, function (match) { if (match == "_") { return "__"; } else { return "_" + match.charCodeAt(0).toString(16) + "_"; } }); }; var wiktGadgetPrefs__namespace_to_key = function (namespace) { return "wiktgadgetprefs-" + wiktGadgetPrefs__asciify(namespace); }; var wiktGadgetPrefs__is_integer = function (num) { return num == (num | 0); }; var wiktGadgetPrefs__parse_one = function (value, preference, key) { var defaultValue = preference["default"]; switch (preference.type) { case "boolean": // data type if (typeof value != "boolean") return defaultValue; return value; case "integer": // data type if (typeof value != "number") return defaultValue; // integer check if (!wiktGadgetPrefs__is_integer(value)) return defaultValue; // constraints if ((preference.minimum != null && value < preference.minimum) || (preference.maximum != null && value > preference.maximum)) return defaultValue; return value; case "string": // data type if (typeof value != "string") return defaultValue; // constraints if (preference.maximumLength != null && value.length > preference.maximumLength) return defaultValue; return value; case "strenum": // data type if (typeof value != "string") return defaultValue; // constraints if (preference.choices.indexOf(value) < 0) return defaultValue; return value; case "object": if (typeof value == "undefined") return defaultValue; return value; } throw wiktGadgetPrefs__error("Invalid preference specification '" + key + "'"); }; var wiktGadgetPrefs__parse_all = function (values, preferences) { var parsed = {}; if (!values) values = {}; for (var key in preferences) { if (preferences.hasOwnProperty(key)) { parsed[key] = wiktGadgetPrefs__parse_one(values[key], preferences[key], key); } } return parsed; }; var wiktGadgetPrefs__resolve = function (namespaceKey, preferences) { var resolved; var mwOptions; try { mwOptions = mw.user.options; } catch (e) { } if (!resolved && window.localStorage && window.localStorage.getItem("anon" + namespaceKey) != null) { try { resolved = JSON.parse(window.localStorage.getItem("anon" + namespaceKey)); } catch (e) { } } if (!resolved && mwOptions && mwOptions.exists("userjs-" + namespaceKey)) { try { resolved = JSON.parse(mwOptions.get("userjs-" + namespaceKey)); } catch (e) { } } return wiktGadgetPrefs__parse_all(resolved || {}, preferences); }; /** * Resolve preferences. * * Note that there is a maximum length imposed by MediaWiki * on the total size of the preferences for each namespace. * * @param {string} namespace * - An arbitrary string. This should be unique to each gadget. * @param {WiktGadgetOptions} options * - Options. * @param {{[key: string]: WiktGadgetPreference}} preferences * - Requested preferences, indexed by name. * @returns {{[key: string]: any}} */ var wiktGadgetPrefs_get = function (namespace, options, preferences) { if (wiktGadgetPrefs__registeredPrefs[namespace]) { throw wiktGadgetPrefs__error("wiktGadgetPrefs_get has already been called with the namespace '" + namespace + "'."); } wiktGadgetPrefs__registeredPrefs[namespace] = { options: options, preferences: preferences }; var namespaceKey = wiktGadgetPrefs__namespace_to_key(namespace); if (namespaceKey.length >= 240) { throw wiktGadgetPrefs__error("Namespace key '" + namespace + "' is too long. " + "Please prefer ASCII characters A-Z, a-z, 0-9 and the hyphen, " + "as other characters need to be converted, which increases their size."); } return wiktGadgetPrefs__resolve(namespaceKey, preferences); }; mw.wiktGadgetPrefs = {}; mw.wiktGadgetPrefs.get = wiktGadgetPrefs_get; // Only to be used by the preferences page. mw.wiktGadgetPrefs._namespaceToKey = wiktGadgetPrefs__namespace_to_key; mw.wiktGadgetPrefs._resolve = wiktGadgetPrefs__resolve; mw.wiktGadgetPrefs._registeredPrefs = wiktGadgetPrefs__registeredPrefs; })(); // </nowiki> o4n21hnlfqc4ly11ntzob901aoo3w3p 88943 88942 2026-08-06T23:17:09Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-WiktGadgetPrefs.js]] 88942 javascript text/javascript /* global mw */ // <nowiki> /*jshint shadow:true, undef:true, latedef:true, unused:true, esversion:3 */ /** * WiktGadgetPrefs -- developed by [[wikt:en:User:Surjection]] * * *********************************************************************** * Documentation for gadget authors: * Example usage (remember to add ext.gadget.WiktGadgetPrefs as a dependency): const preferences = mw.wiktGadgetPrefs.get("gadgetfoobar", { "label": { "en": "Foobar Gadget" } }, { "frobulate": { "type": "boolean", "default": false, "label": { "en": "Whether this gadget should frobulate" } } } ); const shouldFrobulate = preferences.frobulate; // strenum example const preferences = mw.wiktGadgetPrefs.get("gadgetfoobar", { "label": { "en": "Foobar Gadget" } }, { "frobulate": { "type": "strenum", "default": "yes", "label": { "en": "Whether this gadget should frobulate" }, "choices": [ "yes", "no", "maybe" ], "choiceLabels": { "en": { "yes": "Yes!", "no": "No!!", "maybe": "Maybe?" } } } } ); const shouldFrobulate = preferences.frobulate; *********************************************************************** * * Dependencies needed: mw.user, user.options */ (function() { "use strict"; /** * @typedef WiktGadgetOptions * - Represents gadget options. * @property {{[languageCode: string]: string}} [label] * - The label to display on the preferences page for this * gadget/namespace. The language code should be a MediaWiki * language code, e.g. "en" for English. */ /** * @typedef WiktGadgetPreference * - Represents a single preference. * @property {{"boolean"|"integer"|"string"|"strenum"|"object"}} type * - Must be one of the following: * - "boolean" for boolean values, either true or false. * - "integer" for an integer value. * - "string" for a string value. * - "strenum" for a string value that must be one of the options. * - "object" for an arbitrary JSON value, including null. * No type checks are done. * @property {any} default * - The default value for this preference if missing, or if * the value is invalid. * - The developer is responsible for ensuring that this value is * given, and that it meets the preconditions defined below. * @property {string[]} [choices] * - If the type is "strenum", then this must be an array of * allowed options. If the value is not in this list, the default * value will be returned. * @property {number} [minimum] * - If the type is "integer", this is the minimum allowed value. * @property {number} [maximum] * - If the type is "integer", this is the maximum allowed value. * @property {number} [maximumLength] * - If the type is "string", this is the maximum allowed length. * @property {{[languageCode: string]: string}} [label] * - The label to display on the preferences page for this * preference. The language code should be a MediaWiki * language code, e.g. "en" for English. * @property {{[languageCode: string]: {[choice: string]: string}}} [choiceLabels] * - The label to display on the preferences page for the choices * of this preference (if it is an enum type). The language code * should be a MediaWiki language code, e.g. "en" for English. */ var wiktGadgetPrefs__registeredPrefs = {}; var wiktGadgetPrefs__error = (Error ? function (message) { return new Error(message); } : function (message) { return message; }); var wiktGadgetPrefs__asciify = function (text) { return text.replace(/[^A-Za-z0-9-]/g, function (match) { if (match == "_") { return "__"; } else { return "_" + match.charCodeAt(0).toString(16) + "_"; } }); }; var wiktGadgetPrefs__namespace_to_key = function (namespace) { return "wiktgadgetprefs-" + wiktGadgetPrefs__asciify(namespace); }; var wiktGadgetPrefs__is_integer = function (num) { return num == (num | 0); }; var wiktGadgetPrefs__parse_one = function (value, preference, key) { var defaultValue = preference["default"]; switch (preference.type) { case "boolean": // data type if (typeof value != "boolean") return defaultValue; return value; case "integer": // data type if (typeof value != "number") return defaultValue; // integer check if (!wiktGadgetPrefs__is_integer(value)) return defaultValue; // constraints if ((preference.minimum != null && value < preference.minimum) || (preference.maximum != null && value > preference.maximum)) return defaultValue; return value; case "string": // data type if (typeof value != "string") return defaultValue; // constraints if (preference.maximumLength != null && value.length > preference.maximumLength) return defaultValue; return value; case "strenum": // data type if (typeof value != "string") return defaultValue; // constraints if (preference.choices.indexOf(value) < 0) return defaultValue; return value; case "object": if (typeof value == "undefined") return defaultValue; return value; } throw wiktGadgetPrefs__error("Invalid preference specification '" + key + "'"); }; var wiktGadgetPrefs__parse_all = function (values, preferences) { var parsed = {}; if (!values) values = {}; for (var key in preferences) { if (preferences.hasOwnProperty(key)) { parsed[key] = wiktGadgetPrefs__parse_one(values[key], preferences[key], key); } } return parsed; }; var wiktGadgetPrefs__resolve = function (namespaceKey, preferences) { var resolved; var mwOptions; try { mwOptions = mw.user.options; } catch (e) { } if (!resolved && window.localStorage && window.localStorage.getItem("anon" + namespaceKey) != null) { try { resolved = JSON.parse(window.localStorage.getItem("anon" + namespaceKey)); } catch (e) { } } if (!resolved && mwOptions && mwOptions.exists("userjs-" + namespaceKey)) { try { resolved = JSON.parse(mwOptions.get("userjs-" + namespaceKey)); } catch (e) { } } return wiktGadgetPrefs__parse_all(resolved || {}, preferences); }; /** * Resolve preferences. * * Note that there is a maximum length imposed by MediaWiki * on the total size of the preferences for each namespace. * * @param {string} namespace * - An arbitrary string. This should be unique to each gadget. * @param {WiktGadgetOptions} options * - Options. * @param {{[key: string]: WiktGadgetPreference}} preferences * - Requested preferences, indexed by name. * @returns {{[key: string]: any}} */ var wiktGadgetPrefs_get = function (namespace, options, preferences) { if (wiktGadgetPrefs__registeredPrefs[namespace]) { throw wiktGadgetPrefs__error("wiktGadgetPrefs_get has already been called with the namespace '" + namespace + "'."); } wiktGadgetPrefs__registeredPrefs[namespace] = { options: options, preferences: preferences }; var namespaceKey = wiktGadgetPrefs__namespace_to_key(namespace); if (namespaceKey.length >= 240) { throw wiktGadgetPrefs__error("Namespace key '" + namespace + "' is too long. " + "Please prefer ASCII characters A-Z, a-z, 0-9 and the hyphen, " + "as other characters need to be converted, which increases their size."); } return wiktGadgetPrefs__resolve(namespaceKey, preferences); }; mw.wiktGadgetPrefs = {}; mw.wiktGadgetPrefs.get = wiktGadgetPrefs_get; // Only to be used by the preferences page. mw.wiktGadgetPrefs._namespaceToKey = wiktGadgetPrefs__namespace_to_key; mw.wiktGadgetPrefs._resolve = wiktGadgetPrefs__resolve; mw.wiktGadgetPrefs._registeredPrefs = wiktGadgetPrefs__registeredPrefs; })(); // </nowiki> o4n21hnlfqc4ly11ntzob901aoo3w3p MediaWiki:Gadget-InflectionTable.css 8 17971 88944 2026-08-01T14:08:56Z en>Fenakhay 0 Fenakhay moved page [[Template:inflection-table-top/style.css]] to [[MediaWiki:Gadget-InflectionTable.css]] without leaving a redirect 88944 sanitized-css text/css /** * This CSS page provides styling for the {{inflection-table-top}} family of templates. * * The style rules are complex and have various dependencies on one another. * They have been comprehensively tested on desktop and mobile. * Take care before making any changes. If you're not confident with CSS, * consider requesting help from an interface administrator. */ .inflection-table-wrapper { padding: 3px; margin: 0.5em 0; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-grey); position: relative; max-width: 100%; box-sizing: border-box; overflow-x: auto; } .inflection-table-wrapper.inflection-table-collapsed { overflow: hidden; } .inflection-table-wrapper.inflection-table-no-title { border: 0; padding: 0; } .inflection-table-wrapper > table { display: table; width: 100%; margin: 0; text-align: center; border-collapse: collapse; border: 1px solid var(--wikt-palette-grey-6); background: var(--wikt-palette-white); } .inflection-table-wrapper > table > caption { display: table-caption; background: var(--wikt-palette-paleblue); text-align: left; font-size: 95%; padding: 0.1em 0.5em; font-weight: bold; } .inflection-table-wrapper.wide > table > tbody > tr { font-size: 90%; } .inflection-table-wrapper > table > tbody > tr > td, .inflection-table-wrapper > table > tbody > tr > th { padding: 0.15em 0.6em; border: solid var(--wikt-palette-grey-6); border-width: 0 1px 1px 0; } .inflection-table-wrapper > table > tbody > tr > td:not(.secondary):not(.separator) { min-width: 5em; } /* very-narrow is for tables of unusually short words (e.g. pronouns). The :not selectors are styling-wise unnecessary but must stay: they give this rule the specificity it needs to beat the previous one. */ .inflection-table-wrapper.very-narrow > table > tbody > tr > td:not(.secondary):not(.separator) { min-width: auto; } .inflection-table-wrapper > table > tbody > tr > td.secondary { background: var(--wikt-palette-lightergrey); } .inflection-table-wrapper > table > tbody > tr > th.secondary, .inflection-table-wrapper > table > tbody > tr > th.outer { font-style: italic; } .inflection-table-wrapper > table > tbody > tr > th.secondary > sup, .inflection-table-wrapper > table > tbody > tr > th.outer > sup { font-style: normal; } /* separator and blank cells: see [[Template:la-adecl]], [[Template:ga-decl-noun]] */ .inflection-table-wrapper .separator { height: 0.5em; width: 0.5em; min-height: 0.5em; min-width: 0.5em; padding: 0; background: var(--wikt-palette-paleblue); } .inflection-table-wrapper .separator[rowspan] { border-top: 1px solid var(--wikt-palette-paleblue); border-bottom: 1px solid var(--wikt-palette-paleblue); } .inflection-table-wrapper .separator[colspan] { border-left: 1px solid var(--wikt-palette-paleblue); border-right: 1px solid var(--wikt-palette-paleblue); } /* blank cell at end of row: see [[Template:sco-conj-be]] */ .inflection-table-wrapper .blank-end-row { background: var(--wikt-palette-paleblue); border-right: 1px solid var(--wikt-palette-paleblue); border-top: 1px solid var(--wikt-palette-paleblue); border-bottom: 1px solid var(--wikt-palette-paleblue); } /* Notes at foot of table */ .inflection-table-notes { text-align: left; margin: 0.2em 0.5em 0.2em; } .inflection-table-notes p { margin: 0.5em 0 0.2em; } .inflection-table-wrapper.wide > .inflection-table-notes { font-size: 90%; } /* Collapsibility */ html.client-js .inflection-table-collapsed > table, html.client-js .inflection-table-collapsed > table > tbody > tr > td, html.client-js .inflection-table-collapsed > table > tbody > tr > th { border-color: transparent; } html.client-js .inflection-table-collapsed > table > tbody { visibility: collapse; /* not implemented in Safari - see the .no-vc fallback below */ } html.client-js .inflection-table-collapsed > table > caption { margin-bottom: -0.15em; /* hack: trims excess height from the collapsed box */ } html.client-js .inflection-table-collapsed .inflection-table-notes { display: none; } /* Fallback for browsers without visibility: collapse. JS removes .no-vc when unneeded. */ html.client-js .inflection-table-collapsible.no-vc.inflection-table-collapsed { max-height: calc(1.5em + 8px); /* almost 1lh (= 1.6em) + wrapper padding and border */ overflow: hidden; } html.client-js .inflection-table-collapsible.no-vc.inflection-table-collapsed > table > tbody { visibility: hidden; } html.client-js .inflection-table-collapsible.no-vc > table > caption { white-space: nowrap; /* a second line would be occluded by the max-height above */ } .inflection-table-wrapper .no-vc-spacer { display: inline-block; width: 4em; } /* keeps the [hide] link from scrolling away when the table is uncollapsed */ .inflection-table-wrapper .NavToggle { position: sticky; right: 0.5em; /* matches padding on <caption> */ background: inherit; } /* Single border display style - EXPERIMENTAL! */ .inflection-table-wrapper.single-border { padding: 0; border: 0; } .inflection-table-wrapper.single-border > table > caption { border: 1px solid var(--wikt-palette-grey); border-bottom: 0; } html.client-js .inflection-table-collapsed.single-border > table > caption { border-bottom: 1px solid var(--wikt-palette-grey); } .inflection-table-wrapper.inflection-table-collapsible.single-border .inflection-table-notes { border: 1px solid var(--wikt-palette-grey); border-top: 0; } /* Mobile styling */ @media all and (max-width: 639px) { /* matches calc(640px - 1px) in Minerva CSS */ .inflection-table-wrapper { overflow: auto; max-width: 100%; width: auto !important; /* overrides the inline style that works around a CSS sanitiser lacuna; !important is required to win */ } .inflection-table-collapsed tbody { display: none; } .inflection-table-wrapper .NavToggle { position: sticky; right: 0.5em; background: inherit; } /* stick a single left-hand column of header cells in place */ .inflection-table-wrapper.sticky-left-column > table > tbody > tr > th:first-child { position: sticky; left: -4px; /* counteracts 3px wrapper padding + 1px table border */ max-width: 35vw; } .inflection-table-wrapper.inflection-table-no-title.sticky-left-column > table > tbody > tr > th:first-child { left: -1px; /* counteracts 1px table border */ } } /* Transliterations: paler, on their own line */ .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.tr { color: var(--wikt-palette-grey-9); /* TODO slightly below AAA contrast on a -0 background */ } .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.tr:before { content: "\a"; /* newline */ white-space: pre; } .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.mention-gloss-paren { display: none; } /* Inflection boxes - multiple tables inside one box */ .inflection-box > table { background: none; border: 0; } .inflection-box > table > tbody > tr > td { padding: 0 0.2em; border: 0; vertical-align: top; } .inflection-box .inflection-table-wrapper { display: inline-block; vertical-align: top; margin: 0.2em 0.1em; } /* overqualified on purpose, to beat the no-title palette rule below */ .inflection-box .inflection-table-wrapper > table.inflection-table { background: var(--wikt-palette-white); } .inflection-box.flow-vertical .inflection-table-wrapper { display: block; width: auto !important; /* see the note on the mobile rule above */ } .inflection-box.flow-vertical .inflection-table-wrapper + .inflection-table-wrapper { margin-top: 0.5em; } /* Palettes: dark-on-light */ .inflection-table-wrapper.inflection-table-no-title > table { background-color: var(--wikt-p-0); } .inflection-table tr.secondary > th, .inflection-table th.secondary { background-color: var(--wikt-p-1); } .inflection-table th { background-color: var(--wikt-p-2); } .inflection-table tr.outer > th, .inflection-table th.outer { background-color: var(--wikt-p-4); } .inflection-table tr.darker > td, .inflection-table td.darker { background-color: var(--wikt-p-g-1) !important; /* !important beats the more specific td.secondary rule */ } nyqjz103vuorcxh3kh6hiehkkfh889b 88945 88944 2026-08-06T23:17:29Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-InflectionTable.css]] 88944 sanitized-css text/css /** * This CSS page provides styling for the {{inflection-table-top}} family of templates. * * The style rules are complex and have various dependencies on one another. * They have been comprehensively tested on desktop and mobile. * Take care before making any changes. If you're not confident with CSS, * consider requesting help from an interface administrator. */ .inflection-table-wrapper { padding: 3px; margin: 0.5em 0; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-grey); position: relative; max-width: 100%; box-sizing: border-box; overflow-x: auto; } .inflection-table-wrapper.inflection-table-collapsed { overflow: hidden; } .inflection-table-wrapper.inflection-table-no-title { border: 0; padding: 0; } .inflection-table-wrapper > table { display: table; width: 100%; margin: 0; text-align: center; border-collapse: collapse; border: 1px solid var(--wikt-palette-grey-6); background: var(--wikt-palette-white); } .inflection-table-wrapper > table > caption { display: table-caption; background: var(--wikt-palette-paleblue); text-align: left; font-size: 95%; padding: 0.1em 0.5em; font-weight: bold; } .inflection-table-wrapper.wide > table > tbody > tr { font-size: 90%; } .inflection-table-wrapper > table > tbody > tr > td, .inflection-table-wrapper > table > tbody > tr > th { padding: 0.15em 0.6em; border: solid var(--wikt-palette-grey-6); border-width: 0 1px 1px 0; } .inflection-table-wrapper > table > tbody > tr > td:not(.secondary):not(.separator) { min-width: 5em; } /* very-narrow is for tables of unusually short words (e.g. pronouns). The :not selectors are styling-wise unnecessary but must stay: they give this rule the specificity it needs to beat the previous one. */ .inflection-table-wrapper.very-narrow > table > tbody > tr > td:not(.secondary):not(.separator) { min-width: auto; } .inflection-table-wrapper > table > tbody > tr > td.secondary { background: var(--wikt-palette-lightergrey); } .inflection-table-wrapper > table > tbody > tr > th.secondary, .inflection-table-wrapper > table > tbody > tr > th.outer { font-style: italic; } .inflection-table-wrapper > table > tbody > tr > th.secondary > sup, .inflection-table-wrapper > table > tbody > tr > th.outer > sup { font-style: normal; } /* separator and blank cells: see [[Template:la-adecl]], [[Template:ga-decl-noun]] */ .inflection-table-wrapper .separator { height: 0.5em; width: 0.5em; min-height: 0.5em; min-width: 0.5em; padding: 0; background: var(--wikt-palette-paleblue); } .inflection-table-wrapper .separator[rowspan] { border-top: 1px solid var(--wikt-palette-paleblue); border-bottom: 1px solid var(--wikt-palette-paleblue); } .inflection-table-wrapper .separator[colspan] { border-left: 1px solid var(--wikt-palette-paleblue); border-right: 1px solid var(--wikt-palette-paleblue); } /* blank cell at end of row: see [[Template:sco-conj-be]] */ .inflection-table-wrapper .blank-end-row { background: var(--wikt-palette-paleblue); border-right: 1px solid var(--wikt-palette-paleblue); border-top: 1px solid var(--wikt-palette-paleblue); border-bottom: 1px solid var(--wikt-palette-paleblue); } /* Notes at foot of table */ .inflection-table-notes { text-align: left; margin: 0.2em 0.5em 0.2em; } .inflection-table-notes p { margin: 0.5em 0 0.2em; } .inflection-table-wrapper.wide > .inflection-table-notes { font-size: 90%; } /* Collapsibility */ html.client-js .inflection-table-collapsed > table, html.client-js .inflection-table-collapsed > table > tbody > tr > td, html.client-js .inflection-table-collapsed > table > tbody > tr > th { border-color: transparent; } html.client-js .inflection-table-collapsed > table > tbody { visibility: collapse; /* not implemented in Safari - see the .no-vc fallback below */ } html.client-js .inflection-table-collapsed > table > caption { margin-bottom: -0.15em; /* hack: trims excess height from the collapsed box */ } html.client-js .inflection-table-collapsed .inflection-table-notes { display: none; } /* Fallback for browsers without visibility: collapse. JS removes .no-vc when unneeded. */ html.client-js .inflection-table-collapsible.no-vc.inflection-table-collapsed { max-height: calc(1.5em + 8px); /* almost 1lh (= 1.6em) + wrapper padding and border */ overflow: hidden; } html.client-js .inflection-table-collapsible.no-vc.inflection-table-collapsed > table > tbody { visibility: hidden; } html.client-js .inflection-table-collapsible.no-vc > table > caption { white-space: nowrap; /* a second line would be occluded by the max-height above */ } .inflection-table-wrapper .no-vc-spacer { display: inline-block; width: 4em; } /* keeps the [hide] link from scrolling away when the table is uncollapsed */ .inflection-table-wrapper .NavToggle { position: sticky; right: 0.5em; /* matches padding on <caption> */ background: inherit; } /* Single border display style - EXPERIMENTAL! */ .inflection-table-wrapper.single-border { padding: 0; border: 0; } .inflection-table-wrapper.single-border > table > caption { border: 1px solid var(--wikt-palette-grey); border-bottom: 0; } html.client-js .inflection-table-collapsed.single-border > table > caption { border-bottom: 1px solid var(--wikt-palette-grey); } .inflection-table-wrapper.inflection-table-collapsible.single-border .inflection-table-notes { border: 1px solid var(--wikt-palette-grey); border-top: 0; } /* Mobile styling */ @media all and (max-width: 639px) { /* matches calc(640px - 1px) in Minerva CSS */ .inflection-table-wrapper { overflow: auto; max-width: 100%; width: auto !important; /* overrides the inline style that works around a CSS sanitiser lacuna; !important is required to win */ } .inflection-table-collapsed tbody { display: none; } .inflection-table-wrapper .NavToggle { position: sticky; right: 0.5em; background: inherit; } /* stick a single left-hand column of header cells in place */ .inflection-table-wrapper.sticky-left-column > table > tbody > tr > th:first-child { position: sticky; left: -4px; /* counteracts 3px wrapper padding + 1px table border */ max-width: 35vw; } .inflection-table-wrapper.inflection-table-no-title.sticky-left-column > table > tbody > tr > th:first-child { left: -1px; /* counteracts 1px table border */ } } /* Transliterations: paler, on their own line */ .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.tr { color: var(--wikt-palette-grey-9); /* TODO slightly below AAA contrast on a -0 background */ } .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.tr:before { content: "\a"; /* newline */ white-space: pre; } .inflection-table-wrapper:not(.tr-alongside) table > tbody td span.mention-gloss-paren { display: none; } /* Inflection boxes - multiple tables inside one box */ .inflection-box > table { background: none; border: 0; } .inflection-box > table > tbody > tr > td { padding: 0 0.2em; border: 0; vertical-align: top; } .inflection-box .inflection-table-wrapper { display: inline-block; vertical-align: top; margin: 0.2em 0.1em; } /* overqualified on purpose, to beat the no-title palette rule below */ .inflection-box .inflection-table-wrapper > table.inflection-table { background: var(--wikt-palette-white); } .inflection-box.flow-vertical .inflection-table-wrapper { display: block; width: auto !important; /* see the note on the mobile rule above */ } .inflection-box.flow-vertical .inflection-table-wrapper + .inflection-table-wrapper { margin-top: 0.5em; } /* Palettes: dark-on-light */ .inflection-table-wrapper.inflection-table-no-title > table { background-color: var(--wikt-p-0); } .inflection-table tr.secondary > th, .inflection-table th.secondary { background-color: var(--wikt-p-1); } .inflection-table th { background-color: var(--wikt-p-2); } .inflection-table tr.outer > th, .inflection-table th.outer { background-color: var(--wikt-p-4); } .inflection-table tr.darker > td, .inflection-table td.darker { background-color: var(--wikt-p-g-1) !important; /* !important beats the more specific td.secondary rule */ } nyqjz103vuorcxh3kh6hiehkkfh889b MediaWiki:Gadget-Site.js 8 17972 88946 2025-11-22T01:10:38Z en>Fenakhay 0 88946 javascript text/javascript // This gadget contains code that will run unconditionally for everyone - both on mobile and desktop. // Consider instead adding your code to [[MediaWiki:Common.js]], [[MediaWiki:Mobile.js]], or a gadget. // <nowiki> const pageName = mw.config.get("wgPageName"); const ns = mw.config.get("wgNamespaceNumber"); /* ***** Page-specific code ***** */ switch (pageName) { case "Wiktionary:Main_Page": // [[Wiktionary:Main_Page]] // Workaround for [[phab:T335552]]. document.querySelector(".mw-searchInput").autocapitalize = "off"; break; case "Wiktionary:Gadget_preferences": // [[Wiktionary:Gadget_preferences]] if (mw.config.get("wgAction") === "view") importScript("MediaWiki:WiktGadgetPrefsPage.js"); // [[MediaWiki:WiktGadgetPrefsPage.js]] break; case "MediaWiki:Gadgets-definition": // [[MediaWiki:Gadgets-definition]] importScript("MediaWiki:BetterGadgetsDefinition.js"); // [[MediaWiki:BetterGadgetsDefinition.js]] break; case "Special:Search": // [[Special:Search]] importScript("MediaWiki:FindTrans.js"); // [[MediaWiki:FindTrans.js]] break; case "Wiktionary:Fonts/list": // [[Wiktionary:Fonts/list]] if (mw.config.get("wgAction") === "view") importScript("MediaWiki:InteractiveFontList.js"); // [[MediaWiki:InteractiveFontList.js]] break; case "Wiktionary:Tracking": importScript("MediaWiki:BrowseTrackingCats.js"); // [[MediaWiki:BrowseTrackingCats.js]] } if ( document.querySelector(".mw-parser-output p:first-of-type") && [ "Module:languages/code_to_canonical_name", "Module:languages/canonical_names", "Module:etymology_languages/code_to_canonical_name", "Module:etymology_languages/canonical_names", "Module:families/code_to_canonical_name", "Module:families/canonical_names", "Module:scripts/code_to_canonical_name", "Module:scripts/canonical_names", "Module:Hani-sortkey/data/serialized", ].some(title => pageName.startsWith(title)) ) importScript("MediaWiki:UpdateLanguageNameAndCode.js"); // [[MediaWiki:UpdateLanguageNameAndCode.js]] /* ***** Append #English to all links in definition sense lines ***** */ // Run this code in the main or Reconstruction namespaces, // and on the Main Page (for WOTD and FWOTD), // and in the Appendix namespace when there is a lemma or non-lemma form category. if (!window.noDefinitionLineFragmentAddition && (ns === 0 || ns === 118 || pageName === "Wiktionary:Main_Page" || (ns === 100 && document.querySelector("#catlinks [href$=lemmas], #catlinks [href$=non-lemma_forms]")) ) ) { // Look for links inside a numbered list (<ol> tag). // Must use [lang|=en] rather than :lang(en) because, at least in Firefox, // :lang(en) always matches wherever it is put in a selector // because all text is within <html lang="en">. for (const elem of document.querySelectorAll(".mw-parser-output ol a:not(.mw-parser-output [lang] a), .mw-parser-output ol [lang|=en] a")) { // Only append to local existing main-namespace links without an existing anchor const href = elem.getAttribute("href"); if (href && !/[#?:]/.test(href) && href[1] !== "/") elem.href += "#English"; } } /* ***** New entry wizard ***** */ if (document.getElementById("necplaceholder")) importScript("MediaWiki:NewEntryWizard.js"); // [[MediaWiki:NewEntryWizard.js]] /* ***** Hide certain parts of the page from Google snippets ***** */ // Not sure whether this is working... for (const elem of document.querySelectorAll(".mw-editsection, #toc, #catlinks")) { elem.setAttribute("data-nosnippet", ""); if (navigator.userAgent.toLowerCase().includes("googlebot")) elem.style.display = "none"; } /* ***** Clean up category pages showing "0 c" or "0 e", e.g. [[Category:Pages with entries]] ***** */ for (const elem of document.querySelectorAll(".CategoryTreeItem bdi + span")) elem.textContent = elem.textContent .replace(/\b0 c, /, "") .replace(/, 0 e\b/, "") .replace(/\(0 c\)/, "(0 e)"); /* ***** Template gadget for [[Module:UnitTests]]: e.g. [[Module:vi/testcases]] ***** */ for (const corner of document.querySelectorAll(".unit-tests .unit-tests-img-corner")) corner.addEventListener("click", () => corner.closest(".unit-tests").classList.toggle("unit-tests-hide-passing")); /* ***** WikiHiero kludge: see [[phab:T210695]] ***** */ if (document.querySelector(".mw-hiero-outer")) importScript("MediaWiki:WikiHieroTempFix.js"); // [[MediaWiki:WikiHieroTempFix.js]] /* ***** `#new-section-redirect` changes the URL for "Add topic" (e.g. for [[Wiktionary:Beer parlour]]) ***** */ const newSectionRedirect = document.querySelector("#new-section-redirect a"); const newSectionButton = document.querySelector("#ca-addsection:is(a), #ca-addsection a"); if (newSectionRedirect && newSectionButton) newSectionButton.href = newSectionRedirect.href; // </nowiki> 7mjrwzkppzm15ivt1r40af7t8tqn8kc 88947 88946 2026-08-06T23:17:36Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Site.js]] 88946 javascript text/javascript // This gadget contains code that will run unconditionally for everyone - both on mobile and desktop. // Consider instead adding your code to [[MediaWiki:Common.js]], [[MediaWiki:Mobile.js]], or a gadget. // <nowiki> const pageName = mw.config.get("wgPageName"); const ns = mw.config.get("wgNamespaceNumber"); /* ***** Page-specific code ***** */ switch (pageName) { case "Wiktionary:Main_Page": // [[Wiktionary:Main_Page]] // Workaround for [[phab:T335552]]. document.querySelector(".mw-searchInput").autocapitalize = "off"; break; case "Wiktionary:Gadget_preferences": // [[Wiktionary:Gadget_preferences]] if (mw.config.get("wgAction") === "view") importScript("MediaWiki:WiktGadgetPrefsPage.js"); // [[MediaWiki:WiktGadgetPrefsPage.js]] break; case "MediaWiki:Gadgets-definition": // [[MediaWiki:Gadgets-definition]] importScript("MediaWiki:BetterGadgetsDefinition.js"); // [[MediaWiki:BetterGadgetsDefinition.js]] break; case "Special:Search": // [[Special:Search]] importScript("MediaWiki:FindTrans.js"); // [[MediaWiki:FindTrans.js]] break; case "Wiktionary:Fonts/list": // [[Wiktionary:Fonts/list]] if (mw.config.get("wgAction") === "view") importScript("MediaWiki:InteractiveFontList.js"); // [[MediaWiki:InteractiveFontList.js]] break; case "Wiktionary:Tracking": importScript("MediaWiki:BrowseTrackingCats.js"); // [[MediaWiki:BrowseTrackingCats.js]] } if ( document.querySelector(".mw-parser-output p:first-of-type") && [ "Module:languages/code_to_canonical_name", "Module:languages/canonical_names", "Module:etymology_languages/code_to_canonical_name", "Module:etymology_languages/canonical_names", "Module:families/code_to_canonical_name", "Module:families/canonical_names", "Module:scripts/code_to_canonical_name", "Module:scripts/canonical_names", "Module:Hani-sortkey/data/serialized", ].some(title => pageName.startsWith(title)) ) importScript("MediaWiki:UpdateLanguageNameAndCode.js"); // [[MediaWiki:UpdateLanguageNameAndCode.js]] /* ***** Append #English to all links in definition sense lines ***** */ // Run this code in the main or Reconstruction namespaces, // and on the Main Page (for WOTD and FWOTD), // and in the Appendix namespace when there is a lemma or non-lemma form category. if (!window.noDefinitionLineFragmentAddition && (ns === 0 || ns === 118 || pageName === "Wiktionary:Main_Page" || (ns === 100 && document.querySelector("#catlinks [href$=lemmas], #catlinks [href$=non-lemma_forms]")) ) ) { // Look for links inside a numbered list (<ol> tag). // Must use [lang|=en] rather than :lang(en) because, at least in Firefox, // :lang(en) always matches wherever it is put in a selector // because all text is within <html lang="en">. for (const elem of document.querySelectorAll(".mw-parser-output ol a:not(.mw-parser-output [lang] a), .mw-parser-output ol [lang|=en] a")) { // Only append to local existing main-namespace links without an existing anchor const href = elem.getAttribute("href"); if (href && !/[#?:]/.test(href) && href[1] !== "/") elem.href += "#English"; } } /* ***** New entry wizard ***** */ if (document.getElementById("necplaceholder")) importScript("MediaWiki:NewEntryWizard.js"); // [[MediaWiki:NewEntryWizard.js]] /* ***** Hide certain parts of the page from Google snippets ***** */ // Not sure whether this is working... for (const elem of document.querySelectorAll(".mw-editsection, #toc, #catlinks")) { elem.setAttribute("data-nosnippet", ""); if (navigator.userAgent.toLowerCase().includes("googlebot")) elem.style.display = "none"; } /* ***** Clean up category pages showing "0 c" or "0 e", e.g. [[Category:Pages with entries]] ***** */ for (const elem of document.querySelectorAll(".CategoryTreeItem bdi + span")) elem.textContent = elem.textContent .replace(/\b0 c, /, "") .replace(/, 0 e\b/, "") .replace(/\(0 c\)/, "(0 e)"); /* ***** Template gadget for [[Module:UnitTests]]: e.g. [[Module:vi/testcases]] ***** */ for (const corner of document.querySelectorAll(".unit-tests .unit-tests-img-corner")) corner.addEventListener("click", () => corner.closest(".unit-tests").classList.toggle("unit-tests-hide-passing")); /* ***** WikiHiero kludge: see [[phab:T210695]] ***** */ if (document.querySelector(".mw-hiero-outer")) importScript("MediaWiki:WikiHieroTempFix.js"); // [[MediaWiki:WikiHieroTempFix.js]] /* ***** `#new-section-redirect` changes the URL for "Add topic" (e.g. for [[Wiktionary:Beer parlour]]) ***** */ const newSectionRedirect = document.querySelector("#new-section-redirect a"); const newSectionButton = document.querySelector("#ca-addsection:is(a), #ca-addsection a"); if (newSectionRedirect && newSectionButton) newSectionButton.href = newSectionRedirect.href; // </nowiki> 7mjrwzkppzm15ivt1r40af7t8tqn8kc MediaWiki:Gadget-UTCLiveClock-pagestyles.css 8 17973 88948 2017-10-06T15:00:19Z en>Gamren 0 Created page with "/** * This is loaded as a hidden peer gadget of UTCLiveClock. * Before UTCLiveClock has loaded, it adds space where the clock would go, * so that the personal toolbar does..." 88948 css text/css /** * This is loaded as a hidden peer gadget of UTCLiveClock. * Before UTCLiveClock has loaded, it adds space where the clock would go, * so that the personal toolbar does not "jump". */ /* * In Vector, by default the li elements in the p-personal bar have a font-size * of 0.75em. Duplicate that here so that we can be sure of the proper factor to * multiply the ul element's margin-right by. And just in case, override any * possible changes to the font size in Monobook too, although by default there * is no change in font size between the ul and li elements. */ .client-js > body.skin-vector #p-personal li { font-size: 0.75em; } .client-js > body.skin-monobook #p-personal li { font-size: 1em; } /* * Reserve space for the clock gadget after the end of the p-personal ul * element. */ .client-js > body.skin-vector #p-personal ul { /* * The clock width plus its left margin, multiplied by the relative font * size: (6em + 0.75em) * 0.75 */ margin-right: 5.0625em; } .client-js > body.skin-monobook #p-personal ul { /* * Clock width: 6.279em * Left margin: 1em * Space separator after "log out" link: 0.321em (found through trial and * error) * Total space: 6.279em + 1em + 0.321em */ margin-right: 7.6em; } 5z8u3sry5p8f5l96yrqrxf2j4uun111 88949 88948 2026-08-06T23:17:45Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-UTCLiveClock-pagestyles.css]] 88948 css text/css /** * This is loaded as a hidden peer gadget of UTCLiveClock. * Before UTCLiveClock has loaded, it adds space where the clock would go, * so that the personal toolbar does not "jump". */ /* * In Vector, by default the li elements in the p-personal bar have a font-size * of 0.75em. Duplicate that here so that we can be sure of the proper factor to * multiply the ul element's margin-right by. And just in case, override any * possible changes to the font size in Monobook too, although by default there * is no change in font size between the ul and li elements. */ .client-js > body.skin-vector #p-personal li { font-size: 0.75em; } .client-js > body.skin-monobook #p-personal li { font-size: 1em; } /* * Reserve space for the clock gadget after the end of the p-personal ul * element. */ .client-js > body.skin-vector #p-personal ul { /* * The clock width plus its left margin, multiplied by the relative font * size: (6em + 0.75em) * 0.75 */ margin-right: 5.0625em; } .client-js > body.skin-monobook #p-personal ul { /* * Clock width: 6.279em * Left margin: 1em * Space separator after "log out" link: 0.321em (found through trial and * error) * Total space: 6.279em + 1em + 0.321em */ margin-right: 7.6em; } 5z8u3sry5p8f5l96yrqrxf2j4uun111 MediaWiki:Gadget-CssTest.css 8 17974 88950 2023-03-27T02:10:02Z en>Erutuon 0 switch to Ullikummi fonts 88950 css text/css @font-face { font-family: 'UllikummiC'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } @font-face { font-family: 'UllikummiB'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } @font-face { font-family: 'UllikummiA'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } hzn7lgylehppz0sd8jb0y50h62svr55 88951 88950 2026-08-06T23:17:54Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-CssTest.css]] 88950 css text/css @font-face { font-family: 'UllikummiC'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } @font-face { font-family: 'UllikummiB'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } @font-face { font-family: 'UllikummiA'; src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2'); font-weight: normal; font-style: normal; font-display: swap; } hzn7lgylehppz0sd8jb0y50h62svr55 MediaWiki:Gadget-UnsupportedTitles.json 8 17975 88952 2024-12-25T15:39:44Z en>J3133 0 Added text display (see [[Wiktionary:Grease pit/2022/August#Preventing emoji display in titles|Wiktionary:Grease pit/2022/August § Preventing emoji display in titles]]). (Most are symbols, but I do not oppose changing any if needed.) 88952 json application/json { "UnsupportedCharacterEscapes": { "grave": "`", "num": "#", "repl": "�", "percnt": "%", "tilde": "~", "rcub": "}", "amp": "\u0026", "vert": "|", "lcub": "{", "lsqb": "[", "gt": "\u003E", "rsqb": "]", "lt": "\u003C", "lowbar": "_", "period": "." }, "UnsupportedTitles": { "": "", "Space": "[space]", "Cifrão": "[Cifrão]", "Ogham space": "[Ogham space]", "Old Israeli shekel": "[Old Israeli shekel]", "Ancient Greek dish": "λοπαδο­τεμαχο­σελαχο­γαλεο­κρανιο­λειψανο­δριμυ­ποτριμματο­σιλφιο­καραβο­μελιτο­κατακεχυμενο­κιχλε­πικοσσυφο­φαττο­περιστερα­λεκτρυο­νοπτο­κεφαλλιο­κιγκλο­πελειο­λαγῳο­σιραιο­βαφητραγανοπτερύγων", "Thai name of Bangkok": "กรุงเทพมหานคร อมรรัตนโกสินทร์ มหินทรายุธยา มหาดิลกภพ นพรัตนราชธานีบูรีรมย์ อุดมราชนิเวศน์มหาสถาน อมรพิมานอวตารสถิต สักกะทัตติยวิษณุกรรมประสิทธิ์" }, "TitleDisplay": { "⌛": "⌛︎", "⏩": "⏩︎", "⏪": "⏪︎", "☕": "☕︎", "♀": "♀︎", "♂": "♂︎", "♈": "♈︎", "♉": "♉︎", "♊": "♊︎", "♋": "♋︎", "♌": "♌︎", "♍": "♍︎", "♎": "♎︎", "♏": "♏︎", "♐": "♐︎", "♑": "♑︎", "♒": "♒︎", "♓": "♓︎", "♿": "♿︎", "⚓": "⚓︎", "⚡": "⚡︎", "⚪": "⚪︎", "⚫": "⚫︎", "⚽": "⚽︎", "⛎": "⛎︎", "⛔": "⛔︎", "⛳": "⛳︎", "⛺": "⛺︎", "⛽": "⛽︎", "✊": "✊︎", "✋": "✋︎", "✍": "✍︎", "✨": "✨︎", "➿": "➿︎", "🆎": "🆎︎", "🆑": "🆑︎", "🆒": "🆒︎", "🆓": "🆓︎", "🆔": "🆔︎", "🆕": "🆕︎", "🆖": "🆖︎", "🆗": "🆗︎", "🆘": "🆘︎", "🆙": "🆙︎", "🈁": "🈁︎", "🈚": "🈚︎", "🈯": "🈯︎", "🈲": "🈲︎", "🈳": "🈳︎", "🈴": "🈴︎", "🈵": "🈵︎", "🈶": "🈶︎", "🉐": "🉐︎", "🌀": "🌀︎", "🌈": "🌈︎", "🌐": "🌐︎", "🌑": "🌑︎", "🌒": "🌒︎", "🌓": "🌓︎", "🌔": "🌔︎", "🌕": "🌕︎", "🌖": "🌖︎", "🌗": "🌗︎", "🌘": "🌘︎", "🌙": "🌙︎", "🌞": "🌞︎", "🌠": "🌠︎", "🌮": "🌮︎", "🌲": "🌲︎", "🌹": "🌹︎", "🌽": "🌽︎", "🍀": "🍀︎", "🍁": "🍁︎", "🍅": "🍅︎", "🍆": "🍆︎", "🍇": "🍇︎", "🍉": "🍉︎", "🍋": "🍋︎", "🍌": "🍌︎", "🍑": "🍑︎", "🍒": "🍒︎", "🍔": "🍔︎", "🍟": "🍟︎", "🍤": "🍤︎", "🍪": "🍪︎", "🍴": "🍴︎", "🍼": "🍼︎", "🍿": "🍿︎", "🎂": "🎂︎", "🎃": "🎃︎", "🎄": "🎄︎", "🎅": "🎅︎", "🎉": "🎉︎", "🎓": "🎓︎", "🎠": "🎠︎", "🎡": "🎡︎", "🎢": "🎢︎", "🎤": "🎤︎", "🎥": "🎥︎", "🎨": "🎨︎", "🎩": "🎩︎", "🎭": "🎭︎", "🎲": "🎲︎", "🎵": "🎵︎", "🏁": "🏁︎", "🏠": "🏠︎", "🐀": "🐀︎", "🐁": "🐁︎", "🐎": "🐎︎", "🐐": "🐐︎", "🐘": "🐘︎", "🐙": "🐙︎", "🐦": "🐦︎", "🐱": "🐱︎", "🐾": "🐾︎", "👀": "👀︎", "👂": "👂︎", "👃": "👃︎", "👆": "👆︎", "👇": "👇︎", "👊": "👊︎", "👋": "👋︎", "👌": "👌︎", "👍": "👍︎", "👎": "👎︎", "👏": "👏︎", "👑": "👑︎", "👤": "👤︎", "👥": "👥︎", "👴": "👴︎", "👵": "👵︎", "👹": "👹︎", "👼": "👼︎", "👽": "👽︎", "👾": "👾︎︎", "👿": "👿︎︎", "💀": "💀︎", "💅": "💅︎", "💉": "💉︎", "💊": "💊︎", "💍": "💍︎", "💎": "💎︎", "💓": "💓︎", "💔": "💔︎", "💕": "💕︎", "💖": "💖︎", "💙": "💙︎", "💚": "💚︎", "💛": "💛︎", "💜": "💜︎", "💝": "💝︎", "💞": "💞︎", "💠": "💠︎", "💡": "💡︎", "💢": "💢︎", "💣": "💣︎", "💤": "💤︎", "💥": "💥︎", "💦": "💦︎", "💧": "💧︎", "💨": "💨︎", "💩": "💩︎", "💪": "💪︎", "💫": "💫︎", "💬": "💬︎", "💭": "💭︎", "💮": "💮︎", "💯": "💯︎", "💱": "💱︎", "💳": "💳︎", "💸": "💸︎", "💼": "💼︎", "💾": "💾︎", "📅": "📅︎", "📈": "📈︎", "📉": "📉︎", "📋": "📋︎", "📌": "📌︎", "📍": "📍︎", "📎": "📎︎", "📖": "📖︎", "📚": "📚︎", "📝": "📝︎", "📞": "📞︎", "📠": "📠︎", "📢": "📢︎", "📣": "📣︎", "📰": "📰︎", "📲": "📲︎", "🔀": "🔀︎", "🔁": "🔁︎", "🔂": "🔂︎", "🔃": "🔃︎", "🔄": "🔄︎", "🔅": "🔅︎", "🔆": "🔆︎", "🔇": "🔇︎", "🔈": "🔈︎", "🔋": "🔋︎", "🔍": "🔍︎", "🔎": "🔎︎", "🔑": "🔑︎", "🔒": "🔒︎", "🔓": "🔓︎", "🔔": "🔔︎", "🔕": "🔕︎", "🔗": "🔗︎", "🔘": "🔘︎", "🔙": "🔙︎", "🔚": "🔚︎", "🔛": "🔛︎", "🔜": "🔜︎", "🔝": "🔝︎", "🔞": "🔞︎", "🔥": "🔥︎", "🔧": "🔧︎", "🔪": "🔪︎", "🔫": "🔫︎", "🔬": "🔬︎", "🔭": "🔭︎", "🔰": "🔰︎", "🔴": "🔴︎", "🔵": "🔵︎", "🔻": "🔻︎", "🕎": "🕎︎", "🖕": "🖕︎", "🖤": "🖤︎", "🗽": "🗽︎", "🗿": "🗿︎", "😀": "😀︎", "😁": "😁︎", "😂": "😂︎", "😃": "😃︎", "😄": "😄︎", "😅": "😅︎", "😆": "😆︎", "😇": "😇︎", "😈": "😈︎", "😉": "😉︎", "😊": "😊︎", "😋": "😋︎", "😌": "😌︎", "😍": "😍︎", "😎": "😎︎", "😏": "😏︎", "😐": "😐︎", "😔": "😔︎", "😕": "😕︎", "😗": "😗︎", "😙": "😙︎", "😚": "😚︎", "😛": "😛︎", "😜": "😜︎", "😝": "😝︎", "😠": "😠︎", "😡": "😡︎", "😤": "😤︎", "😩": "😩︎", "😫": "😫︎", "😬": "😬︎", "😭": "😭︎", "😮": "😮︎", "😱": "😱︎", "😳": "😳︎", "😶": "😶︎", "😸": "😸︎", "😺": "😺︎", "🙃": "🙃︎", "🙄": "🙄︎", "🙈🙉🙊": "🙈︎🙉︎🙊︎", "🙌": "🙌︎", "🙏": "🙏︎", "🚀": "🚀︎", "🚂": "🚂︎", "🚥": "🚥︎", "🚦": "🚦︎", "🚧": "🚧︎", "🚨": "🚨︎", "🚩": "🚩︎", "🚬": "🚬︎", "🚮": "🚮︎", "🚰": "🚰︎", "🚲": "🚲︎", "🚴": "🚴︎", "🚶": "🚶︎", "🚹": "🚹︎", "🚺": "🚺︎", "🚻": "🚻︎", "🚼": "🚼︎", "🚽": "🚽︎", "🚾": "🚾︎", "🚿": "🚿︎", "🛂": "🛂︎", "🛃": "🛃︎", "🛄": "🛄︎", "🛅": "🛅︎", "🛌": "🛌︎", "🛑": "🛑︎", "🛒": "🛒︎", "🛗": "🛗︎", "🛜": "🛜︎", "🛝": "🛝︎", "🛫": "🛫︎", "🛬": "🛬︎", "🟠": "🟠︎", "🟡": "🟡︎", "🟢": "🟢︎", "🟣": "🟣︎", "🟤": "🟤︎", "🤏": "🤏︎", "🤑": "🤑︎", "🤒": "🤒︎", "🤓": "🤓︎", "🤔": "🤔︎", "🤕": "🤕︎", "🤖": "🤖︎", "🤗": "🤗︎", "🤝": "🤝︎", "🤟": "🤟︎", "🤡": "🤡︎", "🤢": "🤢︎", "🤣": "🤣︎", "🤦": "🤦︎", "🤧": "🤧︎", "🤩": "🤩︎", "🤫": "🤫︎", "🤬": "🤬︎", "🤮": "🤮︎", "🤯": "🤯︎", "🥀": "🥀︎", "🥇": "🥇︎", "🥚": "🥚︎", "🥛": "🥛︎", "🥜": "🥜︎", "🥱": "🥱︎", "🥲": "🥲︎", "🥴": "🥴︎", "🥵": "🥵︎", "🥶": "🥶︎", "🥷": "🥷︎", "🥹": "🥹︎", "🥺": "🥺︎", "🥽": "🥽︎", "🦀": "🦀︎", "🦅": "🦅︎", "🦎": "🦎︎", "🦴": "🦴︎", "🦽": "🦽︎", "🧏": "🧏︎", "🧠": "🧠︎", "🧢": "🧢︎", "🧩": "🧩︎", "🧵": "🧵︎", "🧷": "🧷︎", "🧸": "🧸︎", "🧹": "🧹︎", "🩵": "🩵︎", "🩶": "🩶︎", "🩸": "🩸︎", "🪐": "🪐︎", "🪑": "🪑︎", "🪢": "🪢︎", "🪦": "🪦︎", "🪩": "🪩︎", "🪫": "🪫︎", "🪾": "🪾︎", "🫂": "🫂︎", "🫡": "🫡︎", "🫣": "🫣︎", "🫰": "🫰︎", "🫵": "🫵︎", "🫶": "🫶︎" } } aqsryl8nqgv36ixkm84l85nnsl1j9sy 88953 88952 2026-08-06T23:18:02Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-UnsupportedTitles.json]] 88952 json application/json { "UnsupportedCharacterEscapes": { "grave": "`", "num": "#", "repl": "�", "percnt": "%", "tilde": "~", "rcub": "}", "amp": "\u0026", "vert": "|", "lcub": "{", "lsqb": "[", "gt": "\u003E", "rsqb": "]", "lt": "\u003C", "lowbar": "_", "period": "." }, "UnsupportedTitles": { "": "", "Space": "[space]", "Cifrão": "[Cifrão]", "Ogham space": "[Ogham space]", "Old Israeli shekel": "[Old Israeli shekel]", "Ancient Greek dish": "λοπαδο­τεμαχο­σελαχο­γαλεο­κρανιο­λειψανο­δριμυ­ποτριμματο­σιλφιο­καραβο­μελιτο­κατακεχυμενο­κιχλε­πικοσσυφο­φαττο­περιστερα­λεκτρυο­νοπτο­κεφαλλιο­κιγκλο­πελειο­λαγῳο­σιραιο­βαφητραγανοπτερύγων", "Thai name of Bangkok": "กรุงเทพมหานคร อมรรัตนโกสินทร์ มหินทรายุธยา มหาดิลกภพ นพรัตนราชธานีบูรีรมย์ อุดมราชนิเวศน์มหาสถาน อมรพิมานอวตารสถิต สักกะทัตติยวิษณุกรรมประสิทธิ์" }, "TitleDisplay": { "⌛": "⌛︎", "⏩": "⏩︎", "⏪": "⏪︎", "☕": "☕︎", "♀": "♀︎", "♂": "♂︎", "♈": "♈︎", "♉": "♉︎", "♊": "♊︎", "♋": "♋︎", "♌": "♌︎", "♍": "♍︎", "♎": "♎︎", "♏": "♏︎", "♐": "♐︎", "♑": "♑︎", "♒": "♒︎", "♓": "♓︎", "♿": "♿︎", "⚓": "⚓︎", "⚡": "⚡︎", "⚪": "⚪︎", "⚫": "⚫︎", "⚽": "⚽︎", "⛎": "⛎︎", "⛔": "⛔︎", "⛳": "⛳︎", "⛺": "⛺︎", "⛽": "⛽︎", "✊": "✊︎", "✋": "✋︎", "✍": "✍︎", "✨": "✨︎", "➿": "➿︎", "🆎": "🆎︎", "🆑": "🆑︎", "🆒": "🆒︎", "🆓": "🆓︎", "🆔": "🆔︎", "🆕": "🆕︎", "🆖": "🆖︎", "🆗": "🆗︎", "🆘": "🆘︎", "🆙": "🆙︎", "🈁": "🈁︎", "🈚": "🈚︎", "🈯": "🈯︎", "🈲": "🈲︎", "🈳": "🈳︎", "🈴": "🈴︎", "🈵": "🈵︎", "🈶": "🈶︎", "🉐": "🉐︎", "🌀": "🌀︎", "🌈": "🌈︎", "🌐": "🌐︎", "🌑": "🌑︎", "🌒": "🌒︎", "🌓": "🌓︎", "🌔": "🌔︎", "🌕": "🌕︎", "🌖": "🌖︎", "🌗": "🌗︎", "🌘": "🌘︎", "🌙": "🌙︎", "🌞": "🌞︎", "🌠": "🌠︎", "🌮": "🌮︎", "🌲": "🌲︎", "🌹": "🌹︎", "🌽": "🌽︎", "🍀": "🍀︎", "🍁": "🍁︎", "🍅": "🍅︎", "🍆": "🍆︎", "🍇": "🍇︎", "🍉": "🍉︎", "🍋": "🍋︎", "🍌": "🍌︎", "🍑": "🍑︎", "🍒": "🍒︎", "🍔": "🍔︎", "🍟": "🍟︎", "🍤": "🍤︎", "🍪": "🍪︎", "🍴": "🍴︎", "🍼": "🍼︎", "🍿": "🍿︎", "🎂": "🎂︎", "🎃": "🎃︎", "🎄": "🎄︎", "🎅": "🎅︎", "🎉": "🎉︎", "🎓": "🎓︎", "🎠": "🎠︎", "🎡": "🎡︎", "🎢": "🎢︎", "🎤": "🎤︎", "🎥": "🎥︎", "🎨": "🎨︎", "🎩": "🎩︎", "🎭": "🎭︎", "🎲": "🎲︎", "🎵": "🎵︎", "🏁": "🏁︎", "🏠": "🏠︎", "🐀": "🐀︎", "🐁": "🐁︎", "🐎": "🐎︎", "🐐": "🐐︎", "🐘": "🐘︎", "🐙": "🐙︎", "🐦": "🐦︎", "🐱": "🐱︎", "🐾": "🐾︎", "👀": "👀︎", "👂": "👂︎", "👃": "👃︎", "👆": "👆︎", "👇": "👇︎", "👊": "👊︎", "👋": "👋︎", "👌": "👌︎", "👍": "👍︎", "👎": "👎︎", "👏": "👏︎", "👑": "👑︎", "👤": "👤︎", "👥": "👥︎", "👴": "👴︎", "👵": "👵︎", "👹": "👹︎", "👼": "👼︎", "👽": "👽︎", "👾": "👾︎︎", "👿": "👿︎︎", "💀": "💀︎", "💅": "💅︎", "💉": "💉︎", "💊": "💊︎", "💍": "💍︎", "💎": "💎︎", "💓": "💓︎", "💔": "💔︎", "💕": "💕︎", "💖": "💖︎", "💙": "💙︎", "💚": "💚︎", "💛": "💛︎", "💜": "💜︎", "💝": "💝︎", "💞": "💞︎", "💠": "💠︎", "💡": "💡︎", "💢": "💢︎", "💣": "💣︎", "💤": "💤︎", "💥": "💥︎", "💦": "💦︎", "💧": "💧︎", "💨": "💨︎", "💩": "💩︎", "💪": "💪︎", "💫": "💫︎", "💬": "💬︎", "💭": "💭︎", "💮": "💮︎", "💯": "💯︎", "💱": "💱︎", "💳": "💳︎", "💸": "💸︎", "💼": "💼︎", "💾": "💾︎", "📅": "📅︎", "📈": "📈︎", "📉": "📉︎", "📋": "📋︎", "📌": "📌︎", "📍": "📍︎", "📎": "📎︎", "📖": "📖︎", "📚": "📚︎", "📝": "📝︎", "📞": "📞︎", "📠": "📠︎", "📢": "📢︎", "📣": "📣︎", "📰": "📰︎", "📲": "📲︎", "🔀": "🔀︎", "🔁": "🔁︎", "🔂": "🔂︎", "🔃": "🔃︎", "🔄": "🔄︎", "🔅": "🔅︎", "🔆": "🔆︎", "🔇": "🔇︎", "🔈": "🔈︎", "🔋": "🔋︎", "🔍": "🔍︎", "🔎": "🔎︎", "🔑": "🔑︎", "🔒": "🔒︎", "🔓": "🔓︎", "🔔": "🔔︎", "🔕": "🔕︎", "🔗": "🔗︎", "🔘": "🔘︎", "🔙": "🔙︎", "🔚": "🔚︎", "🔛": "🔛︎", "🔜": "🔜︎", "🔝": "🔝︎", "🔞": "🔞︎", "🔥": "🔥︎", "🔧": "🔧︎", "🔪": "🔪︎", "🔫": "🔫︎", "🔬": "🔬︎", "🔭": "🔭︎", "🔰": "🔰︎", "🔴": "🔴︎", "🔵": "🔵︎", "🔻": "🔻︎", "🕎": "🕎︎", "🖕": "🖕︎", "🖤": "🖤︎", "🗽": "🗽︎", "🗿": "🗿︎", "😀": "😀︎", "😁": "😁︎", "😂": "😂︎", "😃": "😃︎", "😄": "😄︎", "😅": "😅︎", "😆": "😆︎", "😇": "😇︎", "😈": "😈︎", "😉": "😉︎", "😊": "😊︎", "😋": "😋︎", "😌": "😌︎", "😍": "😍︎", "😎": "😎︎", "😏": "😏︎", "😐": "😐︎", "😔": "😔︎", "😕": "😕︎", "😗": "😗︎", "😙": "😙︎", "😚": "😚︎", "😛": "😛︎", "😜": "😜︎", "😝": "😝︎", "😠": "😠︎", "😡": "😡︎", "😤": "😤︎", "😩": "😩︎", "😫": "😫︎", "😬": "😬︎", "😭": "😭︎", "😮": "😮︎", "😱": "😱︎", "😳": "😳︎", "😶": "😶︎", "😸": "😸︎", "😺": "😺︎", "🙃": "🙃︎", "🙄": "🙄︎", "🙈🙉🙊": "🙈︎🙉︎🙊︎", "🙌": "🙌︎", "🙏": "🙏︎", "🚀": "🚀︎", "🚂": "🚂︎", "🚥": "🚥︎", "🚦": "🚦︎", "🚧": "🚧︎", "🚨": "🚨︎", "🚩": "🚩︎", "🚬": "🚬︎", "🚮": "🚮︎", "🚰": "🚰︎", "🚲": "🚲︎", "🚴": "🚴︎", "🚶": "🚶︎", "🚹": "🚹︎", "🚺": "🚺︎", "🚻": "🚻︎", "🚼": "🚼︎", "🚽": "🚽︎", "🚾": "🚾︎", "🚿": "🚿︎", "🛂": "🛂︎", "🛃": "🛃︎", "🛄": "🛄︎", "🛅": "🛅︎", "🛌": "🛌︎", "🛑": "🛑︎", "🛒": "🛒︎", "🛗": "🛗︎", "🛜": "🛜︎", "🛝": "🛝︎", "🛫": "🛫︎", "🛬": "🛬︎", "🟠": "🟠︎", "🟡": "🟡︎", "🟢": "🟢︎", "🟣": "🟣︎", "🟤": "🟤︎", "🤏": "🤏︎", "🤑": "🤑︎", "🤒": "🤒︎", "🤓": "🤓︎", "🤔": "🤔︎", "🤕": "🤕︎", "🤖": "🤖︎", "🤗": "🤗︎", "🤝": "🤝︎", "🤟": "🤟︎", "🤡": "🤡︎", "🤢": "🤢︎", "🤣": "🤣︎", "🤦": "🤦︎", "🤧": "🤧︎", "🤩": "🤩︎", "🤫": "🤫︎", "🤬": "🤬︎", "🤮": "🤮︎", "🤯": "🤯︎", "🥀": "🥀︎", "🥇": "🥇︎", "🥚": "🥚︎", "🥛": "🥛︎", "🥜": "🥜︎", "🥱": "🥱︎", "🥲": "🥲︎", "🥴": "🥴︎", "🥵": "🥵︎", "🥶": "🥶︎", "🥷": "🥷︎", "🥹": "🥹︎", "🥺": "🥺︎", "🥽": "🥽︎", "🦀": "🦀︎", "🦅": "🦅︎", "🦎": "🦎︎", "🦴": "🦴︎", "🦽": "🦽︎", "🧏": "🧏︎", "🧠": "🧠︎", "🧢": "🧢︎", "🧩": "🧩︎", "🧵": "🧵︎", "🧷": "🧷︎", "🧸": "🧸︎", "🧹": "🧹︎", "🩵": "🩵︎", "🩶": "🩶︎", "🩸": "🩸︎", "🪐": "🪐︎", "🪑": "🪑︎", "🪢": "🪢︎", "🪦": "🪦︎", "🪩": "🪩︎", "🪫": "🪫︎", "🪾": "🪾︎", "🫂": "🫂︎", "🫡": "🫡︎", "🫣": "🫣︎", "🫰": "🫰︎", "🫵": "🫵︎", "🫶": "🫶︎" } } aqsryl8nqgv36ixkm84l85nnsl1j9sy MediaWiki:Gadget-UnsupportedTitles.js 8 17976 88954 2024-07-24T16:04:52Z en>Ioaxxere 0 try moving logic into a helper function 88954 javascript text/javascript /* To get template for titleTag.textContent, process MediaWiki:pagetitle, open your browser's JavaScript console on a Wiktionary page and run this code: ((msg) => new mw.Api().getMessages(msg).then((messages) => { mw.messages.set(messages); const titleTemplate = new mw.Message(mw.messages, msg, ["$1"]).text(); const { before, after } = /^(?<before>.*)\$1(?<after>.*)/.exec(titleTemplate).groups; console.log(JSON.stringify(before), JSON.stringify(after)) }) .fail(console.error))("pagetitle") We can do this for action=edit and action=submit by replacing "pagetitle" with "editing" in this snippet. */ function setTitle(newTitle) { // Set title tag, which determines the title shown in the browser. var titleTag = document.getElementsByTagName('title')[0]; titleTag.textContent = newTitle + " - Wiktionary, the free dictionary"; // Set the text of the first heading above the page content. document.getElementById('firstHeading').textContent = newTitle; } var UnsupportedTitlesJson = require('./UnsupportedTitles.json'); var prettyPageName = mw.config.get('wgPageName').replace(/_/g, ' '); function generateCharacterToEscapeMap() { var map = {}; Object.entries(UnsupportedTitlesJson.UnsupportedCharacterEscapes).forEach(function(entry) { map[entry[1]] = entry[0]; }); return map; } // Helper function accessible from other scripts function convertUnsupportedTitle(originalTitle) { originalTitle = originalTitle.replaceAll("_", " "); var match = /^(?:Talk:)?Unsupported titles\/(.+)$/.exec(originalTitle); var newTitle; if (match) { var subpage = match && match[1]; newTitle = UnsupportedTitlesJson.UnsupportedTitles[subpage] || subpage.replace(/`([^`]+)`/g, function(wholeMatch, key) { const character = UnsupportedTitlesJson.UnsupportedCharacterEscapes[key]; return character != null ? character : key; }); } else { newTitle = UnsupportedTitlesJson.TitleDisplay[originalTitle]; } if (mw.config.get('wgCanonicalNamespace') == 'Talk') newTitle = 'Talk:' + newTitle; return newTitle } window.convertUnsupportedTitle = convertUnsupportedTitle; /* * On subpages of Unsupported titles and Talk:Unsupported titles, show the * correct title in the header at the top of the page. For instance, on the page * [[Unsupported titles/Left curly bracket]], show the title {. * * This is not enabled in the mobile version of the site. * * For all such pages, see [[Special:PrefixIndex/Unsupported titles]]. */ if (mw.config.get('wgAction') === 'view' && (/^(?:Talk:)?Unsupported titles\//.test(prettyPageName) || UnsupportedTitlesJson.TitleDisplay.hasOwnProperty(prettyPageName))) { $(function() { try { setTitle(convertUnsupportedTitle(prettyPageName)); } catch (e) { console.log('Error while changing title: ' + e.message + '.'); } }); } /* * This redirects a user to the correct Unsupported titles page if they attempt * to access an invalid title. For instance, if you attempt to access the page * for < * https://en.wiktionary.org/wiki/%3C * you will be redirected to * https://en.wiktionary.org/wiki/Unsupported_titles/Less_than */ if (mw.config.get('wgCanonicalSpecialPageName') == 'Badtitle') { // Avoid redirecting twice or more. Set this parameter after redirecting // and don't redirect if it is already set. const alreadyRedirectedParam = "UnsupportedTitleRedirected"; /* * Generate the name of the page that the user attempted to access using * either the portion of the URL after "/wiki/" or the value of the "title" * parameter in the query. That is, the user is accessing the page using * either the path /wiki/<invalid title> or a path similar to * /w/index.php?title=<invalid title>. * * The actual page displayed if a user attempts to access an invalid title * is the special page with the canonical title [[Special:Badtitle]]. */ if (!mw.util.getParamValue(alreadyRedirectedParam)) { var rxArticlePath = new RegExp('^' + mw.config.get('wgArticlePath').replace('$1', '(.*)') + '$'); var m = rxArticlePath.exec(location.pathname); var title = m ? decodeURIComponent(m[1]) : mw.util.getParamValue('title'); const characterToEscapeMap = generateCharacterToEscapeMap(); var badTitleSubpage = title.replace(/./g, function (fullMatch) { var escapeName = characterToEscapeMap[fullMatch]; return escapeName != null ? '`' + escapeName + '`' : fullMatch; }); if (badTitleSubpage != title) { const url = new URL(location.href); const newTitle = 'Unsupported titles/' + badTitleSubpage; if (url.searchParams.get("title")) { url.searchParams.set("title", newTitle); } else { url.pathname = mw.util.getUrl(newTitle); } url.searchParams.set(alreadyRedirectedParam, "1"); location.href = url; } } } bry7wrzns91exdq5miv8mhq40r1pkgh 88955 88954 2026-08-06T23:18:11Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-UnsupportedTitles.js]] 88954 javascript text/javascript /* To get template for titleTag.textContent, process MediaWiki:pagetitle, open your browser's JavaScript console on a Wiktionary page and run this code: ((msg) => new mw.Api().getMessages(msg).then((messages) => { mw.messages.set(messages); const titleTemplate = new mw.Message(mw.messages, msg, ["$1"]).text(); const { before, after } = /^(?<before>.*)\$1(?<after>.*)/.exec(titleTemplate).groups; console.log(JSON.stringify(before), JSON.stringify(after)) }) .fail(console.error))("pagetitle") We can do this for action=edit and action=submit by replacing "pagetitle" with "editing" in this snippet. */ function setTitle(newTitle) { // Set title tag, which determines the title shown in the browser. var titleTag = document.getElementsByTagName('title')[0]; titleTag.textContent = newTitle + " - Wiktionary, the free dictionary"; // Set the text of the first heading above the page content. document.getElementById('firstHeading').textContent = newTitle; } var UnsupportedTitlesJson = require('./UnsupportedTitles.json'); var prettyPageName = mw.config.get('wgPageName').replace(/_/g, ' '); function generateCharacterToEscapeMap() { var map = {}; Object.entries(UnsupportedTitlesJson.UnsupportedCharacterEscapes).forEach(function(entry) { map[entry[1]] = entry[0]; }); return map; } // Helper function accessible from other scripts function convertUnsupportedTitle(originalTitle) { originalTitle = originalTitle.replaceAll("_", " "); var match = /^(?:Talk:)?Unsupported titles\/(.+)$/.exec(originalTitle); var newTitle; if (match) { var subpage = match && match[1]; newTitle = UnsupportedTitlesJson.UnsupportedTitles[subpage] || subpage.replace(/`([^`]+)`/g, function(wholeMatch, key) { const character = UnsupportedTitlesJson.UnsupportedCharacterEscapes[key]; return character != null ? character : key; }); } else { newTitle = UnsupportedTitlesJson.TitleDisplay[originalTitle]; } if (mw.config.get('wgCanonicalNamespace') == 'Talk') newTitle = 'Talk:' + newTitle; return newTitle } window.convertUnsupportedTitle = convertUnsupportedTitle; /* * On subpages of Unsupported titles and Talk:Unsupported titles, show the * correct title in the header at the top of the page. For instance, on the page * [[Unsupported titles/Left curly bracket]], show the title {. * * This is not enabled in the mobile version of the site. * * For all such pages, see [[Special:PrefixIndex/Unsupported titles]]. */ if (mw.config.get('wgAction') === 'view' && (/^(?:Talk:)?Unsupported titles\//.test(prettyPageName) || UnsupportedTitlesJson.TitleDisplay.hasOwnProperty(prettyPageName))) { $(function() { try { setTitle(convertUnsupportedTitle(prettyPageName)); } catch (e) { console.log('Error while changing title: ' + e.message + '.'); } }); } /* * This redirects a user to the correct Unsupported titles page if they attempt * to access an invalid title. For instance, if you attempt to access the page * for < * https://en.wiktionary.org/wiki/%3C * you will be redirected to * https://en.wiktionary.org/wiki/Unsupported_titles/Less_than */ if (mw.config.get('wgCanonicalSpecialPageName') == 'Badtitle') { // Avoid redirecting twice or more. Set this parameter after redirecting // and don't redirect if it is already set. const alreadyRedirectedParam = "UnsupportedTitleRedirected"; /* * Generate the name of the page that the user attempted to access using * either the portion of the URL after "/wiki/" or the value of the "title" * parameter in the query. That is, the user is accessing the page using * either the path /wiki/<invalid title> or a path similar to * /w/index.php?title=<invalid title>. * * The actual page displayed if a user attempts to access an invalid title * is the special page with the canonical title [[Special:Badtitle]]. */ if (!mw.util.getParamValue(alreadyRedirectedParam)) { var rxArticlePath = new RegExp('^' + mw.config.get('wgArticlePath').replace('$1', '(.*)') + '$'); var m = rxArticlePath.exec(location.pathname); var title = m ? decodeURIComponent(m[1]) : mw.util.getParamValue('title'); const characterToEscapeMap = generateCharacterToEscapeMap(); var badTitleSubpage = title.replace(/./g, function (fullMatch) { var escapeName = characterToEscapeMap[fullMatch]; return escapeName != null ? '`' + escapeName + '`' : fullMatch; }); if (badTitleSubpage != title) { const url = new URL(location.href); const newTitle = 'Unsupported titles/' + badTitleSubpage; if (url.searchParams.get("title")) { url.searchParams.set("title", newTitle); } else { url.pathname = mw.util.getUrl(newTitle); } url.searchParams.set(alreadyRedirectedParam, "1"); location.href = url; } } } bry7wrzns91exdq5miv8mhq40r1pkgh MediaWiki:Gadget-catfix.js 8 17977 88956 2025-05-29T19:58:16Z en>Surjection 0 88956 javascript text/javascript // <nowiki> // Makes tweaks to links in language-specific categories, where we would normally // be wrapping them in {{l}}. for (let catfix of document.getElementsByClassName("catfix")) { // Catfix looks something like this: // <ul class="catfix" data-anchor="Russian"><span class="Cyrl" lang="ru"></span></ul> // The outer element records the anchor that we need to use, while the child element is used as the wrapper. // Applies a language-specific wrapper to the link based on the information from `catfix`. // If the link is something like `Appendix:Toki Pona/nasin`, // we need to wrap it like this: `Appendix:Toki Pona/<span prop="blah blah">nasin</span>`. // Otherwise, put the span around the link and add an anchor. function processLink(link) { if (link.catfixed) return; let wrapper = catfix.firstElementChild.cloneNode(); let pageName = link.textContent; let ns = (new mw.Title(pageName)).getNamespaceId(); if (ns === 0) { // Mainspace link.parentElement.append(wrapper); wrapper.append(link); link.hash = catfix.dataset.anchor; } else if (ns === 100 && pageName.includes("/")) { // Appendix let [prefix, ...title] = pageName.split("/"); // only do Appendix:ABC/def if ABC matches the catfix language if (prefix.replace('Appendix:', '') === catfix.dataset.anchor.replaceAll('_', ' ')) { title = title.join('/'); wrapper.textContent = title; link.innerHTML = ""; link.append(prefix + "/", wrapper); } } else if (ns === 118) { // Reconstruction // experiment: try replacing Reconstruction:XYZ/ with * for a cleaner layout // (but only if XYZ matches the catfix's language!) let [prefix, ...title] = pageName.split("/"); if (prefix.replace('Reconstruction:', '') === catfix.dataset.anchor.replaceAll('_', ' ')) { title = title.join('/'); link.textContent = "*" + title; link.parentElement.append(wrapper); wrapper.append(link); } } link.catfixed = true; } // There are currently two types of catfixes: those which apply to an entire category page, // And those applying to a single category tree. // This is a bit of a hack to tell the two kinds apart. let categoryTree = catfix.nextElementSibling; if ( categoryTree && (categoryTree.matches(".CategoryTreeTag") || categoryTree.querySelector(".CategoryTreeTag")) ) { // Skip known empty CategoryTrees var children = categoryTree.querySelector(".CategoryTreeChildren"); if (children) { // Process category tree elements already present on the page. categoryTree.querySelectorAll(".CategoryTreeChildren a").forEach(processLink); // Also deal with any category tree data loaded dynamically using a MutationObserver. (new MutationObserver(events => events .flatMap(event => [...event.addedNodes]) .flatMap(node => [...node.querySelectorAll("a")]) .forEach(processLink) )).observe(children, { childList: true, subtree: true }); } } else { document.querySelectorAll(".mw-category li > a").forEach(processLink); } } // </nowiki> dfngdf1wzoq0uw62b2i6b7eflruxmjb 88957 88956 2026-08-06T23:18:18Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-catfix.js]] 88956 javascript text/javascript // <nowiki> // Makes tweaks to links in language-specific categories, where we would normally // be wrapping them in {{l}}. for (let catfix of document.getElementsByClassName("catfix")) { // Catfix looks something like this: // <ul class="catfix" data-anchor="Russian"><span class="Cyrl" lang="ru"></span></ul> // The outer element records the anchor that we need to use, while the child element is used as the wrapper. // Applies a language-specific wrapper to the link based on the information from `catfix`. // If the link is something like `Appendix:Toki Pona/nasin`, // we need to wrap it like this: `Appendix:Toki Pona/<span prop="blah blah">nasin</span>`. // Otherwise, put the span around the link and add an anchor. function processLink(link) { if (link.catfixed) return; let wrapper = catfix.firstElementChild.cloneNode(); let pageName = link.textContent; let ns = (new mw.Title(pageName)).getNamespaceId(); if (ns === 0) { // Mainspace link.parentElement.append(wrapper); wrapper.append(link); link.hash = catfix.dataset.anchor; } else if (ns === 100 && pageName.includes("/")) { // Appendix let [prefix, ...title] = pageName.split("/"); // only do Appendix:ABC/def if ABC matches the catfix language if (prefix.replace('Appendix:', '') === catfix.dataset.anchor.replaceAll('_', ' ')) { title = title.join('/'); wrapper.textContent = title; link.innerHTML = ""; link.append(prefix + "/", wrapper); } } else if (ns === 118) { // Reconstruction // experiment: try replacing Reconstruction:XYZ/ with * for a cleaner layout // (but only if XYZ matches the catfix's language!) let [prefix, ...title] = pageName.split("/"); if (prefix.replace('Reconstruction:', '') === catfix.dataset.anchor.replaceAll('_', ' ')) { title = title.join('/'); link.textContent = "*" + title; link.parentElement.append(wrapper); wrapper.append(link); } } link.catfixed = true; } // There are currently two types of catfixes: those which apply to an entire category page, // And those applying to a single category tree. // This is a bit of a hack to tell the two kinds apart. let categoryTree = catfix.nextElementSibling; if ( categoryTree && (categoryTree.matches(".CategoryTreeTag") || categoryTree.querySelector(".CategoryTreeTag")) ) { // Skip known empty CategoryTrees var children = categoryTree.querySelector(".CategoryTreeChildren"); if (children) { // Process category tree elements already present on the page. categoryTree.querySelectorAll(".CategoryTreeChildren a").forEach(processLink); // Also deal with any category tree data loaded dynamically using a MutationObserver. (new MutationObserver(events => events .flatMap(event => [...event.addedNodes]) .flatMap(node => [...node.querySelectorAll("a")]) .forEach(processLink) )).observe(children, { childList: true, subtree: true }); } } else { document.querySelectorAll(".mw-category li > a").forEach(processLink); } } // </nowiki> dfngdf1wzoq0uw62b2i6b7eflruxmjb MediaWiki:Gadget-catfixRegrouper-Data.js 8 17978 88958 2026-06-01T00:27:48Z en>Fenakhay 0 88958 javascript text/javascript // {{documentation}} // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /* global mw */ // Configuration and data for [[MediaWiki:Gadget-catfixRegrouper.js]]. /** REGROUPER_DATA_LANG Data format: * IMPORTANT! The regrouper already assumes that the language sort keys * are set up correctly. It does not protect against the same group * heading being repeated *AT ALL*. Do not enable the regrouper for * a language until sort keys are set up for it first (so that * each would-be group is contiguous). * The data is organized by language code. * If the code is missing or the value is undefined, the * regrouper is disabled. This is the default. * If it is ``true``, default values are used. * Otherwise it is an object, with the following fields: * group * A function which is given the following parameters, * in this order: * - page title (minus namespace and language prefixes), * - language code, * - script code, * - namespace number. * ``this`` will be the language data object (so that you * can add your own variables, functions, etc.; but if you * do so, please prefix their names with x_). * It should return the group, i.e. the heading that the * page should be categorized under. If the value returned * is undefined, null, ``false`` or an empty string, * its existing group will be kept. * If ``true``, the group falls back to the * default grouping function. * The default is the default grouping function, either of the * script, or of ``defaultGroup``; * see below for a description thereof. * detectScript * A function which is given the following parameters, * in this order: * - page title (minus namespace and language prefixes), * - language code, * - (default) script code, * - namespace number. * ``this`` will be the language data object (so that you * can add your own variables, functions, etc.; but if you * do so, please prefix their names with x_). * It should return a script code, or undefined to use * the default script. * initials * If the default grouping function is used, this can be a RegExp * of initial letters/digraphs/etc. which are automatically mapped * to that respective group (with titlecase conversion). * initialFallback * Only applies for the default grouping function and if initials * is defined. If ``true``, the default grouping function falls * back to the default logic when the initial doesn't match any * specified in initials; if ``false`` (default), it just returns * ``undefined`` (i.e. keeps the existing group). * ignore * Preceding characters to ignore instead of the default ones. * This is in RegExp character class syntax. * ignoreAdd * Preceding characters to ignore in addition to the default ones. * This is in RegExp character class syntax. * removeDiacritics * If specified, decomposition is applied, diacritics matching * this pattern are removed, and then the remaining text is * recomposed. Corresponds to remove_diacritics in language data. * This only applies with the default grouping function. * removeExceptions * If specified, these precomposed characters are retained, * even if the diacritic would otherwise be subject to removal * as per removeDiacritics. Corresponds to remove_exceptions * in language data. This must be a string containing characters, * not a regex pattern. * This only applies with the default grouping function. * unsupported * If ``true``, unsupported titles are passed directly to * ``group``. If ``false`` (default), they are ignored, and their * existing groups are kept. * dottedDotlessI * Used in case conversion; ``true`` means the language has both * dotted and dotless I as separate letters (like in Turkish), * and ``false`` (default) means it doesn't. * * REGROUPER_DATA_SC data format: * This data is organized by script. Note that these configurations are * still only considered for languages that have regrouping enabled. * * If missing, defaults are used. Else, an object may override: * group * A function that works just like group in REGROUPER_DATA_LANG. * If missing, the default grouping function is used. * The priority of grouping functions is: * - group in language data, * - group in script data, * - default grouping. * * The default grouping function: * Checks initials and initialFallback. * If there are initials, it matches them first. * Initial matching ignores certain preceding characters, * e.g. hyphens. * If an initial is found, the matching portion is converted * to title case with ``titleCase`` and returned. * Otherwise, we fall back to 'fallback' logic only if * `initialFallback` is `true`, and else return `undefined` * to keep the existing group. * We may fall into the fallback logic: * remove preceding characters (e.g. hyphens), * take the first remaining Unicode character * (or the first character in general if none would remain * from the previous step), * convert it to title case with ``titleCase`` and return it. */ window.RegrouperMetadata = function() { const REGROUPER_COMMON_DIACRITICS = /[\u0300-\u034E\u0350-\u036F\u1AB0-\u1ACE\u1DC0-\u1DFF\u20D0-\u20F0\uFE20-\uFE2F]/g; const REGROUPER_DATA_LANG = { "da": { initials: /[ÆØÅ]/i, removeDiacritics: /[\u0300\u0301\u0302\u0303\u0304\u030B\u030C\u0327]/g, removeExceptions: "Åå", }, "et": { initials: /[ŠZŽÕÄÖÜ]/i, }, "fi": { initials: /[Å]/i, removeDiacritics: REGROUPER_COMMON_DIACRITICS, removeExceptions: "ÅÄÖåäö", }, // TODO check with editors. // "hu": { // initials: /(?:[ÁÉÍÓÖŐÚÜŰ]|C[sz]|Dzs?|[GLNT]y|Sz)/i, // }, "liv": { initials: /[ĀÄǞḐĒĪĻŅŌȮȰÕȬÖȪŖŠȚŪÜṺȲŽ]/i, }, "lud": { initials: /[ČŠZŽÜÄÖʹ]/i, }, "mt": { initials: /(?:Għ|Ie|[ĊĠĦŻCGHIZ])/i, }, "sv": { initials: /[Å]/i, removeDiacritics: /[\u0300\u0301\u0302\u0303\u0304\u030B\u030C\u0327]/g, removeExceptions: "Åå", }, "vot": { initials: /(?:[ČŠZŽÕÄÖÜ]|Tš)/i, }, }; const REGROUPER_DATA_SC = { }; this.getByLang = lang => REGROUPER_DATA_LANG[lang]; this.getBySc = sc => REGROUPER_DATA_SC[sc]; } //</nowiki> 23l97ycefmpgfemndxsnvstxjvvb4j4 88959 88958 2026-08-06T23:18:26Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-catfixRegrouper-Data.js]] 88958 javascript text/javascript // {{documentation}} // <nowiki> /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /* global mw */ // Configuration and data for [[MediaWiki:Gadget-catfixRegrouper.js]]. /** REGROUPER_DATA_LANG Data format: * IMPORTANT! The regrouper already assumes that the language sort keys * are set up correctly. It does not protect against the same group * heading being repeated *AT ALL*. Do not enable the regrouper for * a language until sort keys are set up for it first (so that * each would-be group is contiguous). * The data is organized by language code. * If the code is missing or the value is undefined, the * regrouper is disabled. This is the default. * If it is ``true``, default values are used. * Otherwise it is an object, with the following fields: * group * A function which is given the following parameters, * in this order: * - page title (minus namespace and language prefixes), * - language code, * - script code, * - namespace number. * ``this`` will be the language data object (so that you * can add your own variables, functions, etc.; but if you * do so, please prefix their names with x_). * It should return the group, i.e. the heading that the * page should be categorized under. If the value returned * is undefined, null, ``false`` or an empty string, * its existing group will be kept. * If ``true``, the group falls back to the * default grouping function. * The default is the default grouping function, either of the * script, or of ``defaultGroup``; * see below for a description thereof. * detectScript * A function which is given the following parameters, * in this order: * - page title (minus namespace and language prefixes), * - language code, * - (default) script code, * - namespace number. * ``this`` will be the language data object (so that you * can add your own variables, functions, etc.; but if you * do so, please prefix their names with x_). * It should return a script code, or undefined to use * the default script. * initials * If the default grouping function is used, this can be a RegExp * of initial letters/digraphs/etc. which are automatically mapped * to that respective group (with titlecase conversion). * initialFallback * Only applies for the default grouping function and if initials * is defined. If ``true``, the default grouping function falls * back to the default logic when the initial doesn't match any * specified in initials; if ``false`` (default), it just returns * ``undefined`` (i.e. keeps the existing group). * ignore * Preceding characters to ignore instead of the default ones. * This is in RegExp character class syntax. * ignoreAdd * Preceding characters to ignore in addition to the default ones. * This is in RegExp character class syntax. * removeDiacritics * If specified, decomposition is applied, diacritics matching * this pattern are removed, and then the remaining text is * recomposed. Corresponds to remove_diacritics in language data. * This only applies with the default grouping function. * removeExceptions * If specified, these precomposed characters are retained, * even if the diacritic would otherwise be subject to removal * as per removeDiacritics. Corresponds to remove_exceptions * in language data. This must be a string containing characters, * not a regex pattern. * This only applies with the default grouping function. * unsupported * If ``true``, unsupported titles are passed directly to * ``group``. If ``false`` (default), they are ignored, and their * existing groups are kept. * dottedDotlessI * Used in case conversion; ``true`` means the language has both * dotted and dotless I as separate letters (like in Turkish), * and ``false`` (default) means it doesn't. * * REGROUPER_DATA_SC data format: * This data is organized by script. Note that these configurations are * still only considered for languages that have regrouping enabled. * * If missing, defaults are used. Else, an object may override: * group * A function that works just like group in REGROUPER_DATA_LANG. * If missing, the default grouping function is used. * The priority of grouping functions is: * - group in language data, * - group in script data, * - default grouping. * * The default grouping function: * Checks initials and initialFallback. * If there are initials, it matches them first. * Initial matching ignores certain preceding characters, * e.g. hyphens. * If an initial is found, the matching portion is converted * to title case with ``titleCase`` and returned. * Otherwise, we fall back to 'fallback' logic only if * `initialFallback` is `true`, and else return `undefined` * to keep the existing group. * We may fall into the fallback logic: * remove preceding characters (e.g. hyphens), * take the first remaining Unicode character * (or the first character in general if none would remain * from the previous step), * convert it to title case with ``titleCase`` and return it. */ window.RegrouperMetadata = function() { const REGROUPER_COMMON_DIACRITICS = /[\u0300-\u034E\u0350-\u036F\u1AB0-\u1ACE\u1DC0-\u1DFF\u20D0-\u20F0\uFE20-\uFE2F]/g; const REGROUPER_DATA_LANG = { "da": { initials: /[ÆØÅ]/i, removeDiacritics: /[\u0300\u0301\u0302\u0303\u0304\u030B\u030C\u0327]/g, removeExceptions: "Åå", }, "et": { initials: /[ŠZŽÕÄÖÜ]/i, }, "fi": { initials: /[Å]/i, removeDiacritics: REGROUPER_COMMON_DIACRITICS, removeExceptions: "ÅÄÖåäö", }, // TODO check with editors. // "hu": { // initials: /(?:[ÁÉÍÓÖŐÚÜŰ]|C[sz]|Dzs?|[GLNT]y|Sz)/i, // }, "liv": { initials: /[ĀÄǞḐĒĪĻŅŌȮȰÕȬÖȪŖŠȚŪÜṺȲŽ]/i, }, "lud": { initials: /[ČŠZŽÜÄÖʹ]/i, }, "mt": { initials: /(?:Għ|Ie|[ĊĠĦŻCGHIZ])/i, }, "sv": { initials: /[Å]/i, removeDiacritics: /[\u0300\u0301\u0302\u0303\u0304\u030B\u030C\u0327]/g, removeExceptions: "Åå", }, "vot": { initials: /(?:[ČŠZŽÕÄÖÜ]|Tš)/i, }, }; const REGROUPER_DATA_SC = { }; this.getByLang = lang => REGROUPER_DATA_LANG[lang]; this.getBySc = sc => REGROUPER_DATA_SC[sc]; } //</nowiki> 23l97ycefmpgfemndxsnvstxjvvb4j4 MediaWiki:Gadget-catfixRegrouper.js 8 17979 88960 2026-05-13T23:39:38Z en>Surjection 0 88960 javascript text/javascript // {{documentation}} // <nowiki> // implicit dependencies : mediawiki.Title, ext.gadget.catfixRegrouper-Data /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw, RegrouperMetadata */ /* data is in [[MediaWiki:Gadget-catfixRegrouper-Data.js]] */ // characters to ignore when looking for the initial in a title. // this is embedded inside a RegExp character class const REGROUPER_INITIALS = "-"; function safeUpperCase(text, dottedDotlessI) { if (dottedDotlessI) return text.replace(/i/g, "İ").toUpperCase(); else return text.toUpperCase(); } function safeLowerCase(text, dottedDotlessI) { if (dottedDotlessI) return text.replace(/I/g, "ı").toLowerCase(); else return text.toLowerCase(); } function titleCase(text, lang, sc) { return safeUpperCase(text.charAt(0), this.dottedDotlessI) + safeLowerCase(text.substring(1), this.dottedDotlessI); } function makeRemoveExceptionsMap(chars) { const pairs = []; let code = 0x100000; for (let char of chars) { pairs.push([char, String.fromCodePoint(code++)]); } return pairs; } function escapeRegexp(text) { return text.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&"); } function replaceAll(text, source, destination) { return text.replace(new RegExp(escapeRegexp(source), "g"), destination); } function removeDiacritics(text, diacritics, exceptions) { if (exceptions != null) { for (let pair of exceptions) { text = replaceAll(text, pair[0], pair[1]); } } text = text.normalize("NFD"); text = text.replace(diacritics, ""); if (exceptions != null) { for (let pair of exceptions) { text = replaceAll(text, pair[1], pair[0]); } } return text.normalize("NFC"); } function defaultGroup(title, lang, sc) { if (title.length < 1) return undefined; let cleaned = title.replace(this._clean_regex, ""); if (this.removeDiacritics) { cleaned = removeDiacritics(cleaned, this.removeDiacritics, this._removeExceptions_map); } if (this.initials) { const initialMatch = cleaned.match(this._initials_regex); if (initialMatch) { return titleCase(initialMatch[0], lang, sc); } if (!this.initialFallback) return undefined; } title = cleaned || title; return titleCase(title.charAt(0), lang, sc); } function makeGroup(groupText) { const groupDiv = document.createElement("div"); groupDiv.className = "mw-category-group"; const groupH3 = document.createElement("h3"); groupH3.textContent = groupText; groupDiv.append(groupH3); const groupUl = document.createElement("ul"); groupDiv.append(groupUl); return [groupDiv, groupUl]; } function getLiText(el) { const child = $(el).find("a, span").first(); const rawText = el.textContent || el.innerText; return (child.length > 0 && child.text()) || rawText; } jQuery(() => { 'use strict'; let catfix; // Apply only to pages in the Category namespace // containing an element with the id "catfix". // Set window.disableCatfixRegrouper to true to prevent this script from running. if (!(!window.disableCatfixRegrouper && mw.config.get('wgNamespaceNumber') === 14 && (catfix = $(".catfix")).length)) return; catfix = catfix[0]; const catfixSpan = catfix.querySelector("span"); if (!catfixSpan) return; const regrouperMeta = new RegrouperMetadata(); // Get the language name and script catfix. const langName = decodeURIComponent(catfix.getAttribute("data-anchor").replace(/_/g, " ")); catfix = catfix.getElementsByTagName("*")[0] || document.createElement("span"); const lang = catfixSpan.getAttribute("lang"); const defaultSc = catfixSpan.classList[0] || "None"; const cachedScriptData = {}; if (!lang) return; const UNPREFIXED_NAMESPACES = ["", "Talk", "Citations"]; const PREFIXED_NAMESPACES = ["Appendix", "Appendix talk", "Reconstruction", "Reconstruction talk"]; function isEntry(namespaceName, pageName) { // main, Talk, Citations, // Reconstruction/Appendix (Talk) if it starts with language name and "/" return UNPREFIXED_NAMESPACES.indexOf(namespaceName) !== -1 || (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1 && pageName.slice(0, langName.length + 1) === langName + "/"); } const formattedNamespaces = mw.config.get("wgFormattedNamespaces"); const regrouperData = regrouperMeta.getByLang(lang); if (!regrouperData) return; // set up stuff for the default regrouper regrouperData._clean_regex = new RegExp("^[" + ((regrouperData.ignoreAdd || "") + (regrouperData.ignore || REGROUPER_INITIALS)) + "]+"); if (regrouperData.initials) regrouperData._initials_regex = new RegExp("^" + regrouperData.initials.source, regrouperData.initials.flags); if (regrouperData.removeExceptions) regrouperData._removeExceptions_map = makeRemoveExceptionsMap(regrouperData.removeExceptions); const groupFunction = regrouperData.group; const detectScriptFunction = regrouperData.detectScript; function getGroup(pageTitle, oldGroup) { const titleobj = new mw.Title(pageTitle); const namespaceId = titleobj.getNamespaceId(); const namespaceName = formattedNamespaces[namespaceId]; const pageName = titleobj.getMainText(); if (!isEntry(namespaceName, pageName)) return oldGroup; // verify language prefix if the namespace should have one let formattedTitle = pageName; const langPrefix = langName + "/"; if (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1) { if (formattedTitle.startsWith(langPrefix)) { formattedTitle = formattedTitle.substring(langPrefix.length); } else { return oldGroup; } } // ignore unsupported titles unless the language data requests otherwise if (formattedTitle.startsWith("Unsupported titles/") && !regrouperData.unsupported) return oldGroup; // script detection let sc = defaultSc; if (detectScriptFunction) sc = detectScriptFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId) || sc; let scData = cachedScriptData[sc]; if (!scData) scData = cachedScriptData[sc] = regrouperMeta.getBySc(sc) || {}; let newGroup = true; // the language group function may return true to fall back if (groupFunction) newGroup = groupFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId); if (newGroup === true && scData.group) newGroup = scData.group.call(regrouperData, formattedTitle, lang, sc, namespaceId); if (newGroup === true) newGroup = defaultGroup.call(regrouperData, formattedTitle, lang, sc, namespaceId); return newGroup || oldGroup; } const GROUP_QUERY = "#mw-pages > .mw-content-ltr .mw-category-group"; let regroupOk = true; const regroupData = new Map(); // Process each group in the category listing. jQuery(GROUP_QUERY) .each(function () { // Get the existing group. const group = $(this).find("h3").first().text(); if (!group) { // Failed to get group -- something has gone wrong. regroupOk = false; return; } $(this).find("li") .each(function () { try { const liText = getLiText(this); const newGroup = getGroup(liText, group); regroupData.set(liText, newGroup); } catch (e) { console.error(e); regroupOk = false; } }); }); // Find the existing groups, which we will delete. const groups = jQuery(GROUP_QUERY); // Cannot regroup if there are no groups. if (!groups.length) return; const parent = groups.first().parent()[0]; if (!parent) return; const fragment = document.createDocumentFragment(); if (regroupOk) { let lastGroup, groupUl; jQuery(GROUP_QUERY + " li") .each(function () { const liText = getLiText(this); const newGroup = regroupData.get(liText) || ""; if (lastGroup !== newGroup) { const elements = makeGroup(newGroup); const groupDiv = elements[0]; fragment.appendChild(groupDiv); groupUl = elements[1]; lastGroup = newGroup; } groupUl.appendChild(this); }); groups.remove(); parent.appendChild(fragment); } }); // </nowiki> 4pdvkpkfjbwt3g1mhmh3mkt22id34z1 88961 88960 2026-08-06T23:18:40Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-catfixRegrouper.js]] 88960 javascript text/javascript // {{documentation}} // <nowiki> // implicit dependencies : mediawiki.Title, ext.gadget.catfixRegrouper-Data /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */ /* global $, mw, RegrouperMetadata */ /* data is in [[MediaWiki:Gadget-catfixRegrouper-Data.js]] */ // characters to ignore when looking for the initial in a title. // this is embedded inside a RegExp character class const REGROUPER_INITIALS = "-"; function safeUpperCase(text, dottedDotlessI) { if (dottedDotlessI) return text.replace(/i/g, "İ").toUpperCase(); else return text.toUpperCase(); } function safeLowerCase(text, dottedDotlessI) { if (dottedDotlessI) return text.replace(/I/g, "ı").toLowerCase(); else return text.toLowerCase(); } function titleCase(text, lang, sc) { return safeUpperCase(text.charAt(0), this.dottedDotlessI) + safeLowerCase(text.substring(1), this.dottedDotlessI); } function makeRemoveExceptionsMap(chars) { const pairs = []; let code = 0x100000; for (let char of chars) { pairs.push([char, String.fromCodePoint(code++)]); } return pairs; } function escapeRegexp(text) { return text.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&"); } function replaceAll(text, source, destination) { return text.replace(new RegExp(escapeRegexp(source), "g"), destination); } function removeDiacritics(text, diacritics, exceptions) { if (exceptions != null) { for (let pair of exceptions) { text = replaceAll(text, pair[0], pair[1]); } } text = text.normalize("NFD"); text = text.replace(diacritics, ""); if (exceptions != null) { for (let pair of exceptions) { text = replaceAll(text, pair[1], pair[0]); } } return text.normalize("NFC"); } function defaultGroup(title, lang, sc) { if (title.length < 1) return undefined; let cleaned = title.replace(this._clean_regex, ""); if (this.removeDiacritics) { cleaned = removeDiacritics(cleaned, this.removeDiacritics, this._removeExceptions_map); } if (this.initials) { const initialMatch = cleaned.match(this._initials_regex); if (initialMatch) { return titleCase(initialMatch[0], lang, sc); } if (!this.initialFallback) return undefined; } title = cleaned || title; return titleCase(title.charAt(0), lang, sc); } function makeGroup(groupText) { const groupDiv = document.createElement("div"); groupDiv.className = "mw-category-group"; const groupH3 = document.createElement("h3"); groupH3.textContent = groupText; groupDiv.append(groupH3); const groupUl = document.createElement("ul"); groupDiv.append(groupUl); return [groupDiv, groupUl]; } function getLiText(el) { const child = $(el).find("a, span").first(); const rawText = el.textContent || el.innerText; return (child.length > 0 && child.text()) || rawText; } jQuery(() => { 'use strict'; let catfix; // Apply only to pages in the Category namespace // containing an element with the id "catfix". // Set window.disableCatfixRegrouper to true to prevent this script from running. if (!(!window.disableCatfixRegrouper && mw.config.get('wgNamespaceNumber') === 14 && (catfix = $(".catfix")).length)) return; catfix = catfix[0]; const catfixSpan = catfix.querySelector("span"); if (!catfixSpan) return; const regrouperMeta = new RegrouperMetadata(); // Get the language name and script catfix. const langName = decodeURIComponent(catfix.getAttribute("data-anchor").replace(/_/g, " ")); catfix = catfix.getElementsByTagName("*")[0] || document.createElement("span"); const lang = catfixSpan.getAttribute("lang"); const defaultSc = catfixSpan.classList[0] || "None"; const cachedScriptData = {}; if (!lang) return; const UNPREFIXED_NAMESPACES = ["", "Talk", "Citations"]; const PREFIXED_NAMESPACES = ["Appendix", "Appendix talk", "Reconstruction", "Reconstruction talk"]; function isEntry(namespaceName, pageName) { // main, Talk, Citations, // Reconstruction/Appendix (Talk) if it starts with language name and "/" return UNPREFIXED_NAMESPACES.indexOf(namespaceName) !== -1 || (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1 && pageName.slice(0, langName.length + 1) === langName + "/"); } const formattedNamespaces = mw.config.get("wgFormattedNamespaces"); const regrouperData = regrouperMeta.getByLang(lang); if (!regrouperData) return; // set up stuff for the default regrouper regrouperData._clean_regex = new RegExp("^[" + ((regrouperData.ignoreAdd || "") + (regrouperData.ignore || REGROUPER_INITIALS)) + "]+"); if (regrouperData.initials) regrouperData._initials_regex = new RegExp("^" + regrouperData.initials.source, regrouperData.initials.flags); if (regrouperData.removeExceptions) regrouperData._removeExceptions_map = makeRemoveExceptionsMap(regrouperData.removeExceptions); const groupFunction = regrouperData.group; const detectScriptFunction = regrouperData.detectScript; function getGroup(pageTitle, oldGroup) { const titleobj = new mw.Title(pageTitle); const namespaceId = titleobj.getNamespaceId(); const namespaceName = formattedNamespaces[namespaceId]; const pageName = titleobj.getMainText(); if (!isEntry(namespaceName, pageName)) return oldGroup; // verify language prefix if the namespace should have one let formattedTitle = pageName; const langPrefix = langName + "/"; if (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1) { if (formattedTitle.startsWith(langPrefix)) { formattedTitle = formattedTitle.substring(langPrefix.length); } else { return oldGroup; } } // ignore unsupported titles unless the language data requests otherwise if (formattedTitle.startsWith("Unsupported titles/") && !regrouperData.unsupported) return oldGroup; // script detection let sc = defaultSc; if (detectScriptFunction) sc = detectScriptFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId) || sc; let scData = cachedScriptData[sc]; if (!scData) scData = cachedScriptData[sc] = regrouperMeta.getBySc(sc) || {}; let newGroup = true; // the language group function may return true to fall back if (groupFunction) newGroup = groupFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId); if (newGroup === true && scData.group) newGroup = scData.group.call(regrouperData, formattedTitle, lang, sc, namespaceId); if (newGroup === true) newGroup = defaultGroup.call(regrouperData, formattedTitle, lang, sc, namespaceId); return newGroup || oldGroup; } const GROUP_QUERY = "#mw-pages > .mw-content-ltr .mw-category-group"; let regroupOk = true; const regroupData = new Map(); // Process each group in the category listing. jQuery(GROUP_QUERY) .each(function () { // Get the existing group. const group = $(this).find("h3").first().text(); if (!group) { // Failed to get group -- something has gone wrong. regroupOk = false; return; } $(this).find("li") .each(function () { try { const liText = getLiText(this); const newGroup = getGroup(liText, group); regroupData.set(liText, newGroup); } catch (e) { console.error(e); regroupOk = false; } }); }); // Find the existing groups, which we will delete. const groups = jQuery(GROUP_QUERY); // Cannot regroup if there are no groups. if (!groups.length) return; const parent = groups.first().parent()[0]; if (!parent) return; const fragment = document.createDocumentFragment(); if (regroupOk) { let lastGroup, groupUl; jQuery(GROUP_QUERY + " li") .each(function () { const liText = getLiText(this); const newGroup = regroupData.get(liText) || ""; if (lastGroup !== newGroup) { const elements = makeGroup(newGroup); const groupDiv = elements[0]; fragment.appendChild(groupDiv); groupUl = elements[1]; lastGroup = newGroup; } groupUl.appendChild(this); }); groups.remove(); parent.appendChild(fragment); } }); // </nowiki> 4pdvkpkfjbwt3g1mhmh3mkt22id34z1 MediaWiki:Gadget-nearby.js 8 17980 88962 2025-12-13T23:46:16Z en>Ioaxxere 0 adjust display text for mammoth pages 88962 javascript text/javascript // <nowiki> (async () => { // Do a preliminary check to avoid running the gadget unnecessarily. if ([...document.querySelectorAll("#catlinks li")].some(cat => cat.textContent.endsWith(" lemmas"))) { mw.util.addCSS(` .nearby-entries-box { padding: 6px; margin-top: 10px; background: var(--wikt-palette-palergreen); width: fit-content; max-width: 100%; border: 1.5px solid var(--wikt-palette-forestgreen); border-radius: 2px; overflow-wrap: break-word; } `); let actionAPI = new mw.Api({ajax: {headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); let pageName = mw.config.values.wgPageName; const N_ENTRIES = 3; // the number of preview entries on each side of the current page // Given a page title (no underscores), return the prettified title. const makeDisplayTitle = rawTitle => { rawTitle = rawTitle.replaceAll("_", " ").replace(/\/languages [A-Z] to [A-Z]$/g, ""); if (rawTitle.startsWith("Reconstruction:")) return `*${rawTitle.split("/").pop()}`; if (rawTitle.startsWith("Appendix:")) return rawTitle.split("/").pop(); if (rawTitle.startsWith("Unsupported titles/")) return convertUnsupportedTitle(rawTitle); // from [[MediaWiki:Gadget-UnsupportedTitles.js]] return rawTitle; }; // Build pageCategorySortkeys, a map from each page category to its associated sortkey. let pageCategorySortkeys = new Map(); let continueParam; while (true) { let params = { action: "query", format: "json", cllimit: "max", clprop: "sortkey", prop: "categories", titles: pageName }; if (continueParam) params.clcontinue = continueParam; let response = await actionAPI.get(params); for (let category of Object.values(response.query.pages)[0].categories) pageCategorySortkeys.set(category.title, category.sortkeyprefix); if (!response.continue) break; continueParam = response.continue.clcontinue; } document.querySelectorAll(".mw-heading2 h2").forEach(async h2 => { let language = h2.id.replaceAll("_", " "); let category = `Category:${language} lemmas`; if (!pageCategorySortkeys.has(category)) return; // skip non-lemmas and malformed entries let params = { action: "query", cmlimit: 40, // arbitrary; we don't know how many we need ahead of time format: "json", list: "categorymembers", cmsort: "sortkey", cmtitle: category, cmstartsortkeyprefix: pageCategorySortkeys.get(category) }; let titles = (await actionAPI.get(params)).query.categorymembers .filter(page => page.ns !== 14) // Filter out namespace 14 (Category:) .map(page => page.title); // pageName is guaranteed to be in this list unless there are over `cmlimit` pages with the same sortkey. let currPagePosition = titles.indexOf(pageName.replaceAll("_", " ")); let entriesAhead = titles.slice(currPagePosition + 1, currPagePosition + N_ENTRIES + 1); let entriesBehind = titles.slice(Math.max(currPagePosition - N_ENTRIES, 0), currPagePosition); if (entriesBehind.length < N_ENTRIES) { // If entriesBehind isn't yet long enough, switch direction and get the entries coming before. // There are no duplicates between the first and second queries. params.cmdir = "desc"; entriesBehind = (await actionAPI.get(params)).query.categorymembers .filter(page => page.ns !== 14) .map(page => page.title) .slice(0, N_ENTRIES - entriesBehind.length) .reverse() .concat(entriesBehind); } // Display nearby entries on the page. let nearbyEntriesDiv = document.createElement("div"); nearbyEntriesDiv.className = "nearby-entries-box"; nearbyEntriesDiv.innerText = "» "; // Need to account for both HTML formats. if (h2.parentElement.nextElementSibling.tagName === "SECTION") h2.parentElement.nextElementSibling.prepend(nearbyEntriesDiv); else h2.parentElement.parentElement.insertBefore(nearbyEntriesDiv, h2.parentElement.nextElementSibling); for (let entry of entriesBehind) { let entryLink = document.createElement("a"); entryLink.href = `/wiki/${mw.util.wikiUrlencode(entry)}#${h2.id}`; entryLink.title = entry; entryLink.textContent = makeDisplayTitle(entry); nearbyEntriesDiv.append(entryLink, " • "); } let selflink = document.createElement("a"); selflink.className = "mw-selflink selflink"; selflink.textContent = makeDisplayTitle(pageName); nearbyEntriesDiv.append(selflink); for (let entry of entriesAhead) { let entryLink = document.createElement("a"); entryLink.href = `/wiki/${mw.util.wikiUrlencode(entry)}#${h2.id}`; entryLink.title = entry; entryLink.textContent = makeDisplayTitle(entry); nearbyEntriesDiv.append(" • ", entryLink); } }); } })(); // </nowiki> qrnvvsk960y6rne2zimvyueuhlrbfh9 88963 88962 2026-08-06T23:21:08Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-nearby.js]] 88962 javascript text/javascript // <nowiki> (async () => { // Do a preliminary check to avoid running the gadget unnecessarily. if ([...document.querySelectorAll("#catlinks li")].some(cat => cat.textContent.endsWith(" lemmas"))) { mw.util.addCSS(` .nearby-entries-box { padding: 6px; margin-top: 10px; background: var(--wikt-palette-palergreen); width: fit-content; max-width: 100%; border: 1.5px solid var(--wikt-palette-forestgreen); border-radius: 2px; overflow-wrap: break-word; } `); let actionAPI = new mw.Api({ajax: {headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); let pageName = mw.config.values.wgPageName; const N_ENTRIES = 3; // the number of preview entries on each side of the current page // Given a page title (no underscores), return the prettified title. const makeDisplayTitle = rawTitle => { rawTitle = rawTitle.replaceAll("_", " ").replace(/\/languages [A-Z] to [A-Z]$/g, ""); if (rawTitle.startsWith("Reconstruction:")) return `*${rawTitle.split("/").pop()}`; if (rawTitle.startsWith("Appendix:")) return rawTitle.split("/").pop(); if (rawTitle.startsWith("Unsupported titles/")) return convertUnsupportedTitle(rawTitle); // from [[MediaWiki:Gadget-UnsupportedTitles.js]] return rawTitle; }; // Build pageCategorySortkeys, a map from each page category to its associated sortkey. let pageCategorySortkeys = new Map(); let continueParam; while (true) { let params = { action: "query", format: "json", cllimit: "max", clprop: "sortkey", prop: "categories", titles: pageName }; if (continueParam) params.clcontinue = continueParam; let response = await actionAPI.get(params); for (let category of Object.values(response.query.pages)[0].categories) pageCategorySortkeys.set(category.title, category.sortkeyprefix); if (!response.continue) break; continueParam = response.continue.clcontinue; } document.querySelectorAll(".mw-heading2 h2").forEach(async h2 => { let language = h2.id.replaceAll("_", " "); let category = `Category:${language} lemmas`; if (!pageCategorySortkeys.has(category)) return; // skip non-lemmas and malformed entries let params = { action: "query", cmlimit: 40, // arbitrary; we don't know how many we need ahead of time format: "json", list: "categorymembers", cmsort: "sortkey", cmtitle: category, cmstartsortkeyprefix: pageCategorySortkeys.get(category) }; let titles = (await actionAPI.get(params)).query.categorymembers .filter(page => page.ns !== 14) // Filter out namespace 14 (Category:) .map(page => page.title); // pageName is guaranteed to be in this list unless there are over `cmlimit` pages with the same sortkey. let currPagePosition = titles.indexOf(pageName.replaceAll("_", " ")); let entriesAhead = titles.slice(currPagePosition + 1, currPagePosition + N_ENTRIES + 1); let entriesBehind = titles.slice(Math.max(currPagePosition - N_ENTRIES, 0), currPagePosition); if (entriesBehind.length < N_ENTRIES) { // If entriesBehind isn't yet long enough, switch direction and get the entries coming before. // There are no duplicates between the first and second queries. params.cmdir = "desc"; entriesBehind = (await actionAPI.get(params)).query.categorymembers .filter(page => page.ns !== 14) .map(page => page.title) .slice(0, N_ENTRIES - entriesBehind.length) .reverse() .concat(entriesBehind); } // Display nearby entries on the page. let nearbyEntriesDiv = document.createElement("div"); nearbyEntriesDiv.className = "nearby-entries-box"; nearbyEntriesDiv.innerText = "» "; // Need to account for both HTML formats. if (h2.parentElement.nextElementSibling.tagName === "SECTION") h2.parentElement.nextElementSibling.prepend(nearbyEntriesDiv); else h2.parentElement.parentElement.insertBefore(nearbyEntriesDiv, h2.parentElement.nextElementSibling); for (let entry of entriesBehind) { let entryLink = document.createElement("a"); entryLink.href = `/wiki/${mw.util.wikiUrlencode(entry)}#${h2.id}`; entryLink.title = entry; entryLink.textContent = makeDisplayTitle(entry); nearbyEntriesDiv.append(entryLink, " • "); } let selflink = document.createElement("a"); selflink.className = "mw-selflink selflink"; selflink.textContent = makeDisplayTitle(pageName); nearbyEntriesDiv.append(selflink); for (let entry of entriesAhead) { let entryLink = document.createElement("a"); entryLink.href = `/wiki/${mw.util.wikiUrlencode(entry)}#${h2.id}`; entryLink.title = entry; entryLink.textContent = makeDisplayTitle(entry); nearbyEntriesDiv.append(" • ", entryLink); } }); } })(); // </nowiki> qrnvvsk960y6rne2zimvyueuhlrbfh9 MediaWiki:Gadget-linkLanguageHeaders.js 8 17981 88964 2024-09-29T14:02:18Z en>Surjection 0 88964 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> (function linkLanguageHeadersGadget() { var CACHE_DURATION = 24 * 60 * 60; // 24 hours var ALLOWED_NAMESPACES = [ 0, // main 118 // Reconstruction ]; function categoryNameFromLanguageName(name) { return (name + " language").replace(/ Language language$/, " Language"); } function getLanguageCodesByCanonicalName(callback, cacheDuration) { var KEY = "enwiktLanguageCanonicalNamesJson"; var timeNow = new Date().getTime() * 1e-3; try { var cachedData = JSON.parse(localStorage.getItem(KEY)); if (timeNow - cachedData.timestamp < cacheDuration) { callback(cachedData.data); return; } } catch (e) { } var request = new mw.Api().get({ "action": "parse", "page": "Module:languages/canonical names.json", "prop": "wikitext", "formatversion": 2, "format": "json" }); request.done(function(response) { var languageData = JSON.parse(response.parse.wikitext); callback(languageData); localStorage.setItem(KEY, JSON.stringify({ timestamp: timeNow, data: languageData })); }); } function linkLanguageHeaders(codeByCanonicalName) { var categoryPrefix = encodeURIComponent(mw.config.get("wgFormattedNamespaces")[14].replace(/ /g, "_")) + ":"; $("#mw-content-text h2 .mw-headline, #mw-content-text .mw-heading2 h2").each(function() { var headline = $(this); var languageName = headline.text(); var languageCode = codeByCanonicalName[languageName]; if (languageCode) { var categoryName = categoryNameFromLanguageName(languageName); headline.html($("<a>", { text: languageName, title: languageName + " [" + languageCode + "]", href: mw.config.get("wgArticlePath").replace("$1", categoryPrefix + encodeURIComponent(categoryName.replace(/ /g, "_"))) })); } }); } mw.hook("wikipage.content").add(function($) { if (mw.config.get("wgAction") === "view" && ALLOWED_NAMESPACES.indexOf(mw.config.get("wgNamespaceNumber")) >= 0) { getLanguageCodesByCanonicalName(function (codeByCanonicalName) { linkLanguageHeaders(codeByCanonicalName); }, CACHE_DURATION); } }); })(); // </nowiki> 9mbznzssi1tt0p2j4o8fhijrpvduxiw 88965 88964 2026-08-06T23:21:19Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-linkLanguageHeaders.js]] 88964 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> (function linkLanguageHeadersGadget() { var CACHE_DURATION = 24 * 60 * 60; // 24 hours var ALLOWED_NAMESPACES = [ 0, // main 118 // Reconstruction ]; function categoryNameFromLanguageName(name) { return (name + " language").replace(/ Language language$/, " Language"); } function getLanguageCodesByCanonicalName(callback, cacheDuration) { var KEY = "enwiktLanguageCanonicalNamesJson"; var timeNow = new Date().getTime() * 1e-3; try { var cachedData = JSON.parse(localStorage.getItem(KEY)); if (timeNow - cachedData.timestamp < cacheDuration) { callback(cachedData.data); return; } } catch (e) { } var request = new mw.Api().get({ "action": "parse", "page": "Module:languages/canonical names.json", "prop": "wikitext", "formatversion": 2, "format": "json" }); request.done(function(response) { var languageData = JSON.parse(response.parse.wikitext); callback(languageData); localStorage.setItem(KEY, JSON.stringify({ timestamp: timeNow, data: languageData })); }); } function linkLanguageHeaders(codeByCanonicalName) { var categoryPrefix = encodeURIComponent(mw.config.get("wgFormattedNamespaces")[14].replace(/ /g, "_")) + ":"; $("#mw-content-text h2 .mw-headline, #mw-content-text .mw-heading2 h2").each(function() { var headline = $(this); var languageName = headline.text(); var languageCode = codeByCanonicalName[languageName]; if (languageCode) { var categoryName = categoryNameFromLanguageName(languageName); headline.html($("<a>", { text: languageName, title: languageName + " [" + languageCode + "]", href: mw.config.get("wgArticlePath").replace("$1", categoryPrefix + encodeURIComponent(categoryName.replace(/ /g, "_"))) })); } }); } mw.hook("wikipage.content").add(function($) { if (mw.config.get("wgAction") === "view" && ALLOWED_NAMESPACES.indexOf(mw.config.get("wgNamespaceNumber")) >= 0) { getLanguageCodesByCanonicalName(function (codeByCanonicalName) { linkLanguageHeaders(codeByCanonicalName); }, CACHE_DURATION); } }); })(); // </nowiki> 9mbznzssi1tt0p2j4o8fhijrpvduxiw MediaWiki:Gadget-AggregateInterprojectLinks.js 8 17982 88966 2024-09-11T13:19:41Z en>Surjection 0 88966 javascript text/javascript /* ** Generates a sidebar list of links to other projects from {{pedia}}, etc. ** <nowiki> */ $(function () { // Broken on Minerva... if (mw.config.values.skin === "minerva") return; var spans = $('span.interProject a:first-child').clone(); if (spans.length === 0) return; // sort alphabetically function sortbylabel(a, b) { // get labels a = $(a).text(); b = $(b).text(); // return sort order if (a < b) return -1; if (a > b) return 1; return 0; } spans.sort(sortbylabel); var isVector2022 = mw.config.get('skin') === 'vector-2022'; var newLinksWrapper = $('<div>', { 'class': 'pBody body vector-menu-content', 'style': 'display:block' }); if (isVector2022) newLinksWrapper.addClass('mw-portlet mw-portlet-projects'); $(spans).wrap('<li class="mw-list-item">').parent() .appendTo($('<ul class="vector-menu-content-list">')).parent() .appendTo(newLinksWrapper); var collapsed = mw.cookie.get("vector-nav-p-projects") == "false"; var projectBox = $('<div>', { addClass: 'vector-menu vector-menu-portal portlet portal ' + (collapsed ? "collapsed" : "expanded"), id: 'p-projects' }) .append($(isVector2022 ? '<div id="p-projects-label" class="vector-menu-heading">In other projects</div>' : '<label id="p-projects-label" aria-label="" class="vector-menu-heading"><span class="vector-menu-heading-label">In other projects</span></label>')) .append(newLinksWrapper); $('#p-tb').after(projectBox); }); //</nowiki> 4mxst2h6pxj1o22mlp5bicxzmqi368j 88967 88966 2026-08-06T23:21:29Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AggregateInterprojectLinks.js]] 88966 javascript text/javascript /* ** Generates a sidebar list of links to other projects from {{pedia}}, etc. ** <nowiki> */ $(function () { // Broken on Minerva... if (mw.config.values.skin === "minerva") return; var spans = $('span.interProject a:first-child').clone(); if (spans.length === 0) return; // sort alphabetically function sortbylabel(a, b) { // get labels a = $(a).text(); b = $(b).text(); // return sort order if (a < b) return -1; if (a > b) return 1; return 0; } spans.sort(sortbylabel); var isVector2022 = mw.config.get('skin') === 'vector-2022'; var newLinksWrapper = $('<div>', { 'class': 'pBody body vector-menu-content', 'style': 'display:block' }); if (isVector2022) newLinksWrapper.addClass('mw-portlet mw-portlet-projects'); $(spans).wrap('<li class="mw-list-item">').parent() .appendTo($('<ul class="vector-menu-content-list">')).parent() .appendTo(newLinksWrapper); var collapsed = mw.cookie.get("vector-nav-p-projects") == "false"; var projectBox = $('<div>', { addClass: 'vector-menu vector-menu-portal portlet portal ' + (collapsed ? "collapsed" : "expanded"), id: 'p-projects' }) .append($(isVector2022 ? '<div id="p-projects-label" class="vector-menu-heading">In other projects</div>' : '<label id="p-projects-label" aria-label="" class="vector-menu-heading"><span class="vector-menu-heading-label">In other projects</span></label>')) .append(newLinksWrapper); $('#p-tb').after(projectBox); }); //</nowiki> 4mxst2h6pxj1o22mlp5bicxzmqi368j MediaWiki:Gadget-TargetedTranslations.js 8 17983 88968 2025-11-06T18:30:16Z en>Surjection 0 88968 javascript text/javascript // Initialize preferred languages from local storage. const storedLangs = localStorage.getItem("targetedTranslationsLangs"); let preferredLanguages = new Set(storedLangs ? JSON.parse(storedLangs) : []); // SVG icons for bookmark states. const ICONS = { unselected: ` <svg xmlns="http://www.w3.org/2000/svg" width="25" height="17" viewBox="0 0 20 20" fill="currentColor" style="vertical-align: text-top; cursor: pointer"> <g> <path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z"/> </g> </svg>`, selected: ` <svg xmlns="http://www.w3.org/2000/svg" width="25" height="17" viewBox="0 0 20 20" fill="currentColor" style="vertical-align: text-top; cursor: pointer"> <g> <path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z"/> </g> </svg>`, }; // Cache all translation tables up front. const translationTables = Array.from( document.querySelectorAll("table.translations") ); /** * Iterate over each non-empty translation line (<li> or <dd>) and compute its language key. * Calls callback(lineElem, langKey) for each valid line. */ function forEachTranslationLine(table, callback) { const lines = table.querySelectorAll( ".translations-cell li, .translations-cell dd" ); for (const line of lines) { const text = line.textContent.trim(); // Must have “Lang: …” format. if (!text.includes(":")) continue; const [base, ...rest] = text.split(":"); const baseLang = base.trim(); if (!baseLang || rest.join(":").trim().length === 0) continue; let fullKey = baseLang; // If this <li> is actually a sub‐entry, its grandparent is an <li> whose text is the macrolanguage. const containerLi = line.parentElement.parentElement.tagName === "LI" ? line.parentElement.parentElement : null; if (containerLi) { const parentText = containerLi.textContent.split(":")[0].trim(); fullKey = `${parentText}>${baseLang}`; } callback(line, fullKey); } } /** * Render the “— Lang: translation; …” snippet under each NavHead, * based on preferredLanguages. */ function renderTargetedTranslations() { // Remove any existing markers. document .querySelectorAll(".targeted-translations") .forEach((el) => el.remove()); for (const table of translationTables) { // *** FIXED: NavHead is the previous sibling of table.parentElement, not table itself. const navHead = table.parentElement.previousElementSibling; if (!navHead || !navHead.matches("div.NavHead")) { continue; } const frag = document.createDocumentFragment(); let foundAny = false; forEachTranslationLine(table, (line, langKey) => { if (!preferredLanguages.has(langKey)) return; if (foundAny) { frag.append(document.createTextNode("; ")); } foundAny = true; const span = document.createElement("span"); const [macro, sub] = langKey.split(">"); if (sub) { span.append(`${macro} (${sub}): `); } else { span.append(`${macro}: `); } // Clone all child nodes except the first text node (which holds the language name). for (let i = 1; i < line.childNodes.length; i++) { if (line.childNodes[i].tagName !== "DL") { span.append(line.childNodes[i].cloneNode(true)); } } frag.append(span); }); if (foundAny) { const wrapper = document.createElement("span"); wrapper.className = "targeted-translations"; wrapper.append(" — ", frag); navHead.append(wrapper); } } } /** * Toggle a single icon’s class and update preferredLanguages. */ function toggleIcon(iconEl, langKey) { if (preferredLanguages.has(langKey)) { preferredLanguages.delete(langKey); iconEl.classList.replace("tt-icon-selected", "tt-icon-unselected"); iconEl.innerHTML = ICONS.unselected; } else { preferredLanguages.add(langKey); iconEl.classList.replace("tt-icon-unselected", "tt-icon-selected"); iconEl.innerHTML = ICONS.selected; } } /** * Enter “select mode” on a given table: * - Convert each translation line into a clickable icon. * - Change the button to “Save preferred languages.” * - Show the “Clear all” link. */ function enterSelectMode(table, selectBtn, clearBtn) { // If any other table is already in “save” mode, force it to save first. document.querySelectorAll(".tt-button-select").forEach((btn) => { if (btn !== selectBtn && btn.textContent === "Save preferred languages") { btn.click(); } }); selectBtn.textContent = "Save preferred languages"; clearBtn.parentElement.style.display = ""; forEachTranslationLine(table, (line, langKey) => { const icon = document.createElement("span"); icon.setAttribute("role", "button"); icon.classList.add( preferredLanguages.has(langKey) ? "tt-icon-selected" : "tt-icon-unselected" ); icon.innerHTML = preferredLanguages.has(langKey) ? ICONS.selected : ICONS.unselected; line.insertAdjacentElement("afterbegin", icon); icon.addEventListener("click", () => toggleIcon(icon, langKey)); }); } /** * Exit “select mode” on a given table: * - Save preferredLanguages → localStorage. * - Remove all icons. * - Re-render the targeted translations. */ function exitSelectMode(table, selectBtn, clearBtn) { localStorage.setItem( "targetedTranslationsLangs", JSON.stringify([...preferredLanguages]) ); table .querySelectorAll(".tt-icon-selected, .tt-icon-unselected") .forEach((el) => el.remove()); selectBtn.textContent = "Select preferred languages"; clearBtn.parentElement.style.display = "none"; renderTargetedTranslations(); } // ---------------------------------------------------- // INITIAL SETUP: insert the control row & wire up events // ---------------------------------------------------- translationTables.forEach((table) => { // Build the <tr> for “Select preferred languages” / “Clear all”. const headerRow = document.createElement("tr"); headerRow.innerHTML = ` <td colspan="100%" style="font-size: 85%" class="targeted-translations-select"> [<a role="button" class="tt-button-select">Select preferred languages</a>] <span style="display: none"> &#32; [<a role="button" class="tt-button-clear">Clear all</a>] </span> </td> `; // Insert at the very top of <tbody>. const tbody = table.firstElementChild; tbody.insertBefore(headerRow, tbody.firstElementChild); const selectBtn = table.querySelector(".tt-button-select"); const clearBtn = table.querySelector(".tt-button-clear"); selectBtn.addEventListener("click", () => { if (selectBtn.textContent === "Select preferred languages") { enterSelectMode(table, selectBtn, clearBtn); } else { exitSelectMode(table, selectBtn, clearBtn); } }); clearBtn.addEventListener("click", () => { preferredLanguages.clear(); table.querySelectorAll(".tt-icon-selected").forEach((icon) => { icon.classList.replace("tt-icon-selected", "tt-icon-unselected"); icon.innerHTML = ICONS.unselected; }); }); }); // Initial display of preferred translations. renderTargetedTranslations(); bjskcznhr4hueglve7hzzkkk78c0cxq 88969 88968 2026-08-06T23:23:17Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TargetedTranslations.js]] 88968 javascript text/javascript // Initialize preferred languages from local storage. const storedLangs = localStorage.getItem("targetedTranslationsLangs"); let preferredLanguages = new Set(storedLangs ? JSON.parse(storedLangs) : []); // SVG icons for bookmark states. const ICONS = { unselected: ` <svg xmlns="http://www.w3.org/2000/svg" width="25" height="17" viewBox="0 0 20 20" fill="currentColor" style="vertical-align: text-top; cursor: pointer"> <g> <path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z"/> </g> </svg>`, selected: ` <svg xmlns="http://www.w3.org/2000/svg" width="25" height="17" viewBox="0 0 20 20" fill="currentColor" style="vertical-align: text-top; cursor: pointer"> <g> <path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z"/> </g> </svg>`, }; // Cache all translation tables up front. const translationTables = Array.from( document.querySelectorAll("table.translations") ); /** * Iterate over each non-empty translation line (<li> or <dd>) and compute its language key. * Calls callback(lineElem, langKey) for each valid line. */ function forEachTranslationLine(table, callback) { const lines = table.querySelectorAll( ".translations-cell li, .translations-cell dd" ); for (const line of lines) { const text = line.textContent.trim(); // Must have “Lang: …” format. if (!text.includes(":")) continue; const [base, ...rest] = text.split(":"); const baseLang = base.trim(); if (!baseLang || rest.join(":").trim().length === 0) continue; let fullKey = baseLang; // If this <li> is actually a sub‐entry, its grandparent is an <li> whose text is the macrolanguage. const containerLi = line.parentElement.parentElement.tagName === "LI" ? line.parentElement.parentElement : null; if (containerLi) { const parentText = containerLi.textContent.split(":")[0].trim(); fullKey = `${parentText}>${baseLang}`; } callback(line, fullKey); } } /** * Render the “— Lang: translation; …” snippet under each NavHead, * based on preferredLanguages. */ function renderTargetedTranslations() { // Remove any existing markers. document .querySelectorAll(".targeted-translations") .forEach((el) => el.remove()); for (const table of translationTables) { // *** FIXED: NavHead is the previous sibling of table.parentElement, not table itself. const navHead = table.parentElement.previousElementSibling; if (!navHead || !navHead.matches("div.NavHead")) { continue; } const frag = document.createDocumentFragment(); let foundAny = false; forEachTranslationLine(table, (line, langKey) => { if (!preferredLanguages.has(langKey)) return; if (foundAny) { frag.append(document.createTextNode("; ")); } foundAny = true; const span = document.createElement("span"); const [macro, sub] = langKey.split(">"); if (sub) { span.append(`${macro} (${sub}): `); } else { span.append(`${macro}: `); } // Clone all child nodes except the first text node (which holds the language name). for (let i = 1; i < line.childNodes.length; i++) { if (line.childNodes[i].tagName !== "DL") { span.append(line.childNodes[i].cloneNode(true)); } } frag.append(span); }); if (foundAny) { const wrapper = document.createElement("span"); wrapper.className = "targeted-translations"; wrapper.append(" — ", frag); navHead.append(wrapper); } } } /** * Toggle a single icon’s class and update preferredLanguages. */ function toggleIcon(iconEl, langKey) { if (preferredLanguages.has(langKey)) { preferredLanguages.delete(langKey); iconEl.classList.replace("tt-icon-selected", "tt-icon-unselected"); iconEl.innerHTML = ICONS.unselected; } else { preferredLanguages.add(langKey); iconEl.classList.replace("tt-icon-unselected", "tt-icon-selected"); iconEl.innerHTML = ICONS.selected; } } /** * Enter “select mode” on a given table: * - Convert each translation line into a clickable icon. * - Change the button to “Save preferred languages.” * - Show the “Clear all” link. */ function enterSelectMode(table, selectBtn, clearBtn) { // If any other table is already in “save” mode, force it to save first. document.querySelectorAll(".tt-button-select").forEach((btn) => { if (btn !== selectBtn && btn.textContent === "Save preferred languages") { btn.click(); } }); selectBtn.textContent = "Save preferred languages"; clearBtn.parentElement.style.display = ""; forEachTranslationLine(table, (line, langKey) => { const icon = document.createElement("span"); icon.setAttribute("role", "button"); icon.classList.add( preferredLanguages.has(langKey) ? "tt-icon-selected" : "tt-icon-unselected" ); icon.innerHTML = preferredLanguages.has(langKey) ? ICONS.selected : ICONS.unselected; line.insertAdjacentElement("afterbegin", icon); icon.addEventListener("click", () => toggleIcon(icon, langKey)); }); } /** * Exit “select mode” on a given table: * - Save preferredLanguages → localStorage. * - Remove all icons. * - Re-render the targeted translations. */ function exitSelectMode(table, selectBtn, clearBtn) { localStorage.setItem( "targetedTranslationsLangs", JSON.stringify([...preferredLanguages]) ); table .querySelectorAll(".tt-icon-selected, .tt-icon-unselected") .forEach((el) => el.remove()); selectBtn.textContent = "Select preferred languages"; clearBtn.parentElement.style.display = "none"; renderTargetedTranslations(); } // ---------------------------------------------------- // INITIAL SETUP: insert the control row & wire up events // ---------------------------------------------------- translationTables.forEach((table) => { // Build the <tr> for “Select preferred languages” / “Clear all”. const headerRow = document.createElement("tr"); headerRow.innerHTML = ` <td colspan="100%" style="font-size: 85%" class="targeted-translations-select"> [<a role="button" class="tt-button-select">Select preferred languages</a>] <span style="display: none"> &#32; [<a role="button" class="tt-button-clear">Clear all</a>] </span> </td> `; // Insert at the very top of <tbody>. const tbody = table.firstElementChild; tbody.insertBefore(headerRow, tbody.firstElementChild); const selectBtn = table.querySelector(".tt-button-select"); const clearBtn = table.querySelector(".tt-button-clear"); selectBtn.addEventListener("click", () => { if (selectBtn.textContent === "Select preferred languages") { enterSelectMode(table, selectBtn, clearBtn); } else { exitSelectMode(table, selectBtn, clearBtn); } }); clearBtn.addEventListener("click", () => { preferredLanguages.clear(); table.querySelectorAll(".tt-icon-selected").forEach((icon) => { icon.classList.replace("tt-icon-selected", "tt-icon-unselected"); icon.innerHTML = ICONS.unselected; }); }); }); // Initial display of preferred translations. renderTargetedTranslations(); bjskcznhr4hueglve7hzzkkk78c0cxq MediaWiki:Gadget-TargetedTranslations.css 8 17984 88970 2021-05-28T08:17:31Z en>Erutuon 0 fix images: replace unstable Vector skin paths with Commons paths 88970 css text/css .translationtargetstar { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Watch-icon.svg/16px-Watch-icon.svg.png); position: absolute; margin-top: 3px; margin-left: -17px; cursor: pointer; width: 16px; height: 15px; } .translationtargetstar:hover { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/Watch-icon-hl.svg/16px-Watch-icon-hl.svg.png) } .translationtargetstarchecked { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Unwatch-icon.svg/16px-Unwatch-icon.svg.png); position: absolute; margin-top: 3px; margin-left: -17px; cursor: pointer; width: 16px; height: 15px; } .translationtargetstarchecked:hover { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Unwatch-icon-hl.svg/16px-Unwatch-icon-hl.svg.png); } ja0uic48113z7jqimkwe2ujkpgbxs24 88971 88970 2026-08-06T23:23:21Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TargetedTranslations.css]] 88970 css text/css .translationtargetstar { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Watch-icon.svg/16px-Watch-icon.svg.png); position: absolute; margin-top: 3px; margin-left: -17px; cursor: pointer; width: 16px; height: 15px; } .translationtargetstar:hover { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/Watch-icon-hl.svg/16px-Watch-icon-hl.svg.png) } .translationtargetstarchecked { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Unwatch-icon.svg/16px-Unwatch-icon.svg.png); position: absolute; margin-top: 3px; margin-left: -17px; cursor: pointer; width: 16px; height: 15px; } .translationtargetstarchecked:hover { background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Unwatch-icon-hl.svg/16px-Unwatch-icon-hl.svg.png); } ja0uic48113z7jqimkwe2ujkpgbxs24 MediaWiki:Gadget-searchFocus.js 8 17985 88972 2024-09-02T16:43:37Z en>Ioaxxere 0 this gadget should probably focus the main input bar instead 88972 javascript text/javascript if (mw.config.get("wgIsMainPage")) document.querySelector(".mw-searchInput").focus(); tevyt1geg33xkr9fk0chzx33hp7t9t5 88973 88972 2026-08-06T23:23:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-searchFocus.js]] 88972 javascript text/javascript if (mw.config.get("wgIsMainPage")) document.querySelector(".mw-searchInput").focus(); tevyt1geg33xkr9fk0chzx33hp7t9t5 MediaWiki:Gadget-TabbedLanguages.js 8 17986 88974 2025-09-17T01:06:23Z en>Ioaxxere 0 Polyfill deprecated function newNode 88974 javascript text/javascript // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** (function ( $ ) { // {{documentation}} // This is a (very) modified version of User:Atelaes/TabbedLanguages.js. // Tabbed languages with tabs on the side. // Tabs design by [[User:Jorm (WMF)]] /*jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /*global mw, jQuery, importScript, importScriptURI, $, ObjectStorage */ if (($.cookie('disable-tabbed-languages') !== null) || (location.search.indexOf("tabbedlanguages=off") !== -1)) return; if (!((mw.config.get('wgNamespaceNumber') === 0) || (mw.config.get('wgPageName') === "Wiktionary:Sandbox"))) return; var bodyContent = $(".mw-content-ltr .mw-parser-output")[0], // NOT #bodyContent languageLinks, ttr, languageButtons, caption, bodyContentFragment, complete = false, MO = window.MutationObserver || window.WebKitMutationObserver, observerStyleSheet; // Setting up the tabs has not yet been started. function makeTabsfromScratch() { // Set up the variables... window.tabbedLanguages = []; window.languageContainers = []; window.currentLanguageTab = 0; window.languageHeaderEditButtons = []; languageButtons = []; window.tabstable = newNode('table', {id: 'tabstable'}, newNode('tbody', ttr = newNode('tr', newNode('td', {'style': 'padding-top:0px;vertical-align:top;'}, newNode('table', {'style': 'margin-top: -2px;'}, languageLinks = newNode('tbody', {id: 'languageLinks'})))))); window.loadremovecatbuttons = false; bodyContentFragment = document.createDocumentFragment(); // If bodyContent is complete, do it all at once. // Otherwise, only start working, but don't attempt the whole thing. // Use catlinks+*, as gEBCN isn't always available. var catlinks = document.getElementById( "catlinks" ); if( bodyContent && catlinks && catlinks.nextSibling ) { allAtOnce(); } else { createObserver(); } } function allAtOnce() { var languageContainer, toc = document.getElementById( "toc" ); currentLanguageTab = 0; while ( bodyContent.firstChild ) { if ( bodyContent.firstChild.nodeName === "SECTION" ) { // Unwrap and remove top-level <section> tags in Parsoid content // https://www.mediawiki.org/wiki/Specs/HTML/2.8.0#Headings_and_Sections while ( bodyContent.firstChild.firstChild ) { bodyContentFragment.appendChild( bodyContent.firstChild.firstChild ); } bodyContent.removeChild( bodyContent.firstChild ); } else { bodyContentFragment.appendChild( bodyContent.firstChild ); } } try { for( var child = bodyContentFragment.firstChild; child && !isHeader( child ); ){ child = child.nextSibling; } for ( child = child && bodyContentFragment.insertBefore(tabstable, child).nextSibling; child && child.className !== 'printfooter' && child.className !== 'catlinks'; child = child.nextSibling ) { if ( isHeader( child ) ) { var langspan = getHeaderContent( child ), language = langspan && ( langspan.innerText || langspan.textContent ); if ( language ) { newTab( tabbedLanguages.push(language) - 1, language ); processEditButton( child.getElementsByClassName('mw-editsection')[ 0 ] ); // should probably be set from a return value of above. languageContainer = languageContainers[ languageContainers.length - 1 ]; bodyContentFragment.removeChild( child ); child = tabstable; } } else { if ( child.nodeName !== "HR" ) { languageContainer.insertBefore(child, languageContainer.lastChild); } else { bodyContentFragment.removeChild(child); } child = tabstable; } } if( tabbedLanguages.length ) { if( toc ) { toc.parentNode.removeChild( toc ); } sortCats(); bodyContent.appendChild( bodyContentFragment ); setUpHashChange()(); if( location.hash === '' ) { location.replace( "#" + tabbedLanguages[ currentLanguageTab ] ); } complete = true; } else { bodyContent.appendChild( bodyContentFragment ); } } catch( e ) { window.console && console.error( e ); bodyContent.appendChild( bodyContentFragment ); complete || setUpHashChange()(); } } // Set up a MutationObserver to detect when new elements are loaded. function createObserver() { // If .ready happens early (or MO and animstart aren't supported), go ahead. // TODO the following code was commented out 2023-11-09 as $.isReady was suddenly // always evaluating to true, meaning that TabbedLanguages would not load. //if( $.isReady ) { // return; // ??? How did we get $.isReady if bC or catlinks aren't loaded? //} else { $( document ).ready( function () { if( tabbedLanguages.length === 0 ) { removeObserver(); if( !bodyContent ) { bodyContent = $(".mw-content-ltr")[0]; } if( bodyContent ) { allAtOnce(); } } }); //} if( !document.getElementsByClassName ) { return; } if( !MO ) { var supportsAnimations = false; // Check if we can use animations as a fallback. If not, abort. // Basically yoinked from Modernizr. $.each( "animationName WebkitAnimationName MozAnimationName OAnimationName msAnimationName".split(" "), function(a, b){ // Do documentElements even always have .style? If not, this'll need fixing. if( document.documentElement.style[ b ] !== undefined ) { supportsAnimations = true; return false; } } ); if( supportsAnimations === false ) { return; } } var foundHeader = false, toc, recentChild, timer = false, // It's the setTimeout value, or false otherwise. recentHeader = -1, checkTab, tabFound = false, // If anyone on this project even considers making a random element // on a page have the class "visualClear"... visualClear = document.getElementsByClassName( "visualClear" ), languageContainer, observer; // TODO: Deal with the little jumping elements below the tabstable. // ...How? function elemFound() { if( timer === false ) { timer = setTimeout( function() { reactToObserver(); timer = false; }, 1); } } if( MO ) { observer = new MO( elemFound ); observer.observe( document, { childList: true, subtree: true } ); } else { // Fallback for browsers that don't support MO, but do support animations: // IE10, FF5-13, Chrome 17<, Safari 4-5.1, Opera 12-12.1 // Set up a stylesheet that uses animations/keyframes to allow // animationStart to see each time a new node loads onto the bodyContent. observerStyleSheet = document.getElementsByTagName( 'head' )[0].appendChild( document.createElement( "style" ) ); var oSSText = "@/@-moz-/@-webkit-/@-ms-/@-o-/".split("/") .join("keyframes nodeInserted{" + "from{outline-color:#fff;}" + "to{outline-color:#000;}" + "}\n") + ".mw-content-ltr>*,.mw-content-ltr+*,.visualClear{" + // TODO: Fix duplication here. "/-moz-/-webkit-/-ms-/-o-/".split("/").join("animation-duration:0.01s;") + "/-moz-/-webkit-/-ms-/-o-/".split("/").join("animation-name:nodeInserted;") + "}"; // Pretty much copied from mw.util. // Don't have time to wait until it would ordinarily load. if( observerStyleSheet.styleSheet ) { observerStyleSheet.styleSheet.cssText = oSSText; } else { observerStyleSheet.appendChild( document.createTextNode( oSSText ) ); } observerStyleSheet = observerStyleSheet.sheet || observerStyleSheet.styleSheet || observerStyleSheet; document.addEventListener('animationstart', elemFound, false); document.addEventListener('MSAnimationStart', elemFound, false); document.addEventListener('webkitAnimationStart', elemFound, false); } function reactToObserver() { if( complete ) { return; } // TODO: Surround main areas in try{} so that if it breaks, at least // the content gets dumped back into visibility. // First: What part are we up to? if( !foundHeader ) { // search for header or toc if( !recentChild ) { // Just starting, apparently. if( !bodyContent ) { bodyContent = $(".mw-content-ltr")[0]; if( !bodyContent ) { // bC hasn't loaded yet. Nothing to do here. return; } } // Check if we can do the whole thing in one go. if( visualClear.length ) { removeObserver(); allAtOnce(); return; } recentChild = bodyContent.firstChild; if( !recentChild ) { return; // Somehow got activated between bodyContent load // and bodyContent's content's load. } } for( ; !isHeader( recentChild ) && recentChild.nextSibling; ) { recentChild = recentChild.nextSibling; } if( isHeader( recentChild ) ) { // should simplify check. Maybe !recentChild.nextSibling? // We have our first header. foundHeader = true; checkTab = setUpHashChange(); // Default to the first tab. currentLanguageTab = 0; toc = document.getElementById('toc'); if ( toc ) { if ( toc.nextSibling ) { // And we have a usable ToC. Makes things much easier. // Analyze the ToC. We'll be using it to determine what // the tabs are going to be. $( ".toclevel-1 > a > .toctext" ).each( function() { var language = $( this ).text(); tabbedLanguages.push( language ); }); // Build all the tabs. $( tabbedLanguages ).each( newTab ); toc.parentNode.removeChild( toc ); // Afterwards, we'll check if the right section // is already available. } else { // Potential panic situation: Evil formatting places // ToC *after* the first header, so it's actually // *partly* loaded at this point, with no nextSibling. // (Alternatively, someone put it alone in a box.) CSS // builds it up as a huge tabbing block, but we can't // remove it here. Oy. // "Solution": // Temporarily hide the ToC until ready() fires, then // remove it. I'm not removing it right away, as I have // no idea what doom might occur if something like this // is removed while stuff is being loaded into it. toc.style.display = "none"; ( function ( toc ) { $( function() { if( toc.parentNode ) { toc.parentNode.removeChild( toc ); } }); })( toc ); toc = undefined; window.console && console.error( "TL notice: " + "Malformed entry. ToC either appears after " + "headers, or is placed in a box. Mind fixing " + "it or alerting me? Thanks. -- YR" ); } } languageContainer = languageContainers[ 0 ]; // Edit buttons. processEditButton( recentChild.getElementsByClassName( "mw-editsection" )[ 0 ] ); // Either way, start displaying the tabs right. bodyContent.insertBefore( tabstable, recentChild ); if( toc ) { tabFound = checkTab(); } } } if( foundHeader ) { // Note that there may or may not be a ToC available... // Should this be reworked so that the toc check is inside the loop? if( recentChild.nextSibling ) { // I hope I'm not going to regret leaving out a recentChild && condition here... for( var nextChild; recentChild.nextSibling; ) { nextChild = recentChild.nextSibling; if( isHeader( recentChild ) ) { var langspan = getHeaderContent( recentChild ); var editspan = recentChild.getElementsByClassName('mw-editsection')[ 0 ]; if( recentHeader >= 0 ) { languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); } recentHeader++; var language = ( language = langspan ).innerText || language.textContent; // Make sure it actually matches, when necessary. if( toc && language !== tabbedLanguages[ recentHeader ]) { // PANIC!!! // Okay, maybe don't panic. TL has encountered // a header that doesn't match the ToC's // description of the page. Possibilities // include an h1 on the page, a fake header // around somewhere, or some other malformed // kind of header. This really isn't supposed // to happen ever. // Response: Clear everything after this point, // and from there act as though the ToC never // existed. if( recentHeader > 0 ) { toggleLanguageTabs( tabbedLanguages[ 0 ] ); } else { currentLanguageTab = 0; } while( tabbedLanguages.length > recentHeader ) { tabbedLanguages.pop(); ttr.removeChild( languageContainers.pop() ); languageLinks.removeChild( languageButtons.pop().parentNode ); } toc = undefined; // Never. Existed. tabFound = false; window.console && console.error( "TL notice: " + "Malformed entry. ToC does not match " + "headers. Possibly a misplaced H1, fake " + "header, or header with incorrect " + "contents. Mind fixing it or " + "alerting me? Thanks. -- YR " ); } if( !toc ) { tabbedLanguages.push( language ); newTab( recentHeader, language ); } // Check to see if the target tab is found. // TODO: Need a better system of knowing when to check: // If it's found, stop checking. // Whether or not we have a ToC, checking can be necessary. // If we do have a ToC, but no hash, we don't check, right? // Put another way: // No hash? W/ ToC, don't check. W/o ToC, only check when new headers come in. // Hash? Depends. // W/ ToC: Technically, target could come in at any non-header element... ??? // W/o ToC: Could be whenever. Target header coming in is rather likely, in fact. Oy. // Either way: If the target, whether header or random element, is found, stop looking. // Does delaying the tab switch to a element target until full load matter? Not sure. // // Plan B: Regardless of ToC presence, only // check for potential target elems // at each new header, unless target is found. if( recentHeader > 0 && tabFound === false ) { tabFound = checkTab(); } languageContainer = languageContainers[ recentHeader ]; if( recentHeader > 0 ) { // I have too many of these checks... // Don't duplicate earlier pEB for first header. processEditButton( editspan ); } // All done. Clear. bodyContent.removeChild( recentChild ); } else { if( recentChild.nodeName === "HR" ) { // Kill unnecessary bars. bodyContent.removeChild( recentChild ); } else { // Regular content. Prepare for dumping into the // latest tab. bodyContentFragment.appendChild( recentChild ); } } recentChild = nextChild; } } /* // If we're all done, finish up. // How to tell? // Option one: Repeatedly check for nextSibling. // - Won't work. bodyContent doesn't always have a nS at the end. // - Currently in use only for dealing with the last elem. (Uses O2 as fallback.) // Option two: Set up getElemsByClassName, and poll for length. // - presumably visualClear. This would probably be pretty heavy. // - Currently in use. // Option three: Use $.ready. // - Potentially introduces substantial delay... // Option four: In the listener, check for classnames each time. // - Every time there's a new node? Lots of processing. // Option five: ... */ if( bodyContent.nextSibling && bodyContent.lastChild === recentChild ) { // are we done? ... // bodyContent.nextSibling doesn't always exist, but if it // does, get a head start on the stuff that can be done already. bodyContentFragment.appendChild( bodyContent.lastChild ); /* // Problem: recentChild is now inside the languageContainer, // and it's possible that reactToObserver will be called again // before the post-visualClear stuff runs. // Option one: recentChild = tabstable; // - Nope. That would mean bodyContent.lastChild = recentChild again // Option two: recentChild = false; // - Nope. The check at the top would cause us to start over again. // Blargh. This is an awful solution that probably violates every... */ recentChild = 1; // "1" is hereby the indicator that we're not doing anything with // this particular variable, okay? // I'll try to make this nicer later. } // Dump collected elems into most recent languageContainer. if( bodyContentFragment.firstChild ) { // Exact duplicate of above code. TODO: Fix. languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); } if( visualClear.length ) { complete = true; if( bodyContent.lastChild === recentChild ) { // bC.nS didn't exist. Move the last one left now. languageContainer.insertBefore( bodyContent.lastChild, languageContainer.lastChild ); } removeObserver(); sortCats(); if( tabFound !== true ) { checkTab(); if( location.hash === '' ) { location.replace( "#" + tabbedLanguages[currentLanguageTab] ); } } } } } function removeObserver() { if( observer ) { observer.disconnect(); } else if( observerStyleSheet ) { document.removeEventListener('animationstart', elemFound, false); document.removeEventListener('MSAnimationStart', elemFound, false); document.removeEventListener('webkitAnimationStart', elemFound, false); observerStyleSheet.disabled = true; } if( timer !== false ) { clearTimeout( timer ); } } } function isHeader( elem ) { // Handle two versions of the markup: https://www.mediawiki.org/wiki/Heading_HTML_changes return elem && elem.nodeType === Node.ELEMENT_NODE && ( elem.nodeName === "H2" && elem.getElementsByClassName( "mw-headline" ).length !== 0 || elem.classList.contains( "mw-heading2" ) && elem.getElementsByTagName( "H2" ).length !== 0 ); } function getHeaderContent( elem ) { // Handle two versions of the markup: https://www.mediawiki.org/wiki/Heading_HTML_changes return elem.nodeName === "H2" ? elem.getElementsByClassName( "mw-headline" )[0] : elem.getElementsByTagName( "H2" )[0]; } function newTab( index, language ) { var active = index === currentLanguageTab; var languageContainer = ttr.appendChild( newNode('td', { 'class': 'languageContainer', 'id': language + 'container' }, active ? undefined : { 'style' : 'display:none;' } )); languageContainers.push( languageContainer ); newCategoryBox( languageContainer, language ); // lB contains .(un)?selectedTab nodes languageButtons.push( languageLinks.appendChild( newNode('tr', newNode('td', { 'class': ( active ? '' : 'un' ) + 'selectedTab' }, newNode('a', language, { // Note: ' + language' makes this inconsistent with the ordinary links // themselves, which have the language name encoded. Issue? // Keep in mind that the parser itself actually corrects for this, // changing #!Xóõ links to the proper #.C7.83X.C3.B3.C3.B5 links. // Probably nothing to worry about. 'href': location.pathname + location.search + '#' + language.replace(/ /g, '_') }), ' '))).firstChild ); } function newCategoryBox( container, name ) { // Put a container in each for categories. return container.appendChild( newNode('div', name + ' categories: ', newNode('ul'), { 'class': 'catlinks', 'id': 'catlinks' })); } function processEditButton( button ) { if( button ) { // Yes, theoretically if you have some fake H2s the edit buttons will // be misplaced. Yet another TODO... var len = languageHeaderEditButtons.push( button ); if( len === 1 ) { caption = document.createElement('caption'); tabstable.insertBefore( caption, tabstable.firstChild ); } button.className += " editlangsection"; // use a argument or variable ( from .push? ) instead of .length? if( len - 1 === currentLanguageTab ) { caption.firstChild && caption.removeChild( caption.firstChild ); caption.appendChild( button ); } } } // Sets up the hash toggle system. // Returns the checkTab() function, which returns true if // we found whatever it was. function setUpHashChange() { // Important Note: The decodeURI mess is a real mess. // #.C7.83X.C3.B3.C3.B5 should go to tab "!Xóõ", with // the id "!Xóõcontainer" (no encoding). Urgh. // Also, "#Old_English" needs to go to decoded "Old English". // Remember to .substr( 1 ) before passing here. function decodeHash( hash ) { return decodeURI( hash .replace(/\.(?=[0-9A-F]{2})/g, '%') .replace(/_/g, ' ') ); } // Called by onhashchange. function hashToggleLT() { var destination = decodeHash( location.hash.substr(1) ); toggleLanguageTabs( destination ); tabbedLanguages[currentLanguageTab] !== destination && resetHash(); } // For updating page positioning. // Doesn't activate hashchange, at least in Chrome. Not sure about others. function resetHash() { location.replace( location.hash ); } // Need to decide if language arg is encoded or decoded. // Will work with either for the moment. Decoded works earlier. // Currently passed as decoded by every function but itself. // The hashes are encoded, but hashToggleLT decodes them. // Toggles to a different language tab. window.toggleLanguageTabs = function (language) { // Find the destination language. var destinationLanguageTab = $.inArray( language, tabbedLanguages ); if( destinationLanguageTab === -1 ) { var decoded = decodeHash( language ); if( decoded !== language ) { destinationLanguageTab = $.inArray( decoded, tabbedLanguages ); } } // Style the right toggle button, hide the old language section and show the new one. // var languageButtons = $("#languageLinks .selectedTab, #languageLinks .unselectedTab"); if (destinationLanguageTab !== -1 ) { if( destinationLanguageTab !== currentLanguageTab ) { languageButtons[currentLanguageTab].className = 'unselectedTab'; languageContainers[currentLanguageTab].style.display = 'none'; currentLanguageTab = destinationLanguageTab; languageButtons[destinationLanguageTab].className = 'selectedTab'; languageContainers[destinationLanguageTab].style.display = ''; if (caption) { // extra checks shouldn't be necessary... caption.firstChild && caption.removeChild(caption.firstChild); languageHeaderEditButtons[currentLanguageTab] && caption.appendChild(languageHeaderEditButtons[currentLanguageTab]); } } } else { // Does the hash match the id of a node in a tab? language = encodeURI( language.replace(/\ /g, '_') ); // Yes, I just possibly undid the decoding from hashToggleLT. // Worse, this might double-encode, breaking things. // Or maybe not? I think everything might be decoded before being // sent here? // I'll deal with it later. // Find the node, and go up the node tree until // you hit .languageContainer, or nothing. language = document.getElementById( language ); for( ; language && ( language = language.parentNode ) && language.className !== 'languageContainer'; ) ; // language = language && language.parentNode.parentNode; if ( language ) { // If someone maliciously makes a languageContainer with a // non-compliant ID, boom. toggleLanguageTabs( language.id.split('container')[0] ); } // Possible doom bug: Endless loop? } }; // This function gets returned as checkTab(), btw. // For during or immediately after load: Check if we have a // good "starting" tab. Return true if we have a definitive find. function checkTab() { // If there's a location hash, the window may have scrolled down before // we got a chance to reorganize everything. // If the destination was a subsection or sense id, switch to the right // tab, and rescroll. // If it was simply a language, switch to the appropriate tab, and // scroll back up. // If there's no hash at all, work off the TargetedTranslations prefs. try { var hash = ''; var destination = 'English'; if ( location.hash !== '' ) { hash = ( location.hash ).substr( 1 ); // does hash.substr always exist? destination = decodeHash( hash ); } // 'k, this is still awful. if ( $.inArray( destination, tabbedLanguages ) !== -1 ) { toggleLanguageTabs( destination ); window.scrollY && window.scroll(0, 0); return true; } else if ( hash !== '' && document.getElementById( hash ) ) { // This was going // to receive an area to search from an argument, but it turns // out that elem.getElementById doesn't actually exist. Meh. toggleLanguageTabs( destination ); resetHash(); // Scroll to the element. (Necessary since we // this isn't running through hashToggleLT, which normally does // it in these situations.) return true; } // No hash. Work from TargetedTranslations. if ('localStorage' in window) { if (tabbedLanguages[0] !== 'Translingual' && tabbedLanguages[0] !== 'English' && localStorage.TargetedTranslations) { for ( var tt_ = localStorage.TargetedTranslations.split("|"), tt = tt_[0].split(";").concat( $.grep( tt_[1].replace(/[^;\/]+\//g, '').split(";"), function (z) { return z && z !== "Latin" && z !== "Hebrew" && z !== "Arabic"; } ) ).concat( tt_[1].replace(/\/[^;]+/g, '').split(";") ), i = 0; i < tt.length; i++ ) { if ($.inArray(tt[i], tabbedLanguages) !== -1) { toggleLanguageTabs(tabbedLanguages[$.inArray(tt[i], tabbedLanguages)]); break; } } } } return false; } catch ( e ) { // This probably isn't all that unlikely to happen. Too complicated. :( window.console && console.error( "TL error: checkTab broke.", e ); } } if ("onhashchange" in window && (document.documentMode === undefined || document.documentMode > 7)) { window.onhashchange = hashToggleLT; } else { $( bodyContent ).on( 'click', 'a[href^="' + location.pathname + location.search + '#"], a[href^="#"]', function () { setTimeout( hashToggleLT, 10 ); } ); } return checkTab; } function sortCats() { var catDiv = document.getElementById('mw-normal-catlinks'), currentCatDiv; if (catDiv) { var cats = catDiv.getElementsByTagName('li'), catname, langcurrent = 0, catskip = 1; do { while (cats.length > 0) { catname = cats[ 0 ].getElementsByTagName('a')[0].innerHTML; if (catname.indexOf(tabbedLanguages[langcurrent + catskip]) === 0 && !/letter\snames$|script\scharacters$|mythology$/.test(catname) ) { langcurrent += catskip; catskip = 1; } currentCatDiv = languageContainers[langcurrent].lastChild; currentCatDiv.lastChild.appendChild(cats[0]); } if (langcurrent + 1 < languageContainers.length - catskip) { // Didn't make it to the end, which means there's a section // without any categories. Dump what's left back and try again. while (currentCatDiv.lastChild.firstChild) { catDiv.lastChild.appendChild(currentCatDiv.lastChild.firstChild); } catskip++; } else { break; } } while (true); } if( currentCatDiv ) { // place patrol link at the bottom of the page var pl = currentCatDiv.previousSibling; // languageContainer.lastChild.previousSibling; // Got it, the patrollink is sometimes the lagging last elem. if( pl && pl.className === "patrollink" ) { tabstable.parentNode.appendChild(pl); } } /* // category editing buttons if (mw.config.get('wgAction') === "view" && !/&printable=yes|&diff=|&oldid=/.test(location.search)) { for (z = 0; z < languageContainers.length; z++) { // TODO: import // addTabbedLanguageNewCatButton(z); } if ( window.loadremovecatbuttons === true ) { $.get( mw.config.get( 'wgScript' ), { 'title' : mw.config.get('wgPageName'), 'action' : 'raw' }, // Note that this isn't actually defined. I'm considering not // actually importing the function, and just dumping this section. addRemoveCatButtons ); } } */ // Remove old cat box, allow display of hidden cats box. if (catDiv && !(catDiv.nextSibling && catDiv.nextSibling.className === "mw-hidden-catlinks mw-hidden-cats-user-shown")) { catDiv.parentNode.style.display = 'none'; } else { if (catDiv) { catDiv.style.display = 'none'; } } } function testStuff() { var delay = 5000, f = document.createDocumentFragment(); var x = [ function () { // $("#toc").remove(); var x = document.getElementById( "mw-content-text" ); while( x.nextSibling ) { f.appendChild( x.nextSibling ); } }, function () { var y = $( ".mw-content-ltr" )[ 0 ]; var q = document.createDocumentFragment(); while( y.firstChild ) { q.appendChild( y.firstChild ); } function u( i, e ) { setTimeout( function () { y.appendChild( q.firstChild ); }, i / e * delay ); } for( var i = 0, e = q.childNodes.length; i < e; i++ ) { u( i, e ); // encapsulate } makeTabsfromScratch(); }, function () { function u( i, e ) { setTimeout( function () { $(".mw-content-ltr").after( f.firstChild ); }, i / e * delay / 5 ); } for( var i = 0, e = f.childNodes.length; i < e; i++ ) { u( i, e ); // encapsulate } console.log(9); } ]; x[0](); for( var i = 1; i < x.length; i++ ) { setTimeout( x[ i ], (i-1) * delay + 50 ); } } //testStuff(); makeTabsfromScratch(); // This is officially deprecated as of MW1.22. Should be replaced by mw.hook, // but the docs don't say what event, so... $(mw).on('LivePreviewDone', function () { bodyContent = $(".mw-content-ltr")[0]; // reset makeTabsfromScratch(); }); })( window.jQuery ); bo3vk8t8xgwm7kymt0gkaic1zrtyvzq 88975 88974 2026-08-06T23:23:55Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TabbedLanguages.js]] 88974 javascript text/javascript // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** (function ( $ ) { // {{documentation}} // This is a (very) modified version of User:Atelaes/TabbedLanguages.js. // Tabbed languages with tabs on the side. // Tabs design by [[User:Jorm (WMF)]] /*jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /*global mw, jQuery, importScript, importScriptURI, $, ObjectStorage */ if (($.cookie('disable-tabbed-languages') !== null) || (location.search.indexOf("tabbedlanguages=off") !== -1)) return; if (!((mw.config.get('wgNamespaceNumber') === 0) || (mw.config.get('wgPageName') === "Wiktionary:Sandbox"))) return; var bodyContent = $(".mw-content-ltr .mw-parser-output")[0], // NOT #bodyContent languageLinks, ttr, languageButtons, caption, bodyContentFragment, complete = false, MO = window.MutationObserver || window.WebKitMutationObserver, observerStyleSheet; // Setting up the tabs has not yet been started. function makeTabsfromScratch() { // Set up the variables... window.tabbedLanguages = []; window.languageContainers = []; window.currentLanguageTab = 0; window.languageHeaderEditButtons = []; languageButtons = []; window.tabstable = newNode('table', {id: 'tabstable'}, newNode('tbody', ttr = newNode('tr', newNode('td', {'style': 'padding-top:0px;vertical-align:top;'}, newNode('table', {'style': 'margin-top: -2px;'}, languageLinks = newNode('tbody', {id: 'languageLinks'})))))); window.loadremovecatbuttons = false; bodyContentFragment = document.createDocumentFragment(); // If bodyContent is complete, do it all at once. // Otherwise, only start working, but don't attempt the whole thing. // Use catlinks+*, as gEBCN isn't always available. var catlinks = document.getElementById( "catlinks" ); if( bodyContent && catlinks && catlinks.nextSibling ) { allAtOnce(); } else { createObserver(); } } function allAtOnce() { var languageContainer, toc = document.getElementById( "toc" ); currentLanguageTab = 0; while ( bodyContent.firstChild ) { if ( bodyContent.firstChild.nodeName === "SECTION" ) { // Unwrap and remove top-level <section> tags in Parsoid content // https://www.mediawiki.org/wiki/Specs/HTML/2.8.0#Headings_and_Sections while ( bodyContent.firstChild.firstChild ) { bodyContentFragment.appendChild( bodyContent.firstChild.firstChild ); } bodyContent.removeChild( bodyContent.firstChild ); } else { bodyContentFragment.appendChild( bodyContent.firstChild ); } } try { for( var child = bodyContentFragment.firstChild; child && !isHeader( child ); ){ child = child.nextSibling; } for ( child = child && bodyContentFragment.insertBefore(tabstable, child).nextSibling; child && child.className !== 'printfooter' && child.className !== 'catlinks'; child = child.nextSibling ) { if ( isHeader( child ) ) { var langspan = getHeaderContent( child ), language = langspan && ( langspan.innerText || langspan.textContent ); if ( language ) { newTab( tabbedLanguages.push(language) - 1, language ); processEditButton( child.getElementsByClassName('mw-editsection')[ 0 ] ); // should probably be set from a return value of above. languageContainer = languageContainers[ languageContainers.length - 1 ]; bodyContentFragment.removeChild( child ); child = tabstable; } } else { if ( child.nodeName !== "HR" ) { languageContainer.insertBefore(child, languageContainer.lastChild); } else { bodyContentFragment.removeChild(child); } child = tabstable; } } if( tabbedLanguages.length ) { if( toc ) { toc.parentNode.removeChild( toc ); } sortCats(); bodyContent.appendChild( bodyContentFragment ); setUpHashChange()(); if( location.hash === '' ) { location.replace( "#" + tabbedLanguages[ currentLanguageTab ] ); } complete = true; } else { bodyContent.appendChild( bodyContentFragment ); } } catch( e ) { window.console && console.error( e ); bodyContent.appendChild( bodyContentFragment ); complete || setUpHashChange()(); } } // Set up a MutationObserver to detect when new elements are loaded. function createObserver() { // If .ready happens early (or MO and animstart aren't supported), go ahead. // TODO the following code was commented out 2023-11-09 as $.isReady was suddenly // always evaluating to true, meaning that TabbedLanguages would not load. //if( $.isReady ) { // return; // ??? How did we get $.isReady if bC or catlinks aren't loaded? //} else { $( document ).ready( function () { if( tabbedLanguages.length === 0 ) { removeObserver(); if( !bodyContent ) { bodyContent = $(".mw-content-ltr")[0]; } if( bodyContent ) { allAtOnce(); } } }); //} if( !document.getElementsByClassName ) { return; } if( !MO ) { var supportsAnimations = false; // Check if we can use animations as a fallback. If not, abort. // Basically yoinked from Modernizr. $.each( "animationName WebkitAnimationName MozAnimationName OAnimationName msAnimationName".split(" "), function(a, b){ // Do documentElements even always have .style? If not, this'll need fixing. if( document.documentElement.style[ b ] !== undefined ) { supportsAnimations = true; return false; } } ); if( supportsAnimations === false ) { return; } } var foundHeader = false, toc, recentChild, timer = false, // It's the setTimeout value, or false otherwise. recentHeader = -1, checkTab, tabFound = false, // If anyone on this project even considers making a random element // on a page have the class "visualClear"... visualClear = document.getElementsByClassName( "visualClear" ), languageContainer, observer; // TODO: Deal with the little jumping elements below the tabstable. // ...How? function elemFound() { if( timer === false ) { timer = setTimeout( function() { reactToObserver(); timer = false; }, 1); } } if( MO ) { observer = new MO( elemFound ); observer.observe( document, { childList: true, subtree: true } ); } else { // Fallback for browsers that don't support MO, but do support animations: // IE10, FF5-13, Chrome 17<, Safari 4-5.1, Opera 12-12.1 // Set up a stylesheet that uses animations/keyframes to allow // animationStart to see each time a new node loads onto the bodyContent. observerStyleSheet = document.getElementsByTagName( 'head' )[0].appendChild( document.createElement( "style" ) ); var oSSText = "@/@-moz-/@-webkit-/@-ms-/@-o-/".split("/") .join("keyframes nodeInserted{" + "from{outline-color:#fff;}" + "to{outline-color:#000;}" + "}\n") + ".mw-content-ltr>*,.mw-content-ltr+*,.visualClear{" + // TODO: Fix duplication here. "/-moz-/-webkit-/-ms-/-o-/".split("/").join("animation-duration:0.01s;") + "/-moz-/-webkit-/-ms-/-o-/".split("/").join("animation-name:nodeInserted;") + "}"; // Pretty much copied from mw.util. // Don't have time to wait until it would ordinarily load. if( observerStyleSheet.styleSheet ) { observerStyleSheet.styleSheet.cssText = oSSText; } else { observerStyleSheet.appendChild( document.createTextNode( oSSText ) ); } observerStyleSheet = observerStyleSheet.sheet || observerStyleSheet.styleSheet || observerStyleSheet; document.addEventListener('animationstart', elemFound, false); document.addEventListener('MSAnimationStart', elemFound, false); document.addEventListener('webkitAnimationStart', elemFound, false); } function reactToObserver() { if( complete ) { return; } // TODO: Surround main areas in try{} so that if it breaks, at least // the content gets dumped back into visibility. // First: What part are we up to? if( !foundHeader ) { // search for header or toc if( !recentChild ) { // Just starting, apparently. if( !bodyContent ) { bodyContent = $(".mw-content-ltr")[0]; if( !bodyContent ) { // bC hasn't loaded yet. Nothing to do here. return; } } // Check if we can do the whole thing in one go. if( visualClear.length ) { removeObserver(); allAtOnce(); return; } recentChild = bodyContent.firstChild; if( !recentChild ) { return; // Somehow got activated between bodyContent load // and bodyContent's content's load. } } for( ; !isHeader( recentChild ) && recentChild.nextSibling; ) { recentChild = recentChild.nextSibling; } if( isHeader( recentChild ) ) { // should simplify check. Maybe !recentChild.nextSibling? // We have our first header. foundHeader = true; checkTab = setUpHashChange(); // Default to the first tab. currentLanguageTab = 0; toc = document.getElementById('toc'); if ( toc ) { if ( toc.nextSibling ) { // And we have a usable ToC. Makes things much easier. // Analyze the ToC. We'll be using it to determine what // the tabs are going to be. $( ".toclevel-1 > a > .toctext" ).each( function() { var language = $( this ).text(); tabbedLanguages.push( language ); }); // Build all the tabs. $( tabbedLanguages ).each( newTab ); toc.parentNode.removeChild( toc ); // Afterwards, we'll check if the right section // is already available. } else { // Potential panic situation: Evil formatting places // ToC *after* the first header, so it's actually // *partly* loaded at this point, with no nextSibling. // (Alternatively, someone put it alone in a box.) CSS // builds it up as a huge tabbing block, but we can't // remove it here. Oy. // "Solution": // Temporarily hide the ToC until ready() fires, then // remove it. I'm not removing it right away, as I have // no idea what doom might occur if something like this // is removed while stuff is being loaded into it. toc.style.display = "none"; ( function ( toc ) { $( function() { if( toc.parentNode ) { toc.parentNode.removeChild( toc ); } }); })( toc ); toc = undefined; window.console && console.error( "TL notice: " + "Malformed entry. ToC either appears after " + "headers, or is placed in a box. Mind fixing " + "it or alerting me? Thanks. -- YR" ); } } languageContainer = languageContainers[ 0 ]; // Edit buttons. processEditButton( recentChild.getElementsByClassName( "mw-editsection" )[ 0 ] ); // Either way, start displaying the tabs right. bodyContent.insertBefore( tabstable, recentChild ); if( toc ) { tabFound = checkTab(); } } } if( foundHeader ) { // Note that there may or may not be a ToC available... // Should this be reworked so that the toc check is inside the loop? if( recentChild.nextSibling ) { // I hope I'm not going to regret leaving out a recentChild && condition here... for( var nextChild; recentChild.nextSibling; ) { nextChild = recentChild.nextSibling; if( isHeader( recentChild ) ) { var langspan = getHeaderContent( recentChild ); var editspan = recentChild.getElementsByClassName('mw-editsection')[ 0 ]; if( recentHeader >= 0 ) { languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); } recentHeader++; var language = ( language = langspan ).innerText || language.textContent; // Make sure it actually matches, when necessary. if( toc && language !== tabbedLanguages[ recentHeader ]) { // PANIC!!! // Okay, maybe don't panic. TL has encountered // a header that doesn't match the ToC's // description of the page. Possibilities // include an h1 on the page, a fake header // around somewhere, or some other malformed // kind of header. This really isn't supposed // to happen ever. // Response: Clear everything after this point, // and from there act as though the ToC never // existed. if( recentHeader > 0 ) { toggleLanguageTabs( tabbedLanguages[ 0 ] ); } else { currentLanguageTab = 0; } while( tabbedLanguages.length > recentHeader ) { tabbedLanguages.pop(); ttr.removeChild( languageContainers.pop() ); languageLinks.removeChild( languageButtons.pop().parentNode ); } toc = undefined; // Never. Existed. tabFound = false; window.console && console.error( "TL notice: " + "Malformed entry. ToC does not match " + "headers. Possibly a misplaced H1, fake " + "header, or header with incorrect " + "contents. Mind fixing it or " + "alerting me? Thanks. -- YR " ); } if( !toc ) { tabbedLanguages.push( language ); newTab( recentHeader, language ); } // Check to see if the target tab is found. // TODO: Need a better system of knowing when to check: // If it's found, stop checking. // Whether or not we have a ToC, checking can be necessary. // If we do have a ToC, but no hash, we don't check, right? // Put another way: // No hash? W/ ToC, don't check. W/o ToC, only check when new headers come in. // Hash? Depends. // W/ ToC: Technically, target could come in at any non-header element... ??? // W/o ToC: Could be whenever. Target header coming in is rather likely, in fact. Oy. // Either way: If the target, whether header or random element, is found, stop looking. // Does delaying the tab switch to a element target until full load matter? Not sure. // // Plan B: Regardless of ToC presence, only // check for potential target elems // at each new header, unless target is found. if( recentHeader > 0 && tabFound === false ) { tabFound = checkTab(); } languageContainer = languageContainers[ recentHeader ]; if( recentHeader > 0 ) { // I have too many of these checks... // Don't duplicate earlier pEB for first header. processEditButton( editspan ); } // All done. Clear. bodyContent.removeChild( recentChild ); } else { if( recentChild.nodeName === "HR" ) { // Kill unnecessary bars. bodyContent.removeChild( recentChild ); } else { // Regular content. Prepare for dumping into the // latest tab. bodyContentFragment.appendChild( recentChild ); } } recentChild = nextChild; } } /* // If we're all done, finish up. // How to tell? // Option one: Repeatedly check for nextSibling. // - Won't work. bodyContent doesn't always have a nS at the end. // - Currently in use only for dealing with the last elem. (Uses O2 as fallback.) // Option two: Set up getElemsByClassName, and poll for length. // - presumably visualClear. This would probably be pretty heavy. // - Currently in use. // Option three: Use $.ready. // - Potentially introduces substantial delay... // Option four: In the listener, check for classnames each time. // - Every time there's a new node? Lots of processing. // Option five: ... */ if( bodyContent.nextSibling && bodyContent.lastChild === recentChild ) { // are we done? ... // bodyContent.nextSibling doesn't always exist, but if it // does, get a head start on the stuff that can be done already. bodyContentFragment.appendChild( bodyContent.lastChild ); /* // Problem: recentChild is now inside the languageContainer, // and it's possible that reactToObserver will be called again // before the post-visualClear stuff runs. // Option one: recentChild = tabstable; // - Nope. That would mean bodyContent.lastChild = recentChild again // Option two: recentChild = false; // - Nope. The check at the top would cause us to start over again. // Blargh. This is an awful solution that probably violates every... */ recentChild = 1; // "1" is hereby the indicator that we're not doing anything with // this particular variable, okay? // I'll try to make this nicer later. } // Dump collected elems into most recent languageContainer. if( bodyContentFragment.firstChild ) { // Exact duplicate of above code. TODO: Fix. languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); } if( visualClear.length ) { complete = true; if( bodyContent.lastChild === recentChild ) { // bC.nS didn't exist. Move the last one left now. languageContainer.insertBefore( bodyContent.lastChild, languageContainer.lastChild ); } removeObserver(); sortCats(); if( tabFound !== true ) { checkTab(); if( location.hash === '' ) { location.replace( "#" + tabbedLanguages[currentLanguageTab] ); } } } } } function removeObserver() { if( observer ) { observer.disconnect(); } else if( observerStyleSheet ) { document.removeEventListener('animationstart', elemFound, false); document.removeEventListener('MSAnimationStart', elemFound, false); document.removeEventListener('webkitAnimationStart', elemFound, false); observerStyleSheet.disabled = true; } if( timer !== false ) { clearTimeout( timer ); } } } function isHeader( elem ) { // Handle two versions of the markup: https://www.mediawiki.org/wiki/Heading_HTML_changes return elem && elem.nodeType === Node.ELEMENT_NODE && ( elem.nodeName === "H2" && elem.getElementsByClassName( "mw-headline" ).length !== 0 || elem.classList.contains( "mw-heading2" ) && elem.getElementsByTagName( "H2" ).length !== 0 ); } function getHeaderContent( elem ) { // Handle two versions of the markup: https://www.mediawiki.org/wiki/Heading_HTML_changes return elem.nodeName === "H2" ? elem.getElementsByClassName( "mw-headline" )[0] : elem.getElementsByTagName( "H2" )[0]; } function newTab( index, language ) { var active = index === currentLanguageTab; var languageContainer = ttr.appendChild( newNode('td', { 'class': 'languageContainer', 'id': language + 'container' }, active ? undefined : { 'style' : 'display:none;' } )); languageContainers.push( languageContainer ); newCategoryBox( languageContainer, language ); // lB contains .(un)?selectedTab nodes languageButtons.push( languageLinks.appendChild( newNode('tr', newNode('td', { 'class': ( active ? '' : 'un' ) + 'selectedTab' }, newNode('a', language, { // Note: ' + language' makes this inconsistent with the ordinary links // themselves, which have the language name encoded. Issue? // Keep in mind that the parser itself actually corrects for this, // changing #!Xóõ links to the proper #.C7.83X.C3.B3.C3.B5 links. // Probably nothing to worry about. 'href': location.pathname + location.search + '#' + language.replace(/ /g, '_') }), ' '))).firstChild ); } function newCategoryBox( container, name ) { // Put a container in each for categories. return container.appendChild( newNode('div', name + ' categories: ', newNode('ul'), { 'class': 'catlinks', 'id': 'catlinks' })); } function processEditButton( button ) { if( button ) { // Yes, theoretically if you have some fake H2s the edit buttons will // be misplaced. Yet another TODO... var len = languageHeaderEditButtons.push( button ); if( len === 1 ) { caption = document.createElement('caption'); tabstable.insertBefore( caption, tabstable.firstChild ); } button.className += " editlangsection"; // use a argument or variable ( from .push? ) instead of .length? if( len - 1 === currentLanguageTab ) { caption.firstChild && caption.removeChild( caption.firstChild ); caption.appendChild( button ); } } } // Sets up the hash toggle system. // Returns the checkTab() function, which returns true if // we found whatever it was. function setUpHashChange() { // Important Note: The decodeURI mess is a real mess. // #.C7.83X.C3.B3.C3.B5 should go to tab "!Xóõ", with // the id "!Xóõcontainer" (no encoding). Urgh. // Also, "#Old_English" needs to go to decoded "Old English". // Remember to .substr( 1 ) before passing here. function decodeHash( hash ) { return decodeURI( hash .replace(/\.(?=[0-9A-F]{2})/g, '%') .replace(/_/g, ' ') ); } // Called by onhashchange. function hashToggleLT() { var destination = decodeHash( location.hash.substr(1) ); toggleLanguageTabs( destination ); tabbedLanguages[currentLanguageTab] !== destination && resetHash(); } // For updating page positioning. // Doesn't activate hashchange, at least in Chrome. Not sure about others. function resetHash() { location.replace( location.hash ); } // Need to decide if language arg is encoded or decoded. // Will work with either for the moment. Decoded works earlier. // Currently passed as decoded by every function but itself. // The hashes are encoded, but hashToggleLT decodes them. // Toggles to a different language tab. window.toggleLanguageTabs = function (language) { // Find the destination language. var destinationLanguageTab = $.inArray( language, tabbedLanguages ); if( destinationLanguageTab === -1 ) { var decoded = decodeHash( language ); if( decoded !== language ) { destinationLanguageTab = $.inArray( decoded, tabbedLanguages ); } } // Style the right toggle button, hide the old language section and show the new one. // var languageButtons = $("#languageLinks .selectedTab, #languageLinks .unselectedTab"); if (destinationLanguageTab !== -1 ) { if( destinationLanguageTab !== currentLanguageTab ) { languageButtons[currentLanguageTab].className = 'unselectedTab'; languageContainers[currentLanguageTab].style.display = 'none'; currentLanguageTab = destinationLanguageTab; languageButtons[destinationLanguageTab].className = 'selectedTab'; languageContainers[destinationLanguageTab].style.display = ''; if (caption) { // extra checks shouldn't be necessary... caption.firstChild && caption.removeChild(caption.firstChild); languageHeaderEditButtons[currentLanguageTab] && caption.appendChild(languageHeaderEditButtons[currentLanguageTab]); } } } else { // Does the hash match the id of a node in a tab? language = encodeURI( language.replace(/\ /g, '_') ); // Yes, I just possibly undid the decoding from hashToggleLT. // Worse, this might double-encode, breaking things. // Or maybe not? I think everything might be decoded before being // sent here? // I'll deal with it later. // Find the node, and go up the node tree until // you hit .languageContainer, or nothing. language = document.getElementById( language ); for( ; language && ( language = language.parentNode ) && language.className !== 'languageContainer'; ) ; // language = language && language.parentNode.parentNode; if ( language ) { // If someone maliciously makes a languageContainer with a // non-compliant ID, boom. toggleLanguageTabs( language.id.split('container')[0] ); } // Possible doom bug: Endless loop? } }; // This function gets returned as checkTab(), btw. // For during or immediately after load: Check if we have a // good "starting" tab. Return true if we have a definitive find. function checkTab() { // If there's a location hash, the window may have scrolled down before // we got a chance to reorganize everything. // If the destination was a subsection or sense id, switch to the right // tab, and rescroll. // If it was simply a language, switch to the appropriate tab, and // scroll back up. // If there's no hash at all, work off the TargetedTranslations prefs. try { var hash = ''; var destination = 'English'; if ( location.hash !== '' ) { hash = ( location.hash ).substr( 1 ); // does hash.substr always exist? destination = decodeHash( hash ); } // 'k, this is still awful. if ( $.inArray( destination, tabbedLanguages ) !== -1 ) { toggleLanguageTabs( destination ); window.scrollY && window.scroll(0, 0); return true; } else if ( hash !== '' && document.getElementById( hash ) ) { // This was going // to receive an area to search from an argument, but it turns // out that elem.getElementById doesn't actually exist. Meh. toggleLanguageTabs( destination ); resetHash(); // Scroll to the element. (Necessary since we // this isn't running through hashToggleLT, which normally does // it in these situations.) return true; } // No hash. Work from TargetedTranslations. if ('localStorage' in window) { if (tabbedLanguages[0] !== 'Translingual' && tabbedLanguages[0] !== 'English' && localStorage.TargetedTranslations) { for ( var tt_ = localStorage.TargetedTranslations.split("|"), tt = tt_[0].split(";").concat( $.grep( tt_[1].replace(/[^;\/]+\//g, '').split(";"), function (z) { return z && z !== "Latin" && z !== "Hebrew" && z !== "Arabic"; } ) ).concat( tt_[1].replace(/\/[^;]+/g, '').split(";") ), i = 0; i < tt.length; i++ ) { if ($.inArray(tt[i], tabbedLanguages) !== -1) { toggleLanguageTabs(tabbedLanguages[$.inArray(tt[i], tabbedLanguages)]); break; } } } } return false; } catch ( e ) { // This probably isn't all that unlikely to happen. Too complicated. :( window.console && console.error( "TL error: checkTab broke.", e ); } } if ("onhashchange" in window && (document.documentMode === undefined || document.documentMode > 7)) { window.onhashchange = hashToggleLT; } else { $( bodyContent ).on( 'click', 'a[href^="' + location.pathname + location.search + '#"], a[href^="#"]', function () { setTimeout( hashToggleLT, 10 ); } ); } return checkTab; } function sortCats() { var catDiv = document.getElementById('mw-normal-catlinks'), currentCatDiv; if (catDiv) { var cats = catDiv.getElementsByTagName('li'), catname, langcurrent = 0, catskip = 1; do { while (cats.length > 0) { catname = cats[ 0 ].getElementsByTagName('a')[0].innerHTML; if (catname.indexOf(tabbedLanguages[langcurrent + catskip]) === 0 && !/letter\snames$|script\scharacters$|mythology$/.test(catname) ) { langcurrent += catskip; catskip = 1; } currentCatDiv = languageContainers[langcurrent].lastChild; currentCatDiv.lastChild.appendChild(cats[0]); } if (langcurrent + 1 < languageContainers.length - catskip) { // Didn't make it to the end, which means there's a section // without any categories. Dump what's left back and try again. while (currentCatDiv.lastChild.firstChild) { catDiv.lastChild.appendChild(currentCatDiv.lastChild.firstChild); } catskip++; } else { break; } } while (true); } if( currentCatDiv ) { // place patrol link at the bottom of the page var pl = currentCatDiv.previousSibling; // languageContainer.lastChild.previousSibling; // Got it, the patrollink is sometimes the lagging last elem. if( pl && pl.className === "patrollink" ) { tabstable.parentNode.appendChild(pl); } } /* // category editing buttons if (mw.config.get('wgAction') === "view" && !/&printable=yes|&diff=|&oldid=/.test(location.search)) { for (z = 0; z < languageContainers.length; z++) { // TODO: import // addTabbedLanguageNewCatButton(z); } if ( window.loadremovecatbuttons === true ) { $.get( mw.config.get( 'wgScript' ), { 'title' : mw.config.get('wgPageName'), 'action' : 'raw' }, // Note that this isn't actually defined. I'm considering not // actually importing the function, and just dumping this section. addRemoveCatButtons ); } } */ // Remove old cat box, allow display of hidden cats box. if (catDiv && !(catDiv.nextSibling && catDiv.nextSibling.className === "mw-hidden-catlinks mw-hidden-cats-user-shown")) { catDiv.parentNode.style.display = 'none'; } else { if (catDiv) { catDiv.style.display = 'none'; } } } function testStuff() { var delay = 5000, f = document.createDocumentFragment(); var x = [ function () { // $("#toc").remove(); var x = document.getElementById( "mw-content-text" ); while( x.nextSibling ) { f.appendChild( x.nextSibling ); } }, function () { var y = $( ".mw-content-ltr" )[ 0 ]; var q = document.createDocumentFragment(); while( y.firstChild ) { q.appendChild( y.firstChild ); } function u( i, e ) { setTimeout( function () { y.appendChild( q.firstChild ); }, i / e * delay ); } for( var i = 0, e = q.childNodes.length; i < e; i++ ) { u( i, e ); // encapsulate } makeTabsfromScratch(); }, function () { function u( i, e ) { setTimeout( function () { $(".mw-content-ltr").after( f.firstChild ); }, i / e * delay / 5 ); } for( var i = 0, e = f.childNodes.length; i < e; i++ ) { u( i, e ); // encapsulate } console.log(9); } ]; x[0](); for( var i = 1; i < x.length; i++ ) { setTimeout( x[ i ], (i-1) * delay + 50 ); } } //testStuff(); makeTabsfromScratch(); // This is officially deprecated as of MW1.22. Should be replaced by mw.hook, // but the docs don't say what event, so... $(mw).on('LivePreviewDone', function () { bodyContent = $(".mw-content-ltr")[0]; // reset makeTabsfromScratch(); }); })( window.jQuery ); bo3vk8t8xgwm7kymt0gkaic1zrtyvzq MediaWiki:Gadget-TabbedLanguages.css 8 17987 88976 2025-12-24T19:33:28Z en>Benwing 0 [[User:Mahagaja]] exclude mammoth-minitoc tables from being turned off by TabbedLanguages 88976 css text/css /* Styles for the Tabbed Languages gadget */ #languageLinks .selectedTab a { font-size: 19px; color: #000; padding: 6px; display: block; border-left: 1px solid #CCC; border-bottom: 1px solid #CCC; margin-bottom: -3px; background-color: #fff; margin-right: -6px; position: relative; border-top: 1px solid #CCC; white-space: nowrap; } #languageLinks .unselectedTab a { font-size: 16px; color: #929292; padding: 6px; display: block; border-left: 1px solid #CCC; border-top: 1px solid #CCC; border-bottom: 1px solid #CCC; margin-bottom: -3px; margin-left: 15px; margin-right: -5px; white-space: nowrap; background-color: #F6F6F6; } #languageLinks tr td { padding: 0px; } tr td.languageContainer { padding-left: 8px; padding-bottom: 10px; padding-right: 8px; border: 1px solid #CCC; vertical-align: top; width: 100%; } .unselectedtab { margin-left: 5px; } .editlangsection { margin-top: -13px; margin-right: 5px; border: 1px solid #CCC; margin-bottom: -2px; border-bottom-width: 0px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; color: white; line-height: 14px; font-size: 12px; padding: 0px 7px; text-align: center; clear: both; background-color: white; float: right; } #languageLinks a.addLanguageButton { font-size: 12px; padding: 3px 6px; } @media screen and (max-width:36em) { #tabstable > tbody > tr > td { display: block; float: left; width: 100%; } #languageLinks tr { display: block; float: left; margin-bottom: -3px; margin-left: -5px; margin-top: 5px; } #languageLinks .unselectedTab a { margin-left: 0; margin-right: 5px; border-right: 1px solid #CCC; } #languageLinks .selectedTab a { margin-left: 0; margin-right: 5px; border-right: 1px solid #CCC; border-bottom: 1px solid #FFF; } #tabstable { width: 100%; } #languageLinks a.addLanguageButton { margin-top: 2px; margin-bottom: 1px; } .editlangsection { border-bottom-width: 1px; } } .minitoc:not(.mammoth-minitoc) { display: none; } 0vfsobgurlx0r6mcpypw92v32flnn6t 88977 88976 2026-08-06T23:23:58Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-TabbedLanguages.css]] 88976 css text/css /* Styles for the Tabbed Languages gadget */ #languageLinks .selectedTab a { font-size: 19px; color: #000; padding: 6px; display: block; border-left: 1px solid #CCC; border-bottom: 1px solid #CCC; margin-bottom: -3px; background-color: #fff; margin-right: -6px; position: relative; border-top: 1px solid #CCC; white-space: nowrap; } #languageLinks .unselectedTab a { font-size: 16px; color: #929292; padding: 6px; display: block; border-left: 1px solid #CCC; border-top: 1px solid #CCC; border-bottom: 1px solid #CCC; margin-bottom: -3px; margin-left: 15px; margin-right: -5px; white-space: nowrap; background-color: #F6F6F6; } #languageLinks tr td { padding: 0px; } tr td.languageContainer { padding-left: 8px; padding-bottom: 10px; padding-right: 8px; border: 1px solid #CCC; vertical-align: top; width: 100%; } .unselectedtab { margin-left: 5px; } .editlangsection { margin-top: -13px; margin-right: 5px; border: 1px solid #CCC; margin-bottom: -2px; border-bottom-width: 0px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; color: white; line-height: 14px; font-size: 12px; padding: 0px 7px; text-align: center; clear: both; background-color: white; float: right; } #languageLinks a.addLanguageButton { font-size: 12px; padding: 3px 6px; } @media screen and (max-width:36em) { #tabstable > tbody > tr > td { display: block; float: left; width: 100%; } #languageLinks tr { display: block; float: left; margin-bottom: -3px; margin-left: -5px; margin-top: 5px; } #languageLinks .unselectedTab a { margin-left: 0; margin-right: 5px; border-right: 1px solid #CCC; } #languageLinks .selectedTab a { margin-left: 0; margin-right: 5px; border-right: 1px solid #CCC; border-bottom: 1px solid #FFF; } #tabstable { width: 100%; } #languageLinks a.addLanguageButton { margin-top: 2px; margin-bottom: 1px; } .editlangsection { border-bottom-width: 1px; } } .minitoc:not(.mammoth-minitoc) { display: none; } 0vfsobgurlx0r6mcpypw92v32flnn6t MediaWiki:Gadget-FastRollback.js 8 17988 88978 2025-09-17T22:36:28Z en>Ioaxxere 0 [[mw:Migrating mw.Uri to URL]] 88978 javascript text/javascript // {{documentation}} /*jshint undef:true, latedef:true, undef:true, shadow:true, scripturl:true */ /*global mw, jQuery */ (function () { var api = new mw.Api(); function processLink(link, title, token, user, markbot) { var wrapper = link.parentNode; var bracketed = (wrapper.textContent[0] === '['); link.addEventListener('click', function (ev) { ev.preventDefault(); var summary = prompt('About to rollback edits by [[User:' + user + ']] to [[' + title + ']].\n\nEdit summary (empty for default):', 'Reverted edits by [[Special:Contributions/' + user + '|' + user + ']]. If you think this rollback is in error, please leave a message on my [[User talk:' + mw.config.get('wgUserName') + '|talk page]].'); if (summary === null) return; wrapper.textContent = bracketed ? '[wait]' : 'wait'; api.post({ action: 'rollback', title: title, user: user, token: token, markbot: markbot ? '1' : void(0), summary: summary ? summary : void(0) }).then(function (result) { var diffLink = document.createElement('a'); diffLink.href = mw.config.get('wgScript') + '?diff=' + result.rollback.revid + '&diffonly=1'; diffLink.textContent = 'diff'; var reloadLink = document.createElement('a'); reloadLink.href = 'javascript:location.reload();'; reloadLink.textContent = 'reload'; wrapper.textContent = ''; if (bracketed) wrapper.appendChild(document.createTextNode('[')); wrapper.appendChild(document.createTextNode('done: ')); wrapper.appendChild(diffLink); wrapper.appendChild(document.createTextNode(' | ')); wrapper.appendChild(reloadLink); if (bracketed) wrapper.appendChild(document.createTextNode(']')); }, function (code, result, xhr) { link.textContent = 'retry'; var cnode = document.createElement('code'); cnode.style.borderBottom = '1px dotted black'; cnode.style.cursor = 'help'; cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; default: cnode.title = result.error.info; } wrapper.textContent = ''; if (bracketed) wrapper.appendChild(document.createTextNode('[')); wrapper.appendChild(document.createTextNode('error: ')); wrapper.appendChild(cnode); wrapper.appendChild(document.createTextNode(' (')); wrapper.appendChild(link); wrapper.appendChild(document.createTextNode(')')); if (bracketed) wrapper.appendChild(document.createTextNode(']')); console.error(result); }); }, false); } jQuery(document).ready(function() { var rolllinks = document.getElementsByClassName('mw-rollback-link'); for (var i = 0; i < rolllinks.length; ++i) { var links = rolllinks[i].getElementsByTagName('a'); if (links.length !== 1) continue; var link = links[0]; try { var uri = new URL(link.href); if (uri.searchParams.get("action") === 'rollback') processLink(link, uri.searchParams.get("title"), uri.searchParams.get("token"), uri.searchParams.get("from"), uri.searchParams.get("bot") && true); } catch (e) { /* swallow */ } } function makeRestoreLink(oldid, uname) { var link = document.createElement('a'); var span = document.createElement('span'); link.href = mw.config.get('wgScript') + '?action=edit&oldid=' + oldid; function doRestore() { function showError(action, code, result) { var cnode = document.createElement('code'); cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; case 'edit-failure': cnode.textContent = result.edit.code; cnode.title = 'Edit error: ' + result.edit.info; break; default: cnode.title = result.error.info; } var retryLink = document.createElement('a'); retryLink.href = link.href; retryLink.textContent = 'retry'; retryLink.addEventListener('click', function (ev) { ev.preventDefault(); doRestore(); }, false); span.textContent = ''; span.appendChild(document.createTextNode('error: ')); span.appendChild(cnode); span.appendChild(document.createTextNode(' (')); span.appendChild(retryLink); span.appendChild(document.createTextNode(')')); } var summary = prompt('Edit summary for this reversion:', 'Restored [[Special:Permalink/' + oldid + '|revision ' + oldid + ']] by [[User:' + uname + ']]'); if (summary === null) return; span.textContent = 'grabbing oldid'; if (link.parentNode) { link.parentNode.insertBefore(span, link); link.parentNode.removeChild(link); } api.get({ action: 'query', pageids: mw.config.get('wgArticleId'), prop: 'revisions', rvstartid: oldid, rvlimit: 1, rvprop: 'content' }).then(function (result, xhr) { console.info(result); var starttimestamp = (new Date(xhr.getResponseHeader('Date'))).toISOString(); // XXX: acceptable? var content = result.query.pages[mw.config.get('wgArticleId')].revisions[0]['*']; span.textContent = 'grabbing latest revision'; api.get({ action: 'query', pageids: mw.config.get('wgArticleId'), prop: 'revisions', rvlimit: 1, rvprop: 'ids|timestamp' }).then(function (result) { console.info(result); var basetimestamp = result.query.pages[mw.config.get('wgArticleId')].revisions[0].timestamp; if (result.query.pages[mw.config.get('wgArticleId')].revisions[0].revid === Number(oldid)) { span.textContent = 'this is already the latest revision'; return; } span.textContent = 'reverting'; api.post({ action: 'edit', pageid: mw.config.get('wgArticleId'), token: mw.user.tokens.get('csrfToken'), basetimestamp: basetimestamp, starttimestamp: starttimestamp, nocreate: '1', text: content, summary: summary }).then(function (result) { if (result.edit.result === 'Success') { span.textContent = 'done'; } else { showError('saving', 'edit-failure', result); } }, function (code, result) { showError('saving', code, result); }); }, function (code, result) { showError('grabbing latest revision data', code, result); }); }, function (code, result) { showError('grabbing old revision text', code, result); }); } link.addEventListener('click', function (ev) { ev.preventDefault(); doRestore(); }, false); return link; } // are we viewing an old revision? var revnav = document.getElementById('mw-revision-nav'); if (revnav) { var uname = document.getElementById('mw-revision-info').getElementsByClassName('mw-userlink')[0].textContent; var oldid = mw.config.get('wgRevisionId'); // XXX: suppress if this is the latest revid var link = makeRestoreLink(oldid, uname); link.textContent = 'restore this version'; revnav.appendChild(document.createTextNode(' (')); revnav.appendChild(link); revnav.appendChild(document.createTextNode(')')); return; } // intentionally not enabled on history pages; // I want the user to see to what version they are reverting // either directly or at least a diff // may be changed on request, though function addRestoreLink(titlenode) { if (!titlenode) return; var titlelinks = titlenode.getElementsByTagName('a'); var userlink = titlenode.parentNode.getElementsByClassName('mw-userlink')[0]; var uname = userlink.textContent; var uri = new URL(titlelinks[0].href); // XXX: suppress for latest revid var rlink = makeRestoreLink(uri.searchParams.get("oldid"), userlink.textContent); rlink.textContent = 'restore'; titlelinks[1].parentNode.insertBefore(rlink, titlelinks[1].nextSibling); titlelinks[1].parentNode.insertBefore(document.createTextNode(' | '), titlelinks[1].nextSibling); } // are we viewing a diff? var ot = document.getElementById('mw-diff-otitle1'); var nt = document.getElementById('mw-diff-ntitle1'); var ri = document.getElementById('mw-revision-info'); if ((nt || ot) && mw.config.get('wgArticleId')) { addRestoreLink(ot); addRestoreLink(nt); } else if (ri && (mw.config.get('wgRevisionId') !== mw.config.get('wgCurRevisionId'))) { var userlink = ri.getElementsByClassName('mw-userlink')[0]; var rlink = makeRestoreLink(mw.config.get('wgRevisionId'), userlink.textContent); rlink.textContent = 'restore'; var fh = document.getElementById('firstHeading'); var span = document.createElement('span'); span.className = 'mw-editsection'; span.appendChild(document.createTextNode('[')); span.appendChild(rlink); span.appendChild(document.createTextNode(']')); fh.appendChild(span); } }); })(); qf0oxyah5m8wbu56gcchqp2bu762ig5 88979 88978 2026-08-06T23:24:08Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-FastRollback.js]] 88978 javascript text/javascript // {{documentation}} /*jshint undef:true, latedef:true, undef:true, shadow:true, scripturl:true */ /*global mw, jQuery */ (function () { var api = new mw.Api(); function processLink(link, title, token, user, markbot) { var wrapper = link.parentNode; var bracketed = (wrapper.textContent[0] === '['); link.addEventListener('click', function (ev) { ev.preventDefault(); var summary = prompt('About to rollback edits by [[User:' + user + ']] to [[' + title + ']].\n\nEdit summary (empty for default):', 'Reverted edits by [[Special:Contributions/' + user + '|' + user + ']]. If you think this rollback is in error, please leave a message on my [[User talk:' + mw.config.get('wgUserName') + '|talk page]].'); if (summary === null) return; wrapper.textContent = bracketed ? '[wait]' : 'wait'; api.post({ action: 'rollback', title: title, user: user, token: token, markbot: markbot ? '1' : void(0), summary: summary ? summary : void(0) }).then(function (result) { var diffLink = document.createElement('a'); diffLink.href = mw.config.get('wgScript') + '?diff=' + result.rollback.revid + '&diffonly=1'; diffLink.textContent = 'diff'; var reloadLink = document.createElement('a'); reloadLink.href = 'javascript:location.reload();'; reloadLink.textContent = 'reload'; wrapper.textContent = ''; if (bracketed) wrapper.appendChild(document.createTextNode('[')); wrapper.appendChild(document.createTextNode('done: ')); wrapper.appendChild(diffLink); wrapper.appendChild(document.createTextNode(' | ')); wrapper.appendChild(reloadLink); if (bracketed) wrapper.appendChild(document.createTextNode(']')); }, function (code, result, xhr) { link.textContent = 'retry'; var cnode = document.createElement('code'); cnode.style.borderBottom = '1px dotted black'; cnode.style.cursor = 'help'; cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; default: cnode.title = result.error.info; } wrapper.textContent = ''; if (bracketed) wrapper.appendChild(document.createTextNode('[')); wrapper.appendChild(document.createTextNode('error: ')); wrapper.appendChild(cnode); wrapper.appendChild(document.createTextNode(' (')); wrapper.appendChild(link); wrapper.appendChild(document.createTextNode(')')); if (bracketed) wrapper.appendChild(document.createTextNode(']')); console.error(result); }); }, false); } jQuery(document).ready(function() { var rolllinks = document.getElementsByClassName('mw-rollback-link'); for (var i = 0; i < rolllinks.length; ++i) { var links = rolllinks[i].getElementsByTagName('a'); if (links.length !== 1) continue; var link = links[0]; try { var uri = new URL(link.href); if (uri.searchParams.get("action") === 'rollback') processLink(link, uri.searchParams.get("title"), uri.searchParams.get("token"), uri.searchParams.get("from"), uri.searchParams.get("bot") && true); } catch (e) { /* swallow */ } } function makeRestoreLink(oldid, uname) { var link = document.createElement('a'); var span = document.createElement('span'); link.href = mw.config.get('wgScript') + '?action=edit&oldid=' + oldid; function doRestore() { function showError(action, code, result) { var cnode = document.createElement('code'); cnode.textContent = code; switch (code) { case 'http': cnode.title = 'HTTP error: ' + result.textStatus; break; case 'ok-but-empty': cnode.title = 'Received empty response from the server'; break; case 'edit-failure': cnode.textContent = result.edit.code; cnode.title = 'Edit error: ' + result.edit.info; break; default: cnode.title = result.error.info; } var retryLink = document.createElement('a'); retryLink.href = link.href; retryLink.textContent = 'retry'; retryLink.addEventListener('click', function (ev) { ev.preventDefault(); doRestore(); }, false); span.textContent = ''; span.appendChild(document.createTextNode('error: ')); span.appendChild(cnode); span.appendChild(document.createTextNode(' (')); span.appendChild(retryLink); span.appendChild(document.createTextNode(')')); } var summary = prompt('Edit summary for this reversion:', 'Restored [[Special:Permalink/' + oldid + '|revision ' + oldid + ']] by [[User:' + uname + ']]'); if (summary === null) return; span.textContent = 'grabbing oldid'; if (link.parentNode) { link.parentNode.insertBefore(span, link); link.parentNode.removeChild(link); } api.get({ action: 'query', pageids: mw.config.get('wgArticleId'), prop: 'revisions', rvstartid: oldid, rvlimit: 1, rvprop: 'content' }).then(function (result, xhr) { console.info(result); var starttimestamp = (new Date(xhr.getResponseHeader('Date'))).toISOString(); // XXX: acceptable? var content = result.query.pages[mw.config.get('wgArticleId')].revisions[0]['*']; span.textContent = 'grabbing latest revision'; api.get({ action: 'query', pageids: mw.config.get('wgArticleId'), prop: 'revisions', rvlimit: 1, rvprop: 'ids|timestamp' }).then(function (result) { console.info(result); var basetimestamp = result.query.pages[mw.config.get('wgArticleId')].revisions[0].timestamp; if (result.query.pages[mw.config.get('wgArticleId')].revisions[0].revid === Number(oldid)) { span.textContent = 'this is already the latest revision'; return; } span.textContent = 'reverting'; api.post({ action: 'edit', pageid: mw.config.get('wgArticleId'), token: mw.user.tokens.get('csrfToken'), basetimestamp: basetimestamp, starttimestamp: starttimestamp, nocreate: '1', text: content, summary: summary }).then(function (result) { if (result.edit.result === 'Success') { span.textContent = 'done'; } else { showError('saving', 'edit-failure', result); } }, function (code, result) { showError('saving', code, result); }); }, function (code, result) { showError('grabbing latest revision data', code, result); }); }, function (code, result) { showError('grabbing old revision text', code, result); }); } link.addEventListener('click', function (ev) { ev.preventDefault(); doRestore(); }, false); return link; } // are we viewing an old revision? var revnav = document.getElementById('mw-revision-nav'); if (revnav) { var uname = document.getElementById('mw-revision-info').getElementsByClassName('mw-userlink')[0].textContent; var oldid = mw.config.get('wgRevisionId'); // XXX: suppress if this is the latest revid var link = makeRestoreLink(oldid, uname); link.textContent = 'restore this version'; revnav.appendChild(document.createTextNode(' (')); revnav.appendChild(link); revnav.appendChild(document.createTextNode(')')); return; } // intentionally not enabled on history pages; // I want the user to see to what version they are reverting // either directly or at least a diff // may be changed on request, though function addRestoreLink(titlenode) { if (!titlenode) return; var titlelinks = titlenode.getElementsByTagName('a'); var userlink = titlenode.parentNode.getElementsByClassName('mw-userlink')[0]; var uname = userlink.textContent; var uri = new URL(titlelinks[0].href); // XXX: suppress for latest revid var rlink = makeRestoreLink(uri.searchParams.get("oldid"), userlink.textContent); rlink.textContent = 'restore'; titlelinks[1].parentNode.insertBefore(rlink, titlelinks[1].nextSibling); titlelinks[1].parentNode.insertBefore(document.createTextNode(' | '), titlelinks[1].nextSibling); } // are we viewing a diff? var ot = document.getElementById('mw-diff-otitle1'); var nt = document.getElementById('mw-diff-ntitle1'); var ri = document.getElementById('mw-revision-info'); if ((nt || ot) && mw.config.get('wgArticleId')) { addRestoreLink(ot); addRestoreLink(nt); } else if (ri && (mw.config.get('wgRevisionId') !== mw.config.get('wgCurRevisionId'))) { var userlink = ri.getElementsByClassName('mw-userlink')[0]; var rlink = makeRestoreLink(mw.config.get('wgRevisionId'), userlink.textContent); rlink.textContent = 'restore'; var fh = document.getElementById('firstHeading'); var span = document.createElement('span'); span.className = 'mw-editsection'; span.appendChild(document.createTextNode('[')); span.appendChild(rlink); span.appendChild(document.createTextNode(']')); fh.appendChild(span); } }); })(); qf0oxyah5m8wbu56gcchqp2bu762ig5 MediaWiki:Gadget-AudioBotBlacklist.js 8 17989 88980 2026-02-20T22:56:09Z en>Fenakhay 0 88980 javascript text/javascript /** * AudioBot Blacklist Gadget * * Adds a button on the blacklist page to add audio files without editing. * The blacklist is stored as JSON at [[Wiktionary:Approved Lingua Libre users/AudioBotBlacklist]]. */ /* jshint esversion: 8 */ ( function () { 'use strict'; const BLACKLIST_PAGE = 'Wiktionary:Approved Lingua Libre users/AudioBotBlacklist'; let AddDialog = null; let EditDialog = null; let BulkAddDialog = null; const createStore = ( initial ) => { let data = initial; let subscribers = []; const notify = () => subscribers.forEach( ( fn ) => fn( data ) ); return { get: () => data, set: ( value ) => { data = value; notify(); }, subscribe: ( fn ) => { subscribers.push( fn ); return () => { subscribers = subscribers.filter( ( f ) => f !== fn ); }; }, has: ( key ) => data.hasOwnProperty( key ), put: ( key, value ) => { data[ key ] = value; notify(); }, remove: ( key ) => { delete data[ key ]; notify(); }, entries: () => Object.entries( data ).sort( sortByAdded ), count: () => Object.keys( data ).length }; }; const blacklistStore = createStore( {} ); let blacklistLoaded = false; let blacklistBaseRevId = null; const normalizeFilename = ( name ) => name.trim().replace( /^File:/i, '' ).replace( /_/g, ' ' ).trim(); const getEntryReason = ( val ) => ( val && val.reason !== undefined ? val.reason : '' ); const getEntryAdded = ( val ) => ( val && val.added ); const makeEntry = ( reason, added ) => ( added ? { reason, added } : { reason } ); const sortByAdded = ( a, b ) => { const addedA = getEntryAdded( a[ 1 ] ) || '\u0000'; const addedB = getEntryAdded( b[ 1 ] ) || '\u0000'; return addedB.localeCompare( addedA ); }; let api = null; let commonsApi = null; const loadBlacklist = async ( forceReload ) => { if ( blacklistLoaded && !forceReload ) { return; } const response = await api.get( { action: 'query', titles: BLACKLIST_PAGE, prop: 'revisions', rvprop: 'content|ids', rvslots: 'main', formatversion: 2 } ); const page = response.query.pages[ 0 ]; if ( page.missing ) { blacklistStore.set( {} ); blacklistBaseRevId = null; } else { blacklistStore.set( JSON.parse( page.revisions[ 0 ].slots.main.content ) ); blacklistBaseRevId = page.revisions[ 0 ].revid; } blacklistLoaded = true; }; const saveBlacklist = async ( summary ) => { const data = blacklistStore.get(); const sortedBlacklist = Object.entries( data ).sort( sortByAdded ).reduce( ( acc, entry ) => { acc[ entry[ 0 ] ] = entry[ 1 ]; return acc; }, {} ); const params = { action: 'edit', title: BLACKLIST_PAGE, text: JSON.stringify( sortedBlacklist, null, 2 ), summary, minor: false }; if ( blacklistBaseRevId ) { params.baserevid = blacklistBaseRevId; } const result = await api.postWithToken( 'csrf', params ); if ( result.edit && result.edit.newrevid ) { blacklistBaseRevId = result.edit.newrevid; } }; const checkFileExists = async ( filename ) => { const data = await commonsApi.get( { action: 'query', titles: 'File:' + filename, formatversion: 2 } ); const page = data.query.pages[ 0 ]; return !page.missing; }; const addToBlacklist = async ( filename, reason ) => { await loadBlacklist( true ); if ( blacklistStore.has( filename ) ) { throw new Error( 'This file is already in the blacklist.' ); } const added = new Date().toISOString(); blacklistStore.put( filename, makeEntry( reason, added ) ); await saveBlacklist( `Added [[File:${filename}]] to blacklist: ${reason.substring( 0, 100 )}` ); }; const addBulkToBlacklist = async ( entries ) => { await loadBlacklist( true ); let added = 0; const data = blacklistStore.get(); const addedAt = new Date().toISOString(); for ( const [ filename, reason ] of entries ) { if ( !data.hasOwnProperty( filename ) ) { data[ filename ] = makeEntry( reason, addedAt ); added++; } } if ( added > 0 ) { blacklistStore.set( data ); await saveBlacklist( `Bulk added ${added} file(s) to blacklist` ); } return added; }; const editBlacklistEntry = async ( filename, newReason ) => { await loadBlacklist( true ); if ( !blacklistStore.has( filename ) ) { throw new Error( 'This file is not in the blacklist.' ); } const existingAdded = getEntryAdded( blacklistStore.get()[ filename ] ); blacklistStore.put( filename, makeEntry( newReason, existingAdded ) ); await saveBlacklist( `Updated reason for [[File:${filename}]]` ); }; const removeFromBlacklist = async ( filename ) => { await loadBlacklist( true ); if ( !blacklistStore.has( filename ) ) { throw new Error( 'This file is not in the blacklist.' ); } blacklistStore.remove( filename ); await saveBlacklist( `Removed [[File:${filename}]] from blacklist` ); }; const removeBulkFromBlacklist = async ( filenames ) => { await loadBlacklist( true ); let removed = 0; const data = blacklistStore.get(); for ( const filename of filenames ) { if ( data.hasOwnProperty( filename ) ) { delete data[ filename ]; removed++; } } if ( removed > 0 ) { blacklistStore.set( data ); await saveBlacklist( `Bulk removed ${removed} file(s) from blacklist` ); } return removed; }; const createDialog = ( config ) => { class Dialog extends OO.ui.ProcessDialog { initialize() { super.initialize(); config.init( this ); return this; } getSetupProcess( data ) { return super.getSetupProcess( data ).next( () => config.setup( this, data || {} ) ); } getActionProcess( action ) { if ( action === 'save' ) { return new OO.ui.Process( async () => { try { await config.onSave( this ); this.close( { action } ); } catch ( error ) { throw new OO.ui.Error( error.message || String( error ) ); } } ); } return super.getActionProcess( action ); } getBodyHeight() { return config.bodyHeight || 200; } } Dialog.static = Object.assign( {}, OO.ui.ProcessDialog.static, { name: config.name, title: config.title, actions: [ { action: 'save', label: config.saveLabel || 'Save', flags: [ 'primary', 'progressive' ] }, { label: 'Cancel', flags: 'safe' } ] } ); return Dialog; }; const createAddDialog = () => createDialog( { name: 'audiobotAdd', title: 'Add to AudioBot Blacklist', saveLabel: 'Add to Blacklist', bodyHeight: 250, init( dialog ) { dialog.filenameInput = new OO.ui.TextInputWidget( { placeholder: 'e.g. En-us-example.ogg' } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); dialog.fileExistsMessage = new OO.ui.MessageWidget( { type: 'warning', inline: true, label: 'This file does not exist on Commons.' } ); dialog.fileExistsMessage.$element.hide(); dialog.filenameInput.on( 'change', OO.ui.debounce( async () => { const filename = normalizeFilename( dialog.filenameInput.getValue() ); if ( filename ) { const exists = await checkFileExists( filename ); dialog.fileExistsMessage.$element.toggle( !exists ); } else { dialog.fileExistsMessage.$element.hide(); } }, 500 ) ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filenameInput, { label: 'Audio filename (without File: prefix):', align: 'top' } ).$element, dialog.fileExistsMessage.$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason:', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog, data ) { dialog.filenameInput.setValue( data.prefillFilename || '' ); dialog.reasonInput.setValue( '' ); dialog.fileExistsMessage.$element.hide(); if ( data.prefillFilename ) { dialog.filenameInput.emit( 'change' ); } }, async onSave( dialog ) { const filename = normalizeFilename( dialog.filenameInput.getValue() ); const reason = dialog.reasonInput.getValue().trim(); if ( !filename ) { throw new Error( 'Please enter a filename.' ); } if ( !reason ) { throw new Error( 'Please enter a reason.' ); } await addToBlacklist( filename, reason ); mw.notify( `Successfully added "${filename}" to the blacklist.`, { type: 'success' } ); } } ); const createEditDialog = () => createDialog( { name: 'audiobotEdit', title: 'Edit Blacklist Reason', saveLabel: 'Save', bodyHeight: 180, init( dialog ) { dialog.filename = ''; dialog.filenameLabel = new OO.ui.LabelWidget( { label: '' } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filenameLabel, { label: 'Filename:', align: 'top' } ).$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason:', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog, data ) { dialog.filename = data.filename || ''; dialog.filenameLabel.setLabel( dialog.filename ); dialog.reasonInput.setValue( data.reason || '' ); }, async onSave( dialog ) { const reason = dialog.reasonInput.getValue().trim(); if ( !reason ) { throw new Error( 'Please enter a reason.' ); } await editBlacklistEntry( dialog.filename, reason ); mw.notify( `Successfully updated reason for "${dialog.filename}".`, { type: 'success' } ); } } ); const createBulkAddDialog = () => createDialog( { name: 'audiobotBulkAdd', title: 'Bulk Add to AudioBot Blacklist', saveLabel: 'Add All', bodyHeight: 320, init( dialog ) { dialog.filesInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Enter one filename per line...', rows: 6 } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filesInput, { label: 'Filenames (one per line, without File: prefix):', align: 'top' } ).$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason (applies to all):', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog ) { dialog.filesInput.setValue( '' ); dialog.reasonInput.setValue( '' ); }, async onSave( dialog ) { const filesText = dialog.filesInput.getValue().trim(); const reason = dialog.reasonInput.getValue().trim(); if ( !filesText ) { throw new Error( 'Please enter at least one filename.' ); } if ( !reason ) { throw new Error( 'Please enter a reason.' ); } const filenames = filesText.split( '\n' ).map( normalizeFilename ).filter( ( n ) => n.length > 0 ); if ( filenames.length === 0 ) { throw new Error( 'Please enter at least one valid filename.' ); } const entries = filenames.map( ( f ) => [ f, reason ] ); const added = await addBulkToBlacklist( entries ); mw.notify( `Successfully added ${added} file(s) to the blacklist.`, { type: 'success' } ); } } ); let windowManager = null; const showDialog = ( DialogClass, data ) => { if ( !windowManager ) { windowManager = new OO.ui.WindowManager(); $( document.body ).append( windowManager.$element ); } const dialog = new DialogClass( { size: 'medium' } ); windowManager.addWindows( [ dialog ] ); windowManager.openWindow( dialog, data || {} ); }; let selectedFiles = new Set(); let $selectAllCheckbox = null; let $removeSelectedBtn = null; const CELL_STYLE = { padding: '8px 12px', borderBottom: '1px solid var(--border-color-base)', verticalAlign: 'middle' }; const cellCss = ( overrides ) => Object.assign( {}, CELL_STYLE, overrides ); const createIconButton = ( icon, title, destructive ) => new OO.ui.ButtonWidget( { icon, title, framed: false, flags: destructive ? [ 'destructive' ] : [] } ); const confirmAndRun = async ( message, action, successMsg ) => { const confirmed = await OO.ui.confirm( message ); if ( !confirmed ) { return false; } try { const result = await action(); const msg = typeof successMsg === 'function' ? successMsg( result ) : successMsg; mw.notify( msg, { type: 'success' } ); return true; } catch ( error ) { mw.notify( error.message || String( error ), { type: 'error' } ); return false; } }; const updateRemoveSelectedButton = () => { if ( $removeSelectedBtn ) { $removeSelectedBtn.setDisabled( selectedFiles.size === 0 ); $removeSelectedBtn.setLabel( `Remove selected (${selectedFiles.size})` ); } }; const updateEntryCount = () => { $( '#audiobot-entry-count' ).text( `${blacklistStore.count()} file(s) in blacklist` ); }; const renderBlacklistTable = () => { if ( !$( '#audiobot-blacklist-controls' ).length ) { return; } const entries = blacklistStore.entries(); updateEntryCount(); $( '.mw-json' ).hide(); $( '#audiobot-blacklist-table' ).remove(); selectedFiles.clear(); $selectAllCheckbox = new OO.ui.CheckboxInputWidget(); $selectAllCheckbox.on( 'change', ( selected ) => { selectedFiles.clear(); $( '#audiobot-blacklist-table tbody tr' ).each( function () { const $checkbox = $( this ).find( '.oo-ui-checkboxInputWidget input' ); $checkbox.prop( 'checked', selected ).trigger( 'change' ); if ( selected ) { const filename = $( this ).data( 'filename' ); selectedFiles.add( filename ); } } ); updateRemoveSelectedButton(); } ); const $table = $( '<table>' ) .attr( 'id', 'audiobot-blacklist-table' ) .css( { width: '100%', borderCollapse: 'collapse', marginTop: '1em' } ); const formatAdded = ( iso ) => { if ( !iso ) { return ''; } const d = new Date( iso ); if ( isNaN( d.getTime() ) ) { return iso; } return d.toLocaleDateString( 'en-GB', { year: 'numeric', month: '2-digit', day: '2-digit' } ); }; const $thead = $( '<thead>' ).append( $( '<tr>' ).css( { backgroundColor: 'var(--background-color-interactive)' } ).append( $( '<th>' ).css( cellCss( { width: '40px', textAlign: 'center' } ) ).append( $selectAllCheckbox.$element ), $( '<th>' ).text( 'Filename' ).css( cellCss( { textAlign: 'left' } ) ), $( '<th>' ).text( 'Reason' ).css( cellCss( { textAlign: 'left' } ) ), $( '<th>' ).text( 'Added' ).css( cellCss( { width: '100px', textAlign: 'left' } ) ), $( '<th>' ).text( 'Actions' ).css( cellCss( { width: '100px', textAlign: 'center' } ) ) ) ); const $tbody = $( '<tbody>' ); for ( const [ filename, rawValue ] of entries ) { const reason = getEntryReason( rawValue ); const added = getEntryAdded( rawValue ); const checkbox = new OO.ui.CheckboxInputWidget(); checkbox.on( 'change', ( selected ) => { if ( selected ) { selectedFiles.add( filename ); } else { selectedFiles.delete( filename ); } updateRemoveSelectedButton(); } ); const editBtn = createIconButton( 'edit', 'Edit reason', false ); editBtn.on( 'click', () => showDialog( EditDialog, { filename, reason } ) ); const removeBtn = createIconButton( 'trash', 'Remove from blacklist', true ); removeBtn.on( 'click', () => confirmAndRun( `Remove "${filename}" from the blacklist?`, () => removeFromBlacklist( filename ), `Removed "${filename}" from the blacklist.` ) ); const $row = $( '<tr>' ).data( 'filename', filename ).append( $( '<td>' ).css( cellCss( { textAlign: 'center' } ) ).append( checkbox.$element ), $( '<td>' ).css( CELL_STYLE ).text( filename ), $( '<td>' ).css( CELL_STYLE ).text( reason ), $( '<td>' ).css( CELL_STYLE ).attr( 'title', added || '' ).text( formatAdded( added ) ), $( '<td>' ).css( cellCss( { textAlign: 'center', whiteSpace: 'nowrap' } ) ).append( editBtn.$element, removeBtn.$element ) ); $tbody.append( $row ); } $table.append( $thead, $tbody ); $( '#audiobot-blacklist-controls' ).after( $table ); }; const addBlacklistPageButtons = () => { const addButton = new OO.ui.ButtonWidget( { label: 'Add file', icon: 'add', flags: [ 'progressive' ] } ); addButton.on( 'click', () => showDialog( AddDialog ) ); const bulkAddButton = new OO.ui.ButtonWidget( { label: 'Bulk add', icon: 'add' } ); bulkAddButton.on( 'click', () => showDialog( BulkAddDialog ) ); $removeSelectedBtn = new OO.ui.ButtonWidget( { label: 'Remove selected (0)', icon: 'trash', flags: [ 'destructive' ], disabled: true } ); $removeSelectedBtn.on( 'click', () => { if ( selectedFiles.size === 0 ) { return; } confirmAndRun( `Remove ${selectedFiles.size} file(s) from the blacklist?`, () => removeBulkFromBlacklist( Array.from( selectedFiles ) ), ( removed ) => `Removed ${removed} file(s) from the blacklist.` ); } ); const $label = $( '<span>' ) .text( 'AudioBot Blacklist: ' ) .css( 'font-weight', 'bold' ); const $entryCount = $( '<span>' ) .attr( 'id', 'audiobot-entry-count' ) .css( { marginLeft: '1em', fontStyle: 'italic' } ) .text( 'Loading...' ); const $controls = $( '<div>' ) .attr( 'id', 'audiobot-blacklist-controls' ) .css( { marginBottom: '1em', padding: '0.5em 1em', backgroundColor: 'var(--background-color-neutral-subtle)', border: '1px solid var(--border-color-subtle)', borderRadius: '2px', color: 'var(--color-base)' } ) .append( $label, addButton.$element, ' ', bulkAddButton.$element, ' ', $removeSelectedBtn.$element, $entryCount ); $( '#mw-content-text' ).prepend( $controls ); renderBlacklistTable(); }; const addInlineBlacklistButtons = ( $content ) => { const $root = ( $content && $content.length ) ? $content : $( document ); for ( const table of $root.find( 'table.audiotable' ).toArray() ) { const $table = $( table ); const $player = $table.find( '[data-mwtitle]' ); if ( !$player.length ) { continue; } const filename = $player.attr( 'data-mwtitle' ); if ( !filename || $table.data( 'blacklistAdded' ) ) { continue; } $table.data( 'blacklistAdded', true ); const btn = createIconButton( 'block', 'Add to AudioBot blacklist', true ); btn.on( 'click', () => showDialog( AddDialog, { prefillFilename: normalizeFilename( filename ) } ) ); const $actionsCell = $( '<td>' ) .addClass( 'audio-actions' ) .css( { verticalAlign: 'middle' } ) .append( btn.$element ); $table.find( 'tr' ).first().append( $actionsCell ); } }; const init = async () => { try { await mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-interactions', 'mediawiki.api', 'mediawiki.ForeignApi' ] ); api = new mw.Api(); commonsApi = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' ); const userGroups = mw.config.get( 'wgUserGroups' ) || []; if ( !userGroups.includes( 'autoconfirmed' ) ) { return; } const prefs = mw.wiktGadgetPrefs.get( 'audiobot-blacklist', { label: { en: 'AudioBot Blacklist' } }, { showInlineButtons: { type: 'boolean', default: false, label: { en: 'Show inline blacklist buttons next to audio files' } } } ); AddDialog = createAddDialog(); EditDialog = createEditDialog(); BulkAddDialog = createBulkAddDialog(); const isBlacklistPage = mw.config.get( 'wgPageName' ) === BLACKLIST_PAGE.replace( / /g, '_' ); const isViewAction = mw.config.get( 'wgAction' ) === 'view'; const isDiff = mw.config.get( 'wgDiffOldId' ) || mw.config.get( 'wgDiffNewId' ); if ( isBlacklistPage && !isDiff ) { $( '#ca-edit, #ca-ve-edit' ).hide(); if ( isViewAction ) { await loadBlacklist(); blacklistStore.subscribe( () => { updateEntryCount(); renderBlacklistTable(); } ); addBlacklistPageButtons(); } } if ( prefs.showInlineButtons ) { mw.hook( 'wikipage.content' ).add( addInlineBlacklistButtons ); } } catch ( error ) { mw.log.error( 'AudioBot Blacklist gadget: failed', error ); } }; init(); }() ); 00dk55mkgf6r5lm0fgfxlj7b254k1ff 88981 88980 2026-08-06T23:24:23Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AudioBotBlacklist.js]] 88980 javascript text/javascript /** * AudioBot Blacklist Gadget * * Adds a button on the blacklist page to add audio files without editing. * The blacklist is stored as JSON at [[Wiktionary:Approved Lingua Libre users/AudioBotBlacklist]]. */ /* jshint esversion: 8 */ ( function () { 'use strict'; const BLACKLIST_PAGE = 'Wiktionary:Approved Lingua Libre users/AudioBotBlacklist'; let AddDialog = null; let EditDialog = null; let BulkAddDialog = null; const createStore = ( initial ) => { let data = initial; let subscribers = []; const notify = () => subscribers.forEach( ( fn ) => fn( data ) ); return { get: () => data, set: ( value ) => { data = value; notify(); }, subscribe: ( fn ) => { subscribers.push( fn ); return () => { subscribers = subscribers.filter( ( f ) => f !== fn ); }; }, has: ( key ) => data.hasOwnProperty( key ), put: ( key, value ) => { data[ key ] = value; notify(); }, remove: ( key ) => { delete data[ key ]; notify(); }, entries: () => Object.entries( data ).sort( sortByAdded ), count: () => Object.keys( data ).length }; }; const blacklistStore = createStore( {} ); let blacklistLoaded = false; let blacklistBaseRevId = null; const normalizeFilename = ( name ) => name.trim().replace( /^File:/i, '' ).replace( /_/g, ' ' ).trim(); const getEntryReason = ( val ) => ( val && val.reason !== undefined ? val.reason : '' ); const getEntryAdded = ( val ) => ( val && val.added ); const makeEntry = ( reason, added ) => ( added ? { reason, added } : { reason } ); const sortByAdded = ( a, b ) => { const addedA = getEntryAdded( a[ 1 ] ) || '\u0000'; const addedB = getEntryAdded( b[ 1 ] ) || '\u0000'; return addedB.localeCompare( addedA ); }; let api = null; let commonsApi = null; const loadBlacklist = async ( forceReload ) => { if ( blacklistLoaded && !forceReload ) { return; } const response = await api.get( { action: 'query', titles: BLACKLIST_PAGE, prop: 'revisions', rvprop: 'content|ids', rvslots: 'main', formatversion: 2 } ); const page = response.query.pages[ 0 ]; if ( page.missing ) { blacklistStore.set( {} ); blacklistBaseRevId = null; } else { blacklistStore.set( JSON.parse( page.revisions[ 0 ].slots.main.content ) ); blacklistBaseRevId = page.revisions[ 0 ].revid; } blacklistLoaded = true; }; const saveBlacklist = async ( summary ) => { const data = blacklistStore.get(); const sortedBlacklist = Object.entries( data ).sort( sortByAdded ).reduce( ( acc, entry ) => { acc[ entry[ 0 ] ] = entry[ 1 ]; return acc; }, {} ); const params = { action: 'edit', title: BLACKLIST_PAGE, text: JSON.stringify( sortedBlacklist, null, 2 ), summary, minor: false }; if ( blacklistBaseRevId ) { params.baserevid = blacklistBaseRevId; } const result = await api.postWithToken( 'csrf', params ); if ( result.edit && result.edit.newrevid ) { blacklistBaseRevId = result.edit.newrevid; } }; const checkFileExists = async ( filename ) => { const data = await commonsApi.get( { action: 'query', titles: 'File:' + filename, formatversion: 2 } ); const page = data.query.pages[ 0 ]; return !page.missing; }; const addToBlacklist = async ( filename, reason ) => { await loadBlacklist( true ); if ( blacklistStore.has( filename ) ) { throw new Error( 'This file is already in the blacklist.' ); } const added = new Date().toISOString(); blacklistStore.put( filename, makeEntry( reason, added ) ); await saveBlacklist( `Added [[File:${filename}]] to blacklist: ${reason.substring( 0, 100 )}` ); }; const addBulkToBlacklist = async ( entries ) => { await loadBlacklist( true ); let added = 0; const data = blacklistStore.get(); const addedAt = new Date().toISOString(); for ( const [ filename, reason ] of entries ) { if ( !data.hasOwnProperty( filename ) ) { data[ filename ] = makeEntry( reason, addedAt ); added++; } } if ( added > 0 ) { blacklistStore.set( data ); await saveBlacklist( `Bulk added ${added} file(s) to blacklist` ); } return added; }; const editBlacklistEntry = async ( filename, newReason ) => { await loadBlacklist( true ); if ( !blacklistStore.has( filename ) ) { throw new Error( 'This file is not in the blacklist.' ); } const existingAdded = getEntryAdded( blacklistStore.get()[ filename ] ); blacklistStore.put( filename, makeEntry( newReason, existingAdded ) ); await saveBlacklist( `Updated reason for [[File:${filename}]]` ); }; const removeFromBlacklist = async ( filename ) => { await loadBlacklist( true ); if ( !blacklistStore.has( filename ) ) { throw new Error( 'This file is not in the blacklist.' ); } blacklistStore.remove( filename ); await saveBlacklist( `Removed [[File:${filename}]] from blacklist` ); }; const removeBulkFromBlacklist = async ( filenames ) => { await loadBlacklist( true ); let removed = 0; const data = blacklistStore.get(); for ( const filename of filenames ) { if ( data.hasOwnProperty( filename ) ) { delete data[ filename ]; removed++; } } if ( removed > 0 ) { blacklistStore.set( data ); await saveBlacklist( `Bulk removed ${removed} file(s) from blacklist` ); } return removed; }; const createDialog = ( config ) => { class Dialog extends OO.ui.ProcessDialog { initialize() { super.initialize(); config.init( this ); return this; } getSetupProcess( data ) { return super.getSetupProcess( data ).next( () => config.setup( this, data || {} ) ); } getActionProcess( action ) { if ( action === 'save' ) { return new OO.ui.Process( async () => { try { await config.onSave( this ); this.close( { action } ); } catch ( error ) { throw new OO.ui.Error( error.message || String( error ) ); } } ); } return super.getActionProcess( action ); } getBodyHeight() { return config.bodyHeight || 200; } } Dialog.static = Object.assign( {}, OO.ui.ProcessDialog.static, { name: config.name, title: config.title, actions: [ { action: 'save', label: config.saveLabel || 'Save', flags: [ 'primary', 'progressive' ] }, { label: 'Cancel', flags: 'safe' } ] } ); return Dialog; }; const createAddDialog = () => createDialog( { name: 'audiobotAdd', title: 'Add to AudioBot Blacklist', saveLabel: 'Add to Blacklist', bodyHeight: 250, init( dialog ) { dialog.filenameInput = new OO.ui.TextInputWidget( { placeholder: 'e.g. En-us-example.ogg' } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); dialog.fileExistsMessage = new OO.ui.MessageWidget( { type: 'warning', inline: true, label: 'This file does not exist on Commons.' } ); dialog.fileExistsMessage.$element.hide(); dialog.filenameInput.on( 'change', OO.ui.debounce( async () => { const filename = normalizeFilename( dialog.filenameInput.getValue() ); if ( filename ) { const exists = await checkFileExists( filename ); dialog.fileExistsMessage.$element.toggle( !exists ); } else { dialog.fileExistsMessage.$element.hide(); } }, 500 ) ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filenameInput, { label: 'Audio filename (without File: prefix):', align: 'top' } ).$element, dialog.fileExistsMessage.$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason:', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog, data ) { dialog.filenameInput.setValue( data.prefillFilename || '' ); dialog.reasonInput.setValue( '' ); dialog.fileExistsMessage.$element.hide(); if ( data.prefillFilename ) { dialog.filenameInput.emit( 'change' ); } }, async onSave( dialog ) { const filename = normalizeFilename( dialog.filenameInput.getValue() ); const reason = dialog.reasonInput.getValue().trim(); if ( !filename ) { throw new Error( 'Please enter a filename.' ); } if ( !reason ) { throw new Error( 'Please enter a reason.' ); } await addToBlacklist( filename, reason ); mw.notify( `Successfully added "${filename}" to the blacklist.`, { type: 'success' } ); } } ); const createEditDialog = () => createDialog( { name: 'audiobotEdit', title: 'Edit Blacklist Reason', saveLabel: 'Save', bodyHeight: 180, init( dialog ) { dialog.filename = ''; dialog.filenameLabel = new OO.ui.LabelWidget( { label: '' } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filenameLabel, { label: 'Filename:', align: 'top' } ).$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason:', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog, data ) { dialog.filename = data.filename || ''; dialog.filenameLabel.setLabel( dialog.filename ); dialog.reasonInput.setValue( data.reason || '' ); }, async onSave( dialog ) { const reason = dialog.reasonInput.getValue().trim(); if ( !reason ) { throw new Error( 'Please enter a reason.' ); } await editBlacklistEntry( dialog.filename, reason ); mw.notify( `Successfully updated reason for "${dialog.filename}".`, { type: 'success' } ); } } ); const createBulkAddDialog = () => createDialog( { name: 'audiobotBulkAdd', title: 'Bulk Add to AudioBot Blacklist', saveLabel: 'Add All', bodyHeight: 320, init( dialog ) { dialog.filesInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Enter one filename per line...', rows: 6 } ); dialog.reasonInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'Reason for blacklisting...', rows: 3 } ); const content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); content.$element.append( new OO.ui.FieldLayout( dialog.filesInput, { label: 'Filenames (one per line, without File: prefix):', align: 'top' } ).$element, new OO.ui.FieldLayout( dialog.reasonInput, { label: 'Reason (applies to all):', align: 'top' } ).$element ); dialog.$body.append( content.$element ); }, setup( dialog ) { dialog.filesInput.setValue( '' ); dialog.reasonInput.setValue( '' ); }, async onSave( dialog ) { const filesText = dialog.filesInput.getValue().trim(); const reason = dialog.reasonInput.getValue().trim(); if ( !filesText ) { throw new Error( 'Please enter at least one filename.' ); } if ( !reason ) { throw new Error( 'Please enter a reason.' ); } const filenames = filesText.split( '\n' ).map( normalizeFilename ).filter( ( n ) => n.length > 0 ); if ( filenames.length === 0 ) { throw new Error( 'Please enter at least one valid filename.' ); } const entries = filenames.map( ( f ) => [ f, reason ] ); const added = await addBulkToBlacklist( entries ); mw.notify( `Successfully added ${added} file(s) to the blacklist.`, { type: 'success' } ); } } ); let windowManager = null; const showDialog = ( DialogClass, data ) => { if ( !windowManager ) { windowManager = new OO.ui.WindowManager(); $( document.body ).append( windowManager.$element ); } const dialog = new DialogClass( { size: 'medium' } ); windowManager.addWindows( [ dialog ] ); windowManager.openWindow( dialog, data || {} ); }; let selectedFiles = new Set(); let $selectAllCheckbox = null; let $removeSelectedBtn = null; const CELL_STYLE = { padding: '8px 12px', borderBottom: '1px solid var(--border-color-base)', verticalAlign: 'middle' }; const cellCss = ( overrides ) => Object.assign( {}, CELL_STYLE, overrides ); const createIconButton = ( icon, title, destructive ) => new OO.ui.ButtonWidget( { icon, title, framed: false, flags: destructive ? [ 'destructive' ] : [] } ); const confirmAndRun = async ( message, action, successMsg ) => { const confirmed = await OO.ui.confirm( message ); if ( !confirmed ) { return false; } try { const result = await action(); const msg = typeof successMsg === 'function' ? successMsg( result ) : successMsg; mw.notify( msg, { type: 'success' } ); return true; } catch ( error ) { mw.notify( error.message || String( error ), { type: 'error' } ); return false; } }; const updateRemoveSelectedButton = () => { if ( $removeSelectedBtn ) { $removeSelectedBtn.setDisabled( selectedFiles.size === 0 ); $removeSelectedBtn.setLabel( `Remove selected (${selectedFiles.size})` ); } }; const updateEntryCount = () => { $( '#audiobot-entry-count' ).text( `${blacklistStore.count()} file(s) in blacklist` ); }; const renderBlacklistTable = () => { if ( !$( '#audiobot-blacklist-controls' ).length ) { return; } const entries = blacklistStore.entries(); updateEntryCount(); $( '.mw-json' ).hide(); $( '#audiobot-blacklist-table' ).remove(); selectedFiles.clear(); $selectAllCheckbox = new OO.ui.CheckboxInputWidget(); $selectAllCheckbox.on( 'change', ( selected ) => { selectedFiles.clear(); $( '#audiobot-blacklist-table tbody tr' ).each( function () { const $checkbox = $( this ).find( '.oo-ui-checkboxInputWidget input' ); $checkbox.prop( 'checked', selected ).trigger( 'change' ); if ( selected ) { const filename = $( this ).data( 'filename' ); selectedFiles.add( filename ); } } ); updateRemoveSelectedButton(); } ); const $table = $( '<table>' ) .attr( 'id', 'audiobot-blacklist-table' ) .css( { width: '100%', borderCollapse: 'collapse', marginTop: '1em' } ); const formatAdded = ( iso ) => { if ( !iso ) { return ''; } const d = new Date( iso ); if ( isNaN( d.getTime() ) ) { return iso; } return d.toLocaleDateString( 'en-GB', { year: 'numeric', month: '2-digit', day: '2-digit' } ); }; const $thead = $( '<thead>' ).append( $( '<tr>' ).css( { backgroundColor: 'var(--background-color-interactive)' } ).append( $( '<th>' ).css( cellCss( { width: '40px', textAlign: 'center' } ) ).append( $selectAllCheckbox.$element ), $( '<th>' ).text( 'Filename' ).css( cellCss( { textAlign: 'left' } ) ), $( '<th>' ).text( 'Reason' ).css( cellCss( { textAlign: 'left' } ) ), $( '<th>' ).text( 'Added' ).css( cellCss( { width: '100px', textAlign: 'left' } ) ), $( '<th>' ).text( 'Actions' ).css( cellCss( { width: '100px', textAlign: 'center' } ) ) ) ); const $tbody = $( '<tbody>' ); for ( const [ filename, rawValue ] of entries ) { const reason = getEntryReason( rawValue ); const added = getEntryAdded( rawValue ); const checkbox = new OO.ui.CheckboxInputWidget(); checkbox.on( 'change', ( selected ) => { if ( selected ) { selectedFiles.add( filename ); } else { selectedFiles.delete( filename ); } updateRemoveSelectedButton(); } ); const editBtn = createIconButton( 'edit', 'Edit reason', false ); editBtn.on( 'click', () => showDialog( EditDialog, { filename, reason } ) ); const removeBtn = createIconButton( 'trash', 'Remove from blacklist', true ); removeBtn.on( 'click', () => confirmAndRun( `Remove "${filename}" from the blacklist?`, () => removeFromBlacklist( filename ), `Removed "${filename}" from the blacklist.` ) ); const $row = $( '<tr>' ).data( 'filename', filename ).append( $( '<td>' ).css( cellCss( { textAlign: 'center' } ) ).append( checkbox.$element ), $( '<td>' ).css( CELL_STYLE ).text( filename ), $( '<td>' ).css( CELL_STYLE ).text( reason ), $( '<td>' ).css( CELL_STYLE ).attr( 'title', added || '' ).text( formatAdded( added ) ), $( '<td>' ).css( cellCss( { textAlign: 'center', whiteSpace: 'nowrap' } ) ).append( editBtn.$element, removeBtn.$element ) ); $tbody.append( $row ); } $table.append( $thead, $tbody ); $( '#audiobot-blacklist-controls' ).after( $table ); }; const addBlacklistPageButtons = () => { const addButton = new OO.ui.ButtonWidget( { label: 'Add file', icon: 'add', flags: [ 'progressive' ] } ); addButton.on( 'click', () => showDialog( AddDialog ) ); const bulkAddButton = new OO.ui.ButtonWidget( { label: 'Bulk add', icon: 'add' } ); bulkAddButton.on( 'click', () => showDialog( BulkAddDialog ) ); $removeSelectedBtn = new OO.ui.ButtonWidget( { label: 'Remove selected (0)', icon: 'trash', flags: [ 'destructive' ], disabled: true } ); $removeSelectedBtn.on( 'click', () => { if ( selectedFiles.size === 0 ) { return; } confirmAndRun( `Remove ${selectedFiles.size} file(s) from the blacklist?`, () => removeBulkFromBlacklist( Array.from( selectedFiles ) ), ( removed ) => `Removed ${removed} file(s) from the blacklist.` ); } ); const $label = $( '<span>' ) .text( 'AudioBot Blacklist: ' ) .css( 'font-weight', 'bold' ); const $entryCount = $( '<span>' ) .attr( 'id', 'audiobot-entry-count' ) .css( { marginLeft: '1em', fontStyle: 'italic' } ) .text( 'Loading...' ); const $controls = $( '<div>' ) .attr( 'id', 'audiobot-blacklist-controls' ) .css( { marginBottom: '1em', padding: '0.5em 1em', backgroundColor: 'var(--background-color-neutral-subtle)', border: '1px solid var(--border-color-subtle)', borderRadius: '2px', color: 'var(--color-base)' } ) .append( $label, addButton.$element, ' ', bulkAddButton.$element, ' ', $removeSelectedBtn.$element, $entryCount ); $( '#mw-content-text' ).prepend( $controls ); renderBlacklistTable(); }; const addInlineBlacklistButtons = ( $content ) => { const $root = ( $content && $content.length ) ? $content : $( document ); for ( const table of $root.find( 'table.audiotable' ).toArray() ) { const $table = $( table ); const $player = $table.find( '[data-mwtitle]' ); if ( !$player.length ) { continue; } const filename = $player.attr( 'data-mwtitle' ); if ( !filename || $table.data( 'blacklistAdded' ) ) { continue; } $table.data( 'blacklistAdded', true ); const btn = createIconButton( 'block', 'Add to AudioBot blacklist', true ); btn.on( 'click', () => showDialog( AddDialog, { prefillFilename: normalizeFilename( filename ) } ) ); const $actionsCell = $( '<td>' ) .addClass( 'audio-actions' ) .css( { verticalAlign: 'middle' } ) .append( btn.$element ); $table.find( 'tr' ).first().append( $actionsCell ); } }; const init = async () => { try { await mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows', 'oojs-ui.styles.icons-moderation', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-interactions', 'mediawiki.api', 'mediawiki.ForeignApi' ] ); api = new mw.Api(); commonsApi = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' ); const userGroups = mw.config.get( 'wgUserGroups' ) || []; if ( !userGroups.includes( 'autoconfirmed' ) ) { return; } const prefs = mw.wiktGadgetPrefs.get( 'audiobot-blacklist', { label: { en: 'AudioBot Blacklist' } }, { showInlineButtons: { type: 'boolean', default: false, label: { en: 'Show inline blacklist buttons next to audio files' } } } ); AddDialog = createAddDialog(); EditDialog = createEditDialog(); BulkAddDialog = createBulkAddDialog(); const isBlacklistPage = mw.config.get( 'wgPageName' ) === BLACKLIST_PAGE.replace( / /g, '_' ); const isViewAction = mw.config.get( 'wgAction' ) === 'view'; const isDiff = mw.config.get( 'wgDiffOldId' ) || mw.config.get( 'wgDiffNewId' ); if ( isBlacklistPage && !isDiff ) { $( '#ca-edit, #ca-ve-edit' ).hide(); if ( isViewAction ) { await loadBlacklist(); blacklistStore.subscribe( () => { updateEntryCount(); renderBlacklistTable(); } ); addBlacklistPageButtons(); } } if ( prefs.showInlineButtons ) { mw.hook( 'wikipage.content' ).add( addInlineBlacklistButtons ); } } catch ( error ) { mw.log.error( 'AudioBot Blacklist gadget: failed', error ); } }; init(); }() ); 00dk55mkgf6r5lm0fgfxlj7b254k1ff MediaWiki:Gadget-OrangeLinks.js 8 17990 88982 2025-12-06T18:34:13Z en>Erutuon 0 make hook callback more versatile, handling $(document) or $(element) handed to wikipage.content hook, whether element is .mw-parser-content or parent or child of it; and don't makeLinksOrange in loop body 88982 javascript text/javascript // <nowiki> function HTML_unescape(text) { return new DOMParser().parseFromString(text, "text/html").body.textContent; } mw.util.addCSS(` .orange-link { color: var(--wikt-palette-gold); } .orange-link:visited { color: var(--wikt-palette-dullgold); } .orange-link:hover, .orange-link:visited:hover { color: var(--wikt-palette-honey); } `); const actionAPI = new mw.Api({ajax: {headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); // Maps each page title to a list of IDs. const pageIDsOf = new Map(); let count = 0; const linkTitles = new Set(); class OrangeLinker { constructor() { this.pagesToProcess = []; this.linksToProcess = []; } static getTitleAndAnchor(link) { const linkTitle = link.pathname.startsWith("/wiki/") ? decodeURIComponent(link.pathname.split("/wiki/")[1]) : new URLSearchParams(link.search).get("title"); const linkAnchor = decodeURIComponent(link.hash.slice(1) || ""); return [linkTitle, linkAnchor]; } addLink(link) { // Check whether the linked page is in the right domain // and whether the path starts with [[mw:Manual:$wgArticlePath]] // or goes to [[mw:Manual:$wgScript]] // and whether it exists and has not already been processed by makeLinksOrange. if (!(link.hostname === "en.wiktionary.org" && (link.pathname.startsWith("/wiki/") || link.pathname === "/" /* This covers links without / after en.wiktionary.org */ || link.pathname === "/w" || link.pathname === "/w/" || link.pathname === "/w/index.php") && !link.matches(".orange-link, .not-orange-link, .new"))) return; const [linkTitle, linkAnchor] = OrangeLinker.getTitleAndAnchor(link); if (!(linkTitle && linkAnchor) || /^[a-z]/.test(linkAnchor) // Only handle links to main, Appendix, Reconstruction namespaces. || ![0, 100, 118].includes(new mw.Title(linkTitle).namespace)) return; if (!linkTitles.has(linkTitle)) { this.pagesToProcess.push(linkTitle); linkTitles.add(linkTitle); } this.linksToProcess.push(link); } addLinksInElement(element) { for (const link of element.querySelectorAll("a")) { this.addLink(link); } } async makeLinksOrange() { if (this.linksToProcess.length === 0) return; // Process links in small enough chunks that [[Module:get IDs]] // doesn't hit a timeout error. // There should be no duplicates because we check linkTitles before // adding a link. const queries = []; for (let i = 0; i < this.pagesToProcess.length; i += 100) { const pageTitles = this.pagesToProcess.slice(i, i + 100); // If there are no titles to query, create an empty set of promises // and immediately start oranging links. if (pageTitles.length === 0) break; count++; console.info("OrangeLinks request #" + count + " for " + pageTitles.join(", ")); // Query the IDs for all the pages using [[Module:get IDs]]. const params = { action: "expandtemplates", format: "json", prop: "wikitext", text: `{{#invoke:get IDs|show|${pageTitles.join("|")}}}`, }; queries.push(actionAPI.post(params).then(response => { // Integrate the results into `pageIDsOf`. const pageIDs = HTML_unescape(response.expandtemplates.wikitext).split("\n\n"); for (let j = 0; j < pageTitles.length; j++) pageIDsOf.set(pageTitles[j], pageIDs[j].split(" ")); })); } // After all the queries have returned, determine whether each link needs to be orange. await Promise.all(queries); for (const link of this.linksToProcess) { const [linkTitle, linkAnchor] = OrangeLinker.getTitleAndAnchor(link); const existingAnchors = pageIDsOf.get(linkTitle); const anchorExists = existingAnchors instanceof Array && existingAnchors.includes(linkAnchor); link.classList.add(anchorExists ? "not-orange-link" : "orange-link"); } this.pagesToProcess = []; this.linksToProcess = []; } } // Activate the gadget. mw.hook("wikipage.content").add($content => { var orangeLinker = new OrangeLinker(); for (const element of $content) { if (!(element instanceof Element || element instanceof Document)) continue; const parserOutput = element.querySelector(".mw-parser-output"); if (parserOutput) { orangeLinker.addLinksInElement(parserOutput); } else if (element.matches(".mw-parser-output, .mw-parser-output *")) { if (element.tagName === "A") { orangeLinker.addLink(element); } else { orangeLinker.addLinksInElement(element); } } } orangeLinker.makeLinksOrange(); }); // Create a global hook in case any other gadget or script would like to activate it. window.OrangeLinker = OrangeLinker; // </nowiki> 15b9o6bccse18zbj9bz81anab6u3dq5 88983 88982 2026-08-06T23:24:32Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-OrangeLinks.js]] 88982 javascript text/javascript // <nowiki> function HTML_unescape(text) { return new DOMParser().parseFromString(text, "text/html").body.textContent; } mw.util.addCSS(` .orange-link { color: var(--wikt-palette-gold); } .orange-link:visited { color: var(--wikt-palette-dullgold); } .orange-link:hover, .orange-link:visited:hover { color: var(--wikt-palette-honey); } `); const actionAPI = new mw.Api({ajax: {headers: {"Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); // Maps each page title to a list of IDs. const pageIDsOf = new Map(); let count = 0; const linkTitles = new Set(); class OrangeLinker { constructor() { this.pagesToProcess = []; this.linksToProcess = []; } static getTitleAndAnchor(link) { const linkTitle = link.pathname.startsWith("/wiki/") ? decodeURIComponent(link.pathname.split("/wiki/")[1]) : new URLSearchParams(link.search).get("title"); const linkAnchor = decodeURIComponent(link.hash.slice(1) || ""); return [linkTitle, linkAnchor]; } addLink(link) { // Check whether the linked page is in the right domain // and whether the path starts with [[mw:Manual:$wgArticlePath]] // or goes to [[mw:Manual:$wgScript]] // and whether it exists and has not already been processed by makeLinksOrange. if (!(link.hostname === "en.wiktionary.org" && (link.pathname.startsWith("/wiki/") || link.pathname === "/" /* This covers links without / after en.wiktionary.org */ || link.pathname === "/w" || link.pathname === "/w/" || link.pathname === "/w/index.php") && !link.matches(".orange-link, .not-orange-link, .new"))) return; const [linkTitle, linkAnchor] = OrangeLinker.getTitleAndAnchor(link); if (!(linkTitle && linkAnchor) || /^[a-z]/.test(linkAnchor) // Only handle links to main, Appendix, Reconstruction namespaces. || ![0, 100, 118].includes(new mw.Title(linkTitle).namespace)) return; if (!linkTitles.has(linkTitle)) { this.pagesToProcess.push(linkTitle); linkTitles.add(linkTitle); } this.linksToProcess.push(link); } addLinksInElement(element) { for (const link of element.querySelectorAll("a")) { this.addLink(link); } } async makeLinksOrange() { if (this.linksToProcess.length === 0) return; // Process links in small enough chunks that [[Module:get IDs]] // doesn't hit a timeout error. // There should be no duplicates because we check linkTitles before // adding a link. const queries = []; for (let i = 0; i < this.pagesToProcess.length; i += 100) { const pageTitles = this.pagesToProcess.slice(i, i + 100); // If there are no titles to query, create an empty set of promises // and immediately start oranging links. if (pageTitles.length === 0) break; count++; console.info("OrangeLinks request #" + count + " for " + pageTitles.join(", ")); // Query the IDs for all the pages using [[Module:get IDs]]. const params = { action: "expandtemplates", format: "json", prop: "wikitext", text: `{{#invoke:get IDs|show|${pageTitles.join("|")}}}`, }; queries.push(actionAPI.post(params).then(response => { // Integrate the results into `pageIDsOf`. const pageIDs = HTML_unescape(response.expandtemplates.wikitext).split("\n\n"); for (let j = 0; j < pageTitles.length; j++) pageIDsOf.set(pageTitles[j], pageIDs[j].split(" ")); })); } // After all the queries have returned, determine whether each link needs to be orange. await Promise.all(queries); for (const link of this.linksToProcess) { const [linkTitle, linkAnchor] = OrangeLinker.getTitleAndAnchor(link); const existingAnchors = pageIDsOf.get(linkTitle); const anchorExists = existingAnchors instanceof Array && existingAnchors.includes(linkAnchor); link.classList.add(anchorExists ? "not-orange-link" : "orange-link"); } this.pagesToProcess = []; this.linksToProcess = []; } } // Activate the gadget. mw.hook("wikipage.content").add($content => { var orangeLinker = new OrangeLinker(); for (const element of $content) { if (!(element instanceof Element || element instanceof Document)) continue; const parserOutput = element.querySelector(".mw-parser-output"); if (parserOutput) { orangeLinker.addLinksInElement(parserOutput); } else if (element.matches(".mw-parser-output, .mw-parser-output *")) { if (element.tagName === "A") { orangeLinker.addLink(element); } else { orangeLinker.addLinksInElement(element); } } } orangeLinker.makeLinksOrange(); }); // Create a global hook in case any other gadget or script would like to activate it. window.OrangeLinker = OrangeLinker; // </nowiki> 15b9o6bccse18zbj9bz81anab6u3dq5 MediaWiki:Gadget-U2693.js 8 17991 88984 2025-09-17T22:39:01Z en>Ioaxxere 0 [[mw:Migrating mw.Uri to URL]] 88984 javascript text/javascript /* jshint undef:true, latedef:true, shadow:true, boss:true, scripturl:true */ /* global mw, jQuery */ // <nowiki> "use strict"; mw.loader.using(["mediawiki.util"]).then(() => $(function() { var curRevisionId = mw.config.get("wgCurRevisionId"); function createAnchorLink(label, href, wikilink, title) { var span = document.createElement("span"); var link = document.createElement("a"); link.href = href; link.addEventListener( "click", function(ev) { ev.preventDefault(); // IE if (window.clipboardData && window.clipboardData.setData) { window.clipboardData.setData("text", wikilink); mw.util.jsMessage("Wikitext copied to the clipboard."); return; } // XXX: there is a brand new shiny ClipboardEvent API, but I could not get it to work on my browser. // plus, there is no graceful fallback if it fails to work. going back to good ol' prompt(). prompt("Hit Ctrl-C to copy this to your clipboard", wikilink); }, false ); link.appendChild(document.createTextNode(label)); link.title = title; span.appendChild(document.createTextNode("[")); span.appendChild(link); span.appendChild(document.createTextNode("]")); span.className = "mw-editsection-like anchor-gadget-link"; return span; } // XXX: not ideal; it may over-unescape things, but it usually works as intended function unescapeAnchor(anchor) { anchor = anchor.replace(/_/g, " "); try { return decodeURIComponent( anchor.replace(/\.([0-9A-F][0-9A-F])/g, "%$1") ); } catch (e) { return anchor; } } function forEachHeader(callback) { var headers = document.querySelectorAll( ".mw-heading > h2, .mw-heading > h3, .mw-heading > h4, .mw-heading > h5, .mw-heading > h6, .mw-headline" ); for (var i = 0; i < headers.length; ++i) { var links = headers[i].parentNode.getElementsByTagName("a"); var title = null; for (var j = 0; j < links.length; ++j) { try { var u = new URL(links[j].href); if ( u.hostname === location.host && u.pathname === mw.config.get("wgScript") && u.searchParams.get("action") === "edit" && !u.searchParams.get("redlink") ) { title = new mw.Title(u.searchParams.get("title")); } } catch (e) { /* screw it */ } } if (!title) continue; callback(headers[i], title); } } function getRevInfo(oldid, callback) { // XXX: of course I have it right on the page, but I cannot rely on it being in any particular format. // hence wasting bandwidth on an API request. mw.loader.using(["mediawiki.api", "mediawiki.util"], function() { var api = new mw.Api(); api .get({ action: "query", pageids: mw.config.get("wgArticleId"), prop: "revisions", rvprop: "user|timestamp", rvstartid: oldid, rvlimit: 1, }) .then(function(result) { var revobj = result.query.pages[mw.config.get("wgArticleId")].revisions[0]; callback(revobj); }); }); } function createUnsignedLink(revobj) { var userpart = (mw.util.isIPv4Address(revobj.user) || mw.util.isIPv6Address(revobj.user) ? "{{unsigned-ip|" : "{{unsigned|") + revobj.user; var datepart = "}}"; var m; if ( (m = /^(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/.exec( revobj.timestamp )) ) { var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; datepart = "|" + m[4] + ":" + m[5] + ", " + m[3].replace(/^0+/, "") + " " + monthNames[parseInt(m[2], 10) - 1] + " " + m[1] + " (UTC)}}"; } return createAnchorLink( "✎", "javascript:void window.warranty", userpart + datepart, "{{unsigned}}" ); } if (mw.config.get("wgAction") !== "view") return; mw.util.addCSS( ".anchor-gadget-link { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; }" ); if (mw.util.getParamValue("diff")) { // viewing a diff var oldid, newid; var ot = document.getElementById("mw-diff-otitle1"); var nt = document.getElementById("mw-diff-ntitle1"); if (ot) { ot = new URL(ot.getElementsByTagName("a")[0].href); oldid = ot.searchParams.get("oldid"); } if (nt) { nt = new URL(nt.getElementsByTagName("a")[0].href); newid = nt.searchParams.get("oldid"); } document .getElementById("firstHeading") .appendChild( createAnchorLink( "⚓", mw.config.get("wgScript") + "?oldid=" + oldid + "&diff=" + newid, "[[Special:Diff/" + oldid + "/" + newid + "]]", "Link to this diff" ) ); if ( document.getElementsByClassName("diffmulti").length === 0 && mw.config.get("wgArticleId") ) { getRevInfo(newid, function(revobj) { document .getElementById("firstHeading") .appendChild(createUnsignedLink(revobj)); }); } } else if (mw.util.getParamValue("oldid") || curRevisionId) { // viewing an old page revision var oldid = mw.util.getParamValue("oldid") || curRevisionId; document .getElementById("firstHeading") .appendChild( createAnchorLink( "⚓", mw.config.get("wgScript") + "?oldid=" + oldid, "[[Special:Permalink/" + oldid + "]]", "Link to this revision" ) ); getRevInfo(oldid, function(revobj) { document .getElementById("firstHeading") .appendChild(createUnsignedLink(revobj)); }); } if ( mw.config.get("wgRevisionId") === curRevisionId && // 100 = appendix, 114 = citations [0, 100, 114].indexOf(mw.config.get("wgNamespaceNumber")) === -1 ) { forEachHeader(function(header, title) { var anchorLink = createAnchorLink( "⚓", mw.util.getUrl(title.getPrefixedDb()) + "#" + header.id, "[[" + title.getPrefixedText() + "#" + unescapeAnchor(header.id) + "]]" ); var editSectionLink = header.parentNode.querySelector(".mw-editsection"); if (editSectionLink) { header.parentNode.insertBefore( anchorLink, editSectionLink.nextSibling ); } else { header.parentNode.appendChild(anchorLink); } }); } }) ); // </nowiki> 3r6xwafb4slilr2bjt7unh1dp2j1dru 88985 88984 2026-08-06T23:24:41Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-U2693.js]] 88984 javascript text/javascript /* jshint undef:true, latedef:true, shadow:true, boss:true, scripturl:true */ /* global mw, jQuery */ // <nowiki> "use strict"; mw.loader.using(["mediawiki.util"]).then(() => $(function() { var curRevisionId = mw.config.get("wgCurRevisionId"); function createAnchorLink(label, href, wikilink, title) { var span = document.createElement("span"); var link = document.createElement("a"); link.href = href; link.addEventListener( "click", function(ev) { ev.preventDefault(); // IE if (window.clipboardData && window.clipboardData.setData) { window.clipboardData.setData("text", wikilink); mw.util.jsMessage("Wikitext copied to the clipboard."); return; } // XXX: there is a brand new shiny ClipboardEvent API, but I could not get it to work on my browser. // plus, there is no graceful fallback if it fails to work. going back to good ol' prompt(). prompt("Hit Ctrl-C to copy this to your clipboard", wikilink); }, false ); link.appendChild(document.createTextNode(label)); link.title = title; span.appendChild(document.createTextNode("[")); span.appendChild(link); span.appendChild(document.createTextNode("]")); span.className = "mw-editsection-like anchor-gadget-link"; return span; } // XXX: not ideal; it may over-unescape things, but it usually works as intended function unescapeAnchor(anchor) { anchor = anchor.replace(/_/g, " "); try { return decodeURIComponent( anchor.replace(/\.([0-9A-F][0-9A-F])/g, "%$1") ); } catch (e) { return anchor; } } function forEachHeader(callback) { var headers = document.querySelectorAll( ".mw-heading > h2, .mw-heading > h3, .mw-heading > h4, .mw-heading > h5, .mw-heading > h6, .mw-headline" ); for (var i = 0; i < headers.length; ++i) { var links = headers[i].parentNode.getElementsByTagName("a"); var title = null; for (var j = 0; j < links.length; ++j) { try { var u = new URL(links[j].href); if ( u.hostname === location.host && u.pathname === mw.config.get("wgScript") && u.searchParams.get("action") === "edit" && !u.searchParams.get("redlink") ) { title = new mw.Title(u.searchParams.get("title")); } } catch (e) { /* screw it */ } } if (!title) continue; callback(headers[i], title); } } function getRevInfo(oldid, callback) { // XXX: of course I have it right on the page, but I cannot rely on it being in any particular format. // hence wasting bandwidth on an API request. mw.loader.using(["mediawiki.api", "mediawiki.util"], function() { var api = new mw.Api(); api .get({ action: "query", pageids: mw.config.get("wgArticleId"), prop: "revisions", rvprop: "user|timestamp", rvstartid: oldid, rvlimit: 1, }) .then(function(result) { var revobj = result.query.pages[mw.config.get("wgArticleId")].revisions[0]; callback(revobj); }); }); } function createUnsignedLink(revobj) { var userpart = (mw.util.isIPv4Address(revobj.user) || mw.util.isIPv6Address(revobj.user) ? "{{unsigned-ip|" : "{{unsigned|") + revobj.user; var datepart = "}}"; var m; if ( (m = /^(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/.exec( revobj.timestamp )) ) { var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; datepart = "|" + m[4] + ":" + m[5] + ", " + m[3].replace(/^0+/, "") + " " + monthNames[parseInt(m[2], 10) - 1] + " " + m[1] + " (UTC)}}"; } return createAnchorLink( "✎", "javascript:void window.warranty", userpart + datepart, "{{unsigned}}" ); } if (mw.config.get("wgAction") !== "view") return; mw.util.addCSS( ".anchor-gadget-link { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; }" ); if (mw.util.getParamValue("diff")) { // viewing a diff var oldid, newid; var ot = document.getElementById("mw-diff-otitle1"); var nt = document.getElementById("mw-diff-ntitle1"); if (ot) { ot = new URL(ot.getElementsByTagName("a")[0].href); oldid = ot.searchParams.get("oldid"); } if (nt) { nt = new URL(nt.getElementsByTagName("a")[0].href); newid = nt.searchParams.get("oldid"); } document .getElementById("firstHeading") .appendChild( createAnchorLink( "⚓", mw.config.get("wgScript") + "?oldid=" + oldid + "&diff=" + newid, "[[Special:Diff/" + oldid + "/" + newid + "]]", "Link to this diff" ) ); if ( document.getElementsByClassName("diffmulti").length === 0 && mw.config.get("wgArticleId") ) { getRevInfo(newid, function(revobj) { document .getElementById("firstHeading") .appendChild(createUnsignedLink(revobj)); }); } } else if (mw.util.getParamValue("oldid") || curRevisionId) { // viewing an old page revision var oldid = mw.util.getParamValue("oldid") || curRevisionId; document .getElementById("firstHeading") .appendChild( createAnchorLink( "⚓", mw.config.get("wgScript") + "?oldid=" + oldid, "[[Special:Permalink/" + oldid + "]]", "Link to this revision" ) ); getRevInfo(oldid, function(revobj) { document .getElementById("firstHeading") .appendChild(createUnsignedLink(revobj)); }); } if ( mw.config.get("wgRevisionId") === curRevisionId && // 100 = appendix, 114 = citations [0, 100, 114].indexOf(mw.config.get("wgNamespaceNumber")) === -1 ) { forEachHeader(function(header, title) { var anchorLink = createAnchorLink( "⚓", mw.util.getUrl(title.getPrefixedDb()) + "#" + header.id, "[[" + title.getPrefixedText() + "#" + unescapeAnchor(header.id) + "]]" ); var editSectionLink = header.parentNode.querySelector(".mw-editsection"); if (editSectionLink) { header.parentNode.insertBefore( anchorLink, editSectionLink.nextSibling ); } else { header.parentNode.appendChild(anchorLink); } }); } }) ); // </nowiki> 3r6xwafb4slilr2bjt7unh1dp2j1dru MediaWiki:Gadget-MoreMenu-local.js 8 17992 88986 2023-09-11T01:23:07Z en>Erutuon 0 make it easier to load [[m:MoreMenu]] 88986 javascript text/javascript mw.loader.load('https://meta.wikimedia.org/w/load.php?modules=ext.gadget.MoreMenu'); 4a8nztnsxwdkzojyvj6omx0u6wdapgy 88987 88986 2026-08-06T23:25:00Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-MoreMenu-local.js]] 88986 javascript text/javascript mw.loader.load('https://meta.wikimedia.org/w/load.php?modules=ext.gadget.MoreMenu'); 4a8nztnsxwdkzojyvj6omx0u6wdapgy MediaWiki:Gadget-categoryTreeLanguageNames.js 8 17993 88988 2024-10-13T06:15:16Z en>Ioaxxere 0 convert to ES6 style 88988 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> /* global mw */ (function categoryTreeLanguageNamesGadget() { const ALLOWED_NAMESPACES = [ 0, // Main 14, // Category 100, // Appendix 118 // Reconstruction ]; const CATEGORY_PREFIX = mw.config.get("wgFormattedNamespaces")[14] + ":"; function getLanguageCodeToCanonicalName() { const CACHE_DURATION = 24 * 60 * 60; // 24 hours const KEY = "enwiktLanguageCodeToCanonicalNameJson"; let timeNow = new Date().getTime() * 1e-3; try { let cachedData = JSON.parse(localStorage.getItem(KEY)); if (timeNow - cachedData.timestamp < CACHE_DURATION) return Promise.resolve(cachedData.data); } catch (e) { } const actionAPI = new mw.Api({ ajax: { headers: { "Api-User-Agent": "Gadget developed by [[User:Surjection]]" } } }); return actionAPI.get({ "action": "parse", "page": "Module:languages/code to canonical name.json", "prop": "wikitext", "formatversion": "2", "format": "json" }) .then(response => { let languageData = JSON.parse(response.parse.wikitext); localStorage.setItem(KEY, JSON.stringify({ timestamp: timeNow, data: languageData })); return languageData; }); } function addCategoryTreeLanguageName(codeToCanonicalName, catElement, doNotTagLanguageCode) { // not a category link/name if (!catElement.href.includes(CATEGORY_PREFIX)) return; // do not duplicate if (catElement.querySelector(".wikt-category-tree-language-name")) return; let firstTextNode = Array.from(catElement.childNodes).find(node => node.nodeType === Node.TEXT_NODE); if (!firstTextNode) return; let categoryName = firstTextNode.textContent; let parseCategoryTreeName = categoryName.match(/^([a-z-]+):(.+)/); if (!parseCategoryTreeName) return; let languageCode = parseCategoryTreeName[1]; let subcategoryName = parseCategoryTreeName[2]; let canonicalName = codeToCanonicalName[languageCode]; if (!canonicalName) return; if (catElement.title === categoryName || catElement.title === CATEGORY_PREFIX + categoryName) catElement.title += ` [${canonicalName}: ${subcategoryName}]`; if (languageCode !== doNotTagLanguageCode) { let langElement = document.createElement("span"); langElement.className = "wikt-category-tree-language-name"; langElement.textContent = ` [${canonicalName}]`; catElement.append(langElement); } } mw.hook("wikipage.content").add(() => { if (mw.config.get("wgAction") === "view" && ALLOWED_NAMESPACES.includes(mw.config.get("wgNamespaceNumber"))) { mw.util.addCSS(` .wikt-category-tree-language-name { font-size: 85%; } `); let thisLanguageCode = null; if (mw.config.get("wgNamespaceNumber") === 14) { let categoryName = mw.config.get("wgTitle"); let parseCategoryTreeName = categoryName.match(/^([a-z-]+):(.+)/); if (parseCategoryTreeName) thisLanguageCode = parseCategoryTreeName[1]; } getLanguageCodeToCanonicalName().then(codeToCanonicalName => { for (let catElement of document.querySelectorAll("#catlinks ul > li a")) addCategoryTreeLanguageName(codeToCanonicalName, catElement, thisLanguageCode); if (mw.config.get("wgNamespaceNumber") === 14) { for (let catElement of document.querySelectorAll("#mw-subcategories a")) addCategoryTreeLanguageName(codeToCanonicalName, catElement, thisLanguageCode); } }); } }); })(); // </nowiki> f17fgeickevfnz8qtgra6lmbjihrfci 88989 88988 2026-08-06T23:26:06Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-categoryTreeLanguageNames.js]] 88988 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> /* global mw */ (function categoryTreeLanguageNamesGadget() { const ALLOWED_NAMESPACES = [ 0, // Main 14, // Category 100, // Appendix 118 // Reconstruction ]; const CATEGORY_PREFIX = mw.config.get("wgFormattedNamespaces")[14] + ":"; function getLanguageCodeToCanonicalName() { const CACHE_DURATION = 24 * 60 * 60; // 24 hours const KEY = "enwiktLanguageCodeToCanonicalNameJson"; let timeNow = new Date().getTime() * 1e-3; try { let cachedData = JSON.parse(localStorage.getItem(KEY)); if (timeNow - cachedData.timestamp < CACHE_DURATION) return Promise.resolve(cachedData.data); } catch (e) { } const actionAPI = new mw.Api({ ajax: { headers: { "Api-User-Agent": "Gadget developed by [[User:Surjection]]" } } }); return actionAPI.get({ "action": "parse", "page": "Module:languages/code to canonical name.json", "prop": "wikitext", "formatversion": "2", "format": "json" }) .then(response => { let languageData = JSON.parse(response.parse.wikitext); localStorage.setItem(KEY, JSON.stringify({ timestamp: timeNow, data: languageData })); return languageData; }); } function addCategoryTreeLanguageName(codeToCanonicalName, catElement, doNotTagLanguageCode) { // not a category link/name if (!catElement.href.includes(CATEGORY_PREFIX)) return; // do not duplicate if (catElement.querySelector(".wikt-category-tree-language-name")) return; let firstTextNode = Array.from(catElement.childNodes).find(node => node.nodeType === Node.TEXT_NODE); if (!firstTextNode) return; let categoryName = firstTextNode.textContent; let parseCategoryTreeName = categoryName.match(/^([a-z-]+):(.+)/); if (!parseCategoryTreeName) return; let languageCode = parseCategoryTreeName[1]; let subcategoryName = parseCategoryTreeName[2]; let canonicalName = codeToCanonicalName[languageCode]; if (!canonicalName) return; if (catElement.title === categoryName || catElement.title === CATEGORY_PREFIX + categoryName) catElement.title += ` [${canonicalName}: ${subcategoryName}]`; if (languageCode !== doNotTagLanguageCode) { let langElement = document.createElement("span"); langElement.className = "wikt-category-tree-language-name"; langElement.textContent = ` [${canonicalName}]`; catElement.append(langElement); } } mw.hook("wikipage.content").add(() => { if (mw.config.get("wgAction") === "view" && ALLOWED_NAMESPACES.includes(mw.config.get("wgNamespaceNumber"))) { mw.util.addCSS(` .wikt-category-tree-language-name { font-size: 85%; } `); let thisLanguageCode = null; if (mw.config.get("wgNamespaceNumber") === 14) { let categoryName = mw.config.get("wgTitle"); let parseCategoryTreeName = categoryName.match(/^([a-z-]+):(.+)/); if (parseCategoryTreeName) thisLanguageCode = parseCategoryTreeName[1]; } getLanguageCodeToCanonicalName().then(codeToCanonicalName => { for (let catElement of document.querySelectorAll("#catlinks ul > li a")) addCategoryTreeLanguageName(codeToCanonicalName, catElement, thisLanguageCode); if (mw.config.get("wgNamespaceNumber") === 14) { for (let catElement of document.querySelectorAll("#mw-subcategories a")) addCategoryTreeLanguageName(codeToCanonicalName, catElement, thisLanguageCode); } }); } }); })(); // </nowiki> f17fgeickevfnz8qtgra6lmbjihrfci MediaWiki:Gadget-Streamline.js 8 17994 88990 2026-04-28T15:50:09Z en>Surjection 0 88990 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> /*jshint strict:true, undef:true, latedef:true, esversion:6 */ /* global mw, createNavToggle */ const STREAMLINE_SYMBOL = "⌰"; // [[MediaWiki:Gadget-WiktGadgetPrefs.js]] const preferences = mw.wiktGadgetPrefs.get( "streamline", { label: { en: "Streamline", }, }, { collapseElements: { "type": "strenum", "default": "aboveDefinitions", "label": { "en": "Elements to collapse" }, "choices": [ "aboveDefinitions", "allExceptNotes" ], "choiceLabels": { "en": { "aboveDefinitions": "Sections before definitions", "allExceptNotes": "Sections before and after definitions" } } }, runInReconstructions: { "type": "boolean", "default": true, "label": { "en": "Apply also to reconstruction pages" } } } ); function makeNavFrame(heading, editLinks, toggleCat, contents) { // now make a collapsible box const navHead = document.createElement("div"); navHead.className = "NavHead"; navHead.style.cursor = "pointer"; navHead.style.fontSize = "1.1em"; const navContent = document.createElement("div"); navContent.className = "NavContent boxcontent streamline-boxcontent"; navContent.style.textAlign = "left"; const navFrame = document.createElement("div"); navFrame.className = "NavFrame NavFrame-streamline"; if (toggleCat) navFrame.setAttribute("data-toggle-category", toggleCat); navFrame.style.display = "block"; navFrame.append(navHead, navContent); navHead.append(`${STREAMLINE_SYMBOL} ${heading}`); try { if (createNavToggle) createNavToggle(navFrame); } catch (e) { } if (editLinks) { navContent.append(editLinks); editLinks.style.float = "right"; // try displaying the edit links next to the show button editLinks.style.marginTop = "-1.5em"; editLinks.style.marginRight = "8ch"; } navContent.append(...contents); return navFrame; } function isNavFrameOpen(frame) { const content = frame.querySelector(".NavContent"); if (!content) return false; const computedStyle = window.getComputedStyle(content); if (!computedStyle) return false; return computedStyle.display !== "none"; } function openNavFrame(frame) { if (!isNavFrameOpen(frame)) { const navHead = frame.querySelector(".NavHead"); if (navHead) navHead.click(); } } function anchorInUrl(anchor) { if (window.location.hash) { return window.location.hash.replace(/^#/, "") === anchor; } return false; } function hasElementClass(element, className) { return element.classList.contains(className); } function shouldEndCollapsible(element) { return element.matches("h1, h2, h3, h4, h5, h6, hr") // end on heading or horizontal line || hasElementClass(element, "NavFrame-streamline") // no nested streamline navboxes || hasElementClass(element, "mw-heading") // section heading || element.matches("section") // Parsoid ; // this is on its own line so that it's easier to add new rules } function shouldExcludeFromCollapsible(element) { return hasElementClass(element, "thumb") // images || hasElementClass(element, "sister-project") // sister project box || hasElementClass(element, "kanji-table") // ja-kanjitab || hasElementClass(element, "floatright") // various tables || hasElementClass(element, "template-anchor") // anchor || hasElementClass(element, "t-thumbs-outer") // thumbs || hasElementClass(element, "interproject-box") // interwiki boxes || hasElementClass(element, "normalized-box") // {{normalized}} || hasElementClass(element, "chemical-element-box") // {{chemical element box}} || element.getAttribute("typeof") === "mw:File/Thumb" // new floating image boxes || hasElementClass(element, "mw-halign-right") // mw-halign-right, by new floating image boxes || element.getAttribute("align") === "right" // anything that (explicitly) aligns || element.style.float === "right" // anything that (explicitly) floats || element.matches("style") // TemplateStyles ; // this is on its own line so that it's easier to add new rules } // Applies only to numbered etymologies. function shouldDisplayBeforeCollapsible(element) { return hasElementClass(element, "normalized-box") // {{normalized}} ; // this is on its own line so that it's easier to add new rules } function shouldCollapseForTheSakeOf(element) { if (element.nodeType === 1) { // don't collapse for the sake of senseid or etymid alone if (element.matches(".senseid, .etymid")) return false; if (element.matches("p, div, span")) return Array.prototype.some.call(element.childNodes, shouldCollapseForTheSakeOf); return element.tagName !== "BR"; } else if (element.nodeType === 3) { return !!element.textContent.trim(); // only if not entirely whitespace } else { return false; } } function getHeadingQuery(onlyL3) { return (onlyL3 ? ["h2", "h3"] : ["h2", "h3", "h4", "h5"]) .map(heading => `#mw-content-text ${heading}`) .join(", "); } const navFramesById = {}; function collapseHeadingInNavbox(headingCandidate, heading, toggleCat, headingMatcher, addEditLinks) { let headingId; const hl = headingCandidate.querySelector(".mw-headline"); if (hl && headingMatcher(hl.textContent)) headingId = hl.id; // Parsoid if (hasElementClass(headingCandidate.parentElement, "mw-heading") && headingMatcher(headingCandidate.textContent)) { headingId = headingCandidate.id; headingCandidate = headingCandidate.parentElement; } if (!headingId) return [undefined, undefined]; // pick all elements until next heading const contents = []; let nx = headingCandidate.nextElementSibling; let collapse = false; while (nx) { if (shouldEndCollapsible(nx) || nx.querySelector(".NavFrame-streamline")) break; if (!shouldExcludeFromCollapsible(nx)) { contents.push(nx); collapse = collapse || shouldCollapseForTheSakeOf(nx); } nx = nx.nextElementSibling; } if (!collapse) return [undefined, undefined]; const navFrame = makeNavFrame(heading, addEditLinks ? headingCandidate.querySelector(".mw-editsection") : null, toggleCat, contents); navFrame.id = headingId; navFramesById[navFrame.id] = navFrame; return [navFrame, headingCandidate]; } function makeSingleCollapsible(heading, toggleCat, onlyL3) { document.querySelectorAll(getHeadingQuery(onlyL3)).forEach((e) => { const [navFrame, headingElement] = collapseHeadingInNavbox(e, heading, toggleCat, (headingText) => headingText === heading, true); if (navFrame) headingElement.parentNode.replaceChild(navFrame, headingElement); }); } function makeNumberedCollapsible(heading, toggleCat) { const re = new RegExp("^" + heading + " \\d+(?:\.\\d+)?$"); document.querySelectorAll(getHeadingQuery(false)).forEach((e) => { const [navFrame, headingElement] = collapseHeadingInNavbox(e, heading, toggleCat, (headingText) => headingText.match(re), false); if (navFrame) { let toInsertBefore = headingElement.nextElementSibling; while (toInsertBefore && shouldDisplayBeforeCollapsible(toInsertBefore)) toInsertBefore = toInsertBefore.nextElementSibling; headingElement.parentNode.insertBefore(navFrame, toInsertBefore); } }); } function moveAnagrams() { // move the Anagrams box above Further reading and References document.querySelectorAll(".NavFrame[data-toggle-category=\"anagrams\"]").forEach((e) => { let p = e.previousElementSibling; while (p) { if (p.tagName === "H2") { break; } if (p.tagName === "H3") { const hl = p.querySelector(".mw-headline"); if (hl && (hl.textContent === "Further reading" || hl.textContent === "References")) { e.parentElement.insertBefore(e, p); } } p = p.previousElementSibling; } }); } function addGaps() { // add gaps before streamline navboxes if preceded by certain elements document.querySelectorAll(".NavFrame-streamline").forEach((sl) => { const prev = sl.previousElementSibling; const next = sl.nextElementSibling; let tn; if (prev) { tn = prev.tagName; if (tn === "OL" || tn === "UL") { sl.style.marginTop = "1em"; } } if (next) { tn = next.tagName; if (tn === "HR") { sl.style.marginBottom = "1em"; } } }); } function defaultStreamline() { makeSingleCollapsible("Alternative forms", "alternative forms", true); makeSingleCollapsible("Alternative reconstructions", "alternative reconstructions", true); makeSingleCollapsible("Etymology", "etymology"); makeSingleCollapsible("Glyph origin", "etymology"); makeSingleCollapsible("Description", "description"); makeSingleCollapsible("Pronunciation", "pronunciations"); makeSingleCollapsible("Production", "productions"); makeNumberedCollapsible("Etymology", "etymology"); makeNumberedCollapsible("Pronunciation", "pronunciations"); makeNumberedCollapsible("Production", "productions"); addGaps(); } function superStreamline() { makeSingleCollapsible("Alternative forms", "alternative forms", false); makeSingleCollapsible("Alternative reconstructions", "alternative reconstructions", false); makeSingleCollapsible("Inflection", "inflection"); makeSingleCollapsible("Declension", "inflection"); makeSingleCollapsible("Conjugation", "inflection"); makeSingleCollapsible("Mutation", "mutation"); makeSingleCollapsible("Synonyms", "synonyms"); makeSingleCollapsible("Antonyms", "antonyms"); makeSingleCollapsible("Hypernyms", "hypernyms"); makeSingleCollapsible("Hyponyms", "hyponyms"); makeSingleCollapsible("Meronyms", "meronyms"); makeSingleCollapsible("Holonyms", "holonyms"); makeSingleCollapsible("Troponyms", "troponyms"); makeSingleCollapsible("Coordinate terms", "coordinate terms"); makeSingleCollapsible("Derived terms", "derived terms"); makeSingleCollapsible("Compounds", "derived terms"); makeSingleCollapsible("Related terms", "related terms"); makeSingleCollapsible("Collocations", "collocations"); makeSingleCollapsible("Descendants", "descendants"); makeSingleCollapsible("Trivia", "trivia"); makeSingleCollapsible("See also", "related terms"); makeSingleCollapsible("References", "references"); makeSingleCollapsible("Further reading", "further reading"); makeSingleCollapsible("Anagrams", "anagrams"); moveAnagrams(); addGaps(); } function openNavFrameForElementWithId(targetId) { const navFrameTarget = navFramesById[targetId]; if (navFrameTarget) openNavFrame(navFrameTarget); // if what we targeted is inside a navframe, open it too const targetElement = document.getElementById(targetId); if (targetElement && targetElement.closest) { const navFrameContainingTarget = targetElement.closest(".NavFrame-streamline"); if (navFrameContainingTarget) openNavFrame(navFrameContainingTarget); } } const { collapseElements, runInReconstructions } = preferences; // only run in content namespaces. // this must also run on 4 in [[MediaWiki:Gadgets-definition]] so that [[WT:GPREFS]] works. if (mw.config.get("wgNamespaceNumber") === 0 || (runInReconstructions && mw.config.get("wgNamespaceNumber") === 118)) { mw.hook("wikipage.content").add(() => { try { defaultStreamline(); if (collapseElements !== "aboveDefinitions") superStreamline(); // refocus URL target in case the page layout changed, which it probably did // also open a navframe if targeted window.requestAnimationFrame(() => { if (window.location.hash && window.location.hash.match(/^#/)) { const targetId = window.location.hash.replace(/^#/, ""); const targetElement = document.getElementById(targetId); if (targetElement) targetElement.scrollIntoView(); openNavFrameForElementWithId(targetId); } }); // open a navframe if an internal link targets a section window.addEventListener("hashchange", () => { if (window.location.hash) { const targetId = window.location.hash.replace(/^#/, ""); openNavFrameForElementWithId(targetId); } }); } catch (e) { console.error(e); } }); } // </nowiki> 90zbetucltlf909bqhaojz3k8tp0wj0 88991 88990 2026-08-06T23:26:17Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-Streamline.js]] 88990 javascript text/javascript "use strict"; // {{documentation}} // <nowiki> /*jshint strict:true, undef:true, latedef:true, esversion:6 */ /* global mw, createNavToggle */ const STREAMLINE_SYMBOL = "⌰"; // [[MediaWiki:Gadget-WiktGadgetPrefs.js]] const preferences = mw.wiktGadgetPrefs.get( "streamline", { label: { en: "Streamline", }, }, { collapseElements: { "type": "strenum", "default": "aboveDefinitions", "label": { "en": "Elements to collapse" }, "choices": [ "aboveDefinitions", "allExceptNotes" ], "choiceLabels": { "en": { "aboveDefinitions": "Sections before definitions", "allExceptNotes": "Sections before and after definitions" } } }, runInReconstructions: { "type": "boolean", "default": true, "label": { "en": "Apply also to reconstruction pages" } } } ); function makeNavFrame(heading, editLinks, toggleCat, contents) { // now make a collapsible box const navHead = document.createElement("div"); navHead.className = "NavHead"; navHead.style.cursor = "pointer"; navHead.style.fontSize = "1.1em"; const navContent = document.createElement("div"); navContent.className = "NavContent boxcontent streamline-boxcontent"; navContent.style.textAlign = "left"; const navFrame = document.createElement("div"); navFrame.className = "NavFrame NavFrame-streamline"; if (toggleCat) navFrame.setAttribute("data-toggle-category", toggleCat); navFrame.style.display = "block"; navFrame.append(navHead, navContent); navHead.append(`${STREAMLINE_SYMBOL} ${heading}`); try { if (createNavToggle) createNavToggle(navFrame); } catch (e) { } if (editLinks) { navContent.append(editLinks); editLinks.style.float = "right"; // try displaying the edit links next to the show button editLinks.style.marginTop = "-1.5em"; editLinks.style.marginRight = "8ch"; } navContent.append(...contents); return navFrame; } function isNavFrameOpen(frame) { const content = frame.querySelector(".NavContent"); if (!content) return false; const computedStyle = window.getComputedStyle(content); if (!computedStyle) return false; return computedStyle.display !== "none"; } function openNavFrame(frame) { if (!isNavFrameOpen(frame)) { const navHead = frame.querySelector(".NavHead"); if (navHead) navHead.click(); } } function anchorInUrl(anchor) { if (window.location.hash) { return window.location.hash.replace(/^#/, "") === anchor; } return false; } function hasElementClass(element, className) { return element.classList.contains(className); } function shouldEndCollapsible(element) { return element.matches("h1, h2, h3, h4, h5, h6, hr") // end on heading or horizontal line || hasElementClass(element, "NavFrame-streamline") // no nested streamline navboxes || hasElementClass(element, "mw-heading") // section heading || element.matches("section") // Parsoid ; // this is on its own line so that it's easier to add new rules } function shouldExcludeFromCollapsible(element) { return hasElementClass(element, "thumb") // images || hasElementClass(element, "sister-project") // sister project box || hasElementClass(element, "kanji-table") // ja-kanjitab || hasElementClass(element, "floatright") // various tables || hasElementClass(element, "template-anchor") // anchor || hasElementClass(element, "t-thumbs-outer") // thumbs || hasElementClass(element, "interproject-box") // interwiki boxes || hasElementClass(element, "normalized-box") // {{normalized}} || hasElementClass(element, "chemical-element-box") // {{chemical element box}} || element.getAttribute("typeof") === "mw:File/Thumb" // new floating image boxes || hasElementClass(element, "mw-halign-right") // mw-halign-right, by new floating image boxes || element.getAttribute("align") === "right" // anything that (explicitly) aligns || element.style.float === "right" // anything that (explicitly) floats || element.matches("style") // TemplateStyles ; // this is on its own line so that it's easier to add new rules } // Applies only to numbered etymologies. function shouldDisplayBeforeCollapsible(element) { return hasElementClass(element, "normalized-box") // {{normalized}} ; // this is on its own line so that it's easier to add new rules } function shouldCollapseForTheSakeOf(element) { if (element.nodeType === 1) { // don't collapse for the sake of senseid or etymid alone if (element.matches(".senseid, .etymid")) return false; if (element.matches("p, div, span")) return Array.prototype.some.call(element.childNodes, shouldCollapseForTheSakeOf); return element.tagName !== "BR"; } else if (element.nodeType === 3) { return !!element.textContent.trim(); // only if not entirely whitespace } else { return false; } } function getHeadingQuery(onlyL3) { return (onlyL3 ? ["h2", "h3"] : ["h2", "h3", "h4", "h5"]) .map(heading => `#mw-content-text ${heading}`) .join(", "); } const navFramesById = {}; function collapseHeadingInNavbox(headingCandidate, heading, toggleCat, headingMatcher, addEditLinks) { let headingId; const hl = headingCandidate.querySelector(".mw-headline"); if (hl && headingMatcher(hl.textContent)) headingId = hl.id; // Parsoid if (hasElementClass(headingCandidate.parentElement, "mw-heading") && headingMatcher(headingCandidate.textContent)) { headingId = headingCandidate.id; headingCandidate = headingCandidate.parentElement; } if (!headingId) return [undefined, undefined]; // pick all elements until next heading const contents = []; let nx = headingCandidate.nextElementSibling; let collapse = false; while (nx) { if (shouldEndCollapsible(nx) || nx.querySelector(".NavFrame-streamline")) break; if (!shouldExcludeFromCollapsible(nx)) { contents.push(nx); collapse = collapse || shouldCollapseForTheSakeOf(nx); } nx = nx.nextElementSibling; } if (!collapse) return [undefined, undefined]; const navFrame = makeNavFrame(heading, addEditLinks ? headingCandidate.querySelector(".mw-editsection") : null, toggleCat, contents); navFrame.id = headingId; navFramesById[navFrame.id] = navFrame; return [navFrame, headingCandidate]; } function makeSingleCollapsible(heading, toggleCat, onlyL3) { document.querySelectorAll(getHeadingQuery(onlyL3)).forEach((e) => { const [navFrame, headingElement] = collapseHeadingInNavbox(e, heading, toggleCat, (headingText) => headingText === heading, true); if (navFrame) headingElement.parentNode.replaceChild(navFrame, headingElement); }); } function makeNumberedCollapsible(heading, toggleCat) { const re = new RegExp("^" + heading + " \\d+(?:\.\\d+)?$"); document.querySelectorAll(getHeadingQuery(false)).forEach((e) => { const [navFrame, headingElement] = collapseHeadingInNavbox(e, heading, toggleCat, (headingText) => headingText.match(re), false); if (navFrame) { let toInsertBefore = headingElement.nextElementSibling; while (toInsertBefore && shouldDisplayBeforeCollapsible(toInsertBefore)) toInsertBefore = toInsertBefore.nextElementSibling; headingElement.parentNode.insertBefore(navFrame, toInsertBefore); } }); } function moveAnagrams() { // move the Anagrams box above Further reading and References document.querySelectorAll(".NavFrame[data-toggle-category=\"anagrams\"]").forEach((e) => { let p = e.previousElementSibling; while (p) { if (p.tagName === "H2") { break; } if (p.tagName === "H3") { const hl = p.querySelector(".mw-headline"); if (hl && (hl.textContent === "Further reading" || hl.textContent === "References")) { e.parentElement.insertBefore(e, p); } } p = p.previousElementSibling; } }); } function addGaps() { // add gaps before streamline navboxes if preceded by certain elements document.querySelectorAll(".NavFrame-streamline").forEach((sl) => { const prev = sl.previousElementSibling; const next = sl.nextElementSibling; let tn; if (prev) { tn = prev.tagName; if (tn === "OL" || tn === "UL") { sl.style.marginTop = "1em"; } } if (next) { tn = next.tagName; if (tn === "HR") { sl.style.marginBottom = "1em"; } } }); } function defaultStreamline() { makeSingleCollapsible("Alternative forms", "alternative forms", true); makeSingleCollapsible("Alternative reconstructions", "alternative reconstructions", true); makeSingleCollapsible("Etymology", "etymology"); makeSingleCollapsible("Glyph origin", "etymology"); makeSingleCollapsible("Description", "description"); makeSingleCollapsible("Pronunciation", "pronunciations"); makeSingleCollapsible("Production", "productions"); makeNumberedCollapsible("Etymology", "etymology"); makeNumberedCollapsible("Pronunciation", "pronunciations"); makeNumberedCollapsible("Production", "productions"); addGaps(); } function superStreamline() { makeSingleCollapsible("Alternative forms", "alternative forms", false); makeSingleCollapsible("Alternative reconstructions", "alternative reconstructions", false); makeSingleCollapsible("Inflection", "inflection"); makeSingleCollapsible("Declension", "inflection"); makeSingleCollapsible("Conjugation", "inflection"); makeSingleCollapsible("Mutation", "mutation"); makeSingleCollapsible("Synonyms", "synonyms"); makeSingleCollapsible("Antonyms", "antonyms"); makeSingleCollapsible("Hypernyms", "hypernyms"); makeSingleCollapsible("Hyponyms", "hyponyms"); makeSingleCollapsible("Meronyms", "meronyms"); makeSingleCollapsible("Holonyms", "holonyms"); makeSingleCollapsible("Troponyms", "troponyms"); makeSingleCollapsible("Coordinate terms", "coordinate terms"); makeSingleCollapsible("Derived terms", "derived terms"); makeSingleCollapsible("Compounds", "derived terms"); makeSingleCollapsible("Related terms", "related terms"); makeSingleCollapsible("Collocations", "collocations"); makeSingleCollapsible("Descendants", "descendants"); makeSingleCollapsible("Trivia", "trivia"); makeSingleCollapsible("See also", "related terms"); makeSingleCollapsible("References", "references"); makeSingleCollapsible("Further reading", "further reading"); makeSingleCollapsible("Anagrams", "anagrams"); moveAnagrams(); addGaps(); } function openNavFrameForElementWithId(targetId) { const navFrameTarget = navFramesById[targetId]; if (navFrameTarget) openNavFrame(navFrameTarget); // if what we targeted is inside a navframe, open it too const targetElement = document.getElementById(targetId); if (targetElement && targetElement.closest) { const navFrameContainingTarget = targetElement.closest(".NavFrame-streamline"); if (navFrameContainingTarget) openNavFrame(navFrameContainingTarget); } } const { collapseElements, runInReconstructions } = preferences; // only run in content namespaces. // this must also run on 4 in [[MediaWiki:Gadgets-definition]] so that [[WT:GPREFS]] works. if (mw.config.get("wgNamespaceNumber") === 0 || (runInReconstructions && mw.config.get("wgNamespaceNumber") === 118)) { mw.hook("wikipage.content").add(() => { try { defaultStreamline(); if (collapseElements !== "aboveDefinitions") superStreamline(); // refocus URL target in case the page layout changed, which it probably did // also open a navframe if targeted window.requestAnimationFrame(() => { if (window.location.hash && window.location.hash.match(/^#/)) { const targetId = window.location.hash.replace(/^#/, ""); const targetElement = document.getElementById(targetId); if (targetElement) targetElement.scrollIntoView(); openNavFrameForElementWithId(targetId); } }); // open a navframe if an internal link targets a section window.addEventListener("hashchange", () => { if (window.location.hash) { const targetId = window.location.hash.replace(/^#/, ""); openNavFrameForElementWithId(targetId); } }); } catch (e) { console.error(e); } }); } // </nowiki> 90zbetucltlf909bqhaojz3k8tp0wj0 MediaWiki:Gadget-minitoc.js 8 17995 88992 2025-10-19T02:04:11Z en>Ioaxxere 0 mobile fix, minor cleanup 88992 javascript text/javascript // <nowiki> // Initialize preferred languages from local storage. let preferredLanguages = new Set(JSON.parse(localStorage.getItem("minitocLangs"))); // Empty and filled-in bookmark icons. const unselectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z"></path></g></svg>`; const selectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z"></path></g></svg>`; mw.util.addCSS(` .minitoc-icon-selected, .minitoc-icon-unselected { cursor: pointer; vertical-align: sub; } `); function displayLanguages() { // Clear out previously displayed languages. document.querySelectorAll(".minitoc-linked-languages").forEach(elem => elem.remove()); for (let minitoc of document.querySelectorAll(".minitoc")) { let linkedLanguages = document.createElement("span"); linkedLanguages.className = "minitoc-linked-languages"; for (let languageLink of minitoc.querySelectorAll(`.NavContent > a:not([href="#catlinks"]`)) { if (preferredLanguages.has(languageLink.textContent)) { let link = document.createElement("a"); link.textContent = `→ ${languageLink.textContent}`; link.href = languageLink.href; link.style.whiteSpace = "nowrap"; linkedLanguages.append(" ", link); } } if (linkedLanguages.childElementCount) minitoc.querySelector(".NavHead").append(linkedLanguages); } } // Setup. // Note: the code is generic and can handle multiple miniTOCs on one page, although this probably isn't necessary. for (let minitoc of document.querySelectorAll(".minitoc")) { minitoc.querySelector(".NavContent").insertAdjacentHTML("beforeend", `<span style="font-size: 85%" class="minitoc-button-container"> &#32; [<a class="minitoc-button-select" role="button"> Select preferred languages </a>] <span style="display: none"> &#32; [<a class="minitoc-button-clear" role="button"> Clear all </a>] </span> </span>` .replace(/[\n\t]/g, "") ); let selectButton = minitoc.querySelector(".minitoc-button-select"); let clearButton = minitoc.querySelector(".minitoc-button-clear"); selectButton.addEventListener("click", () => { // The button can be in two states: "select" and "save". if (selectButton.textContent === "Select preferred languages") { clearButton.parentElement.style.display = ""; // Make sure you can't have multiple miniTOCs in "select" mode simultaneously. for (let button of document.querySelectorAll(".minitoc-button-select")) { if (button.textContent === "Save preferred languages") { // Trigger the saving procedure. button.click(); } } selectButton.textContent = "Save preferred languages"; for (let languageLink of minitoc.querySelectorAll(`.NavContent > a:not([href="#catlinks"]`)) { let iconContainer = document.createElement("span"); iconContainer.role = "button"; languageLink.insertAdjacentElement("beforebegin", iconContainer); if (preferredLanguages.has(languageLink.textContent)) { iconContainer.className = "minitoc-icon-selected"; iconContainer.innerHTML = selectedIcon; } else { iconContainer.className = "minitoc-icon-unselected"; iconContainer.innerHTML = unselectedIcon; } iconContainer.addEventListener("click", () => { if (preferredLanguages.has(languageLink.textContent)) { preferredLanguages.delete(languageLink.textContent); iconContainer.className = "minitoc-icon-unselected"; iconContainer.innerHTML = unselectedIcon; } else { preferredLanguages.add(languageLink.textContent); iconContainer.className = "minitoc-icon-selected"; iconContainer.innerHTML = selectedIcon; } }); } } else { // Save to local storage. localStorage.setItem("minitocLangs", JSON.stringify(Array.from(preferredLanguages))); // Reset state. minitoc.querySelectorAll(".minitoc-icon-selected, .minitoc-icon-unselected").forEach(elem => elem.remove()); selectButton.textContent = "Select preferred languages"; clearButton.parentElement.style.display = "none"; displayLanguages(); } }); clearButton.addEventListener("click", () => { preferredLanguages.clear(); for (let iconContainer of minitoc.querySelectorAll(".minitoc-icon-selected")) { iconContainer.innerHTML = unselectedIcon; iconContainer.className = "minitoc-icon-unselected"; } }); } displayLanguages(); // </nowiki> 08fibjrel8pcvuuyqfxb4fc8oev6f0l 88993 88992 2026-08-06T23:26:28Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-minitoc.js]] 88992 javascript text/javascript // <nowiki> // Initialize preferred languages from local storage. let preferredLanguages = new Set(JSON.parse(localStorage.getItem("minitocLangs"))); // Empty and filled-in bookmark icons. const unselectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2zm10 14.25-5-3.5-5 3.5V3h10z"></path></g></svg>`; const selectedIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="17" viewBox="0 0 20 20" aria-hidden="true" fill="currentColor"><g><path d="M5 1a2 2 0 00-2 2v16l7-5 7 5V3a2 2 0 00-2-2z"></path></g></svg>`; mw.util.addCSS(` .minitoc-icon-selected, .minitoc-icon-unselected { cursor: pointer; vertical-align: sub; } `); function displayLanguages() { // Clear out previously displayed languages. document.querySelectorAll(".minitoc-linked-languages").forEach(elem => elem.remove()); for (let minitoc of document.querySelectorAll(".minitoc")) { let linkedLanguages = document.createElement("span"); linkedLanguages.className = "minitoc-linked-languages"; for (let languageLink of minitoc.querySelectorAll(`.NavContent > a:not([href="#catlinks"]`)) { if (preferredLanguages.has(languageLink.textContent)) { let link = document.createElement("a"); link.textContent = `→ ${languageLink.textContent}`; link.href = languageLink.href; link.style.whiteSpace = "nowrap"; linkedLanguages.append(" ", link); } } if (linkedLanguages.childElementCount) minitoc.querySelector(".NavHead").append(linkedLanguages); } } // Setup. // Note: the code is generic and can handle multiple miniTOCs on one page, although this probably isn't necessary. for (let minitoc of document.querySelectorAll(".minitoc")) { minitoc.querySelector(".NavContent").insertAdjacentHTML("beforeend", `<span style="font-size: 85%" class="minitoc-button-container"> &#32; [<a class="minitoc-button-select" role="button"> Select preferred languages </a>] <span style="display: none"> &#32; [<a class="minitoc-button-clear" role="button"> Clear all </a>] </span> </span>` .replace(/[\n\t]/g, "") ); let selectButton = minitoc.querySelector(".minitoc-button-select"); let clearButton = minitoc.querySelector(".minitoc-button-clear"); selectButton.addEventListener("click", () => { // The button can be in two states: "select" and "save". if (selectButton.textContent === "Select preferred languages") { clearButton.parentElement.style.display = ""; // Make sure you can't have multiple miniTOCs in "select" mode simultaneously. for (let button of document.querySelectorAll(".minitoc-button-select")) { if (button.textContent === "Save preferred languages") { // Trigger the saving procedure. button.click(); } } selectButton.textContent = "Save preferred languages"; for (let languageLink of minitoc.querySelectorAll(`.NavContent > a:not([href="#catlinks"]`)) { let iconContainer = document.createElement("span"); iconContainer.role = "button"; languageLink.insertAdjacentElement("beforebegin", iconContainer); if (preferredLanguages.has(languageLink.textContent)) { iconContainer.className = "minitoc-icon-selected"; iconContainer.innerHTML = selectedIcon; } else { iconContainer.className = "minitoc-icon-unselected"; iconContainer.innerHTML = unselectedIcon; } iconContainer.addEventListener("click", () => { if (preferredLanguages.has(languageLink.textContent)) { preferredLanguages.delete(languageLink.textContent); iconContainer.className = "minitoc-icon-unselected"; iconContainer.innerHTML = unselectedIcon; } else { preferredLanguages.add(languageLink.textContent); iconContainer.className = "minitoc-icon-selected"; iconContainer.innerHTML = selectedIcon; } }); } } else { // Save to local storage. localStorage.setItem("minitocLangs", JSON.stringify(Array.from(preferredLanguages))); // Reset state. minitoc.querySelectorAll(".minitoc-icon-selected, .minitoc-icon-unselected").forEach(elem => elem.remove()); selectButton.textContent = "Select preferred languages"; clearButton.parentElement.style.display = "none"; displayLanguages(); } }); clearButton.addEventListener("click", () => { preferredLanguages.clear(); for (let iconContainer of minitoc.querySelectorAll(".minitoc-icon-selected")) { iconContainer.innerHTML = unselectedIcon; iconContainer.className = "minitoc-icon-unselected"; } }); } displayLanguages(); // </nowiki> 08fibjrel8pcvuuyqfxb4fc8oev6f0l MediaWiki:Gadget-JumpToError.js 8 17996 88995 2026-08-03T08:47:50Z en>Fenakhay 0 88995 javascript text/javascript // <nowiki> (async () => { "use strict"; const NOTIFY_TAG = "jump-to-scribunto-error"; const closestAll = (elem, selector) => { const out = []; let node = elem; while (node) { node = node.closest(selector); if (!node) break; out.push(node); node = node.parentElement; } return out; }; const isDisplayNone = elem => !!elem && window.getComputedStyle(elem).display === "none"; const isVisible = elem => !!elem && elem.getClientRects().length > 0; const clickIfPresent = elem => { if (elem && typeof elem.click === "function") { elem.click(); return true; } return false; }; const revealers = [ error => closestAll(error, ".NavContent") .filter(isDisplayNone) .filter(nav => { const sibling = nav.previousElementSibling; if (sibling && sibling.classList.contains("NavHead")) return clickIfPresent(sibling); const frame = nav.closest(".NavFrame"); return !!frame && clickIfPresent(frame.querySelector(".NavHead")); }).length, error => closestAll(error, ".mw-collapsed") .filter(collapsed => { const toggle = [...collapsed.querySelectorAll(".mw-collapsible-toggle-collapsed")] .find(t => t.closest(".mw-collapsed") === collapsed); return clickIfPresent(toggle); }).length, error => closestAll(error, ".vsShow, .vsHide") .filter(isDisplayNone) .filter(vs => { const switcher = vs.closest(".vsSwitcher"); return !!switcher && clickIfPresent(switcher.querySelector(`[role="button"]`)); }).length, error => closestAll(error, "[data-relation-class]") .filter(nym => { if (!isDisplayNone(nym.closest("dl"))) return false; const li = nym.closest("li"); if (!li) return false; const relation = nym.getAttribute("data-relation-class") || ""; const toggle = [...li.querySelectorAll(".nyms-toggle > a")] .find(a => a.textContent.includes(relation)); return clickIfPresent(toggle); }).length, error => closestAll(error, ".wikt-quote-container") .filter(isDisplayNone) .filter(quotes => { const parent = quotes.parentElement; return !!parent && clickIfPresent(parent.querySelector(".HQToggle > a")); }).length ]; const reveal = error => { for (let pass = 0; pass < 10; pass++) { if (isVisible(error)) return; let clicks = 0; for (const revealer of revealers) { // One broken revealer must not stop the others. try { clicks += revealer(error); } catch (err) { mw.log.warn("[jump-to-scribunto-error] revealer failed", err); } } if (!clicks) return; } }; const scrollIntoViewWhenSettled = elem => { const deadline = Date.now() + 1000; let lastTop = NaN; const step = () => { elem.scrollIntoView({block: "center"}); const docTop = elem.getBoundingClientRect().top + window.scrollY; if (Math.abs(docTop - lastTop) < 1 || Date.now() > deadline) return; lastTop = docTop; window.setTimeout(step, 100); }; requestAnimationFrame(step); }; const notifyIfErrors = async () => { const errors = document.querySelectorAll(".scribunto-error"); if (!errors.length) return; const message = document.createElement("span"); message.id = NOTIFY_TAG; message.setAttribute("role", "button"); message.tabIndex = 0; message.style.cursor = "pointer"; message.textContent = `Warning: this page has ${errors.length} Lua error${errors.length === 1 ? "" : "s"}; click here to jump to the error`; const jump = () => { const target = document.querySelector(".scribunto-error"); if (!target) return; reveal(target); scrollIntoViewWhenSettled(target); }; message.addEventListener("click", jump); message.addEventListener("keydown", event => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); jump(); } }); try { await mw.notify(message, {autoHide: false, tag: NOTIFY_TAG}); } catch (err) { mw.log.warn("[jump-to-scribunto-error] mw.notify failed", err); } }; mw.hook("wikipage.content").add(() => { notifyIfErrors(); }); })(); // </nowiki> gj68lrlv2ab3fybfqxx8jqglifjfyww 88996 88995 2026-08-06T23:32:31Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-JumpToError.js]] 88995 javascript text/javascript // <nowiki> (async () => { "use strict"; const NOTIFY_TAG = "jump-to-scribunto-error"; const closestAll = (elem, selector) => { const out = []; let node = elem; while (node) { node = node.closest(selector); if (!node) break; out.push(node); node = node.parentElement; } return out; }; const isDisplayNone = elem => !!elem && window.getComputedStyle(elem).display === "none"; const isVisible = elem => !!elem && elem.getClientRects().length > 0; const clickIfPresent = elem => { if (elem && typeof elem.click === "function") { elem.click(); return true; } return false; }; const revealers = [ error => closestAll(error, ".NavContent") .filter(isDisplayNone) .filter(nav => { const sibling = nav.previousElementSibling; if (sibling && sibling.classList.contains("NavHead")) return clickIfPresent(sibling); const frame = nav.closest(".NavFrame"); return !!frame && clickIfPresent(frame.querySelector(".NavHead")); }).length, error => closestAll(error, ".mw-collapsed") .filter(collapsed => { const toggle = [...collapsed.querySelectorAll(".mw-collapsible-toggle-collapsed")] .find(t => t.closest(".mw-collapsed") === collapsed); return clickIfPresent(toggle); }).length, error => closestAll(error, ".vsShow, .vsHide") .filter(isDisplayNone) .filter(vs => { const switcher = vs.closest(".vsSwitcher"); return !!switcher && clickIfPresent(switcher.querySelector(`[role="button"]`)); }).length, error => closestAll(error, "[data-relation-class]") .filter(nym => { if (!isDisplayNone(nym.closest("dl"))) return false; const li = nym.closest("li"); if (!li) return false; const relation = nym.getAttribute("data-relation-class") || ""; const toggle = [...li.querySelectorAll(".nyms-toggle > a")] .find(a => a.textContent.includes(relation)); return clickIfPresent(toggle); }).length, error => closestAll(error, ".wikt-quote-container") .filter(isDisplayNone) .filter(quotes => { const parent = quotes.parentElement; return !!parent && clickIfPresent(parent.querySelector(".HQToggle > a")); }).length ]; const reveal = error => { for (let pass = 0; pass < 10; pass++) { if (isVisible(error)) return; let clicks = 0; for (const revealer of revealers) { // One broken revealer must not stop the others. try { clicks += revealer(error); } catch (err) { mw.log.warn("[jump-to-scribunto-error] revealer failed", err); } } if (!clicks) return; } }; const scrollIntoViewWhenSettled = elem => { const deadline = Date.now() + 1000; let lastTop = NaN; const step = () => { elem.scrollIntoView({block: "center"}); const docTop = elem.getBoundingClientRect().top + window.scrollY; if (Math.abs(docTop - lastTop) < 1 || Date.now() > deadline) return; lastTop = docTop; window.setTimeout(step, 100); }; requestAnimationFrame(step); }; const notifyIfErrors = async () => { const errors = document.querySelectorAll(".scribunto-error"); if (!errors.length) return; const message = document.createElement("span"); message.id = NOTIFY_TAG; message.setAttribute("role", "button"); message.tabIndex = 0; message.style.cursor = "pointer"; message.textContent = `Warning: this page has ${errors.length} Lua error${errors.length === 1 ? "" : "s"}; click here to jump to the error`; const jump = () => { const target = document.querySelector(".scribunto-error"); if (!target) return; reveal(target); scrollIntoViewWhenSettled(target); }; message.addEventListener("click", jump); message.addEventListener("keydown", event => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); jump(); } }); try { await mw.notify(message, {autoHide: false, tag: NOTIFY_TAG}); } catch (err) { mw.log.warn("[jump-to-scribunto-error] mw.notify failed", err); } }; mw.hook("wikipage.content").add(() => { notifyIfErrors(); }); })(); // </nowiki> gj68lrlv2ab3fybfqxx8jqglifjfyww MediaWiki:Gadget-VetVoters.js 8 17997 88997 2026-04-20T04:35:01Z en>Fenakhay 0 88997 javascript text/javascript const EDIT_COUNT_AT_LEAST = 500; // note: above 500 would require multiple api requests const FIRST_EDIT_PREDATES_VOTE_BY = 30; // days const ELIGIBLE_NAMESPACES = "0|100|106|110|114|118"; const IPV4_REGEX = /^(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,2})?$/; const IPV6_REGEX = /^[\da-f:]+(?:\/\d{1,3})?$/i; const TEMP_ACCT_REGEX = /^~[0-9]{4}(?:-[0-9]{1,5})+/; const USER_LINK_PATTERNS = { '.mw-body-content [href^="//en.wiktionary.org/wiki/User:"]': (title) => title.replace(/^User:/, ""), '.new[href^="//en.wiktionary.org/w/index.php?title=User:"]': (title) => title.replace(/^User:/, "").replace(/ \(page does not exist\)$/, ""), }; const API_HEADERS = { "Api-User-Agent": "Vet Voters (gadget developed by [[User:Ioaxxere]])", }; const actionAPI = new mw.Api({ ajax: { headers: API_HEADERS } }); const restAPI = new mw.Rest({ ajax: { headers: API_HEADERS } }); /** * Guesses when the vote started * @param {Document} doc the document * @returns {Date | null} */ function voteStart(doc) { let endDate = new Date(NaN); let dateMatch = doc .querySelector(".mw-parser-output") .textContent.match( /Vote start(?:s|ed):.*?([0-9]{2}:[0-9]{2}), ([0-9]+ \w+ [0-9]{4})/, ); if (dateMatch) { endDate = new Date(`${dateMatch[2]} ${dateMatch[1]} UTC`); if (!isNaN(endDate)) return endDate; } // If parsing fails here, just check the title. // Votes typically contain the date string in the title (e.g. 2026-04). // Conservatively assume the 1st of the month (catch false positives, avoid false negatives) let titleMatch = mw.config.values.wgTitle.match(/[0-9]{4}-[0-9]{2}/); if (titleMatch) { endDate = new Date(`${titleMatch[0]}-01`); if (!isNaN(endDate)) return endDate; } return null; } let alreadyAddedCss = false; /** * Adds a class to an HTML element for the user, which highlights them as being ineligible to vote * @param {HTMLAnchorElement} elem * @returns {void} */ function highlightIneligible(elem) { if (!alreadyAddedCss) { mw.util.addCSS(` .ineligible-voter { text-decoration: var(--wikt-palette-darkred) wavy underline 0.15em !important; } .ineligible-voter:hover::after { content: " User is ineligible to vote!"; font-size: 0.8em; color: var(--wikt-palette-darkred); text-decoration: none; font-family: sans-serif; } `); alreadyAddedCss = true; } elem.classList.add("ineligible-voter"); } /** * Finds a user's current username * @param {string} username * @returns {string} the current username */ async function resolveRenames(username) { while (true) { let resp = await actionAPI.post({ action: "query", format: "json", list: "logevents", letype: "renameuser", letitle: `User:${username}`, lelimit: 1, }); let entries = resp.query.logevents; if (!entries.length) break; let newuser = entries[0].params.newuser; if (newuser.endsWith("(usurped)")) break; // hacky but ok username = newuser; } return username; } /** * Returns true if the given user can vote, otherwise false * @param {string} username a user or anon user * @param {Date} endDate when the vote ends * @returns boolean */ async function verifyUser(username, endDate) { if (userIsAnon(username)) return false; // anons can never vote username = await resolveRenames(username); const earliestEditPredates = new Date(endDate); earliestEditPredates.setDate( earliestEditPredates.getDate() - FIRST_EDIT_PREDATES_VOTE_BY, ); // This API call already excludes transwiki contributions. const resp1 = await actionAPI.post({ action: "query", format: "json", list: "usercontribs", ucuser: username, uclimit: EDIT_COUNT_AT_LEAST, ucnamespace: ELIGIBLE_NAMESPACES, ucdir: "newer", }); const contribs = resp1.query.usercontribs; let total = contribs.length; let oldest = contribs[0] ? new Date(contribs[0].timestamp) : null; if (total >= EDIT_COUNT_AT_LEAST && oldest <= earliestEditPredates) return true; const resp2 = await actionAPI.post({ action: "query", format: "json", list: "alldeletedrevisions", adrlimit: EDIT_COUNT_AT_LEAST, adruser: username, adrnamespace: ELIGIBLE_NAMESPACES, adrdir: "newer", }); const deleted = resp2.query.alldeletedrevisions; total += deleted.length; if (deleted[0]) { let deletedOldest = new Date(deleted[0].timestamp); oldest = oldest ? new Date(Math.min(oldest.getTime(), deletedOldest.getTime())) : deletedOldest; } return total >= EDIT_COUNT_AT_LEAST && oldest && oldest <= earliestEditPredates; } /** * Returns true if cidr is undefined or in range [0, maxBits]. * @param {string|undefined} cidr * @param {number} maxBits * @returns {boolean} */ function isValidCidr(cidr, maxBits) { if (cidr === undefined) return true; let cidrNum = Number(cidr); return Number.isInteger(cidrNum) && cidrNum >= 0 && cidrNum <= maxBits; } /** * Validates IPv4 with optional CIDR suffix. * @param {string} candidate * @returns {boolean} */ function isValidIPv4(candidate) { if (!IPV4_REGEX.test(candidate)) return false; let [addr, cidr] = candidate.split("/"); let octets = addr.split(".").map(Number); let ipv4Valid = octets.length === 4 && octets.every((n) => Number.isInteger(n) && n >= 0 && n <= 255); return ipv4Valid && isValidCidr(cidr, 32); } /** * Validates IPv6 (full or compressed) with optional CIDR suffix. * @param {string} candidate * @returns {boolean} */ function isValidIPv6(candidate) { if (!IPV6_REGEX.test(candidate) || !candidate.includes(":")) return false; let [addr, cidr] = candidate.split("/"); if (!isValidCidr(cidr, 128)) return false; if (addr.includes(":::")) return false; if (addr.includes("::")) { if ((addr.match(/::/g) || []).length > 1) return false; let [left, right] = addr.split("::"); let leftParts = left ? left.split(":").filter(Boolean) : []; let rightParts = right ? right.split(":").filter(Boolean) : []; let hextets = leftParts.length + rightParts.length; let validParts = [...leftParts, ...rightParts].every((part) => /^[\da-f]{1,4}$/i.test(part), ); return validParts && hextets < 8; } let parts = addr.split(":"); return parts.length === 8 && parts.every((part) => /^[\da-f]{1,4}$/i.test(part)); } /** * Checks if a user is an IP/anon user, returning true if they are * @param {string} user * @returns {bool} */ function userIsAnon(user) { const normalized = user.trim(); if (TEMP_ACCT_REGEX.test(normalized)) return true; return isValidIPv4(normalized) || isValidIPv6(normalized); } // only fire on votes pages let pageName = mw.config.values.wgPageName; if ( pageName.startsWith("Wiktionary:Votes/") || pageName.startsWith("Wiktionary_talk:Votes/") ) { (async () => { // Step 1: find out when the vote ends let endDate; if (pageName.startsWith("Wiktionary_talk:")) { let mainTitle = pageName.replace(/^Wiktionary_talk:/, "Wiktionary:"); let mainPageResp = await restAPI.get( `/v1/page/${encodeURIComponent(mainTitle)}/html`, ); let mainPageDoc = new DOMParser().parseFromString( mainPageResp, "text/html", ); endDate = voteStart(mainPageDoc); } else { endDate = voteStart(document); } if (!(endDate instanceof Date) || isNaN(endDate)) { console.warn( "[vetvoters] Could not parse vote start date; skipping eligibility checks.", ); return; } // Step 2: collect user elements, including anons let userlinks = new Map(); // linkElem [HTMLElement] -> acctName [string] Object.entries(USER_LINK_PATTERNS).forEach(([selector, normalize]) => { document .querySelectorAll(selector) .forEach((link) => userlinks.set(link, normalize(link.title))); }); for (let link of document.querySelectorAll( `.mw-body-content [href^="//en.wiktionary.org/wiki/Special:Contributions/"]`, )) { let acct = link.title.replace(/^Special:Contributions\//, ""); if (!userIsAnon(acct)) continue; userlinks.set(link, acct); } let usernames = [...new Set(userlinks.values())]; let queries = usernames.map(async (user) => { try { return [user, await verifyUser(user, endDate)]; } catch (err) { console.warn( `[vetvoters] Failed to verify ${user}; treating as eligible.`, err, ); return [user, true]; } }); let userIsEligible = new Map(await Promise.all(queries)); for (let [elem, user] of userlinks) { if (userIsEligible.get(user) === false) highlightIneligible(elem); } })(); } 9gnom4jfbcsvkwno0gcyo0t8wii1m9k 88998 88997 2026-08-06T23:32:38Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-VetVoters.js]] 88997 javascript text/javascript const EDIT_COUNT_AT_LEAST = 500; // note: above 500 would require multiple api requests const FIRST_EDIT_PREDATES_VOTE_BY = 30; // days const ELIGIBLE_NAMESPACES = "0|100|106|110|114|118"; const IPV4_REGEX = /^(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,2})?$/; const IPV6_REGEX = /^[\da-f:]+(?:\/\d{1,3})?$/i; const TEMP_ACCT_REGEX = /^~[0-9]{4}(?:-[0-9]{1,5})+/; const USER_LINK_PATTERNS = { '.mw-body-content [href^="//en.wiktionary.org/wiki/User:"]': (title) => title.replace(/^User:/, ""), '.new[href^="//en.wiktionary.org/w/index.php?title=User:"]': (title) => title.replace(/^User:/, "").replace(/ \(page does not exist\)$/, ""), }; const API_HEADERS = { "Api-User-Agent": "Vet Voters (gadget developed by [[User:Ioaxxere]])", }; const actionAPI = new mw.Api({ ajax: { headers: API_HEADERS } }); const restAPI = new mw.Rest({ ajax: { headers: API_HEADERS } }); /** * Guesses when the vote started * @param {Document} doc the document * @returns {Date | null} */ function voteStart(doc) { let endDate = new Date(NaN); let dateMatch = doc .querySelector(".mw-parser-output") .textContent.match( /Vote start(?:s|ed):.*?([0-9]{2}:[0-9]{2}), ([0-9]+ \w+ [0-9]{4})/, ); if (dateMatch) { endDate = new Date(`${dateMatch[2]} ${dateMatch[1]} UTC`); if (!isNaN(endDate)) return endDate; } // If parsing fails here, just check the title. // Votes typically contain the date string in the title (e.g. 2026-04). // Conservatively assume the 1st of the month (catch false positives, avoid false negatives) let titleMatch = mw.config.values.wgTitle.match(/[0-9]{4}-[0-9]{2}/); if (titleMatch) { endDate = new Date(`${titleMatch[0]}-01`); if (!isNaN(endDate)) return endDate; } return null; } let alreadyAddedCss = false; /** * Adds a class to an HTML element for the user, which highlights them as being ineligible to vote * @param {HTMLAnchorElement} elem * @returns {void} */ function highlightIneligible(elem) { if (!alreadyAddedCss) { mw.util.addCSS(` .ineligible-voter { text-decoration: var(--wikt-palette-darkred) wavy underline 0.15em !important; } .ineligible-voter:hover::after { content: " User is ineligible to vote!"; font-size: 0.8em; color: var(--wikt-palette-darkred); text-decoration: none; font-family: sans-serif; } `); alreadyAddedCss = true; } elem.classList.add("ineligible-voter"); } /** * Finds a user's current username * @param {string} username * @returns {string} the current username */ async function resolveRenames(username) { while (true) { let resp = await actionAPI.post({ action: "query", format: "json", list: "logevents", letype: "renameuser", letitle: `User:${username}`, lelimit: 1, }); let entries = resp.query.logevents; if (!entries.length) break; let newuser = entries[0].params.newuser; if (newuser.endsWith("(usurped)")) break; // hacky but ok username = newuser; } return username; } /** * Returns true if the given user can vote, otherwise false * @param {string} username a user or anon user * @param {Date} endDate when the vote ends * @returns boolean */ async function verifyUser(username, endDate) { if (userIsAnon(username)) return false; // anons can never vote username = await resolveRenames(username); const earliestEditPredates = new Date(endDate); earliestEditPredates.setDate( earliestEditPredates.getDate() - FIRST_EDIT_PREDATES_VOTE_BY, ); // This API call already excludes transwiki contributions. const resp1 = await actionAPI.post({ action: "query", format: "json", list: "usercontribs", ucuser: username, uclimit: EDIT_COUNT_AT_LEAST, ucnamespace: ELIGIBLE_NAMESPACES, ucdir: "newer", }); const contribs = resp1.query.usercontribs; let total = contribs.length; let oldest = contribs[0] ? new Date(contribs[0].timestamp) : null; if (total >= EDIT_COUNT_AT_LEAST && oldest <= earliestEditPredates) return true; const resp2 = await actionAPI.post({ action: "query", format: "json", list: "alldeletedrevisions", adrlimit: EDIT_COUNT_AT_LEAST, adruser: username, adrnamespace: ELIGIBLE_NAMESPACES, adrdir: "newer", }); const deleted = resp2.query.alldeletedrevisions; total += deleted.length; if (deleted[0]) { let deletedOldest = new Date(deleted[0].timestamp); oldest = oldest ? new Date(Math.min(oldest.getTime(), deletedOldest.getTime())) : deletedOldest; } return total >= EDIT_COUNT_AT_LEAST && oldest && oldest <= earliestEditPredates; } /** * Returns true if cidr is undefined or in range [0, maxBits]. * @param {string|undefined} cidr * @param {number} maxBits * @returns {boolean} */ function isValidCidr(cidr, maxBits) { if (cidr === undefined) return true; let cidrNum = Number(cidr); return Number.isInteger(cidrNum) && cidrNum >= 0 && cidrNum <= maxBits; } /** * Validates IPv4 with optional CIDR suffix. * @param {string} candidate * @returns {boolean} */ function isValidIPv4(candidate) { if (!IPV4_REGEX.test(candidate)) return false; let [addr, cidr] = candidate.split("/"); let octets = addr.split(".").map(Number); let ipv4Valid = octets.length === 4 && octets.every((n) => Number.isInteger(n) && n >= 0 && n <= 255); return ipv4Valid && isValidCidr(cidr, 32); } /** * Validates IPv6 (full or compressed) with optional CIDR suffix. * @param {string} candidate * @returns {boolean} */ function isValidIPv6(candidate) { if (!IPV6_REGEX.test(candidate) || !candidate.includes(":")) return false; let [addr, cidr] = candidate.split("/"); if (!isValidCidr(cidr, 128)) return false; if (addr.includes(":::")) return false; if (addr.includes("::")) { if ((addr.match(/::/g) || []).length > 1) return false; let [left, right] = addr.split("::"); let leftParts = left ? left.split(":").filter(Boolean) : []; let rightParts = right ? right.split(":").filter(Boolean) : []; let hextets = leftParts.length + rightParts.length; let validParts = [...leftParts, ...rightParts].every((part) => /^[\da-f]{1,4}$/i.test(part), ); return validParts && hextets < 8; } let parts = addr.split(":"); return parts.length === 8 && parts.every((part) => /^[\da-f]{1,4}$/i.test(part)); } /** * Checks if a user is an IP/anon user, returning true if they are * @param {string} user * @returns {bool} */ function userIsAnon(user) { const normalized = user.trim(); if (TEMP_ACCT_REGEX.test(normalized)) return true; return isValidIPv4(normalized) || isValidIPv6(normalized); } // only fire on votes pages let pageName = mw.config.values.wgPageName; if ( pageName.startsWith("Wiktionary:Votes/") || pageName.startsWith("Wiktionary_talk:Votes/") ) { (async () => { // Step 1: find out when the vote ends let endDate; if (pageName.startsWith("Wiktionary_talk:")) { let mainTitle = pageName.replace(/^Wiktionary_talk:/, "Wiktionary:"); let mainPageResp = await restAPI.get( `/v1/page/${encodeURIComponent(mainTitle)}/html`, ); let mainPageDoc = new DOMParser().parseFromString( mainPageResp, "text/html", ); endDate = voteStart(mainPageDoc); } else { endDate = voteStart(document); } if (!(endDate instanceof Date) || isNaN(endDate)) { console.warn( "[vetvoters] Could not parse vote start date; skipping eligibility checks.", ); return; } // Step 2: collect user elements, including anons let userlinks = new Map(); // linkElem [HTMLElement] -> acctName [string] Object.entries(USER_LINK_PATTERNS).forEach(([selector, normalize]) => { document .querySelectorAll(selector) .forEach((link) => userlinks.set(link, normalize(link.title))); }); for (let link of document.querySelectorAll( `.mw-body-content [href^="//en.wiktionary.org/wiki/Special:Contributions/"]`, )) { let acct = link.title.replace(/^Special:Contributions\//, ""); if (!userIsAnon(acct)) continue; userlinks.set(link, acct); } let usernames = [...new Set(userlinks.values())]; let queries = usernames.map(async (user) => { try { return [user, await verifyUser(user, endDate)]; } catch (err) { console.warn( `[vetvoters] Failed to verify ${user}; treating as eligible.`, err, ); return [user, true]; } }); let userIsEligible = new Map(await Promise.all(queries)); for (let [elem, user] of userlinks) { if (userIsEligible.get(user) === false) highlightIneligible(elem); } })(); } 9gnom4jfbcsvkwno0gcyo0t8wii1m9k MediaWiki:Gadget-RhymesAdder.js 8 17998 88999 2025-09-17T22:26:11Z en>Ioaxxere 0 [[mw:Migrating mw.Uri to URL]] 88999 javascript text/javascript /* {{documentation}}<nowiki> Dependencies: ext.gadget.Editor,ext.gadget.LanguageUtils,mediawiki.util,mediawiki.Uri To do: * Make less ugly * Ability to remove/edit rhymes * Put rhyme template at the bottom of pronunciation section? * Add qualifier button */ /*jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /*global mw, WikiXml, importScript, importScriptURI, $ */ var numberOfRhymesAdded = 0; // Derived from [[User:Erutuon/scripts/templateParser.js]]. function parseTemplate(templateText) { var parameters = new Object(null), parameterRegex = /\|(?:([^=|}]+)=([^|}]+)|([^|}]+))/g, template = new Object(null); template.parameters = parameters; var match, index = 1, name = templateText.match(/^{{([^|}]+)/); if (name === null) throw new Error("Invalid template: no name."); template.name = name[1]; while ((match = parameterRegex.exec(templateText)) !== null) { if (match[1]) { parameters[match[1]] = match[2]; } else { parameters[index++] = match[3]; } } return template; } var englishCardinalNumerals = [null, 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty' ]; function extractNumberOfSyllables(h3text) { var m = h3text.match(/(\S+) syllables?/); if (!m) return null; var word = m[1]; var index = englishCardinalNumerals.indexOf(word.toLowerCase()); return index > 0 ? index : null; } function hasRhymeTemplate(wikitext, languageCode, rhyme) { // [[Template:rhyme]] redirects to [[Template:rhymes]]. // Simple regex is sufficient because there are no cases of {{rhymes}} with // nested templates in the dump. (FIXME: Could change in the future.) var match, rhymeTemplate = /{{rhymes?\|.+?}}/g; while ((match = rhymeTemplate.exec(wikitext)) !== null) { var template = parseTemplate(match[0]); var templateLanguageCode = template.parameters.lang || template.parameters[1]; if (templateLanguageCode == languageCode) { for (var i = template.parameters.lang ? 1 : 2; template.parameters[i]; ++i) { if (template.parameters[i].trim() === rhyme) return true; } } } return false; } function setUpRhymeAdderFor(h3, div) { var findNumberOfHeaders = parseInt(new URL(h3.find("a").get(0).href).searchParams.get("section")); var addNewRhymeForm; var syllableCount = extractNumberOfSyllables(h3.text()); var syllableArg = syllableCount ? "|s=" + syllableCount : ""; editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return addNewRhymeForm = $('<form>') .append( $('<label>+Add new rhyme: </label>') .append($('<input>').attr("name", 'rhyme')) ) .append($('<input>').attr('type', 'submit').val('Add'))[0]; }, 'fields': { 'rhyme': function(txt, error) { return txt || error('Please specify a rhyme.'); } }, 'onsubmit': function(values, render) { var langname = mw.config.get("wgTitle").split('/')[0]; var lutils = new LanguageUtilsAsync(); lutils.GetWiktionaryCodeByCanonicalName(langname).then(function(langcode) { $(addNewRhymeForm).find('input')[0].value = ""; var newItem = '{{l|' + langcode + '|' + values.rhyme + '}}'; render(newItem, function(newhtml) { var addedRhymeNode = $("<li>").html(newhtml), collator = window.Intl && new Intl.Collator( langcode, { "case": false } ), sortFunction = collator ? collator.compare : function compare( a, b ) { return a.toUpperCase() < b.toUpperCase() ? -1 : 1; }; editor.addEdit({ 'edit': function(wikitext) { var wikixml = WikiXml.parseWikitext(wikitext); var hdr = $(wikixml.find("section").get(findNumberOfHeaders - 1)); var headerData = hdr.find("data").get(0).textContent; var rhymelistbegin_match = headerData.match(/{{(?:rhyme-top|rhyme list begin)\|?[0-9]?}}/); var rhymelistbegin_index = rhymelistbegin_match.index + rhymelistbegin_match[0].length; var rhymelistend_match = headerData.match(/{{(?:rhyme-bottom|rhyme list end)}}/); var rhymelistend_index = rhymelistend_match.index; var rhymesPrefix = headerData.substring(0, rhymelistbegin_index); var rhymes = headerData.substring(rhymelistbegin_index, rhymelistend_index).trim().split(/\r?\n/); var rhymesSuffix = headerData.substring(rhymelistend_index); rhymes.push("* " + newItem); var canRearrange = true; var sortableLines = rhymes.map(function(line) { var m; m = line.match(/^\* ?{{l\|[a-zA-Z]{2,3}\|(.+)$/); if (m && m[1]) return [m[1], line]; m = line.match(/^\* ?\[\[(.+)$/); if (m && m[1]) return [m[1], line]; canRearrange = false; return null; }); console.trace("canRearrange is " + canRearrange); if (canRearrange) { sortableLines.sort( function(a,b) { return sortFunction(a[0], b[0]);} ); rhymes = sortableLines.map(function(sortableLine) { var match = sortableLine[1].match(/^\* ?\[\[(.+)]\]$/); if (match && match[1]) return "* {{l|" + langcode + "|" + match[1] + "}}"; else return sortableLine[1]; }); } $(hdr.find("data").get(0)).text(rhymesPrefix + "\n" + rhymes.join("\n") + "\n" + rhymesSuffix); return WikiXml.toWikitext(wikixml); }, 'redo': function() { div.find("ul").append(addedRhymeNode); div.find("li").sort(function(a, b) { return sortFunction( $(a).text(), $(b).text() ); }).appendTo(div.find("ul")); }, 'undo': function() { addedRhymeNode.remove(); }, 'summary': "+rhyme [[" + values.rhyme + "]]", 'after_save': function() { numberOfRhymesAdded++; document.body.style.cursor = 'wait'; new mw.Api().edit(values.rhyme, function(text) { text = text.content; var rhymehome = mw.config.get("wgTitle").split("/")[1]; if (hasRhymeTemplate(text, langcode, rhymehome)) { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; return $.Deferred().reject('rhyme already on page'); } if (text.match('==' + langname + '==') && !text.match("\\{\\{rhymes?(\\|" + langcode + "\\|" + mw.util.escapeRegExp(rhymehome) + "|\\|" + mw.util.escapeRegExp(rhymehome) + "\\|" + langcode + "|\\|" + mw.util.escapeRegExp(rhymehome) + ")\\}\\}")) { // If the current L2 section does not contain a pronunciation section, create the header. if (!String(text.match("==" + langname + "==[\\s\\S]*?(\n==[^=]|$)")).match("=Pronunciation=")) { text = text.replace(RegExp("(==" + langname + "==[\\s\\S]*?(?=\n=+(?=[^=])(?!(Etymology=|Alternative))))"), "$1\n===Pronunciation===\n"); } // Add the rhymes template under the pronunciation header. text = text.replace( RegExp('(==' + langname + '==[\\s\\S]*?=+Pronunciation=+[\\s\\S]*?\n(?![\:\*]))'), '$1* {{rhymes|' + langcode + "|" + rhymehome + syllableArg + '}}\n' ); } if (text) return { text: text, summary: "+rhyme [[" + mw.config.get("wgPageName") + "|" + "-" + rhymehome + "]]" }; else { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; return $.Deferred().reject('problem text is false'); } }).then(function() { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; }); } }, addedRhymeNode[ 0 ]); }); }); } }, h3.parent()[0], div[0]); } function setUpRhymeAdder() { $(".rhymes-list-begin").each(function() { var div = $(this); if (div.prev().text().indexOf("syllable") != -1) { try { setUpRhymeAdderFor(div.prev(), $(this)); } catch (e) { console.log(e); } } }); } if (mw.config.get('wgNamespaceNumber') === 106 && mw.config.get("wgAction") == "view") $.getScript("//en.wiktionary.org/w/index.php?title=User:Dixtosa/XMLize.js&action=raw", function() { $(setUpRhymeAdder); }); // </nowiki> bx1tn1mlyjr632ayerjvvzbzv3t34k0 89000 88999 2026-08-06T23:32:47Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-RhymesAdder.js]] 88999 javascript text/javascript /* {{documentation}}<nowiki> Dependencies: ext.gadget.Editor,ext.gadget.LanguageUtils,mediawiki.util,mediawiki.Uri To do: * Make less ugly * Ability to remove/edit rhymes * Put rhyme template at the bottom of pronunciation section? * Add qualifier button */ /*jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true */ /*global mw, WikiXml, importScript, importScriptURI, $ */ var numberOfRhymesAdded = 0; // Derived from [[User:Erutuon/scripts/templateParser.js]]. function parseTemplate(templateText) { var parameters = new Object(null), parameterRegex = /\|(?:([^=|}]+)=([^|}]+)|([^|}]+))/g, template = new Object(null); template.parameters = parameters; var match, index = 1, name = templateText.match(/^{{([^|}]+)/); if (name === null) throw new Error("Invalid template: no name."); template.name = name[1]; while ((match = parameterRegex.exec(templateText)) !== null) { if (match[1]) { parameters[match[1]] = match[2]; } else { parameters[index++] = match[3]; } } return template; } var englishCardinalNumerals = [null, 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty' ]; function extractNumberOfSyllables(h3text) { var m = h3text.match(/(\S+) syllables?/); if (!m) return null; var word = m[1]; var index = englishCardinalNumerals.indexOf(word.toLowerCase()); return index > 0 ? index : null; } function hasRhymeTemplate(wikitext, languageCode, rhyme) { // [[Template:rhyme]] redirects to [[Template:rhymes]]. // Simple regex is sufficient because there are no cases of {{rhymes}} with // nested templates in the dump. (FIXME: Could change in the future.) var match, rhymeTemplate = /{{rhymes?\|.+?}}/g; while ((match = rhymeTemplate.exec(wikitext)) !== null) { var template = parseTemplate(match[0]); var templateLanguageCode = template.parameters.lang || template.parameters[1]; if (templateLanguageCode == languageCode) { for (var i = template.parameters.lang ? 1 : 2; template.parameters[i]; ++i) { if (template.parameters[i].trim() === rhyme) return true; } } } return false; } function setUpRhymeAdderFor(h3, div) { var findNumberOfHeaders = parseInt(new URL(h3.find("a").get(0).href).searchParams.get("section")); var addNewRhymeForm; var syllableCount = extractNumberOfSyllables(h3.text()); var syllableArg = syllableCount ? "|s=" + syllableCount : ""; editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return addNewRhymeForm = $('<form>') .append( $('<label>+Add new rhyme: </label>') .append($('<input>').attr("name", 'rhyme')) ) .append($('<input>').attr('type', 'submit').val('Add'))[0]; }, 'fields': { 'rhyme': function(txt, error) { return txt || error('Please specify a rhyme.'); } }, 'onsubmit': function(values, render) { var langname = mw.config.get("wgTitle").split('/')[0]; var lutils = new LanguageUtilsAsync(); lutils.GetWiktionaryCodeByCanonicalName(langname).then(function(langcode) { $(addNewRhymeForm).find('input')[0].value = ""; var newItem = '{{l|' + langcode + '|' + values.rhyme + '}}'; render(newItem, function(newhtml) { var addedRhymeNode = $("<li>").html(newhtml), collator = window.Intl && new Intl.Collator( langcode, { "case": false } ), sortFunction = collator ? collator.compare : function compare( a, b ) { return a.toUpperCase() < b.toUpperCase() ? -1 : 1; }; editor.addEdit({ 'edit': function(wikitext) { var wikixml = WikiXml.parseWikitext(wikitext); var hdr = $(wikixml.find("section").get(findNumberOfHeaders - 1)); var headerData = hdr.find("data").get(0).textContent; var rhymelistbegin_match = headerData.match(/{{(?:rhyme-top|rhyme list begin)\|?[0-9]?}}/); var rhymelistbegin_index = rhymelistbegin_match.index + rhymelistbegin_match[0].length; var rhymelistend_match = headerData.match(/{{(?:rhyme-bottom|rhyme list end)}}/); var rhymelistend_index = rhymelistend_match.index; var rhymesPrefix = headerData.substring(0, rhymelistbegin_index); var rhymes = headerData.substring(rhymelistbegin_index, rhymelistend_index).trim().split(/\r?\n/); var rhymesSuffix = headerData.substring(rhymelistend_index); rhymes.push("* " + newItem); var canRearrange = true; var sortableLines = rhymes.map(function(line) { var m; m = line.match(/^\* ?{{l\|[a-zA-Z]{2,3}\|(.+)$/); if (m && m[1]) return [m[1], line]; m = line.match(/^\* ?\[\[(.+)$/); if (m && m[1]) return [m[1], line]; canRearrange = false; return null; }); console.trace("canRearrange is " + canRearrange); if (canRearrange) { sortableLines.sort( function(a,b) { return sortFunction(a[0], b[0]);} ); rhymes = sortableLines.map(function(sortableLine) { var match = sortableLine[1].match(/^\* ?\[\[(.+)]\]$/); if (match && match[1]) return "* {{l|" + langcode + "|" + match[1] + "}}"; else return sortableLine[1]; }); } $(hdr.find("data").get(0)).text(rhymesPrefix + "\n" + rhymes.join("\n") + "\n" + rhymesSuffix); return WikiXml.toWikitext(wikixml); }, 'redo': function() { div.find("ul").append(addedRhymeNode); div.find("li").sort(function(a, b) { return sortFunction( $(a).text(), $(b).text() ); }).appendTo(div.find("ul")); }, 'undo': function() { addedRhymeNode.remove(); }, 'summary': "+rhyme [[" + values.rhyme + "]]", 'after_save': function() { numberOfRhymesAdded++; document.body.style.cursor = 'wait'; new mw.Api().edit(values.rhyme, function(text) { text = text.content; var rhymehome = mw.config.get("wgTitle").split("/")[1]; if (hasRhymeTemplate(text, langcode, rhymehome)) { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; return $.Deferred().reject('rhyme already on page'); } if (text.match('==' + langname + '==') && !text.match("\\{\\{rhymes?(\\|" + langcode + "\\|" + mw.util.escapeRegExp(rhymehome) + "|\\|" + mw.util.escapeRegExp(rhymehome) + "\\|" + langcode + "|\\|" + mw.util.escapeRegExp(rhymehome) + ")\\}\\}")) { // If the current L2 section does not contain a pronunciation section, create the header. if (!String(text.match("==" + langname + "==[\\s\\S]*?(\n==[^=]|$)")).match("=Pronunciation=")) { text = text.replace(RegExp("(==" + langname + "==[\\s\\S]*?(?=\n=+(?=[^=])(?!(Etymology=|Alternative))))"), "$1\n===Pronunciation===\n"); } // Add the rhymes template under the pronunciation header. text = text.replace( RegExp('(==' + langname + '==[\\s\\S]*?=+Pronunciation=+[\\s\\S]*?\n(?![\:\*]))'), '$1* {{rhymes|' + langcode + "|" + rhymehome + syllableArg + '}}\n' ); } if (text) return { text: text, summary: "+rhyme [[" + mw.config.get("wgPageName") + "|" + "-" + rhymehome + "]]" }; else { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; return $.Deferred().reject('problem text is false'); } }).then(function() { document.body.style.cursor = --numberOfRhymesAdded ? 'wait' : ''; }); } }, addedRhymeNode[ 0 ]); }); }); } }, h3.parent()[0], div[0]); } function setUpRhymeAdder() { $(".rhymes-list-begin").each(function() { var div = $(this); if (div.prev().text().indexOf("syllable") != -1) { try { setUpRhymeAdderFor(div.prev(), $(this)); } catch (e) { console.log(e); } } }); } if (mw.config.get('wgNamespaceNumber') === 106 && mw.config.get("wgAction") == "view") $.getScript("//en.wiktionary.org/w/index.php?title=User:Dixtosa/XMLize.js&action=raw", function() { $(setUpRhymeAdder); }); // </nowiki> bx1tn1mlyjr632ayerjvvzbzv3t34k0 MediaWiki:Gadget-PatrollingEnhancements.js 8 17999 89001 2025-09-17T01:04:55Z en>Ioaxxere 0 Polyfill deprecated function newNode 89001 javascript text/javascript // {{documentation}} // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** (function PatrollingEnhancements_IIFE() { window.GPE = typeof window.GPE == 'object' ? window.GPE : {}; const GPE = window.GPE; /* </pre> ==Configuration options== <pre> */ // The initial value to put in the "deletion reason" text-field; you can // override this in your common.js (or vector.js or whatnot). GPE.initialDeleteReason = GPE.initialDeleteReason == undefined ? '' : GPE.initialDeleteReason; // The value to use as a deletion reason if you leave the text-field blank; you // can override it in your common.js (or vector.js or whatnot). If you *don't* // override this, then MediaWiki will generate an automatic deletion reason that // indicates the entry's last editor and the beginning of its content. GPE.deleteReasonIfBlank = GPE.deleteReasonIfBlank == undefined ? '' : GPE.deleteReasonIfBlank; // By DCDuring's request. If you set this to true, then Special:Watchlist will // show the deletion-reason text-input, but *not* the deletion-reason dropdown, // when there's an unpatrolled new-page-creation. GPE.hideDeleteReasonDropdownOnWatchlist = GPE.hideDeleteReasonDropdownOnWatchlist == undefined ? false : GPE.hideDeleteReasonDropdownOnWatchlist; /* </pre> ==Automated patrolling (whitelisting)== <pre> */ // set GPE.currMonth and GPE.lastMonth (in the form of, e.g., '2013/February') ( function () { var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; var now = new Date(); var currYear = now.getFullYear(); var currMonthNum = now.getMonth(); GPE.currMonth = currYear + '/' + monthNames[currMonthNum]; var lastYear = (currMonthNum == 0 ? currYear - 1 : currYear); var lastMonthNum = (currMonthNum == 0 ? 11 : currMonthNum - 1); GPE.lastMonth = lastYear + '/' + monthNames[lastMonthNum]; } )(); GPE.individualWhiteListedPages = { "Wiktionary:Requests for cleanup": true, "Wiktionary:Requests for verification": true, "Wiktionary:Requests for deletion": true, "Wiktionary:Requests for deletion/Others": true, "Wiktionary:Requests for moves, mergers and splits": true, "Wiktionary:Information desk": true, "Wiktionary:Tea room": true, "Wiktionary:Etymology scriptorium": true, "Wiktionary:Requested entries (English)": true, "Wiktionary:Requested entries (Spanish)": true, "Wiktionary:List of protologisms": true, "Wiktionary:Translation requests": true, "Wiktionary:Feedback": true, "Wiktionary:Sandbox": true, "Wiktionary talk:Sandbox": true, "Wiktionary:Tutorial (Editing)/sandbox": true, "Wiktionary:Featured word candidates": true, "Wiktionary:Word of the day/Nominations": true }; GPE.individualWhiteListedPages["Wiktionary:Beer parlour/" + GPE.currMonth] = GPE.individualWhiteListedPages["Wiktionary:Beer parlour/" + GPE.lastMonth] = GPE.individualWhiteListedPages["Wiktionary:Grease pit/" + GPE.currMonth] = GPE.individualWhiteListedPages["Wiktionary:Grease pit/" + GPE.lastMonth] = true; // per-user white-listed sub-pages (for example, edits by user Foo // to User:Foo/vector.js should be autopatrolled): GPE.perUserWhiteListedSubPages = { "/Sandbox": true, "/sandbox": true, "/chick.js": true, "/chick.css": true, "/standard.js": true, "/standard.css": true, "/cologneblue.js": true, "/cologneblue.css": true, "/modern.js": true, "/modern.css": true, "/myskin.js": true, "/myskin.css": true, "/nostalgia.js": true, "/nostalgia.css": true, "/simple.js": true, "/simple.css": true, "/vector.js": true, "/vector.css": true, "/common.js": true, "/common.css": true }; GPE.individualWhiteListedContributors = { }; GPE.shouldAutoPatrol = function(link) { var pagename = link.title; if(pagename.indexOf('User talk:') == 0) return true; if(pagename in GPE.individualWhiteListedPages) return true; var contributor; if(mediaWiki.config.get('wgCanonicalSpecialPageName') === 'Contributions') { contributor = document.getElementById('t-contributions') .getElementsByTagName('a')[0].href.replace(/.*\//, ''); } else { var li = link.parentNode; if(li.tagName.toUpperCase() == 'SPAN') li = li.parentNode; var links = li.getElementsByTagName('a'); for(var i = 0; i < links.length; ++i) if(links[i].title.indexOf('Special:Contributions/') == 0) { contributor = links[i].title.substr('Special:Contributions/'.length); break; } } if(pagename.indexOf('User:' + contributor + '/') == 0) if(pagename.substr(contributor.length + 5) in GPE.perUserWhiteListedSubPages) return true; if(contributor in GPE.individualWhiteListedContributors) return true; return false; }; /* </pre> ==Utility functions== <pre> */ GPE.newButton = function(text, color, hoverText) { var button = newNode('button', text); button.style.background = color; button.style.color = '#FFF'; button.style.border = '0'; button.style.padding = '0'; button.style.cursor = 'pointer'; button.title = hoverText; return button; }; GPE.disableButton = function(button, text, hoverText) { button.onclick = null; button.title = (hoverText || ''); button.innerHTML = text; // clear out explicit styling and disable, so we can get appropriate // disabled-button styles: button.style.background = ''; button.style.color = ''; button.style.cursor = ''; button.disabled = 'disabled'; }; /* </pre> ==Individual patrol-buttons== <pre> */ GPE.addPatrolButton = function(link, rcid) { if(link.className.search(/(?:^|\s)gpe-hasPatrolButton(?:\s|$)/) > -1) return; link.className = (link.className + ' gpe-hasPatrolButton').trim(); var button = GPE.newButton('M', '#009', 'click to mark as patrolled'); link.parentNode.insertBefore(button, link.nextSibling); link.parentNode.insertBefore(document.createTextNode(' · '), button); button.onclick = function () { var token = mediaWiki.user.tokens.get('patrolToken'); $.post ( '/w/api.php?format=json&action=patrol&assert=user', { token: token, rcid: rcid }, function (data) { if(data.patrol) GPE.disableButton(button, 'm', 'marked as patrolled'); else if(data.error) { var msg = data.error.code + ': ' + data.error.info; if(data.error.code == 'badtoken') msg += ': "' + token + '"'; alert(msg); } }, 'json' ); }; if(GPE.shouldAutoPatrol(link)) button.click(); // remove the exclamation point: var tmp = link; while(tmp && tmp.nodeName.toUpperCase() !== 'LI') tmp = tmp.parentNode; if(tmp) tmp = tmp.getElementsByClassName('unpatrolled')[0]; if(tmp) tmp.parentNode.removeChild(tmp); }; /* </pre> ==Individual delete-buttons== <pre> */ GPE.addDeleteButton = function(link, title) { if(link.className.search(/(?:^|\s)gpe-hasDeleteButton(?:\s|$)/) > -1) return; link.className = (link.className + ' gpe-hasDeleteButton').trim(); var button = GPE.newButton('D', '#900', 'click to delete'); link.parentNode.insertBefore(button, link.nextSibling); link.parentNode.insertBefore(document.createTextNode(' · '), button); button.onclick = function () { var dropdownReason = document.getElementById('deleteReasonsDropdown') ? document.getElementById('deleteReasonsDropdown').value : ''; if(dropdownReason == 'other') dropdownReason = ''; var textInputReason = document.getElementById('deleteReasonTextInput').value; var reason; if(dropdownReason.length && textInputReason.length) reason = dropdownReason + ': ' + textInputReason; else if(dropdownReason.length || textInputReason.length) reason = dropdownReason + textInputReason; else reason = GPE.deleteReasonIfBlank; var token = mediaWiki.user.tokens.get('deleteToken'); $.post ( '/w/api.php?format=json&action=delete&assert=user', { title: title, token: token, reason: reason }, function (data) { if(data['delete']) GPE.disableButton(button, 'd', 'deleted'); else if(data.error) { var msg = data.error.code + ': ' + data.error.info; if(data.error.code == 'badtoken') msg += ': "' + token + '"'; alert(msg); } }, 'json' ); }; }; /* </pre> ==Delete-reasons== <pre> */ GPE.addDeleteReasonInput = function () { var deleteReasonDiv = ( newNode ( 'div', { style: 'background:#900; color:#FFF; ' + 'position:fixed; bottom:0; right:0; margin-bottom:0' }, '\u00A0Deletion reason:\u00A0' ) ); deleteReasonDiv.title = 'the deletion reason (message/summary) to use when you click "D"'; var deleteReasonTextInput = ( newNode ( 'input', { type: 'text', size: 80, id: 'deleteReasonTextInput', value: GPE.initialDeleteReason, style: 'position:fixed; right:0; margin-bottom:0' } ) ); deleteReasonDiv.appendChild(deleteReasonTextInput); document.getElementById('bodyContent').appendChild(deleteReasonDiv); if(GPE.hideDeleteReasonDropdownOnWatchlist) if(mediaWiki.config.get('wgPageName') == 'Special:Watchlist') return; // get canned messages from [[MediaWiki:Deletereason-dropdown]]: $.getJSON ( '/w/api.php?format=json&action=query&meta=allmessages&ammessages=Deletereason-dropdown', function (data) { var rawDeleteReasons = data.query.allmessages[0]['*']; var deleteReasonsDropdown = newNode('select', { id: 'deleteReasonsDropdown', style: 'vertical-align: bottom' }); deleteReasonsDropdown.appendChild (newNode('option', { value: 'other' }, 'Other reason')); var optGroup = deleteReasonsDropdown; rawDeleteReasons.replace ( /^(\*\*?) *(.+)$/gm, function (s, asterisks, text) { if(asterisks == '*') deleteReasonsDropdown.appendChild (optGroup = newNode('optgroup', { label: text })); else // '**' optGroup.appendChild(newNode('option', { value: text }, text)); } ); deleteReasonDiv.insertBefore(deleteReasonsDropdown, deleteReasonTextInput); deleteReasonDiv.insertBefore(newNode('br'), deleteReasonTextInput); deleteReasonDiv.insertBefore(document.createTextNode('\u00A0'), deleteReasonTextInput); } ); }; /* </pre> ==Namespaces== <pre> */ GPE.computeNamespaces = function (selected, includeAssociated, invertSelection) { var associated = Number(selected) + (selected % 2 === 0 ? 1 : -1); if(invertSelection) { var selector = document.getElementById('namespace'); if(! selector) return []; var ret = []; for(var option = selector.firstChild; option; option = option.nextSibling) if(option.nodeName.toUpperCase() === 'OPTION' && option.value) if(option.value != selected) if(! includeAssociated || option.value != associated) ret.push(option.value); return ret; } else { if(includeAssociated) return [selected, associated]; else return [selected]; } }; GPE.generateRcnamespace = function () { var currUrl = document.location.href; if(! /[?&]namespace=\d+(?:&|$)/.test(currUrl)) return; var selected = /[?&]namespace=(\d+)(?:&|$)/.exec(currUrl)[1]; var includeAssociated = mediaWiki.config.get('wgPageName') !== 'Special:NewPages' && /[?&]associated=(?!0?&|0?$)/.test(currUrl); var invertSelection = /[?&]invert=(?!0?&|0?$)/.test(currUrl); var namespaces = GPE.computeNamespaces(selected, includeAssociated, invertSelection); if(namespaces.length > 0) return namespaces.join('|'); }; /* </pre> ==Find and handle links== <pre> */ GPE.handleUnpatrolledEdits = function (rcidsByRevid) { var links = document.getElementById('bodyContent').getElementsByTagName('a'); for(var i = links.length - 1; i >= 0; --i) { var mapKey = /&diff=(prev&oldid=)?(\d+)(&|$)/.exec(links[i].href); if(mapKey && rcidsByRevid.hasOwnProperty(mapKey[2])) GPE.addPatrolButton(links[i], rcidsByRevid[mapKey[2]]); } }; GPE.findLinksToUnpatrolledNewPages = function (rcidsByTitle) { if(mediaWiki.config.get('wgPageName') === 'Special:NewPages') { var ret = []; $('li.not-patrolled a.mw-newpages-pagename').each(function () { if (this.title && rcidsByTitle.hasOwnProperty(this.title)) ret.push(this); }); return ret; } else { var ret = []; var abbrs = document.getElementById('bodyContent').getElementsByTagName('abbr'); for(var i = abbrs.length - 1; i >= 0; --i) { if(abbrs[i].className != 'newpage') continue; var link = abbrs[i]; while(link && link.nodeName.toUpperCase() != 'A') if(link.nodeName.toUpperCase() === 'SPAN' && link.className === 'mw-title') link = link.firstChild; else link = link.nextSibling; if(link && link.title && rcidsByTitle.hasOwnProperty(link.title)) ret.push(link); } return ret; } }; GPE.handleUnpatrolledNewPages = function (rcidsByTitle) { var userIsSysop = mediaWiki.config.get('wgUserGroups').indexOf('sysop') > -1; var links = GPE.findLinksToUnpatrolledNewPages(rcidsByTitle); for(var i = links.length - 1; i >= 0; --i) { var link = links[i]; // 2016-04: Equinox removing red D delete button because it hasn't worked for a year. // if(userIsSysop) // GPE.addDeleteButton(link, link.title); GPE.addPatrolButton(link, rcidsByTitle[link.title]); } // Remove the rest of the delete features as above // if(userIsSysop && links.length > 0) // { // GPE.getAndStoreDeleteToken(); // GPE.addDeleteReasonInput(); // } }; GPE.getAndStoreDeleteToken = function () { $.getJSON ( '/w/api.php?format=json&action=tokens&type=delete', function (data) { var token = data.tokens.deletetoken; if(! token || token.search(/^[0-9a-f]{32}\+\\$/) != 0) return; mediaWiki.user.tokens.set('deleteToken', token); } ); }; GPE.main = function (params) { var url = '/w/api.php?format=json&action=query&list=recentchanges' + '&rcprop=ids|title' + '&rcshow=!patrolled' + (params.hasOwnProperty('rcshow') ? '|' + params.rcshow : '') + '&rclimit=' + (params.hasOwnProperty('rclimit') ? params.rclimit : 500) + '&rctype=' + (params.hasOwnProperty('rctype') ? params.rctype : 'edit|new') + (params.hasOwnProperty('rcdir') ? '&rcdir=' + params.rcdir : '') + (params.hasOwnProperty('rcstart') ? '&rcstart=' + params.rcstart : '') + (params.hasOwnProperty('rcnamespace') ? '&rcnamespace=' + params.rcnamespace : '') + (params.hasOwnProperty('rcuser') ? '&rcuser=' + params.rcuser : ''); $.getJSON ( url, function (data) { data = data.query.recentchanges; var rcidsByRevid = {}; // for unpatrolled edits var rcidsByTitle = {}; // for unpatrolled new pages for(var i = 0; i < data.length; ++i) if(data[i].type == 'edit') rcidsByRevid[data[i].revid] = data[i].rcid; else rcidsByTitle[data[i].title] = data[i].rcid; GPE.handleUnpatrolledEdits(rcidsByRevid); GPE.handleUnpatrolledNewPages(rcidsByTitle); } ); }; /* </pre> ==Onload-hooks== <pre> */ $( document ).ready ( function () { if(mediaWiki.config.get('wgPageName') === 'Special:RecentChanges') { var currUrl = document.location.href; var params = {}; var rcshow = []; if(currUrl.search(/[?&]hideliu=(?!0?$|0?&)/) > -1) rcshow.push('anon'); else if(currUrl.search(/[?&]hideanons=(?!0?$|0?&)/) > -1) rcshow.push('!anon'); if(document.getElementsByClassName('minoredit').length === 0) rcshow.push('!minor'); if(rcshow.length > 0) params.rcshow = rcshow.join('|'); var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; GPE.main(params); } else if(mediaWiki.config.get('wgPageName') === 'Special:NewPages') { var currUrl = document.location.href; var params = { rctype: 'new' }; var rcshow = []; if(currUrl.search(/[?&]hideliu=(?!0?$|0?&)/) > -1) rcshow.push('anon'); if(currUrl.search(/[?&]hideredirs=0?(?:$|&)/) === -1) rcshow.push('!redirect'); if(rcshow.length > 0) params.rcshow = rcshow.join('|'); if(currUrl.search(/[?&]dir=prev(?=$|&)/) > -1) { params.rcdir = 'newer'; if(currUrl.search(/[?&]offset=\d+(?=$|&)/) > -1) params.rcstart = currUrl.match(/[?&]offset=(\d+)(?=$|&)/)[1]; } var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; GPE.main(params); } else if(mediaWiki.config.get('wgPageName') === 'Special:Watchlist') { var params = {}; var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; // TODO is this the best way to find what we need for the watchlist? GPE.main(params); } else if(mediaWiki.config.get('wgPageName').search(/^Special:Contributions(\/|$)/) === 0) GPE.main({ rcuser: document.getElementById('t-contributions').firstChild.href.replace(/^.*?\/Special:Contributions\//, '') }); else if(mediaWiki.config.get('wgAction') === 'markpatrolled' || mediaWiki.config.get('wgAction') === 'delete' || mediaWiki.config.get('wgAction') === 'rollback') GPE.main({ rclimit: 15 }); } ); })(); g9g0tszn8uzicki57h3lrynnuqr2imv 89002 89001 2026-08-06T23:32:55Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-PatrollingEnhancements.js]] 89001 javascript text/javascript // {{documentation}} // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** (function PatrollingEnhancements_IIFE() { window.GPE = typeof window.GPE == 'object' ? window.GPE : {}; const GPE = window.GPE; /* </pre> ==Configuration options== <pre> */ // The initial value to put in the "deletion reason" text-field; you can // override this in your common.js (or vector.js or whatnot). GPE.initialDeleteReason = GPE.initialDeleteReason == undefined ? '' : GPE.initialDeleteReason; // The value to use as a deletion reason if you leave the text-field blank; you // can override it in your common.js (or vector.js or whatnot). If you *don't* // override this, then MediaWiki will generate an automatic deletion reason that // indicates the entry's last editor and the beginning of its content. GPE.deleteReasonIfBlank = GPE.deleteReasonIfBlank == undefined ? '' : GPE.deleteReasonIfBlank; // By DCDuring's request. If you set this to true, then Special:Watchlist will // show the deletion-reason text-input, but *not* the deletion-reason dropdown, // when there's an unpatrolled new-page-creation. GPE.hideDeleteReasonDropdownOnWatchlist = GPE.hideDeleteReasonDropdownOnWatchlist == undefined ? false : GPE.hideDeleteReasonDropdownOnWatchlist; /* </pre> ==Automated patrolling (whitelisting)== <pre> */ // set GPE.currMonth and GPE.lastMonth (in the form of, e.g., '2013/February') ( function () { var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; var now = new Date(); var currYear = now.getFullYear(); var currMonthNum = now.getMonth(); GPE.currMonth = currYear + '/' + monthNames[currMonthNum]; var lastYear = (currMonthNum == 0 ? currYear - 1 : currYear); var lastMonthNum = (currMonthNum == 0 ? 11 : currMonthNum - 1); GPE.lastMonth = lastYear + '/' + monthNames[lastMonthNum]; } )(); GPE.individualWhiteListedPages = { "Wiktionary:Requests for cleanup": true, "Wiktionary:Requests for verification": true, "Wiktionary:Requests for deletion": true, "Wiktionary:Requests for deletion/Others": true, "Wiktionary:Requests for moves, mergers and splits": true, "Wiktionary:Information desk": true, "Wiktionary:Tea room": true, "Wiktionary:Etymology scriptorium": true, "Wiktionary:Requested entries (English)": true, "Wiktionary:Requested entries (Spanish)": true, "Wiktionary:List of protologisms": true, "Wiktionary:Translation requests": true, "Wiktionary:Feedback": true, "Wiktionary:Sandbox": true, "Wiktionary talk:Sandbox": true, "Wiktionary:Tutorial (Editing)/sandbox": true, "Wiktionary:Featured word candidates": true, "Wiktionary:Word of the day/Nominations": true }; GPE.individualWhiteListedPages["Wiktionary:Beer parlour/" + GPE.currMonth] = GPE.individualWhiteListedPages["Wiktionary:Beer parlour/" + GPE.lastMonth] = GPE.individualWhiteListedPages["Wiktionary:Grease pit/" + GPE.currMonth] = GPE.individualWhiteListedPages["Wiktionary:Grease pit/" + GPE.lastMonth] = true; // per-user white-listed sub-pages (for example, edits by user Foo // to User:Foo/vector.js should be autopatrolled): GPE.perUserWhiteListedSubPages = { "/Sandbox": true, "/sandbox": true, "/chick.js": true, "/chick.css": true, "/standard.js": true, "/standard.css": true, "/cologneblue.js": true, "/cologneblue.css": true, "/modern.js": true, "/modern.css": true, "/myskin.js": true, "/myskin.css": true, "/nostalgia.js": true, "/nostalgia.css": true, "/simple.js": true, "/simple.css": true, "/vector.js": true, "/vector.css": true, "/common.js": true, "/common.css": true }; GPE.individualWhiteListedContributors = { }; GPE.shouldAutoPatrol = function(link) { var pagename = link.title; if(pagename.indexOf('User talk:') == 0) return true; if(pagename in GPE.individualWhiteListedPages) return true; var contributor; if(mediaWiki.config.get('wgCanonicalSpecialPageName') === 'Contributions') { contributor = document.getElementById('t-contributions') .getElementsByTagName('a')[0].href.replace(/.*\//, ''); } else { var li = link.parentNode; if(li.tagName.toUpperCase() == 'SPAN') li = li.parentNode; var links = li.getElementsByTagName('a'); for(var i = 0; i < links.length; ++i) if(links[i].title.indexOf('Special:Contributions/') == 0) { contributor = links[i].title.substr('Special:Contributions/'.length); break; } } if(pagename.indexOf('User:' + contributor + '/') == 0) if(pagename.substr(contributor.length + 5) in GPE.perUserWhiteListedSubPages) return true; if(contributor in GPE.individualWhiteListedContributors) return true; return false; }; /* </pre> ==Utility functions== <pre> */ GPE.newButton = function(text, color, hoverText) { var button = newNode('button', text); button.style.background = color; button.style.color = '#FFF'; button.style.border = '0'; button.style.padding = '0'; button.style.cursor = 'pointer'; button.title = hoverText; return button; }; GPE.disableButton = function(button, text, hoverText) { button.onclick = null; button.title = (hoverText || ''); button.innerHTML = text; // clear out explicit styling and disable, so we can get appropriate // disabled-button styles: button.style.background = ''; button.style.color = ''; button.style.cursor = ''; button.disabled = 'disabled'; }; /* </pre> ==Individual patrol-buttons== <pre> */ GPE.addPatrolButton = function(link, rcid) { if(link.className.search(/(?:^|\s)gpe-hasPatrolButton(?:\s|$)/) > -1) return; link.className = (link.className + ' gpe-hasPatrolButton').trim(); var button = GPE.newButton('M', '#009', 'click to mark as patrolled'); link.parentNode.insertBefore(button, link.nextSibling); link.parentNode.insertBefore(document.createTextNode(' · '), button); button.onclick = function () { var token = mediaWiki.user.tokens.get('patrolToken'); $.post ( '/w/api.php?format=json&action=patrol&assert=user', { token: token, rcid: rcid }, function (data) { if(data.patrol) GPE.disableButton(button, 'm', 'marked as patrolled'); else if(data.error) { var msg = data.error.code + ': ' + data.error.info; if(data.error.code == 'badtoken') msg += ': "' + token + '"'; alert(msg); } }, 'json' ); }; if(GPE.shouldAutoPatrol(link)) button.click(); // remove the exclamation point: var tmp = link; while(tmp && tmp.nodeName.toUpperCase() !== 'LI') tmp = tmp.parentNode; if(tmp) tmp = tmp.getElementsByClassName('unpatrolled')[0]; if(tmp) tmp.parentNode.removeChild(tmp); }; /* </pre> ==Individual delete-buttons== <pre> */ GPE.addDeleteButton = function(link, title) { if(link.className.search(/(?:^|\s)gpe-hasDeleteButton(?:\s|$)/) > -1) return; link.className = (link.className + ' gpe-hasDeleteButton').trim(); var button = GPE.newButton('D', '#900', 'click to delete'); link.parentNode.insertBefore(button, link.nextSibling); link.parentNode.insertBefore(document.createTextNode(' · '), button); button.onclick = function () { var dropdownReason = document.getElementById('deleteReasonsDropdown') ? document.getElementById('deleteReasonsDropdown').value : ''; if(dropdownReason == 'other') dropdownReason = ''; var textInputReason = document.getElementById('deleteReasonTextInput').value; var reason; if(dropdownReason.length && textInputReason.length) reason = dropdownReason + ': ' + textInputReason; else if(dropdownReason.length || textInputReason.length) reason = dropdownReason + textInputReason; else reason = GPE.deleteReasonIfBlank; var token = mediaWiki.user.tokens.get('deleteToken'); $.post ( '/w/api.php?format=json&action=delete&assert=user', { title: title, token: token, reason: reason }, function (data) { if(data['delete']) GPE.disableButton(button, 'd', 'deleted'); else if(data.error) { var msg = data.error.code + ': ' + data.error.info; if(data.error.code == 'badtoken') msg += ': "' + token + '"'; alert(msg); } }, 'json' ); }; }; /* </pre> ==Delete-reasons== <pre> */ GPE.addDeleteReasonInput = function () { var deleteReasonDiv = ( newNode ( 'div', { style: 'background:#900; color:#FFF; ' + 'position:fixed; bottom:0; right:0; margin-bottom:0' }, '\u00A0Deletion reason:\u00A0' ) ); deleteReasonDiv.title = 'the deletion reason (message/summary) to use when you click "D"'; var deleteReasonTextInput = ( newNode ( 'input', { type: 'text', size: 80, id: 'deleteReasonTextInput', value: GPE.initialDeleteReason, style: 'position:fixed; right:0; margin-bottom:0' } ) ); deleteReasonDiv.appendChild(deleteReasonTextInput); document.getElementById('bodyContent').appendChild(deleteReasonDiv); if(GPE.hideDeleteReasonDropdownOnWatchlist) if(mediaWiki.config.get('wgPageName') == 'Special:Watchlist') return; // get canned messages from [[MediaWiki:Deletereason-dropdown]]: $.getJSON ( '/w/api.php?format=json&action=query&meta=allmessages&ammessages=Deletereason-dropdown', function (data) { var rawDeleteReasons = data.query.allmessages[0]['*']; var deleteReasonsDropdown = newNode('select', { id: 'deleteReasonsDropdown', style: 'vertical-align: bottom' }); deleteReasonsDropdown.appendChild (newNode('option', { value: 'other' }, 'Other reason')); var optGroup = deleteReasonsDropdown; rawDeleteReasons.replace ( /^(\*\*?) *(.+)$/gm, function (s, asterisks, text) { if(asterisks == '*') deleteReasonsDropdown.appendChild (optGroup = newNode('optgroup', { label: text })); else // '**' optGroup.appendChild(newNode('option', { value: text }, text)); } ); deleteReasonDiv.insertBefore(deleteReasonsDropdown, deleteReasonTextInput); deleteReasonDiv.insertBefore(newNode('br'), deleteReasonTextInput); deleteReasonDiv.insertBefore(document.createTextNode('\u00A0'), deleteReasonTextInput); } ); }; /* </pre> ==Namespaces== <pre> */ GPE.computeNamespaces = function (selected, includeAssociated, invertSelection) { var associated = Number(selected) + (selected % 2 === 0 ? 1 : -1); if(invertSelection) { var selector = document.getElementById('namespace'); if(! selector) return []; var ret = []; for(var option = selector.firstChild; option; option = option.nextSibling) if(option.nodeName.toUpperCase() === 'OPTION' && option.value) if(option.value != selected) if(! includeAssociated || option.value != associated) ret.push(option.value); return ret; } else { if(includeAssociated) return [selected, associated]; else return [selected]; } }; GPE.generateRcnamespace = function () { var currUrl = document.location.href; if(! /[?&]namespace=\d+(?:&|$)/.test(currUrl)) return; var selected = /[?&]namespace=(\d+)(?:&|$)/.exec(currUrl)[1]; var includeAssociated = mediaWiki.config.get('wgPageName') !== 'Special:NewPages' && /[?&]associated=(?!0?&|0?$)/.test(currUrl); var invertSelection = /[?&]invert=(?!0?&|0?$)/.test(currUrl); var namespaces = GPE.computeNamespaces(selected, includeAssociated, invertSelection); if(namespaces.length > 0) return namespaces.join('|'); }; /* </pre> ==Find and handle links== <pre> */ GPE.handleUnpatrolledEdits = function (rcidsByRevid) { var links = document.getElementById('bodyContent').getElementsByTagName('a'); for(var i = links.length - 1; i >= 0; --i) { var mapKey = /&diff=(prev&oldid=)?(\d+)(&|$)/.exec(links[i].href); if(mapKey && rcidsByRevid.hasOwnProperty(mapKey[2])) GPE.addPatrolButton(links[i], rcidsByRevid[mapKey[2]]); } }; GPE.findLinksToUnpatrolledNewPages = function (rcidsByTitle) { if(mediaWiki.config.get('wgPageName') === 'Special:NewPages') { var ret = []; $('li.not-patrolled a.mw-newpages-pagename').each(function () { if (this.title && rcidsByTitle.hasOwnProperty(this.title)) ret.push(this); }); return ret; } else { var ret = []; var abbrs = document.getElementById('bodyContent').getElementsByTagName('abbr'); for(var i = abbrs.length - 1; i >= 0; --i) { if(abbrs[i].className != 'newpage') continue; var link = abbrs[i]; while(link && link.nodeName.toUpperCase() != 'A') if(link.nodeName.toUpperCase() === 'SPAN' && link.className === 'mw-title') link = link.firstChild; else link = link.nextSibling; if(link && link.title && rcidsByTitle.hasOwnProperty(link.title)) ret.push(link); } return ret; } }; GPE.handleUnpatrolledNewPages = function (rcidsByTitle) { var userIsSysop = mediaWiki.config.get('wgUserGroups').indexOf('sysop') > -1; var links = GPE.findLinksToUnpatrolledNewPages(rcidsByTitle); for(var i = links.length - 1; i >= 0; --i) { var link = links[i]; // 2016-04: Equinox removing red D delete button because it hasn't worked for a year. // if(userIsSysop) // GPE.addDeleteButton(link, link.title); GPE.addPatrolButton(link, rcidsByTitle[link.title]); } // Remove the rest of the delete features as above // if(userIsSysop && links.length > 0) // { // GPE.getAndStoreDeleteToken(); // GPE.addDeleteReasonInput(); // } }; GPE.getAndStoreDeleteToken = function () { $.getJSON ( '/w/api.php?format=json&action=tokens&type=delete', function (data) { var token = data.tokens.deletetoken; if(! token || token.search(/^[0-9a-f]{32}\+\\$/) != 0) return; mediaWiki.user.tokens.set('deleteToken', token); } ); }; GPE.main = function (params) { var url = '/w/api.php?format=json&action=query&list=recentchanges' + '&rcprop=ids|title' + '&rcshow=!patrolled' + (params.hasOwnProperty('rcshow') ? '|' + params.rcshow : '') + '&rclimit=' + (params.hasOwnProperty('rclimit') ? params.rclimit : 500) + '&rctype=' + (params.hasOwnProperty('rctype') ? params.rctype : 'edit|new') + (params.hasOwnProperty('rcdir') ? '&rcdir=' + params.rcdir : '') + (params.hasOwnProperty('rcstart') ? '&rcstart=' + params.rcstart : '') + (params.hasOwnProperty('rcnamespace') ? '&rcnamespace=' + params.rcnamespace : '') + (params.hasOwnProperty('rcuser') ? '&rcuser=' + params.rcuser : ''); $.getJSON ( url, function (data) { data = data.query.recentchanges; var rcidsByRevid = {}; // for unpatrolled edits var rcidsByTitle = {}; // for unpatrolled new pages for(var i = 0; i < data.length; ++i) if(data[i].type == 'edit') rcidsByRevid[data[i].revid] = data[i].rcid; else rcidsByTitle[data[i].title] = data[i].rcid; GPE.handleUnpatrolledEdits(rcidsByRevid); GPE.handleUnpatrolledNewPages(rcidsByTitle); } ); }; /* </pre> ==Onload-hooks== <pre> */ $( document ).ready ( function () { if(mediaWiki.config.get('wgPageName') === 'Special:RecentChanges') { var currUrl = document.location.href; var params = {}; var rcshow = []; if(currUrl.search(/[?&]hideliu=(?!0?$|0?&)/) > -1) rcshow.push('anon'); else if(currUrl.search(/[?&]hideanons=(?!0?$|0?&)/) > -1) rcshow.push('!anon'); if(document.getElementsByClassName('minoredit').length === 0) rcshow.push('!minor'); if(rcshow.length > 0) params.rcshow = rcshow.join('|'); var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; GPE.main(params); } else if(mediaWiki.config.get('wgPageName') === 'Special:NewPages') { var currUrl = document.location.href; var params = { rctype: 'new' }; var rcshow = []; if(currUrl.search(/[?&]hideliu=(?!0?$|0?&)/) > -1) rcshow.push('anon'); if(currUrl.search(/[?&]hideredirs=0?(?:$|&)/) === -1) rcshow.push('!redirect'); if(rcshow.length > 0) params.rcshow = rcshow.join('|'); if(currUrl.search(/[?&]dir=prev(?=$|&)/) > -1) { params.rcdir = 'newer'; if(currUrl.search(/[?&]offset=\d+(?=$|&)/) > -1) params.rcstart = currUrl.match(/[?&]offset=(\d+)(?=$|&)/)[1]; } var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; GPE.main(params); } else if(mediaWiki.config.get('wgPageName') === 'Special:Watchlist') { var params = {}; var rcnamespace = GPE.generateRcnamespace(); if(rcnamespace) params.rcnamespace = rcnamespace; // TODO is this the best way to find what we need for the watchlist? GPE.main(params); } else if(mediaWiki.config.get('wgPageName').search(/^Special:Contributions(\/|$)/) === 0) GPE.main({ rcuser: document.getElementById('t-contributions').firstChild.href.replace(/^.*?\/Special:Contributions\//, '') }); else if(mediaWiki.config.get('wgAction') === 'markpatrolled' || mediaWiki.config.get('wgAction') === 'delete' || mediaWiki.config.get('wgAction') === 'rollback') GPE.main({ rclimit: 15 }); } ); })(); g9g0tszn8uzicki57h3lrynnuqr2imv MediaWiki:Gadget-RegexMenuFramework.js 8 18000 89003 2017-08-20T18:42:21Z en>Dixtosa 0 89003 javascript text/javascript // {{documentation}} /** * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor. * @see [[meta:TemplateScript]] * @author [[User:Pathoschild]] * @update-token [[meta:File:pathoschild/templatescript.js]] */ mw.loader.load('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js'); 7blaltfqd7vx48e4935xh5r92z0lips 89004 89003 2026-08-06T23:33:04Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-RegexMenuFramework.js]] 89003 javascript text/javascript // {{documentation}} /** * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor. * @see [[meta:TemplateScript]] * @author [[User:Pathoschild]] * @update-token [[meta:File:pathoschild/templatescript.js]] */ mw.loader.load('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js'); 7blaltfqd7vx48e4935xh5r92z0lips MediaWiki:Gadget-AcceleratedFormCreation.js 8 18001 89005 2025-10-31T09:35:05Z en>Surjection 0 89005 javascript text/javascript // <nowiki> /* globals mw, $ */ // jshint maxerr:500 // FIXME: This gadget relies to an excessive degree on OrangeLinks to function. These gadgets should be made independent. /* * The starting point of the whole script. * * This adds a hook to the page load event so that the script runs * adds the generated text to the edit window once the page is done loading. */ "use strict"; mw.loader.using(["mediawiki.util"]).done(function() { var pageName = mw.config.get("wgPageName"); // Don't do anything unless the current page is in the main namespace. // Set window.accelEverywhere = true to test this gadget elsewhere. if (window.accelEverywhere || (mw.config.get("wgAction") === "view" && (mw.config.get("wgNamespaceNumber") === 0 || pageName == "Wiktionary:Sandbox"))) { // Stores all accelerated data, by language, by target pagename. // Sub-arrays are in HTML order. var accelParamsByPagename = {}; var getTargetPagename = function(link) { var targetPagename = mw.util.getParamValue("title", link.href); if (targetPagename === null) { var match = link.href.match(/^(.*)\/wiki\/([^#]+)(?:#.+)?$/); if (match) { targetPagename = decodeURIComponent(match[2]); } } return targetPagename; }; var getLang = function (element) { if (element.accelLang !== undefined) { return element.accelLang; } var hasLang = $(element).closest("[lang]")[0]; var lang = hasLang ? hasLang.getAttribute("lang") : null; element.accelLang = lang; return lang; }; var getPartOfSpeech = function(link) { // Acceleration can be added to inflection tables too. // This tells the search script to skip headers with these names. var skipheaders = [ "alternative forms", "antonyms", "conjugation", "declension", "derived terms", "inflection", "mutation", "related terms", "synonyms", "translations", "usage notes" ]; for (var node = link; node !== null; node = node.previousSibling || node.parentNode) { if (node.nodeType == 1 && (node.nodeName.match(/^H[3-6]$/) || (node.nodeName === 'DIV' && node.className.indexOf('mw-heading') !== -1))) { var header = $(node).find(".mw-headline, h3, h4, h5, h6"); if (!header) { continue; } header = header.text().replace(/^[1-9.]* /, "").toLowerCase(); if (skipheaders.indexOf(header) == -1) { return header; } } } throw new Error("This entry seems to be formatted incorrectly. Does it have a language and part-of-speech header?"); }; var createAccelParam = function(link) { var classNames = Array.prototype.filter.call($(link).closest(".form-of")[0].classList, function (className) { return (/^(gender|origin|origin_transliteration|pos|target|transliteration)-.+|.+-form-of$/.test(className)); }); var accelParam = classNames.join(" "); var targetPagename = getTargetPagename(link); var targetHead = (link.innerText || link.textContent).replace(/ /g, "_"); if (targetPagename != targetHead) { accelParam = "target-" + targetHead + " " + accelParam; } return "pos-" + getPartOfSpeech(link).replace(/ /g, "_") + " " + accelParam; }; var storeAccelParam = function(link) { // Extract the targeted pagename from the URL, // and language code from the nearest element with a lang attribute var lang = getLang(link); var targetPagename = getTargetPagename(link); // Add page name to the list if (accelParamsByPagename[lang] === undefined) { accelParamsByPagename[lang] = {}; } if (accelParamsByPagename[lang][targetPagename] === undefined) { accelParamsByPagename[lang][targetPagename] = []; } var accelParam = createAccelParam(link); if (accelParamsByPagename[lang][targetPagename].indexOf(accelParam) === -1) { accelParamsByPagename[lang][targetPagename].push(accelParam); } }; var processLink = function(link) { // Extract the targeted pagename from the URL, // and language code from the nearest element with a lang attribute var lang = getLang(link); var targetPagename = getTargetPagename(link); // Fetch the acceleration parameters from the store var accelParam = accelParamsByPagename[lang][targetPagename] .map(function (accel, i) { return "accel" + (i + 1).toString() + "=" + encodeURIComponent(accel); }) .join("&"); // Convert a non-edit link into an edit link if (link.href.indexOf("action=edit") < 0) { link.href = link.href.replace(/^(.*)\/wiki\/([^#]+)(?:#.+)?$/, "$1/w/index.php?title=$2&action=edit"); } // use URL to ensure we append to the query string, not e.g. the hash. var targetUrl = new URL(link.href); // Now build a new "green link" URL to replace the original red link with targetUrl.search += "&editintro=MediaWiki:Gadget-AcceleratedFormCreation.js/intro" + "&accel_lang=" + encodeURIComponent(lang) + "&accel_lemma=" + encodeURIComponent(pageName.replace(/_/g, " ")) + "&" + accelParam + "&veswitched=1"; link.href = targetUrl.href; link.classList.add("accelerated"); link.processedLink = true; }; // Mutation observer to respond when OrangeLinks modifies links var mutobs = new MutationObserver(function(mutations, observer) { mutations.forEach(function(mutation) { var link = mutation.target; if (!(mutation.attributeName == "class" && link.tagName === "A")) { return; } // Don't process a link we've already been to if (link.processedLink) { return; } if (!$(link).hasClass("orange-link")) { return; } // Process processLink(link); }); }); // First generate and store all the parameters var oldtable = null; // Were we previously inside a table? var columns = []; $(".form-of a").each(function() { // Are we currently inside a table? var $this = $(this); var table = $this.closest("table"); if (table.length > 0) { table = table[0]; } else { table = null; } // Was a column number specified on the current table cell? // jQuery.fn.data automatically converts an integer-like string // to a number. var col = $this.closest("td[data-accel-col]").first().data("accel-col"); if (typeof col !== "number") { col = null; } // If we were in a table, and we changed to another table or are no longer in one, // or if there is no column number attribute, flush the column lists. if (oldtable && (oldtable !== table || col === null)) { for (var i = 0; i < columns.length; ++i) { for (var j = 0; j < columns[i].length; ++j) { storeAccelParam(columns[i][j]); } } columns = []; } oldtable = table; // The nostore parameter causes the link to not be stored, // but it is processed later. The effect is that this link has no // effect on the ordering of forms. if ($(this).closest(".form-of").first().hasClass("form-of-nostore")) { return; } // If there is a column number attribute, defer storing the link, // put it in the columns array instead. if (col !== null) { --col; // Column attributes are 1-based, JS arrays are 0-based // Expand the columns list to fit the number of columns while (columns.length <= col) { columns.push([]); } // Save the link in the columns list columns[col].push(this); } else { // Store the link directly storeAccelParam(this); } }); // Flush column lists for (var i = 0; i < columns.length; ++i) { for (var j = 0; j < columns[i].length; ++j) { storeAccelParam(columns[i][j]); } } // Then add them onto the links, or add a mutation observer $(".form-of a").each(function() { var $this = $(this); if ($this.hasClass("new") || $this.hasClass("orange-link")) { processLink(this); } else { // FIXME: There's a small window for a race condition here. // If the "orange-link" class is added by OrangeLinks after the above if-statement is evaluated, // but before the observer is added, then the link won't be processed. mutobs.observe(this, {attributes : true}); } }); // A function that force-processes all links and adds a class to those that would not have otherwise been processed. var forceProcessAllLinks = function() { $(".form-of a").each(function() { var $this = $(this); if (!($this.hasClass("new") || $this.hasClass("orange-link"))) { this.classList.add("accelerated-forced"); } processLink(this); }); }; window.accelForceProcessAllLinks = forceProcessAllLinks; } else if (mw.config.get("wgAction") === "edit") { // Get the parameters from the URL var getAccelParams = function() { var accelParams = []; var i = 1; while (true) { var acceldata = mw.util.getParamValue("accel" + i.toString()); if (!acceldata) { break; } // Default values var params = { pos: null, form: null, gender: null, transliteration: null, origin: mw.util.getParamValue("accel_lemma"), origin_transliteration: null, target: pageName, }; // Go over each part and add it var parts = acceldata.split(" "); for (var j = 0; j < parts.length; ++j) { var part = parts[j]; var paramMatch = part.match(/^(gender|origin|origin_transliteration|pos|target|transliteration)-(.+)$/); if (paramMatch) { params[paramMatch[1]] = paramMatch[2].replace(/_/g, " ").replace(/\uFFF0/g, "_"); } else { var formMatch = part.match(/^(.+)-form-of$/); if (formMatch) { params.form = formMatch[1].replace(/_/g, " ").replace(/\uFFF0/g, "_"); } } } accelParams.push(params); ++i; } return accelParams; }; // Generates entries from the information var printArgs = function(accelParams) { var args = [ "lang=" + mw.util.getParamValue("accel_lang"), "origin_pagename=" + mw.util.getParamValue("accel_lemma"), "target_pagename=" + pageName, "num=" + accelParams.length, ]; for (var i = 0; i < accelParams.length; ++i) { for (var key in accelParams[i]) { if (accelParams[i][key] !== null) { args.push(key + (i + 1) + "=" + accelParams[i][key].replace(/\|/g, "&#124;")); } } } return args.join("|"); }; var showModuleError = function(errorText) { // Attempt to link to the line of the module in which the error occurred. errorText = errorText.replace( /(Module:[^#<>\[\]|{}_]+)(?: at line |:)(\d+)/, function (wholeMatch, moduleName, lineNumber) { var link = document.createElement('a'); link.href = mw.util.getUrl(moduleName, {action: "edit"}) + "#mw-ce-l" + lineNumber; link.innerHTML = moduleName + " at line " + lineNumber; return "Lua error in " + link.outerHTML; }); var errorBox = "<div id=\"accel-error\">" + "<p><big>An error occurred while generating the entry:</big></p>" + "<p>" + errorText + "</p>" + "</div>"; wikipreview.insertAdjacentHTML("beforebegin", errorBox); }; var receiveModuleResponse = function(response) { var newtext, result; try { result = JSON.parse(response.expandtemplates.wikitext); } catch (err) { // JSON parse error should not happen. mw.notify(err.msg); return; } if (result.error) { // module error showModuleError(result.error); } else { // successfully generated entries newtext = result.entries; } for (i = 0; i < result.messages.length; ++i) { mw.notify(result.messages[i]); } if (!newtext) { return; } var newValue; var langsection_regex = /^==([^=\n]+)==$/mg; var match = langsection_regex.exec(newtext); if (!match) { showModuleError("No language section was found in the returned text."); } var langname = match[1]; // Does the page already exist? if (textbox.value) { var resultInBox = false; // Reset position at which regex starts its search. // Otherwise, regex starts matching after the index where it // found the language header in newtext. langsection_regex.lastIndex = 0; // Go over language sections to find where to insert our new one while ((match = langsection_regex.exec(textbox.value)) !== null) { if (match[1] == langname) { // There already exists a section for our language, display text in a separate box. resultInBox = true; break; } else if (match[1] == "Translingual" || match[1] == "English" || (langname != "English" && match[1] < langname)) { // Skip past English and Translingual, or if the language sorts higher continue; } else { // We found the first match that sorts lower than our language, great. break; } } var scrollIndex; newValue = textbox.value; if (resultInBox) { // Display the result in a separate box. var insertTextBoxIn = document.getElementById("accel-form-conflict-textbox-here"); if (insertTextBoxIn) { var newElement = document.createElement("div"); newElement.id = insertTextBoxIn.id; var warning = document.createElement("p"); warning.textContent = "A section for this language already exists. Please combine the new text manually:"; var textBox = document.createElement("textarea"); textBox.setAttribute("readonly", true); textBox.setAttribute("rows", 10); textBox.textContent = newtext; newElement.appendChild(warning); newElement.appendChild(textBox); insertTextBoxIn.replaceWith(newElement); } scrollIndex = match !== null ? match.index : newValue.length; } else if (match === null) { // We found no language that our section should go before, so insert it at the end. newValue = newValue.trimEnd() + "\n\n"; scrollIndex = newValue.length; newValue = newValue + newtext; } else { // We found a language to insert before, so do that. newValue = newValue.substring(0, match.index) + newtext + "\n\n" + newValue.substring(match.index); scrollIndex = match.index; } // Scroll the textbox to the newly added section. First scroll all the way down, // then set the cursor to the start of the new section, which scrolls back up // to the new section's language header. textbox.scrollTop = textbox.scrollHeight; textbox.selectionStart = scrollIndex; textbox.selectionEnd = scrollIndex; summary.value = "Adding forms of " + langname + " [[" + lemma + "]] ([[WT:ACCEL|Accelerated]])"; } else { newValue = newtext; summary.value = "Creating forms of " + langname + " [[" + lemma + "]] ([[WT:ACCEL|Accelerated]])"; } // Set textbox text. Setting textbox.value is unreliable. $(textbox).val(newValue); }; var wikipreview = document.getElementById("wikiPreview"); var textbox = document.getElementById("wpTextbox1"); var summary = document.getElementById("wpSummary"); var lang = mw.util.getParamValue("accel_lang"); var lemma = mw.util.getParamValue("accel_lemma"); if (!(wikipreview && textbox && summary && lang && lemma)) { return; } // Gather all the information that was given in the URL var accelParams = getAccelParams(); if (!accelParams) { return; } var module = "accel", funcName = "generate_JSON"; mw.loader.using("mediawiki.api", function() { new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:" + module + "|" + funcName + "|" + printArgs(accelParams) + "}}", "prop": "wikitext" }).done(receiveModuleResponse); }); } }); // </nowiki> rswaz1eynco0hjmjyu7gmofe9bjtahv 89006 89005 2026-08-06T23:33:12Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AcceleratedFormCreation.js]] 89005 javascript text/javascript // <nowiki> /* globals mw, $ */ // jshint maxerr:500 // FIXME: This gadget relies to an excessive degree on OrangeLinks to function. These gadgets should be made independent. /* * The starting point of the whole script. * * This adds a hook to the page load event so that the script runs * adds the generated text to the edit window once the page is done loading. */ "use strict"; mw.loader.using(["mediawiki.util"]).done(function() { var pageName = mw.config.get("wgPageName"); // Don't do anything unless the current page is in the main namespace. // Set window.accelEverywhere = true to test this gadget elsewhere. if (window.accelEverywhere || (mw.config.get("wgAction") === "view" && (mw.config.get("wgNamespaceNumber") === 0 || pageName == "Wiktionary:Sandbox"))) { // Stores all accelerated data, by language, by target pagename. // Sub-arrays are in HTML order. var accelParamsByPagename = {}; var getTargetPagename = function(link) { var targetPagename = mw.util.getParamValue("title", link.href); if (targetPagename === null) { var match = link.href.match(/^(.*)\/wiki\/([^#]+)(?:#.+)?$/); if (match) { targetPagename = decodeURIComponent(match[2]); } } return targetPagename; }; var getLang = function (element) { if (element.accelLang !== undefined) { return element.accelLang; } var hasLang = $(element).closest("[lang]")[0]; var lang = hasLang ? hasLang.getAttribute("lang") : null; element.accelLang = lang; return lang; }; var getPartOfSpeech = function(link) { // Acceleration can be added to inflection tables too. // This tells the search script to skip headers with these names. var skipheaders = [ "alternative forms", "antonyms", "conjugation", "declension", "derived terms", "inflection", "mutation", "related terms", "synonyms", "translations", "usage notes" ]; for (var node = link; node !== null; node = node.previousSibling || node.parentNode) { if (node.nodeType == 1 && (node.nodeName.match(/^H[3-6]$/) || (node.nodeName === 'DIV' && node.className.indexOf('mw-heading') !== -1))) { var header = $(node).find(".mw-headline, h3, h4, h5, h6"); if (!header) { continue; } header = header.text().replace(/^[1-9.]* /, "").toLowerCase(); if (skipheaders.indexOf(header) == -1) { return header; } } } throw new Error("This entry seems to be formatted incorrectly. Does it have a language and part-of-speech header?"); }; var createAccelParam = function(link) { var classNames = Array.prototype.filter.call($(link).closest(".form-of")[0].classList, function (className) { return (/^(gender|origin|origin_transliteration|pos|target|transliteration)-.+|.+-form-of$/.test(className)); }); var accelParam = classNames.join(" "); var targetPagename = getTargetPagename(link); var targetHead = (link.innerText || link.textContent).replace(/ /g, "_"); if (targetPagename != targetHead) { accelParam = "target-" + targetHead + " " + accelParam; } return "pos-" + getPartOfSpeech(link).replace(/ /g, "_") + " " + accelParam; }; var storeAccelParam = function(link) { // Extract the targeted pagename from the URL, // and language code from the nearest element with a lang attribute var lang = getLang(link); var targetPagename = getTargetPagename(link); // Add page name to the list if (accelParamsByPagename[lang] === undefined) { accelParamsByPagename[lang] = {}; } if (accelParamsByPagename[lang][targetPagename] === undefined) { accelParamsByPagename[lang][targetPagename] = []; } var accelParam = createAccelParam(link); if (accelParamsByPagename[lang][targetPagename].indexOf(accelParam) === -1) { accelParamsByPagename[lang][targetPagename].push(accelParam); } }; var processLink = function(link) { // Extract the targeted pagename from the URL, // and language code from the nearest element with a lang attribute var lang = getLang(link); var targetPagename = getTargetPagename(link); // Fetch the acceleration parameters from the store var accelParam = accelParamsByPagename[lang][targetPagename] .map(function (accel, i) { return "accel" + (i + 1).toString() + "=" + encodeURIComponent(accel); }) .join("&"); // Convert a non-edit link into an edit link if (link.href.indexOf("action=edit") < 0) { link.href = link.href.replace(/^(.*)\/wiki\/([^#]+)(?:#.+)?$/, "$1/w/index.php?title=$2&action=edit"); } // use URL to ensure we append to the query string, not e.g. the hash. var targetUrl = new URL(link.href); // Now build a new "green link" URL to replace the original red link with targetUrl.search += "&editintro=MediaWiki:Gadget-AcceleratedFormCreation.js/intro" + "&accel_lang=" + encodeURIComponent(lang) + "&accel_lemma=" + encodeURIComponent(pageName.replace(/_/g, " ")) + "&" + accelParam + "&veswitched=1"; link.href = targetUrl.href; link.classList.add("accelerated"); link.processedLink = true; }; // Mutation observer to respond when OrangeLinks modifies links var mutobs = new MutationObserver(function(mutations, observer) { mutations.forEach(function(mutation) { var link = mutation.target; if (!(mutation.attributeName == "class" && link.tagName === "A")) { return; } // Don't process a link we've already been to if (link.processedLink) { return; } if (!$(link).hasClass("orange-link")) { return; } // Process processLink(link); }); }); // First generate and store all the parameters var oldtable = null; // Were we previously inside a table? var columns = []; $(".form-of a").each(function() { // Are we currently inside a table? var $this = $(this); var table = $this.closest("table"); if (table.length > 0) { table = table[0]; } else { table = null; } // Was a column number specified on the current table cell? // jQuery.fn.data automatically converts an integer-like string // to a number. var col = $this.closest("td[data-accel-col]").first().data("accel-col"); if (typeof col !== "number") { col = null; } // If we were in a table, and we changed to another table or are no longer in one, // or if there is no column number attribute, flush the column lists. if (oldtable && (oldtable !== table || col === null)) { for (var i = 0; i < columns.length; ++i) { for (var j = 0; j < columns[i].length; ++j) { storeAccelParam(columns[i][j]); } } columns = []; } oldtable = table; // The nostore parameter causes the link to not be stored, // but it is processed later. The effect is that this link has no // effect on the ordering of forms. if ($(this).closest(".form-of").first().hasClass("form-of-nostore")) { return; } // If there is a column number attribute, defer storing the link, // put it in the columns array instead. if (col !== null) { --col; // Column attributes are 1-based, JS arrays are 0-based // Expand the columns list to fit the number of columns while (columns.length <= col) { columns.push([]); } // Save the link in the columns list columns[col].push(this); } else { // Store the link directly storeAccelParam(this); } }); // Flush column lists for (var i = 0; i < columns.length; ++i) { for (var j = 0; j < columns[i].length; ++j) { storeAccelParam(columns[i][j]); } } // Then add them onto the links, or add a mutation observer $(".form-of a").each(function() { var $this = $(this); if ($this.hasClass("new") || $this.hasClass("orange-link")) { processLink(this); } else { // FIXME: There's a small window for a race condition here. // If the "orange-link" class is added by OrangeLinks after the above if-statement is evaluated, // but before the observer is added, then the link won't be processed. mutobs.observe(this, {attributes : true}); } }); // A function that force-processes all links and adds a class to those that would not have otherwise been processed. var forceProcessAllLinks = function() { $(".form-of a").each(function() { var $this = $(this); if (!($this.hasClass("new") || $this.hasClass("orange-link"))) { this.classList.add("accelerated-forced"); } processLink(this); }); }; window.accelForceProcessAllLinks = forceProcessAllLinks; } else if (mw.config.get("wgAction") === "edit") { // Get the parameters from the URL var getAccelParams = function() { var accelParams = []; var i = 1; while (true) { var acceldata = mw.util.getParamValue("accel" + i.toString()); if (!acceldata) { break; } // Default values var params = { pos: null, form: null, gender: null, transliteration: null, origin: mw.util.getParamValue("accel_lemma"), origin_transliteration: null, target: pageName, }; // Go over each part and add it var parts = acceldata.split(" "); for (var j = 0; j < parts.length; ++j) { var part = parts[j]; var paramMatch = part.match(/^(gender|origin|origin_transliteration|pos|target|transliteration)-(.+)$/); if (paramMatch) { params[paramMatch[1]] = paramMatch[2].replace(/_/g, " ").replace(/\uFFF0/g, "_"); } else { var formMatch = part.match(/^(.+)-form-of$/); if (formMatch) { params.form = formMatch[1].replace(/_/g, " ").replace(/\uFFF0/g, "_"); } } } accelParams.push(params); ++i; } return accelParams; }; // Generates entries from the information var printArgs = function(accelParams) { var args = [ "lang=" + mw.util.getParamValue("accel_lang"), "origin_pagename=" + mw.util.getParamValue("accel_lemma"), "target_pagename=" + pageName, "num=" + accelParams.length, ]; for (var i = 0; i < accelParams.length; ++i) { for (var key in accelParams[i]) { if (accelParams[i][key] !== null) { args.push(key + (i + 1) + "=" + accelParams[i][key].replace(/\|/g, "&#124;")); } } } return args.join("|"); }; var showModuleError = function(errorText) { // Attempt to link to the line of the module in which the error occurred. errorText = errorText.replace( /(Module:[^#<>\[\]|{}_]+)(?: at line |:)(\d+)/, function (wholeMatch, moduleName, lineNumber) { var link = document.createElement('a'); link.href = mw.util.getUrl(moduleName, {action: "edit"}) + "#mw-ce-l" + lineNumber; link.innerHTML = moduleName + " at line " + lineNumber; return "Lua error in " + link.outerHTML; }); var errorBox = "<div id=\"accel-error\">" + "<p><big>An error occurred while generating the entry:</big></p>" + "<p>" + errorText + "</p>" + "</div>"; wikipreview.insertAdjacentHTML("beforebegin", errorBox); }; var receiveModuleResponse = function(response) { var newtext, result; try { result = JSON.parse(response.expandtemplates.wikitext); } catch (err) { // JSON parse error should not happen. mw.notify(err.msg); return; } if (result.error) { // module error showModuleError(result.error); } else { // successfully generated entries newtext = result.entries; } for (i = 0; i < result.messages.length; ++i) { mw.notify(result.messages[i]); } if (!newtext) { return; } var newValue; var langsection_regex = /^==([^=\n]+)==$/mg; var match = langsection_regex.exec(newtext); if (!match) { showModuleError("No language section was found in the returned text."); } var langname = match[1]; // Does the page already exist? if (textbox.value) { var resultInBox = false; // Reset position at which regex starts its search. // Otherwise, regex starts matching after the index where it // found the language header in newtext. langsection_regex.lastIndex = 0; // Go over language sections to find where to insert our new one while ((match = langsection_regex.exec(textbox.value)) !== null) { if (match[1] == langname) { // There already exists a section for our language, display text in a separate box. resultInBox = true; break; } else if (match[1] == "Translingual" || match[1] == "English" || (langname != "English" && match[1] < langname)) { // Skip past English and Translingual, or if the language sorts higher continue; } else { // We found the first match that sorts lower than our language, great. break; } } var scrollIndex; newValue = textbox.value; if (resultInBox) { // Display the result in a separate box. var insertTextBoxIn = document.getElementById("accel-form-conflict-textbox-here"); if (insertTextBoxIn) { var newElement = document.createElement("div"); newElement.id = insertTextBoxIn.id; var warning = document.createElement("p"); warning.textContent = "A section for this language already exists. Please combine the new text manually:"; var textBox = document.createElement("textarea"); textBox.setAttribute("readonly", true); textBox.setAttribute("rows", 10); textBox.textContent = newtext; newElement.appendChild(warning); newElement.appendChild(textBox); insertTextBoxIn.replaceWith(newElement); } scrollIndex = match !== null ? match.index : newValue.length; } else if (match === null) { // We found no language that our section should go before, so insert it at the end. newValue = newValue.trimEnd() + "\n\n"; scrollIndex = newValue.length; newValue = newValue + newtext; } else { // We found a language to insert before, so do that. newValue = newValue.substring(0, match.index) + newtext + "\n\n" + newValue.substring(match.index); scrollIndex = match.index; } // Scroll the textbox to the newly added section. First scroll all the way down, // then set the cursor to the start of the new section, which scrolls back up // to the new section's language header. textbox.scrollTop = textbox.scrollHeight; textbox.selectionStart = scrollIndex; textbox.selectionEnd = scrollIndex; summary.value = "Adding forms of " + langname + " [[" + lemma + "]] ([[WT:ACCEL|Accelerated]])"; } else { newValue = newtext; summary.value = "Creating forms of " + langname + " [[" + lemma + "]] ([[WT:ACCEL|Accelerated]])"; } // Set textbox text. Setting textbox.value is unreliable. $(textbox).val(newValue); }; var wikipreview = document.getElementById("wikiPreview"); var textbox = document.getElementById("wpTextbox1"); var summary = document.getElementById("wpSummary"); var lang = mw.util.getParamValue("accel_lang"); var lemma = mw.util.getParamValue("accel_lemma"); if (!(wikipreview && textbox && summary && lang && lemma)) { return; } // Gather all the information that was given in the URL var accelParams = getAccelParams(); if (!accelParams) { return; } var module = "accel", funcName = "generate_JSON"; mw.loader.using("mediawiki.api", function() { new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:" + module + "|" + funcName + "|" + printArgs(accelParams) + "}}", "prop": "wikitext" }).done(receiveModuleResponse); }); } }); // </nowiki> rswaz1eynco0hjmjyu7gmofe9bjtahv MediaWiki:Gadget-AcceleratedFormCreation.css 8 18002 89007 2023-11-01T14:42:22Z en>Erutuon 0 add yet another selector to override [[MediaWiki:Common.css]] loading its class="new" link style after this and thus taking precedence 89007 css text/css a.accelerated:link, a.partlynew.accelerated:link, a.new.accelerated:link { color: #1fba00; } a.accelerated:visited, a.partlynew.accelerated:visited, a.new.accelerated:visited { color: #66a759; } suyssctv76gv9bekacr2utmfmhwgdtp 89008 89007 2026-08-06T23:33:15Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AcceleratedFormCreation.css]] 89007 css text/css a.accelerated:link, a.partlynew.accelerated:link, a.new.accelerated:link { color: #1fba00; } a.accelerated:visited, a.partlynew.accelerated:visited, a.new.accelerated:visited { color: #66a759; } suyssctv76gv9bekacr2utmfmhwgdtp MediaWiki:Gadget-HotCat.js 8 18003 89009 2025-09-12T09:13:01Z en>Surjection 0 89009 javascript text/javascript // {{documentation}} // See also: MediaWiki:Gadget-HotCat.js/local defaults //window.hotcat_translations_from_commons = true; // Make HotCat load its interface from the Commons (the default setting so no need to set it here) /** HotCat V2.43 en.wiktionary fork (with better support for en.wiktionary templates) upstream: https://commons.wikimedia.org/w/index.php?title=MediaWiki:Gadget-HotCat.js&oldid=818790002 The original script is hosted at [https://commons.wikimedia.org/wiki/MediaWiki:Gadget-HotCat.js]. See it for more information. License: Quadruple licensed, any of the following: GFDL GPL LGPL Creative Commons Attribution 3.0 (CC-BY-3.0) Requires MediaWiki >= MW 1.27. */ // <nowiki> /* eslint-disable vars-on-top, one-var, camelcase, no-alert, curly */ /* global jQuery, mediaWiki, UFUI, JSconfig, UploadForm */ /* jslint strict:false, nonew:false, bitwise:true */ ( function ( $, mw ) { // BEGINNING OF en.wiktionary EXTRA CODE var EN_WIKTIONARY_CONTENT_NAMESPACE = [0, 100, 118].indexOf(mw.config.get("wgNamespaceNumber")) >= 0; var EN_WIKTIONARY_TOPICS = ["C", "c", "topics", "top", "topic", "catlangcode"]; var EN_WIKTIONARY_CATLANGNAME = ["cln", "catlangname", "Cln"]; var EN_WIKTIONARY_CATEGORIZE = ["categorize", "cat"]; var EN_WIKTIONARY_PREFER_TOPICS_FOR_NEW_ADDITIONS = true; var EN_WIKTIONARY_PREFER_CATLANGNAME_FOR_NEW_ADDITIONS = true; function regexpEscape(string) { return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } function cleanUpText(wikitext) { return wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); } function en_wiktionary_find_category_allMatches(regexp, wikitext, data_key, data) { var copiedtext = cleanUpText(wikitext); var result = []; var curr_match = null; while ((curr_match = regexp.exec(copiedtext)) !== null) { var obj = { match: curr_match }; obj[data_key] = data; result.push(obj); } result.re = regexp; return result.length ? result : null; } function en_wiktionary_codeToCanonicalName(callback) { $.get({ "url": mw.util.wikiScript('index'), "data": { "action": "raw", "title": "Module:languages/code to canonical name.json" }, "cache": true }).then(function(r) { var parsedData; try { parsedData = JSON.parse(r); callback({ ok: true, data: parsedData }); } catch (e) { console.error(e); callback({ ok: false }); } }); } function en_wiktionary_populate_langdata(data) { data.langnames = []; data.name_to_code = {}; for (var key in data.code_to_name) { if (data.code_to_name.hasOwnProperty(key)) { var value = data.code_to_name[key]; data.langnames.push(value); data.name_to_code[value] = key; } } var escaped = data.langnames.map(regexpEscape); // sort from longest to shortest to ensure greedy alternation escaped.sort(function (a, b) { return b.length - a.length; }); data.catlangnameRegexp = "^(" + escaped.join("|") + ") (.+)"; } var EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY = "HotCat-en-wiktionary-language-data"; function en_wiktionary_cache_langdata(callback) { if (!window.sessionStorage) { callback(); return; } if (window.sessionStorage.hasOwnProperty(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY)) { try { var timeNow = new Date().getTime(); var data = JSON.parse(window.sessionStorage.getItem(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY)); if (timeNow < data.expiry) { EN_WIKTIONARY_LANGDATA = data.data; EN_WIKTIONARY_LANGDATA_READY = true; EN_WIKTIONARY_LANGDATA.catlangnameRegexpCompiled = null; callback(); return; } } catch (e) { } } en_wiktionary_codeToCanonicalName(function (r) { if (r.ok) { EN_WIKTIONARY_LANGDATA = {}; EN_WIKTIONARY_LANGDATA.code_to_name = r.data; en_wiktionary_populate_langdata(EN_WIKTIONARY_LANGDATA); } EN_WIKTIONARY_LANGDATA_READY = true; if (window.sessionStorage) window.sessionStorage.setItem(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY, JSON.stringify({ expiry: new Date().getTime() + 30 * 60 * 1000, // expire in 30 minutes data: EN_WIKTIONARY_LANGDATA })); callback(); }); } var EN_WIKTIONARY_LANGDATA = null; var EN_WIKTIONARY_LANGDATA_READY = false; var EN_WIKTIONARY_LANGDATA_LOCK = false; var EN_WIKTIONARY_LANGDATA_QUEUE = []; function en_wiktionary_get_langdata(callback) { if (EN_WIKTIONARY_LANGDATA_READY) { callback(); } else { if (!EN_WIKTIONARY_LANGDATA_LOCK) { EN_WIKTIONARY_LANGDATA_LOCK = true; en_wiktionary_cache_langdata(function() { callback(); EN_WIKTIONARY_LANGDATA_QUEUE.forEach(function(fn) { fn(); }); }); return; } EN_WIKTIONARY_LANGDATA_QUEUE.push(callback); } } function EN_WIKTIONARY_TOPICS_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_TOPICS.join("|") + ")\\s*\\|\\s*" + lang + "\\s*\\|" + (bar_required ? "" : "?"); } function EN_WIKTIONARY_CATLANGNAME_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_CATLANGNAME.join("|") + ")\\s*\\|\\s*" + lang + "\\s*\\|" + (bar_required ? "" : "?"); } function EN_WIKTIONARY_CATEGORIZE_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_CATEGORIZE.join("|") + ")\\s*\\|\\s*" + (lang == true ? "(" : "") + "[a-z0-9-]+" + (lang == true ? ")" : "") + "\\s*\\|" + (bar_required ? "" : "?"); } var EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS = "[^}]*"; var EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER = "?(?<=\\|)"; var EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER = "(?=\\s*[\|\}])"; var EN_WIKTIONARY_TEMPLATE_END = "\\}\\}"; var EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE = "\\s*\\}\\}\n?"; function en_wiktionary_category_name_detect(category) { var topicsMatch = category.match(/^([a-z-]+):(.+)$/); if (topicsMatch) { return { type: "topics", lang: topicsMatch[1], topic: topicsMatch[2] }; } if (EN_WIKTIONARY_LANGDATA) { var data = EN_WIKTIONARY_LANGDATA; if (!data.catlangnameRegexpCompiled) { data.catlangnameRegexpCompiled = new RegExp(data.catlangnameRegexp); } var catlangnameMatch = category.match(data.catlangnameRegexpCompiled); if (catlangnameMatch && data.name_to_code[catlangnameMatch[1]]) { return { type: "catlangname", lang: data.name_to_code[catlangnameMatch[1]], topic: catlangnameMatch[2] }; } } return null; } function en_wiktionary_find_category(wikitext, category, once) { if (!EN_WIKTIONARY_CONTENT_NAMESPACE) return null; var catname = en_wiktionary_category_name_detect(category); var data, matched; if (catname) { if (catname.type == "topics") { var topicTemplateRegex = new RegExp( EN_WIKTIONARY_TOPICS_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(catname.topic) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); data = { lang: catname.lang, name: catname.topic }; if (once) { matched = topicTemplateRegex.exec(wikitext); if (matched) { matched.enWiktTopics = data; } return matched; } return en_wiktionary_find_category_allMatches(topicTemplateRegex, wikitext, "enWiktTopics", data); } else if (catname.type == "catlangname") { var clnTemplateRegex = new RegExp( EN_WIKTIONARY_CATLANGNAME_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(catname.topic) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); data = { lang: catname.lang, name: catname.topic }; if (once) { matched = clnTemplateRegex.exec(wikitext); if (matched) { matched.enWiktCatlangname = data; } return matched; } return en_wiktionary_find_category_allMatches(clnTemplateRegex, wikitext, "enWiktCatlangname", data); } } var catTemplateRegex = new RegExp(EN_WIKTIONARY_CATEGORIZE_START(true, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(category) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); var catTemplateMatches = wikitext.match(catTemplateRegex); if (catTemplateMatches) { data = { lang: catTemplateMatches[1], name: category }; if (once) { if (catTemplateMatches) { catTemplateMatches.enWiktCategorize = data; } return catTemplateMatches; } catTemplateRegex.lastIndex = 0; return en_wiktionary_find_category_allMatches(catTemplateRegex, wikitext, "enWiktCategorize", data); } return null; } function en_wiktionary_is_special_match(match) { return !!(match.enWiktTopics || match.enWiktCatlangname || match.enWiktCategorize); } function en_wiktionary_three_to_two_split(wikitext, match) { var before, after, data, removeTopic; if (match.enWiktTopics) { // {{topics}}? data = match.enWiktTopics; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var topicTemplateRegex = new RegExp( EN_WIKTIONARY_TOPICS_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{topics}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_TOPICS_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(topicTemplateRegex, removeTopic)]; } else if (match.enWiktCatlangname) { // {{cln}}? data = match.enWiktCatlangname; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var clnTemplateRegex = new RegExp( EN_WIKTIONARY_CATLANGNAME_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{cln}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_CATLANGNAME_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(clnTemplateRegex, removeTopic)]; } else if (match.enWiktCategorize) { // {{cat}}? data = match.enWiktCategorize; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var catTemplateRegex = new RegExp( EN_WIKTIONARY_CATEGORIZE_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{cln}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_CATEGORIZE_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(catTemplateRegex, removeTopic)]; } before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index + match.match[0].length); return [before, after]; } function en_wiktionary_remove_category(wikitext, match) { var before_after = en_wiktionary_three_to_two_split(wikitext, match); return before_after[0] + before_after[1]; } function en_wiktionary_find_insertionpoint(wikitext, category) { var catname = en_wiktionary_category_name_detect(category); if (catname) { if (catname.lang) { var langname = catname.langname || (EN_WIKTIONARY_LANGDATA ? EN_WIKTIONARY_LANGDATA.code_to_name[catname.lang] : null); if (langname) { // try to put category under the language L2 var l2_heading_this = "^==\\s*" + regexpEscape(langname) + "\\s*==$"; var end_of_l2 = "\\n*(?:^----$)?\\n*^==(?!=)\\s*.*\\s*==$"; var clean_wikitext = cleanUpText(wikitext); var finalRegexp = "(" + l2_heading_this + "[\\s\\S]+?)" + end_of_l2; var match = new RegExp(finalRegexp, "m").exec(clean_wikitext); if (match) { var rawPoint = match.index + match[1].length; var noPreLine = false; if (wikitext.substring(rawPoint - 2, rawPoint) == "]]") { return { idx: rawPoint, onCat: true }; } var cookedPoint = rawPoint; if (wikitext.substring(cookedPoint - 3, cookedPoint) == "}}\n") { // if the preceding line has a topics/cln template, add noPreLine var i = cookedPoint - 2; while (i >= 0 && wikitext[i] !== '\n') { i--; } i += 2; var previousLine = wikitext.substring(i, cookedPoint - 1); if (previousLine.match(new RegExp("^\\{\\{(?:" + EN_WIKTIONARY_TOPICS.join("|") + "|" + EN_WIKTIONARY_CATLANGNAME.join("|") + ")\\|"))) { noPreLine = true; } } // hotfix: fix newline placement if (!noPreLine && wikitext.charAt(cookedPoint - 1) != "\n" && wikitext.substring(cookedPoint, cookedPoint + 2) == "\n\n") { ++cookedPoint; } return { idx: cookedPoint, onCat: false, noPreLine: noPreLine }; } else { var l2match = new RegExp(l2_heading_this, "m").exec(clean_wikitext); if (l2match) { // assuming there are no more L2s... var l2_regex = new RegExp("^==(?!=)\\s*.*\\s*==$", "gm"); l2_regex.lastIndex = l2match.index + l2match[0].length; var l2nextmatch = l2_regex.exec(clean_wikitext); if (!l2nextmatch) { // no more L2s return { idx: -1, onCat: false }; } } } } } } return null; // fallback } function en_wiktionary_add_category_hook(wikitext, category, cat_point) { var catname = en_wiktionary_category_name_detect(category); if (catname) { var match, splitPoint; if (catname.type == "topics") { // try to find the first language template that matches and // add the category there var topicTemplateRegex = new RegExp("(?:^|(?<=\\n))(" + EN_WIKTIONARY_TOPICS_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + ")" + EN_WIKTIONARY_TEMPLATE_END); match = topicTemplateRegex.exec(cleanUpText(wikitext)); if (match) { splitPoint = match.index + match[1].length; return wikitext.substring(0, splitPoint) + "|" + catname.topic + wikitext.substring(splitPoint); } } if (catname.type == "catlangname") { // try to find the first language template that matches and // add the category there var clnTemplateRegex = new RegExp("(?:^|(?<=\\n))(" + EN_WIKTIONARY_CATLANGNAME_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + ")" + EN_WIKTIONARY_TEMPLATE_END); match = clnTemplateRegex.exec(cleanUpText(wikitext)); if (match) { splitPoint = match.index + match[1].length; return wikitext.substring(0, splitPoint) + "|" + catname.topic + wikitext.substring(splitPoint); } } } return null; // fallback } function en_wiktionary_add_category_string(category, onCat) { var catname = en_wiktionary_category_name_detect(category); if (catname) { if (catname.type == "topics" && EN_WIKTIONARY_PREFER_TOPICS_FOR_NEW_ADDITIONS && !onCat) { return "{{" + EN_WIKTIONARY_TOPICS[0] + "|" + catname.lang + "|" + catname.topic + "}}"; } if (catname.type == "catlangname" && EN_WIKTIONARY_PREFER_CATLANGNAME_FOR_NEW_ADDITIONS && !onCat) { return "{{" + EN_WIKTIONARY_CATLANGNAME[0] + "|" + catname.lang + "|" + catname.topic + "}}"; } } return null; // fallback } // END OF en.wiktionary EXTRA CODE // Don't use mw.config.get() as that takes a copy of the config, and so doesn't // account for values changing, e.g. wgCurRevisionId after a VE edit var conf = mw.config.values, // when running on mobile domain - do not use wgServer. wgServer = window.location.host.indexOf('.m.') > -1 ? '//' + window.location.host : mw.config.get( 'wgServer' ); // Guard against double inclusions (in old IE/Opera element ids become window properties) if ( ( window.HotCat && !window.HotCat.nodeName ) || conf.wgAction === 'edit' ) // Not on edit mode return; // Configuration stuff. var HC = window.HotCat = { // Localize these messages to the main language of your wiki. messages: { cat_removed: 'removed [[Category:$1]]', template_removed: 'removed {{[[Category:$1]]}}', cat_added: 'added [[Category:$1]]', cat_keychange: 'new key for [[Category:$1]]: "$2"', // $2 is the new key cat_notFound: 'Category "$1" not found', cat_exists: 'Category "$1" already exists; not added.', cat_resolved: ' (redirect [[Category:$1]] resolved)', uncat_removed: 'removed {{uncategorized}}', separator: '; ', // Some text to prefix to the edit summary. prefix: '', // Some text to append to the edit summary. Named 'using' for historical reasons. If you prefer // to have a marker at the front, use prefix and set this to the empty string. using: ' using [[Help:Gadget-HotCat|HotCat]]', // $1 is replaced by a number. If your language has several plural forms (c.f. [[:en:Dual (grammatical form)]]), // you can set this to an array of strings suitable for passing to mw.language.configPlural(). // If that function doesn't exist, HotCat will simply fall back to using the last // entry in the array. multi_change: '$1 categories', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. commit: 'Save', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. ok: 'OK', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. cancel: 'Cancel', // Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. multi_error: 'Could not retrieve the page text from the server. Therefore, your category changes ' + 'cannot be saved. We apologize for the inconvenience.', // Defaults to '[[' + category_canonical + ':$1]]'. Can be overridden if in the short edit summaries // not the standard category name should be used but, say, a shorter namespace alias. $1 is replaced // by a category name. short_catchange: null }, // Plural of category_canonical. categories: 'Categories', // Any category in this category is deemed a disambiguation category; i.e., a category that should not contain // any items, but that contains links to other categories where stuff should be categorized. If you don't have // that concept on your wiki, set it to null. Use blanks, not underscores. disambig_category: 'Disambiguation', // Any category in this category is deemed a (soft) redirect to some other category defined by a link // to another non-blacklisted category. If your wiki doesn't have soft category redirects, set this to null. // If a soft-redirected category contains more than one link to another non-blacklisted category, it's considered // a disambiguation category instead. redir_category: 'Category redirects', // The little modification links displayed after category names. U+2212 is a minus sign; U+2193 and U+2191 are // downward and upward pointing arrows. Do not use ↓ and ↑ in the code! links: { change: '(±)', remove: '(\u2212)', add: '(+)', restore: '(×)', undo: '(×)', down: '(\u2193)', up: '(\u2191)' }, changeTag: conf.wgUserName ? 'HotCat' : '', // if tag is missing, edit is rejected // The tooltips for the above links tooltips: { change: 'Modify', remove: 'Remove', add: 'Add a new category', restore: 'Undo changes', undo: 'Undo changes', down: 'Open for modifying and display subcategories', up: 'Open for modifying and display parent categories' }, // The HTML content of the "enter multi-mode" link at the front. addmulti: '<span>+<sup>+</sup></span>', // Tooltip for the "enter multi-mode" link multi_tooltip: 'Modify several categories', // Return true to disable HotCat. disable: function () { var ns = conf.wgNamespaceNumber; var nsIds = conf.wgNamespaceIds; return ( ns < 0 || // Special pages; Special:Upload is handled differently ns === 10 || // Templates ns === 828 || // Module (Lua) ns === 8 || // MediaWiki ns === 6 && !conf.wgArticleId || // Non-existing file pages ns === 2 && /\.(js|css)$/.test( conf.wgTitle ) || // User scripts nsIds && ( ns === nsIds.creator || ns === nsIds.timedtext || ns === nsIds.institution ) ); }, // A regexp matching a templates used to mark uncategorized pages, if your wiki does have that. // If not, set it to null. uncat_regexp: /\{\{\s*[Uu]ncategorized\s*[^}]*\}\}\s*(<!--.*?-->\s*)?/g, // The images used for the little indication icon. Should not need changing. existsYes: '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png', existsNo: '//upload.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png', // a list of categories which can be removed by removing a template // key: the category without namespace // value: A regexp matching the template name, again without namespace // If you don't have this at your wiki, or don't want this, set it to an empty object {}. template_categories: {}, // Names for the search engines engine_names: { searchindex: 'Search index', pagelist: 'Page list', combined: 'Combined search', subcat: 'Subcategories', parentcat: 'Parent categories' }, // Override the decision of whether HotCat should help users by automatically // capitalising the title in the user input text if the wiki has case-sensitive page names. // Basically, this will make an API query to check the MediaWiki configuration and HotCat then sets // this to true for most wikis, and to false on Wiktionary. // // You can set this directly if there is a problem with it. For example, Georgian Wikipedia (kawiki), // is known to have different capitalisation logic between MediaWiki PHP and JavaScript. As such, automatic // case changes in JavaScript by HotCat would be wrong. capitalizePageNames: null, // If upload_disabled is true, HotCat will not be used on the Upload form. upload_disabled: false, // Single regular expression matching blacklisted categories that cannot be changed or // added using HotCat. For instance /\bstubs?$/ (any category ending with the word "stub" // or "stubs"), or /(\bstubs?$)|\bmaintenance\b/ (stub categories and any category with the // word "maintenance" in its title. blacklist: null, // Stuff changeable by users: // Background for changed categories in multi-edit mode. Default is a very light salmon pink. bg_changed: '#FCA', // If true, HotCat will never automatically submit changes. HotCat will only open an edit page with // the changes; users must always save explicitly. no_autocommit: false, // If true, the "category deletion" link "(-)" will never save automatically but always show an // edit page where the user has to save the edit manually. Is false by default because that's the // traditional behavior. This setting overrides no_autocommit for "(-)" links. del_needs_diff: false, // Time, in milliseconds, that HotCat waits after a keystroke before making a request to the // server to get suggestions. suggest_delay: 100, // Default width, in characters, of the text input field. editbox_width: 40, // One of the engine_names above, to be used as the default suggestion engine. suggestions: 'combined', // If true, always use the default engine, and never display a selector. fixed_search: false, // If false, do not display the "up" and "down" links use_up_down: true, // Default list size listSize: 10, // If true, single category changes are marked as minor edits. If false, they're not. single_minor: true, // If true, never add a page to the user's watchlist. If false, pages get added to the watchlist if // the user has the "Add pages I edit to my watchlist" or the "Add pages I create to my watchlist" // options in his or her preferences set. dont_add_to_watchlist: false, shortcuts: null, addShortcuts: function ( map ) { if ( !map ) return; window.HotCat.shortcuts = window.HotCat.shortcuts || {}; for ( var k in map ) { if ( !map.hasOwnProperty( k ) || typeof k !== 'string' ) continue; var v = map[ k ]; if ( typeof v !== 'string' ) continue; k = k.replace( /^\s+|\s+$/g, '' ); v = v.replace( /^\s+|\s+$/g, '' ); if ( !k.length || !v.length ) continue; window.HotCat.shortcuts[ k ] = v; } } }; // More backwards compatibility. We have a few places where we test for the browser: once for // Safari < 3.0, and twice for WebKit (Chrome or Safari, any versions) var ua = navigator.userAgent.toLowerCase(); var is_webkit = /applewebkit\/\d+/.test( ua ) && ua.indexOf( 'spoofer' ) < 0; var cat_prefix = null; var noSuggestions = false; function LoadTrigger( needed ) { // Define methods in a closure so that self reference is available, // also allows method calls to be detached. var self = this; self.queue = []; self.needed = needed; self.register = function ( callback ) { if ( self.needed <= 0 ) callback(); // Execute directly else self.queue.push( callback ); }; self.loaded = function () { self.needed--; if ( self.needed === 0 ) { // Run queued callbacks once for ( var i = 0; i < self.queue.length; i++ ) self.queue[ i ](); self.queue = []; } }; } // Used to delay running the HotCat setup until /local_defaults and localizations have been loaded. var loadTrigger = new LoadTrigger( 2 ); function load( uri, callback ) { var s = document.createElement( 'script' ); s.src = uri; var called = false; s.onload = s.onerror = function () { if ( !called && callback ) { called = true; callback(); } if ( s.parentNode ) { s.parentNode.removeChild( s ); } }; document.head.appendChild( s ); } function loadJS( page, callback ) { load( wgServer + conf.wgScript + '?title=' + encodeURIComponent( page ) + '&action=raw&ctype=text/javascript', callback ); } function loadURI( href, callback ) { var url = href; if ( url.substring( 0, 2 ) === '//' ) url = window.location.protocol + url; else if ( url.substring( 0, 1 ) === '/' ) url = wgServer + url; load( url, callback ); } // Load local configurations, overriding the pre-set default values in the HotCat object above. This is always loaded // from the wiki where this script is executing, even if this script itself is hotlinked from Commons. This can // be used to change the default settings, or to provide localized interface texts for edit summaries and so on. loadJS( 'MediaWiki:Gadget-HotCat.js/local_defaults', loadTrigger.loaded ); // Load localized UI texts. These are the texts that HotCat displays on the page itself. Texts shown in edit summaries // should be localized in /local_defaults above. if ( conf.wgUserLanguage !== 'en' ) { // Lupo: somebody thought it would be a good idea to add this. So the default is true, and you have to set it to false // explicitly if you're not on Commons and don't want that. if ( window.hotcat_translations_from_commons === undefined ) window.hotcat_translations_from_commons = true; // Localization hook to localize HotCat messages, tooltips, and engine names for wgUserLanguage. if ( window.hotcat_translations_from_commons && wgServer.indexOf( '//commons' ) < 0 ) { loadURI( '//commons.wikimedia.org/w/index.php?title=' + 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage + '&action=raw&ctype=text/javascript', loadTrigger.loaded ); } else { // Load translations locally loadJS( 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage, loadTrigger.loaded ); } } else { loadTrigger.loaded(); } // No further changes should be necessary here. // The following regular expression strings are used when searching for categories in wikitext. var wikiTextBlank = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+'; var wikiTextBlankRE = new RegExp( wikiTextBlank, 'g' ); // Regexp for handling blanks inside a category title or namespace name. // See http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/Title.php?revision=104051&view=markup#l2722 // See also http://www.fileformat.info/info/unicode/category/Zs/list.htm // MediaWiki collapses several contiguous blanks inside a page title to one single blank. It also replace a // number of special whitespace characters by simple blanks. And finally, blanks are treated as underscores. // Therefore, when looking for page titles in wikitext, we must handle all these cases. // Note: we _do_ include the horizontal tab in the above list, even though the MediaWiki software for some reason // appears to not handle it. The zero-width space \u200B is _not_ handled as a space inside titles by MW. var wikiTextBlankOrBidi = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200B\\u200E\\u200F\\u2028-\\u202F\\u205F\\u3000]*'; // Whitespace regexp for handling whitespace between link components. Including the horizontal tab, but not \n\r\f\v: // a link must be on one single line. // MediaWiki also removes Unicode bidi override characters in page titles (and namespace names) completely. // This is *not* handled, as it would require us to allow any of [\u200E\u200F\u202A-\u202E] between any two // characters inside a category link. It _could_ be done though... We _do_ handle strange spaces, including the // zero-width space \u200B, and bidi overrides between the components of a category link (adjacent to the colon, // or adjacent to and inside of "[[" and "]]"). // First auto-localize the regexps for the category and the template namespaces. var formattedNamespaces = conf.wgFormattedNamespaces; var namespaceIds = conf.wgNamespaceIds; function autoLocalize( namespaceNumber, fallback ) { function createRegexpStr( name ) { if ( !name || !name.length ) return ''; var regex_name = ''; for ( var i = 0; i < name.length; i++ ) { var initial = name.charAt( i ), ll = initial.toLowerCase(), ul = initial.toUpperCase(); if ( ll === ul ) regex_name += initial; else regex_name += '[' + ll + ul + ']'; } return regex_name .replace( /([\\^$.?*+()])/g, '\\$1' ) .replace( wikiTextBlankRE, wikiTextBlank ); } fallback = fallback.toLowerCase(); var canonical = formattedNamespaces[ String( namespaceNumber ) ].toLowerCase(); var regexp = createRegexpStr( canonical ); if ( fallback && canonical !== fallback ) regexp += '|' + createRegexpStr( fallback ); if ( namespaceIds ) { for ( var cat_name in namespaceIds ) { if ( typeof cat_name === 'string' && cat_name.toLowerCase() !== canonical && cat_name.toLowerCase() !== fallback && namespaceIds[ cat_name ] === namespaceNumber ) { regexp += '|' + createRegexpStr( cat_name ); } } } return regexp; } HC.category_canonical = formattedNamespaces[ '14' ]; HC.category_regexp = autoLocalize( 14, 'category' ); if ( formattedNamespaces[ '10' ] ) HC.template_regexp = autoLocalize( 10, 'template' ); // Utility functions. Yes, this duplicates some functionality that also exists in other places, but // to keep this whole stuff in a single file not depending on any other on-wiki JavaScripts, we re-do // these few operations here. function make( arg, literal ) { if ( !arg ) return null; return literal ? document.createTextNode( arg ) : document.createElement( arg ); } function param( name, uri ) { uri = uri || document.location.href; var re = new RegExp( '[&?]' + name + '=([^&#]*)' ); var m = re.exec( uri ); if ( m && m.length > 1 ) return decodeURIComponent( m[ 1 ] ); return null; } function title( href ) { if ( !href ) return null; var script = conf.wgScript + '?'; if ( href.indexOf( script ) === 0 || href.indexOf( wgServer + script ) === 0 || wgServer.substring( 0, 2 ) === '//' && href.indexOf( document.location.protocol + wgServer + script ) === 0 ) { // href="/w/index.php?title=..." return param( 'title', href ); } else { // href="/wiki/..." var prefix = conf.wgArticlePath.replace( '$1', '' ); if ( href.indexOf( prefix ) ) prefix = wgServer + prefix; // Fully expanded URL? if ( href.indexOf( prefix ) && prefix.substring( 0, 2 ) === '//' ) prefix = document.location.protocol + prefix; // Protocol-relative wgServer? if ( href.indexOf( prefix ) === 0 ) return decodeURIComponent( href.substring( prefix.length ) ); } return null; } function hasClass( elem, name ) { return ( ' ' + elem.className + ' ' ).indexOf( ' ' + name + ' ' ) >= 0; } function capitalize( str ) { if ( !str || !str.length ) return str; return str.substr( 0, 1 ).toUpperCase() + str.substr( 1 ); } function wikiPagePath( pageName ) { // Note: do not simply use encodeURI, it doesn't encode '&', which might break if wgArticlePath actually has the $1 in // a query parameter. return conf.wgArticlePath.replace( '$1', encodeURIComponent( pageName ).replace( /%3A/g, ':' ).replace( /%2F/g, '/' ) ); } function escapeRE( str ) { return str.replace( /([\\^$.?*+()[\]])/g, '\\$1' ); } function substituteFactory( options ) { options = options || {}; var lead = options.indicator || '$'; var indicator = escapeRE( lead ); var lbrace = escapeRE( options.lbrace || '{' ); var rbrace = escapeRE( options.rbrace || '}' ); var re; re = new RegExp( // $$ '(?:' + indicator + '(' + indicator + '))|' + // $0, $1 '(?:' + indicator + '(\\d+))|' + // ${key} '(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' + // $key (only if first char after $ is not $, digit, or { ) '(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)', 'g' ); // Replace $1, $2, or ${key1}, ${key2}, or $key1, $key2 by values from map. $$ is replaced by a single $. return function ( str, map ) { if ( !map ) return str; return str.replace( re, function ( match, prefix, idx, key, alpha ) { if ( prefix === lead ) return lead; var k = alpha || key || idx; var replacement = typeof map[ k ] === 'function' ? map[ k ]( match, k ) : map[ k ]; return typeof replacement === 'string' ? replacement : ( replacement || match ); } ); }; } var substitute = substituteFactory(); var replaceShortcuts = ( function () { var replaceHash = substituteFactory( { indicator: '#', lbrace: '[', rbrace: ']' } ); return function ( str, map ) { var s = replaceHash( str, map ); return HC.capitalizePageNames ? capitalize( s ) : s; }; }() ); // Text modification var findCatsRE = new RegExp( '\\[\\[' + wikiTextBlankOrBidi + '(?:' + HC.category_regexp + ')' + wikiTextBlankOrBidi + ':[^\\]]+\\]\\]', 'g' ); function replaceByBlanks( match ) { return match.replace( /(\s|\S)/g, ' ' ); // /./ doesn't match linebreaks. /(\s|\S)/ does. } function find_category( wikitext, category, once ) { var cat_regex = null; var result_hook = en_wiktionary_find_category(wikitext, category, once); if (result_hook) { return result_hook; } if ( HC.template_categories[ category ] ) { cat_regex = new RegExp( '\\{\\{' + wikiTextBlankOrBidi + '(' + HC.template_regexp + '(?=' + wikiTextBlankOrBidi + ':))?' + wikiTextBlankOrBidi + '(?:' + HC.template_categories[ category ] + ')' + wikiTextBlankOrBidi + '(\\|.*?)?\\}\\}', 'g' ); } else { var cat_name = escapeRE( category ); var initial = cat_name.substr( 0, 1 ); cat_regex = new RegExp( '\\[\\[' + wikiTextBlankOrBidi + '(' + HC.category_regexp + ')' + wikiTextBlankOrBidi + ':' + wikiTextBlankOrBidi + ( initial === '\\' || !HC.capitalizePageNames ? initial : '[' + initial.toUpperCase() + initial.toLowerCase() + ']' ) + cat_name.substring( 1 ).replace( wikiTextBlankRE, wikiTextBlank ) + wikiTextBlankOrBidi + '(\\|.*?)?\\]\\]', 'g' ); } if ( once ) return cat_regex.exec( wikitext ); var copiedtext = wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); var result = []; var curr_match = null; while ( ( curr_match = cat_regex.exec( copiedtext ) ) !== null ) { result.push( { match: curr_match } ); } result.re = cat_regex; return result; // An array containing all matches, with positions, in result[ i ].match } var interlanguageRE = null; function change_category( wikitext, toRemove, toAdd, key, is_hidden ) { function find_insertionpoint( wikitext, category ) { var copiedtext = wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); // Search in copiedtext to avoid that we insert inside an HTML comment or a nowiki "element". var result = en_wiktionary_find_insertionpoint( wikitext, category ); if (result) { return result; } var index = -1; findCatsRE.lastIndex = 0; while ( findCatsRE.exec( copiedtext ) !== null ) index = findCatsRE.lastIndex; if ( index < 0 ) { // Find the index of the first interlanguage link... var match = null; if ( !interlanguageRE ) { // Approximation without API: interlanguage links start with 2 to 3 lower case letters, optionally followed by // a sequence of groups consisting of a dash followed by one or more lower case letters. Exceptions are "simple" // and "tokipona". match = /((^|\n\r?)(\[\[\s*(([a-z]{2,3}(-[a-z]+)*)|simple|tokipona)\s*:[^\]]+\]\]\s*))+$/.exec( copiedtext ); } else { match = interlanguageRE.exec( copiedtext ); } if ( match ) index = match.index; return { idx: index, onCat: false }; } return { idx: index, onCat: index >= 0 }; } var summary = [], nameSpace = HC.category_canonical, cat_point = -1, // Position of removed category; keyChange = ( toRemove && toAdd && toRemove === toAdd && toAdd.length ), matches, noOnCatOverride = false; if ( key ) key = '|' + key; // Remove if ( toRemove && toRemove.length ) { matches = find_category( wikitext, toRemove ); if ( !matches || !matches.length ) { return { text: wikitext, summary: summary, error: HC.messages.cat_notFound.replace( /\$1/g, toRemove ) }; } else { var after = wikitext; for (var i = matches.length - 1; i > 0; i--) { after = en_wiktionary_remove_category(after, matches[i]); } var before_after = en_wiktionary_three_to_two_split(after, matches[0]); noOnCatOverride = en_wiktionary_is_special_match(matches[0]); var before = before_after[0]; after = before_after[1]; if ( toAdd ) { // nameSpace = matches[ 0 ].match[ 1 ] || nameSpace; Canonical namespace should be always preferred if ( key === null ) key = matches[ 0 ].match[ 2 ]; // Remember the category key, if any. } // Remove whitespace (properly): strip whitespace, but only up to the next line feed. // If we then have two linefeeds in a row, remove one. Otherwise, if we have two non- // whitespace characters, insert a blank. var i = before.length - 1; while ( i >= 0 && before.charAt( i ) !== '\n' && before.substr( i, 1 ).search( /\s/ ) >= 0 ) i--; var j = 0; while ( j < after.length && after.charAt( j ) !== '\n' && after.substr( j, 1 ).search( /\s/ ) >= 0 ) j++; if ( i >= 0 && before.charAt( i ) === '\n' && ( !after.length || j < after.length && after.charAt( j ) === '\n' ) ) i--; if ( i >= 0 ) before = before.substring( 0, i + 1 ); else before = ''; if ( j < after.length ) after = after.substring( j ); else after = ''; if ( before.length && before.substring( before.length - 1 ).search( /\S/ ) >= 0 && after.length && after.substr( 0, 1 ).search( /\S/ ) >= 0 ) { before += ' '; } cat_point = before.length; if ( cat_point === 0 && after.length && after.substr( 0, 1 ) === '\n' ) after = after.substr( 1 ); wikitext = before + after; if ( !keyChange ) { if ( HC.template_categories[ toRemove ] ) { summary.push( HC.messages.template_removed.replace( /\$1/g, toRemove ) ); } else { summary.push( HC.messages.cat_removed.replace( /\$1/g, toRemove ) ); } } } } // Add if ( toAdd && toAdd.length ) { matches = find_category( wikitext, toAdd ); if ( matches && matches.length ) { // Already exists return { text: wikitext, summary: summary, error: HC.messages.cat_exists.replace( /\$1/g, toAdd ) }; } else { var hooked = en_wiktionary_add_category_hook( wikitext, toAdd, cat_point ); if (hooked) { wikitext = hooked; summary.push( HC.messages.cat_added.replace( /\$1/g, toAdd ) ); } else { var onCat = false; var noPreLine = false; if ( cat_point < 0 ) { var point = find_insertionpoint ( wikitext, toAdd ); cat_point = point.idx; onCat = point.onCat; noPreLine = point.noPreLine; } else { onCat = true; } var newcatstring = en_wiktionary_add_category_string(toAdd, onCat && !noOnCatOverride) || ('[[' + nameSpace + ':' + toAdd + ( key || '' ) + ']]'); if ( cat_point >= 0 ) { var suffix = wikitext.substring( cat_point ); wikitext = wikitext.substring( 0, cat_point ) + ( cat_point > 0 && !noPreLine ? '\n' : '' ) + newcatstring + ( !onCat ? '\n' : '' ); if ( suffix.length && suffix.substr( 0, 1 ) !== '\n' ) wikitext += '\n' + suffix; else wikitext += suffix; } else { if ( wikitext.length && wikitext.substr( wikitext.length - 1, 1 ) !== '\n' ) wikitext += '\n'; wikitext += ( wikitext.length ? '\n' : '' ) + newcatstring; } if ( keyChange ) { var k = key || ''; if ( k.length ) k = k.substr( 1 ); summary.push( substitute( HC.messages.cat_keychange, [ null, toAdd, k ] ) ); } else { summary.push( HC.messages.cat_added.replace( /\$1/g, toAdd ) ); } if ( HC.uncat_regexp && !is_hidden ) { var txt = wikitext.replace( HC.uncat_regexp, '' ); // Remove "uncat" templates if ( txt.length !== wikitext.length ) { wikitext = txt; summary.push( HC.messages.uncat_removed ); } } } } } return { text: wikitext, summary: summary, error: null }; } // The real HotCat UI function evtKeys( e ) { /* eslint-disable no-bitwise */ var code = 0; if ( e.ctrlKey ) { // All modern browsers // Ctrl-click seems to be overloaded in FF/Mac (it opens a pop-up menu), so treat cmd-click // as a ctrl-click, too. if ( e.ctrlKey || e.metaKey ) code |= 1; if ( e.shiftKey ) code |= 2; } return code; } function evtKill( e ) { if ( e.preventDefault ) { e.preventDefault(); e.stopPropagation(); } else { e.cancelBubble = true; } return false; } var catLine = null, onUpload = false, editors = [], commitButton = null, commitForm = null, multiSpan = null, pageText = null, pageTime = null, pageWatched = false, watchCreate = false, watchEdit = false, minorEdits = false, editToken = null, is_rtl = false, serverTime = null, lastRevId = null, pageTextRevId = null, conflictingUser = null, newDOM = false; // true if MediaWiki serves the new UL-LI DOM for categories function CategoryEditor() { this.initialize.apply( this, arguments ); } function setPage( json ) { var startTime = null; if ( json && json.query ) { if ( json.query.pages ) { var page = json.query.pages[ !conf.wgArticleId ? '-1' : String( conf.wgArticleId ) ]; if ( page ) { if ( page.revisions && page.revisions.length ) { // Revisions are sorted by revision ID, hence [ 0 ] is the one we asked for, and possibly there's a [ 1 ] if we're // not on the latest revision (edit conflicts and such). pageText = page.revisions[ 0 ][ '*' ]; if ( page.revisions[ 0 ].timestamp ) pageTime = page.revisions[ 0 ].timestamp.replace( /\D/g, '' ); if ( page.revisions[ 0 ].revid ) pageTextRevId = page.revisions[ 0 ].revid; if ( page.revisions.length > 1 ) conflictingUser = page.revisions[ 1 ].user; } if ( page.lastrevid ) lastRevId = page.lastrevid; if ( page.starttimestamp ) startTime = page.starttimestamp.replace( /\D/g, '' ); pageWatched = typeof page.watched === 'string'; if ( json.query.tokens ) editToken = json.query.tokens.csrftoken; if ( page.langlinks && ( !json[ 'query-continue' ] || !json[ 'query-continue' ].langlinks ) ) { // We have interlanguage links, and we got them all. var re = ''; for ( var i = 0; i < page.langlinks.length; i++ ) re += ( i > 0 ? '|' : '' ) + page.langlinks[ i ].lang.replace( /([\\^$.?*+()])/g, '\\$1' ); if ( re.length ) interlanguageRE = new RegExp( '((^|\\n\\r?)(\\[\\[\\s*(' + re + ')\\s*:[^\\]]+\\]\\]\\s*))+$' ); } } } // Siteinfo if ( json.query.general ) { if ( json.query.general.time && !startTime ) startTime = json.query.general.time.replace( /\D/g, '' ); if ( HC.capitalizePageNames === null ) { // ResourceLoader's JSParser doesn't like .case, so override eslint. // eslint-disable-next-line dot-notation HC.capitalizePageNames = ( json.query.general[ 'case' ] === 'first-letter' ); } } serverTime = startTime; // Userinfo if ( json.query.userinfo && json.query.userinfo.options ) { watchCreate = !HC.dont_add_to_watchlist && json.query.userinfo.options.watchcreations === '1'; watchEdit = !HC.dont_add_to_watchlist && json.query.userinfo.options.watchdefault === '1'; minorEdits = json.query.userinfo.options.minordefault === 1; // If the user has the "All edits are minor" preference enabled, we should honor that // for single category changes, no matter what the site configuration is. if ( minorEdits ) HC.single_minor = true; } } } var saveInProgress = false; function initiateEdit( doEdit, failure ) { if ( saveInProgress ) return; saveInProgress = true; var oldButtonState; if ( commitButton ) { oldButtonState = commitButton.disabled; commitButton.disabled = true; } function fail() { saveInProgress = false; if ( commitButton ) commitButton.disabled = oldButtonState; failure.apply( this, arguments ); } // Must use Ajax here to get the user options and the edit token. $.getJSON( wgServer + conf.wgScriptPath + '/api.php?' + 'format=json&action=query&rawcontinue=&titles=' + encodeURIComponent( conf.wgPageName ) + '&prop=info%7Crevisions%7Clanglinks&inprop=watched&rvprop=content%7Ctimestamp%7Cids%7Cuser&lllimit=500' + '&rvlimit=2&rvdir=newer&rvstartid=' + conf.wgCurRevisionId + '&meta=siteinfo%7Cuserinfo%7Ctokens&type=csrf&uiprop=options', function ( json ) { setPage( json ); doEdit( fail ); } ).fail( function ( req ) { fail( req.status + ' ' + req.statusText ); } ); } function multiChangeMsg( count ) { var msg = HC.messages.multi_change; if ( typeof msg !== 'string' && msg.length ) if ( mw.language && mw.language.convertPlural ) { msg = mw.language.convertPlural( count, msg ); } else { msg = msg[ msg.length - 1 ]; } return substitute( msg, [ null, String( count ) ] ); } function currentTimestamp() { var now = new Date(); var ts = String( now.getUTCFullYear() ); function two( s ) { return s.substr( s.length - 2 ); } ts += two( '0' + ( now.getUTCMonth() + 1 ) ) + two( '0' + now.getUTCDate() ) + two( '00' + now.getUTCHours() ) + two( '00' + now.getUTCMinutes() ) + two( '00' + now.getUTCSeconds() ); return ts; } function performChanges( failure, singleEditor ) { if ( pageText === null ) { failure( HC.messages.multi_error ); return; } // Backwards compatibility after message change (added $2 to cat_keychange) if ( HC.messages.cat_keychange.indexOf( '$2' ) < 0 ) HC.messages.cat_keychange += '"$2"'; // More backwards-compatibility with earlier HotCat versions: if ( !HC.messages.short_catchange ) HC.messages.short_catchange = '[[' + HC.category_canonical + ':$1]]'; // Create a form and submit it. We don't use the edit API (api.php?action=edit) because // (a) sensibly reporting back errors like edit conflicts is always a hassle, and // (b) we want to show a diff for multi-edits anyway, and // (c) we want to trigger onsubmit events, allowing user code to intercept the edit. // Using the form, we can do (b) and (c), and we get (a) for free. And, of course, using the form // automatically reloads the page with the updated categories on a successful submit, which // we would have to do explicitly if we used the edit API. var action; // Normally, we don't have to care about edit conflicts. If some other user edited the page in the meantime, the // server will take care of it and merge the edit automatically or present an edit conflict screen. However, the // server suppresses edit conflicts with oneself. Hence, if we have a conflict, and the conflicting user is the // current user, then we set the "oldid" value and switch to diff, which gives the "you are editing an old version; // if you save, any more recent changes will be lost" screen. var selfEditConflict = ( lastRevId !== null && lastRevId !== conf.wgCurRevisionId || pageTextRevId !== null && pageTextRevId !== conf.wgCurRevisionId ) && conflictingUser && conflictingUser === conf.wgUserName; if ( singleEditor && !singleEditor.noCommit && !HC.no_autocommit && editToken && !selfEditConflict ) { // If we do have an edit conflict, but not with ourself, that's no reason not to attempt to save: the server side may actually be able to // merge the changes. We just need to make sure that we do present a diff view if it's a self edit conflict. commitForm.wpEditToken.value = editToken; action = commitForm.wpDiff; if ( action ) action.name = action.value = 'wpSave'; } else { action = commitForm.wpSave; if ( action ) action.name = action.value = 'wpDiff'; } var result = { text: pageText }, changed = [], added = [], deleted = [], changes = 0, toEdit = singleEditor ? [ singleEditor ] : editors, error = null, edit, i; for ( i = 0; i < toEdit.length; i++ ) { edit = toEdit[ i ]; if ( edit.state === CategoryEditor.CHANGED ) { result = change_category( result.text, edit.originalCategory, edit.currentCategory, edit.currentKey, edit.currentHidden ); if ( !result.error ) { changes++; if ( !edit.originalCategory || !edit.originalCategory.length ) { added.push( edit.currentCategory ); } else { changed.push( { from: edit.originalCategory, to: edit.currentCategory } ); } } else if ( error === null ) { error = result.error; } } else if ( edit.state === CategoryEditor.DELETED && edit.originalCategory && edit.originalCategory.length ) { result = change_category( result.text, edit.originalCategory, null, null, false ); if ( !result.error ) { changes++; deleted.push( edit.originalCategory ); } else if ( error === null ) { error = result.error; } } } if ( error !== null ) { // Do not commit if there were errors action = commitForm.wpSave; if ( action ) action.name = action.value = 'wpDiff'; } // Fill in the form and submit it commitForm.wpMinoredit.checked = minorEdits; commitForm.wpWatchthis.checked = !conf.wgArticleId && watchCreate || watchEdit || pageWatched; if ( conf.wgArticleId || !!singleEditor ) { // Prepare change-tag save if ( action && action.value === 'wpSave' ) { if ( HC.changeTag ) { commitForm.wpChangeTags.value = HC.changeTag; HC.messages.using = ''; HC.messages.prefix = ''; } } else { commitForm.wpAutoSummary.value = HC.changeTag; } if ( changes === 1 ) { if ( result.summary && result.summary.length ) commitForm.wpSummary.value = HC.messages.prefix + result.summary.join( HC.messages.separator ) + HC.messages.using; commitForm.wpMinoredit.checked = HC.single_minor || minorEdits; } else if ( changes ) { var summary = []; var shortSummary = []; // Deleted for ( i = 0; i < deleted.length; i++ ) summary.push( '−' + substitute( HC.messages.short_catchange, [ null, deleted[ i ] ] ) ); if ( deleted.length === 1 ) shortSummary.push( '−' + substitute( HC.messages.short_catchange, [ null, deleted[ 0 ] ] ) ); else if ( deleted.length ) shortSummary.push( '− ' + multiChangeMsg( deleted.length ) ); // Added for ( i = 0; i < added.length; i++ ) summary.push( '+' + substitute( HC.messages.short_catchange, [ null, added[ i ] ] ) ); if ( added.length === 1 ) shortSummary.push( '+' + substitute( HC.messages.short_catchange, [ null, added[ 0 ] ] ) ); else if ( added.length ) shortSummary.push( '+ ' + multiChangeMsg( added.length ) ); // Changed var arrow = is_rtl ? '\u2190' : '\u2192'; // left and right arrows. Don't use ← and → in the code. for ( i = 0; i < changed.length; i++ ) { if ( changed[ i ].from !== changed[ i ].to ) { summary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ i ].from ] ) + arrow + substitute( HC.messages.short_catchange, [ null, changed[ i ].to ] ) ); } else { summary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ i ].from ] ) ); } } if ( changed.length === 1 ) { if ( changed[ 0 ].from !== changed[ 0 ].to ) { shortSummary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].from ] ) + arrow + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].to ] ) ); } else { shortSummary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].from ] ) ); } } else if ( changed.length ) { shortSummary.push( '± ' + multiChangeMsg( changed.length ) ); } if ( summary.length ) { summary = summary.join( HC.messages.separator ); if ( summary.length > 200 - HC.messages.prefix.length - HC.messages.using.length ) summary = shortSummary.join( HC.messages.separator ); commitForm.wpSummary.value = HC.messages.prefix + summary + HC.messages.using; } } } commitForm.wpTextbox1.value = result.text; commitForm.wpStarttime.value = serverTime || currentTimestamp(); commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value; if ( selfEditConflict ) commitForm.oldid.value = String( pageTextRevId || conf.wgCurRevisionId ); // Submit the form in a way that triggers onsubmit events: commitForm.submit() doesn't. commitForm.hcCommit.click(); } function resolveOne( page, toResolve ) { var cats = page.categories, lks = page.links, is_dab = false, is_redir = typeof page.redirect === 'string', // Hard redirect? is_hidden = page.categoryinfo && typeof page.categoryinfo.hidden === 'string', is_missing = typeof page.missing === 'string', i; for ( i = 0; i < toResolve.length; i++ ) { if ( i && toResolve[ i ].dabInputCleaned !== page.title.substring( page.title.indexOf( ':' ) + 1 ) ) continue; // Note: the server returns in page an NFC normalized Unicode title. If our input was not NFC normalized, we may not find // any entry here. If we have only one editor to resolve (the most common case, I presume), we may simply skip the check. toResolve[ i ].currentHidden = is_hidden; toResolve[ i ].inputExists = !is_missing; toResolve[ i ].icon.src = ( is_missing ? HC.existsNo : HC.existsYes ); } if ( is_missing ) return; if ( !is_redir && cats && ( HC.disambig_category || HC.redir_category ) ) { for ( var c = 0; c < cats.length; c++ ) { var cat = cats[ c ].title; // Strip namespace prefix if ( cat ) { cat = cat.substring( cat.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); if ( cat === HC.disambig_category ) { is_dab = true; break; } else if ( cat === HC.redir_category ) { is_redir = true; break; } } } } if ( !is_redir && !is_dab ) return; if ( !lks || !lks.length ) return; var titles = []; for ( i = 0; i < lks.length; i++ ) { if ( // Category namespace -- always true since we ask only for the category links lks[ i ].ns === 14 && // Name not empty lks[ i ].title && lks[ i ].title.length ) { // Internal link to existing thingy. Extract the page name and remove the namespace. var match = lks[ i ].title; match = match.substring( match.indexOf( ':' ) + 1 ); // Exclude blacklisted categories. if ( !HC.blacklist || !HC.blacklist.test( match ) ) titles.push( match ); } } if ( !titles.length ) return; for ( i = 0; i < toResolve.length; i++ ) { if ( i && toResolve[ i ].dabInputCleaned !== page.title.substring( page.title.indexOf( ':' ) + 1 ) ) continue; toResolve[ i ].inputExists = true; // Might actually be wrong if it's a redirect pointing to a non-existing category toResolve[ i ].icon.src = HC.existsYes; if ( titles.length > 1 ) { toResolve[ i ].dab = titles; } else { toResolve[ i ].text.value = titles[ 0 ] + ( toResolve[ i ].currentKey !== null ? '|' + toResolve[ i ].currentKey : '' ); } } } function resolveRedirects( toResolve, params ) { if ( !params || !params.query || !params.query.pages ) return; for ( var p in params.query.pages ) resolveOne( params.query.pages[ p ], toResolve ); } function resolveMulti( toResolve, callback ) { var i; for ( i = 0; i < toResolve.length; i++ ) { toResolve[ i ].dab = null; toResolve[ i ].dabInput = toResolve[ i ].lastInput; } if ( noSuggestions ) { callback( toResolve ); return; } // Use %7C instead of |, otherwise Konqueror insists on re-encoding the arguments, resulting in doubly encoded // category names. (That is a bug in Konqueror. Other browsers don't have this problem.) var args = 'action=query&prop=info%7Clinks%7Ccategories%7Ccategoryinfo&plnamespace=14' + '&pllimit=' + ( toResolve.length * 10 ) + '&cllimit=' + ( toResolve.length * 10 ) + '&format=json&titles='; for ( i = 0; i < toResolve.length; i++ ) { var v = toResolve[ i ].dabInput; v = replaceShortcuts( v, HC.shortcuts ); toResolve[ i ].dabInputCleaned = v; args += encodeURIComponent( 'Category:' + v ); if ( i + 1 < toResolve.length ) args += '%7C'; } $.getJSON( wgServer + conf.wgScriptPath + '/api.php?' + args, function ( json ) { resolveRedirects( toResolve, json ); callback( toResolve ); } ).fail( function ( req ) { if ( !req ) noSuggestions = true; callback( toResolve ); } ); } function makeActive( which ) { if ( which.is_active ) return; for ( var i = 0; i < editors.length; i++ ) if ( editors[ i ] !== which ) editors[ i ].inactivate(); which.is_active = true; if ( which.dab ) { // eslint-disable-next-line no-use-before-define showDab( which ); } else { // Check for programmatic value changes. var expectedInput = which.lastRealInput || which.lastInput || ''; var actualValue = which.text.value || ''; if ( !expectedInput.length && actualValue.length || expectedInput.length && actualValue.indexOf( expectedInput ) ) { // Somehow the field's value appears to have changed, and which.lastSelection therefore is no longer valid. Try to set the // cursor at the end of the category, and do not display the old suggestion list. which.showsList = false; var v = actualValue.split( '|' ); which.lastRealInput = which.lastInput = v[ 0 ]; if ( v.length > 1 ) which.currentKey = v[ 1 ]; if ( which.lastSelection ) { which.lastSelection = { start: v[ 0 ].length, end: v[ 0 ].length }; } } if ( which.showsList ) which.displayList(); if ( which.lastSelection ) { if ( is_webkit ) { // WebKit (Safari, Chrome) has problems selecting inside focus() // See http://code.google.com/p/chromium/issues/detail?id=32865#c6 window.setTimeout( function () { which.setSelection( which.lastSelection.start, which.lastSelection.end ); }, 1 ); } else { which.setSelection( which.lastSelection.start, which.lastSelection.end ); } } } } function showDab( which ) { if ( !which.is_active ) { makeActive( which ); } else { which.showSuggestions( which.dab, false, null, null ); // do autocompletion, no key, no engine selector which.dab = null; } } function multiSubmit() { var toResolve = []; for ( var i = 0; i < editors.length; i++ ) if ( editors[ i ].state === CategoryEditor.CHANGE_PENDING || editors[ i ].state === CategoryEditor.OPEN ) toResolve.push( editors[ i ] ); if ( !toResolve.length ) { initiateEdit( function ( failure ) { performChanges( failure ); }, function ( msg ) { alert( msg ); } ); return; } resolveMulti( toResolve, function ( resolved ) { var firstDab = null; var dontChange = false; for ( var i = 0; i < resolved.length; i++ ) { if ( resolved[ i ].lastInput !== resolved[ i ].dabInput ) { // We didn't disable all the open editors, but we did asynchronous calls. It is // theoretically possible that the user changed something... dontChange = true; } else { if ( resolved[ i ].dab ) { if ( !firstDab ) firstDab = resolved[ i ]; } else { if ( resolved[ i ].acceptCheck( true ) ) resolved[ i ].commit(); } } } if ( firstDab ) { showDab( firstDab ); } else if ( !dontChange ) { initiateEdit( function ( failure ) { performChanges( failure ); }, function ( msg ) { alert( msg ); } ); } } ); } function setMultiInput() { if ( commitButton || onUpload ) return; commitButton = make( 'input' ); commitButton.type = 'button'; commitButton.value = HC.messages.commit; commitButton.onclick = multiSubmit; if ( multiSpan ) multiSpan.parentNode.replaceChild( commitButton, multiSpan ); else catLine.appendChild( commitButton ); } function checkMultiInput() { if ( !commitButton ) return; var hasChanges = false; for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { hasChanges = true; break; } } commitButton.disabled = !hasChanges; } var suggestionEngines = { opensearch: { uri: '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=Category:$1', // $1 = search term // Function to convert result of uri into an array of category names handler: function ( queryResult, queryKey ) { if ( queryResult && queryResult.length >= 2 ) { var key = queryResult[ 0 ].substring( queryResult[ 0 ].indexOf( ':' ) + 1 ); var titles = queryResult[ 1 ]; var exists = false; if ( !cat_prefix ) cat_prefix = new RegExp( '^(' + HC.category_regexp + '):' ); for ( var i = 0; i < titles.length; i++ ) { cat_prefix.lastIndex = 0; var m = cat_prefix.exec( titles[ i ] ); if ( m && m.length > 1 ) { titles[ i ] = titles[ i ].substring( titles[ i ].indexOf( ':' ) + 1 ); // rm namespace if ( key === titles[ i ] ) exists = true; } else { titles.splice( i, 1 ); // Nope, it's not a category after all. i--; } } titles.exists = exists; if ( queryKey !== key ) titles.normalized = key; // Remember the NFC normalized key we got back from the server return titles; } return null; } }, internalsearch: { uri: '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1&apprefix=$1', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.allpages ) { var titles = queryResult.query.allpages; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } return null; } }, exists: { uri: '/api.php?format=json&action=query&prop=info&titles=Category:$1', handler: function ( queryResult, queryKey ) { if ( queryResult && queryResult.query && queryResult.query.pages && !queryResult.query.pages[ -1 ] ) { // Should have exactly 1 for ( var p in queryResult.query.pages ) { var title = queryResult.query.pages[ p ].title; title = title.substring( title.indexOf( ':' ) + 1 ); var titles = [ title ]; titles.exists = true; if ( queryKey !== title ) titles.normalized = title; // NFC return titles; } } return null; } }, subcategories: { uri: '/api.php?format=json&action=query&list=categorymembers&cmtype=subcat&cmlimit=max&cmtitle=Category:$1', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.categorymembers ) { var titles = queryResult.query.categorymembers; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } return null; } }, parentcategories: { uri: '/api.php?format=json&action=query&prop=categories&titles=Category:$1&cllimit=max', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.pages ) { for ( var p in queryResult.query.pages ) { if ( queryResult.query.pages[ p ].categories ) { var titles = queryResult.query.pages[ p ].categories; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } } } return null; } } }; var suggestionConfigs = { searchindex: { name: 'Search index', engines: [ 'opensearch' ], cache: {}, show: true, temp: false, noCompletion: false }, pagelist: { name: 'Page list', engines: [ 'internalsearch', 'exists' ], cache: {}, show: true, temp: false, noCompletion: false }, combined: { name: 'Combined search', engines: [ 'opensearch', 'internalsearch' ], cache: {}, show: true, temp: false, noCompletion: false }, subcat: { name: 'Subcategories', engines: [ 'subcategories' ], cache: {}, show: true, temp: true, noCompletion: true }, parentcat: { name: 'Parent categories', engines: [ 'parentcategories' ], cache: {}, show: true, temp: true, noCompletion: true } }; CategoryEditor.UNCHANGED = 0; CategoryEditor.OPEN = 1; // Open, but no input yet CategoryEditor.CHANGE_PENDING = 2; // Open, some input made CategoryEditor.CHANGED = 3; CategoryEditor.DELETED = 4; // Support: IE6 // IE6 sometimes forgets to redraw the list when editors are opened or closed. // Adding/removing a dummy element helps, at least when opening editors. var dummyElement = make( '\xa0', true ); function forceRedraw() { if ( dummyElement.parentNode ) document.body.removeChild( dummyElement ); else document.body.appendChild( dummyElement ); } // Event keyCodes that we handle in the text input field/suggestion list. var BS = 8, TAB = 9, RET = 13, ESC = 27, SPACE = 32, PGUP = 33, PGDOWN = 34, UP = 38, DOWN = 40, DEL = 46, IME = 229; CategoryEditor.prototype = { initialize: function ( line, span, after, key, is_hidden ) { // If a span is given, 'after' is the category title, otherwise it may be an element after which to // insert the new span. 'key' is likewise overloaded; if a span is given, it is the category key (if // known), otherwise it is a boolean indicating whether a bar shall be prepended. if ( !span ) { this.isAddCategory = true; // Create add span and append to catLinks this.originalCategory = ''; this.originalKey = null; this.originalExists = false; if ( !newDOM ) { span = make( 'span' ); span.className = 'noprint'; if ( key ) { span.appendChild( make( ' | ', true ) ); if ( after ) { after.parentNode.insertBefore( span, after.nextSibling ); after = after.nextSibling; } else if (line) { line.appendChild( span ); } } else if ( line && line.firstChild ) { span.appendChild( make( ' ', true ) ); line.appendChild( span ); } } this.linkSpan = make( 'span' ); this.linkSpan.className = 'noprint nopopups hotcatlink'; var lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.open.bind( this ); lk.appendChild( make( HC.links.add, true ) ); lk.title = HC.tooltips.add; this.linkSpan.appendChild( lk ); span = make( newDOM ? 'li' : 'span' ); span.className = 'noprint'; if ( is_rtl ) span.dir = 'rtl'; span.appendChild( this.linkSpan ); if ( after ) { after.parentNode.insertBefore( span, after.nextSibling ); } else if ( line ) { line.appendChild( span ); } this.normalLinks = null; this.undelLink = null; this.catLink = null; } else { if ( is_rtl ) span.dir = 'rtl'; this.isAddCategory = false; this.catLink = span.firstChild; this.originalCategory = after; this.originalKey = ( key && key.length > 1 ) ? key.substr( 1 ) : null; // > 1 because it includes the leading bar this.originalExists = !hasClass( this.catLink, 'new' ); // Create change and del links this.makeLinkSpan(); if ( !this.originalExists && this.upDownLinks ) this.upDownLinks.style.display = 'none'; span.appendChild( this.linkSpan ); } this.originalHidden = is_hidden; this.line = line; this.engine = HC.suggestions; this.span = span; this.currentCategory = this.originalCategory; this.currentExists = this.originalExists; this.currentHidden = this.originalHidden; this.currentKey = this.originalKey; this.state = CategoryEditor.UNCHANGED; this.lastSavedState = CategoryEditor.UNCHANGED; this.lastSavedCategory = this.originalCategory; this.lastSavedKey = this.originalKey; this.lastSavedExists = this.originalExists; this.lastSavedHidden = this.originalHidden; if ( this.catLink && this.currentKey ) this.catLink.title = this.currentKey; editors[ editors.length ] = this; }, makeLinkSpan: function () { this.normalLinks = make( 'span' ); var lk = null; if ( this.originalCategory && this.originalCategory.length ) { lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.remove.bind( this ); lk.appendChild( make( HC.links.remove, true ) ); lk.title = HC.tooltips.remove; this.normalLinks.appendChild( make( ' ', true ) ); this.normalLinks.appendChild( lk ); } if ( !HC.template_categories[ this.originalCategory ] ) { lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.open.bind( this ); lk.appendChild( make( HC.links.change, true ) ); lk.title = HC.tooltips.change; this.normalLinks.appendChild( make( ' ', true ) ); this.normalLinks.appendChild( lk ); if ( !noSuggestions && HC.use_up_down ) { this.upDownLinks = make( 'span' ); lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.down.bind( this ); lk.appendChild( make( HC.links.down, true ) ); lk.title = HC.tooltips.down; this.upDownLinks.appendChild( make( ' ', true ) ); this.upDownLinks.appendChild( lk ); lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.up.bind( this ); lk.appendChild( make( HC.links.up, true ) ); lk.title = HC.tooltips.up; this.upDownLinks.appendChild( make( ' ', true ) ); this.upDownLinks.appendChild( lk ); this.normalLinks.appendChild( this.upDownLinks ); } } this.linkSpan = make( 'span' ); this.linkSpan.className = 'noprint nopopups hotcatlink'; this.linkSpan.appendChild( this.normalLinks ); this.undelLink = make( 'span' ); this.undelLink.className = 'nopopups hotcatlink'; this.undelLink.style.display = 'none'; lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.restore.bind( this ); lk.appendChild( make( HC.links.restore, true ) ); lk.title = HC.tooltips.restore; this.undelLink.appendChild( make( ' ', true ) ); this.undelLink.appendChild( lk ); this.linkSpan.appendChild( this.undelLink ); }, invokeSuggestions: function ( dont_autocomplete ) { if ( this.engine && suggestionConfigs[ this.engine ] && suggestionConfigs[ this.engine ].temp && !dont_autocomplete ) this.engine = HC.suggestions; // Reset to a search upon input this.state = CategoryEditor.CHANGE_PENDING; var self = this; window.setTimeout( function () { self.textchange( dont_autocomplete ); }, HC.suggest_delay ); }, makeForm: function () { var form = make( 'form' ); form.method = 'POST'; form.onsubmit = this.accept.bind( this ); this.form = form; var self = this; var text = make( 'input' ); text.type = 'text'; text.size = HC.editbox_width; if ( !noSuggestions ) { // Be careful here to handle IME input. This is browser/OS/IME dependent, but basically there are two mechanisms: // - Modern (DOM Level 3) browsers use compositionstart/compositionend events to signal composition; if the // composition is not canceled, there'll be a textInput event following. During a composition key events are // either all suppressed (FF/Gecko), or otherwise have keyDown === IME for all keys (Webkit). // - Webkit sends a textInput followed by keyDown === IME and a keyUp with the key that ended composition. // - Gecko doesn't send textInput but just a keyUp with the key that ended composition, without sending keyDown // first. Gecko doesn't send any keydown while IME is active. // - Older browsers signal composition by keyDown === IME for the first and subsequent keys for a composition. The // first keyDown !== IME is certainly after the end of the composition. Typically, composition end can also be // detected by a keyDown IME with a keyUp of space, tab, escape, or return. text.onkeyup = function ( evt ) { var key = evt.keyCode || 0; if ( self.ime && self.lastKey === IME && !self.usesComposition && ( key === TAB || key === RET || key === ESC || key === SPACE ) ) self.ime = false; if ( self.ime ) return true; if ( key === UP || key === DOWN || key === PGUP || key === PGDOWN ) { // In case a browser doesn't generate keypress events for arrow keys... if ( self.keyCount === 0 ) return self.processKey( evt ); } else { if ( key === ESC && self.lastKey !== IME ) { if ( !self.resetKeySelection() ) { // No undo of key selection: treat ESC as "cancel". self.cancel(); return; } } // Also do this for ESC as a workaround for Firefox bug 524360 // https://bugzilla.mozilla.org/show_bug.cgi?id=524360 self.invokeSuggestions( key === BS || key === DEL || key === ESC ); } return true; }; text.onkeydown = function ( evt ) { var key = evt.keyCode || 0; self.lastKey = key; self.keyCount = 0; // DOM Level < 3 IME input if ( !self.ime && key === IME && !self.usesComposition ) { // self.usesComposition catches browsers that may emit spurious keydown IME after a composition has ended self.ime = true; } else if ( self.ime && key !== IME && !( key >= 16 && key <= 20 || key >= 91 && key <= 93 || key === 144 ) ) { // Ignore control keys: ctrl, shift, alt, alt gr, caps lock, windows/apple cmd keys, num lock. Only the windows keys // terminate IME (apple cmd doesn't), but they also cause a blur, so it's OK to ignore them here. // Note: Safari 4 (530.17) propagates ESC out of an IME composition (observed at least on Win XP). self.ime = false; } if ( self.ime ) return true; // Handle return explicitly, to override the default form submission to be able to check for ctrl if ( key === RET ) return self.accept( evt ); // Inhibit default behavior of ESC (revert to last real input in FF: we do that ourselves) return ( key === ESC ) ? evtKill( evt ) : true; }; // And handle continued pressing of arrow keys text.onkeypress = function ( evt ) { self.keyCount++; return self.processKey( evt ); }; $( text ).on( 'focus', function () { makeActive( self ); } ); // On IE, blur events are asynchronous, and may thus arrive after the element has lost the focus. Since IE // can get the selection only while the element is active (has the focus), we may not always get the selection. // Therefore, use an IE-specific synchronous event on IE... // Don't test for text.selectionStart being defined; $( text ).on( ( text.onbeforedeactivate !== undefined && text.createTextRange ) ? 'beforedeactivate' : 'blur', this.saveView.bind( this ) ); // DOM Level 3 IME handling try { // Setting lastKey = IME provides a fake keyDown for Gecko's single keyUp after a cmposition. If we didn't do this, // cancelling a composition via ESC would also cancel and close the whole category input editor. $( text ).on( 'compositionstart', function () { self.lastKey = IME; self.usesComposition = true; self.ime = true; } ); $( text ).on( 'compositionend', function () { self.lastKey = IME; self.usesComposition = true; self.ime = false; } ); $( text ).on( 'textInput', function () { self.ime = false; self.invokeSuggestions( false ); } ); } catch ( any ) { // Just in case some browsers might produce exceptions with these DOM Level 3 events } $( text ).on( 'blur', function () { self.usesComposition = false; self.ime = false; } ); } this.text = text; this.icon = make( 'img' ); var list = null; if ( !noSuggestions ) { list = make( 'select' ); list.onclick = function () { if ( self.highlightSuggestion( 0 ) ) self.textchange( false, true ); }; list.ondblclick = function ( e ) { if ( self.highlightSuggestion( 0 ) ) self.accept( e ); }; list.onchange = function () { self.highlightSuggestion( 0 ); self.text.focus(); }; list.onkeyup = function ( evt ) { if ( evt.keyCode === ESC ) { self.resetKeySelection(); self.text.focus(); window.setTimeout( function () { self.textchange( true ); }, HC.suggest_delay ); } else if ( evt.keyCode === RET ) { self.accept( evt ); } }; if ( !HC.fixed_search ) { var engineSelector = make( 'select' ); for ( var key in suggestionConfigs ) { if ( suggestionConfigs[ key ].show ) { var opt = make( 'option' ); opt.value = key; if ( key === this.engine ) opt.selected = true; opt.appendChild( make( suggestionConfigs[ key ].name, true ) ); engineSelector.appendChild( opt ); } } engineSelector.onchange = function () { self.engine = self.engineSelector.options[ self.engineSelector.selectedIndex ].value; self.text.focus(); self.textchange( true, true ); // Don't autocomplete, force re-display of list }; this.engineSelector = engineSelector; } } this.list = list; function button_label( id, defaultText ) { var label = null; if ( onUpload && window.UFUI !== undefined && window.UIElements !== undefined && UFUI.getLabel instanceof Function ) { try { label = UFUI.getLabel( id, true ); // Extract the plain text. IE doesn't know that Node.TEXT_NODE === 3 while ( label && label.nodeType !== 3 ) label = label.firstChild; } catch ( ex ) { label = null; } } if ( !label || !label.data ) return defaultText; return label.data; } // Do not use type 'submit'; we cannot detect modifier keys if we do var OK = make( 'input' ); OK.type = 'button'; OK.value = button_label( 'wpOkUploadLbl', HC.messages.ok ); OK.onclick = this.accept.bind( this ); this.ok = OK; var cancel = make( 'input' ); cancel.type = 'button'; cancel.value = button_label( 'wpCancelUploadLbl', HC.messages.cancel ); cancel.onclick = this.cancel.bind( this ); this.cancelButton = cancel; var span = make( 'span' ); span.className = 'hotcatinput'; span.style.position = 'relative'; span.appendChild( text ); // Support: IE8, IE9 // Put some text into this span (a0 is nbsp) and make sure it always stays on the same // line as the input field, otherwise, IE8/9 miscalculates the height of the span and // then the engine selector may overlap the input field. span.appendChild( make( '\xa0', true ) ); span.style.whiteSpace = 'nowrap'; if ( list ) span.appendChild( list ); if ( this.engineSelector ) span.appendChild( this.engineSelector ); if ( !noSuggestions ) span.appendChild( this.icon ); span.appendChild( OK ); span.appendChild( cancel ); form.appendChild( span ); form.style.display = 'none'; this.span.appendChild( form ); }, display: function ( evt ) { if ( this.isAddCategory && !onUpload && this.line ) { // eslint-disable-next-line no-new new CategoryEditor( this.line, null, this.span, true ); // Create a new one } if ( !commitButton && !onUpload ) { for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { setMultiInput(); break; } } } if ( !this.form ) this.makeForm(); if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; this.currentCategory = this.lastSavedCategory; this.currentExists = this.lastSavedExists; this.currentHidden = this.lastSavedHidden; this.currentKey = this.lastSavedKey; this.icon.src = ( this.currentExists ? HC.existsYes : HC.existsNo ); this.text.value = this.currentCategory + ( this.currentKey !== null ? '|' + this.currentKey : '' ); this.originalState = this.state; this.lastInput = this.currentCategory; this.inputExists = this.currentExists; this.state = this.state === CategoryEditor.UNCHANGED ? CategoryEditor.OPEN : CategoryEditor.CHANGE_PENDING; this.lastSelection = { start: this.currentCategory.length, end: this.currentCategory.length }; this.showsList = false; // Display the form if ( this.catLink ) this.catLink.style.display = 'none'; this.linkSpan.style.display = 'none'; this.form.style.display = 'inline'; this.ok.disabled = false; // Kill the event before focussing, otherwise IE will kill the onfocus event! var result = evtKill( evt ); this.text.focus(); this.text.readOnly = false; checkMultiInput(); return result; }, show: function ( evt, engine, readOnly ) { var result = this.display( evt ); var v = this.lastSavedCategory; if ( !v.length ) return result; this.text.readOnly = !!readOnly; this.engine = engine; this.textchange( false, true ); // do autocompletion, force display of suggestions forceRedraw(); return result; }, open: function ( evt ) { return this.show( evt, ( this.engine && suggestionConfigs[ this.engine ].temp ) ? HC.suggestions : this.engine ); }, down: function ( evt ) { return this.show( evt, 'subcat', true ); }, up: function ( evt ) { return this.show( evt, 'parentcat' ); }, cancel: function () { if ( this.isAddCategory && !onUpload ) { this.removeEditor(); // We added a new adder when opening return; } // Close, re-display link this.inactivate(); this.form.style.display = 'none'; if ( this.catLink ) this.catLink.style.display = ''; this.linkSpan.style.display = ''; this.state = this.originalState; this.currentCategory = this.lastSavedCategory; this.currentKey = this.lastSavedKey; this.currentExists = this.lastSavedExists; this.currentHidden = this.lastSavedHidden; if ( this.catLink ) if ( this.currentKey && this.currentKey.length ) { this.catLink.title = this.currentKey; } else { this.catLink.title = ''; } if ( this.state === CategoryEditor.UNCHANGED ) { if ( this.catLink ) this.catLink.style.backgroundColor = 'transparent'; } else { if ( !onUpload ) { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } } checkMultiInput(); forceRedraw(); }, removeEditor: function () { if ( !newDOM ) { var next = this.span.nextSibling; if ( next ) next.parentNode.removeChild( next ); } if (this.span && this.span.parentNode) { this.span.parentNode.removeChild( this.span ); } for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ] === this ) { editors.splice( i, 1 ); break; } } checkMultiInput(); }, rollback: function ( evt ) { this.undoLink.parentNode.removeChild( this.undoLink ); this.undoLink = null; this.currentCategory = this.originalCategory; this.currentKey = this.originalKey; this.currentExists = this.originalExists; this.currentHidden = this.originalHidden; this.lastSavedCategory = this.originalCategory; this.lastSavedKey = this.originalKey; this.lastSavedExists = this.originalExists; this.lastSavedHidden = this.originalHidden; this.state = CategoryEditor.UNCHANGED; if ( !this.currentCategory || !this.currentCategory.length ) { // It was a newly added category. Remove the whole editor. this.removeEditor(); } else { // Redisplay the link... this.catLink.removeChild( this.catLink.firstChild ); this.catLink.appendChild( make( this.currentCategory, true ) ); this.catLink.href = wikiPagePath( HC.category_canonical + ':' + this.currentCategory ); this.catLink.title = this.currentKey || ''; this.catLink.className = this.currentExists ? '' : 'new'; this.catLink.style.backgroundColor = 'transparent'; if ( this.upDownLinks ) this.upDownLinks.style.display = this.currentExists ? '' : 'none'; checkMultiInput(); } return evtKill( evt ); }, inactivate: function () { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; this.is_active = false; }, acceptCheck: function ( dontCheck ) { this.sanitizeInput(); var value = this.text.value.split( '|' ); var key = null; if ( value.length > 1 ) key = value[ 1 ]; var v = value[ 0 ].replace( /_/g, ' ' ).replace( /^\s+|\s+$/g, '' ); if ( HC.capitalizePageNames ) v = capitalize( v ); this.lastInput = v; v = replaceShortcuts( v, HC.shortcuts ); if ( !v.length ) { this.cancel(); return false; } if ( !dontCheck && ( conf.wgNamespaceNumber === 14 && v === conf.wgTitle || HC.blacklist && HC.blacklist.test( v ) ) ) { this.cancel(); return false; } this.currentCategory = v; this.currentKey = key; this.currentExists = this.inputExists; return true; }, accept: function ( evt ) { // eslint-disable-next-line no-bitwise this.noCommit = ( evtKeys( evt ) & 1 ) !== 0; var result = evtKill( evt ); if ( this.acceptCheck() ) { var toResolve = [ this ]; var original = this.currentCategory; resolveMulti( toResolve, function ( resolved ) { if ( resolved[ 0 ].dab ) { showDab( resolved[ 0 ] ); } else { if ( resolved[ 0 ].acceptCheck( true ) ) { resolved[ 0 ].commit( ( resolved[ 0 ].currentCategory !== original ) ? HC.messages.cat_resolved.replace( /\$1/g, original ) : null ); } } } ); } return result; }, close: function () { if ( !this.catLink ) { // Create a catLink this.catLink = make( 'a' ); this.catLink.appendChild( make( 'foo', true ) ); this.catLink.style.display = 'none'; this.span.insertBefore( this.catLink, this.span.firstChild.nextSibling ); } this.catLink.removeChild( this.catLink.firstChild ); this.catLink.appendChild( make( this.currentCategory, true ) ); this.catLink.href = wikiPagePath( HC.category_canonical + ':' + this.currentCategory ); this.catLink.className = this.currentExists ? '' : 'new'; this.lastSavedCategory = this.currentCategory; this.lastSavedKey = this.currentKey; this.lastSavedExists = this.currentExists; this.lastSavedHidden = this.currentHidden; // Close form and redisplay category this.inactivate(); this.form.style.display = 'none'; this.catLink.title = this.currentKey || ''; this.catLink.style.display = ''; if ( this.isAddCategory ) { if ( onUpload && this.line ) { // eslint-disable-next-line no-new new CategoryEditor( this.line, null, this.span, true ); // Create a new one } this.isAddCategory = false; this.linkSpan.parentNode.removeChild( this.linkSpan ); this.makeLinkSpan(); this.span.appendChild( this.linkSpan ); } if ( !this.undoLink ) { // Append an undo link. var span = make( 'span' ); var lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.rollback.bind( this ); lk.appendChild( make( HC.links.undo, true ) ); lk.title = HC.tooltips.undo; span.appendChild( make( ' ', true ) ); span.appendChild( lk ); this.normalLinks.appendChild( span ); this.undoLink = span; if ( !onUpload ) { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } } if ( this.upDownLinks ) this.upDownLinks.style.display = this.lastSavedExists ? '' : 'none'; this.linkSpan.style.display = ''; this.state = CategoryEditor.CHANGED; checkMultiInput(); forceRedraw(); }, commit: function () { // Check again to catch problem cases after redirect resolution if ( ( this.currentCategory === this.originalCategory && ( this.currentKey === this.originalKey || this.currentKey === null && !this.originalKey.length ) ) || conf.wgNamespaceNumber === 14 && this.currentCategory === conf.wgTitle || HC.blacklist && HC.blacklist.test( this.currentCategory ) ) { this.cancel(); return; } this.close(); if ( !commitButton && !onUpload ) { var self = this; initiateEdit( function ( failure ) { performChanges( failure, self ); }, function ( msg ) { alert( msg ); } ); } }, remove: function ( evt ) { // eslint-disable-next-line no-bitwise this.doRemove( evtKeys( evt ) & 1 ); return evtKill( evt ); }, doRemove: function ( noCommit ) { if ( this.isAddCategory ) { // Empty input on adding a new category this.cancel(); return; } if ( !commitButton && !onUpload ) { for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { setMultiInput(); break; } } } if ( commitButton ) { this.catLink.title = ''; this.catLink.style.cssText += '; text-decoration : line-through !important;'; try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} this.originalState = this.state; this.state = CategoryEditor.DELETED; this.normalLinks.style.display = 'none'; this.undelLink.style.display = ''; checkMultiInput(); } else { if ( onUpload ) { // Remove this editor completely this.removeEditor(); } else { this.originalState = this.state; this.state = CategoryEditor.DELETED; this.noCommit = noCommit || HC.del_needs_diff; var self = this; initiateEdit( function ( failure ) { performChanges( failure, self ); }, function ( msg ) { self.state = self.originalState; alert( msg ); } ); } } }, restore: function ( evt ) { // Can occur only if we do have a commit button and are not on the upload form this.catLink.title = this.currentKey || ''; this.catLink.style.textDecoration = ''; this.state = this.originalState; if ( this.state === CategoryEditor.UNCHANGED ) { this.catLink.style.backgroundColor = 'transparent'; } else { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } this.normalLinks.style.display = ''; this.undelLink.style.display = 'none'; checkMultiInput(); return evtKill( evt ); }, // Internal operations selectEngine: function ( engineName ) { if ( !this.engineSelector ) return; for ( var i = 0; i < this.engineSelector.options.length; i++ ) this.engineSelector.options[ i ].selected = this.engineSelector.options[ i ].value === engineName; }, sanitizeInput: function () { var v = this.text.value || ''; v = v.replace( /^(\s|_)+/, '' ); // Trim leading blanks and underscores var re = new RegExp( '^(' + HC.category_regexp + '):' ); if ( re.test( v ) ) v = v.substring( v.indexOf( ':' ) + 1 ).replace( /^(\s|_)+/, '' ); v = v.replace(/\u200E$/, ''); // Trim ending left-to-right mark if ( HC.capitalizePageNames ) v = capitalize( v ); // Update the input field if needed, manually restoring the cursor afterwards // (but not the whole selection, so that further typing does not overwrite anything) if ( this.text.value !== null && this.text.value !== v ) { var cursorPos = this.text.selectionStart; this.text.value = v; this.text.setSelectionRange( cursorPos, cursorPos ); } }, makeCall: function ( url, callbackObj, engine, queryKey, cleanKey ) { var cb = callbackObj, e = engine, v = queryKey, z = cleanKey, thisObj = this; function done() { cb.callsMade++; if ( cb.callsMade === cb.nofCalls ) { if ( cb.exists ) cb.allTitles.exists = true; if ( cb.normalized ) cb.allTitles.normalized = cb.normalized; if ( !cb.dontCache && !suggestionConfigs[ cb.engineName ].cache[ z ] ) suggestionConfigs[ cb.engineName ].cache[ z ] = cb.allTitles; thisObj.text.readOnly = false; if ( !cb.cancelled ) thisObj.showSuggestions( cb.allTitles, cb.noCompletion, v, cb.engineName ); if ( cb === thisObj.callbackObj ) thisObj.callbackObj = null; cb = undefined; } } $.getJSON( url, function ( json ) { var titles = e.handler( json, z ); if ( titles && titles.length ) { if ( cb.allTitles === null ) cb.allTitles = titles; else cb.allTitles = cb.allTitles.concat( titles ); if ( titles.exists ) cb.exists = true; if ( titles.normalized ) cb.normalized = titles.normalized; } done(); } ).fail( function ( req ) { if ( !req ) noSuggestions = true; cb.dontCache = true; done(); } ); }, callbackObj: null, textchange: function ( dont_autocomplete, force ) { // Hide all other lists makeActive( this ); // Get input value, omit sort key, if any this.sanitizeInput(); var v = this.text.value; // Disregard anything after a pipe. var pipe = v.indexOf( '|' ); if ( pipe >= 0 ) { this.currentKey = v.substring( pipe + 1 ); v = v.substring( 0, pipe ); } else { this.currentKey = null; } if ( this.lastInput === v && !force ) return; // No change if ( this.lastInput !== v ) checkMultiInput(); this.lastInput = v; this.lastRealInput = v; // Mark blacklisted inputs. this.ok.disabled = v.length && HC.blacklist && HC.blacklist.test( v ); if ( noSuggestions ) { // No Ajax: just make sure the list is hidden if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( this.icon ) this.icon.style.display = 'none'; return; } if ( !v.length ) { this.showSuggestions( [] ); return; } var cleanKey = v.replace( /[\u200E\u200F\u202A-\u202E]/g, '' ).replace( wikiTextBlankRE, ' ' ); cleanKey = replaceShortcuts( cleanKey, HC.shortcuts ); cleanKey = cleanKey.replace( /^\s+|\s+$/g, '' ); if ( !cleanKey.length ) { this.showSuggestions( [] ); return; } if ( this.callbackObj ) this.callbackObj.cancelled = true; var engineName = suggestionConfigs[ this.engine ] ? this.engine : 'combined'; dont_autocomplete = dont_autocomplete || suggestionConfigs[ engineName ].noCompletion; if ( suggestionConfigs[ engineName ].cache[ cleanKey ] ) { this.showSuggestions( suggestionConfigs[ engineName ].cache[ cleanKey ], dont_autocomplete, v, engineName ); return; } var engines = suggestionConfigs[ engineName ].engines; this.callbackObj = { allTitles: null, callsMade: 0, nofCalls: engines.length, noCompletion: dont_autocomplete, engineName: engineName }; this.makeCalls( engines, this.callbackObj, v, cleanKey ); }, makeCalls: function ( engines, cb, v, cleanKey ) { for ( var j = 0; j < engines.length; j++ ) { var engine = suggestionEngines[ engines[ j ] ]; var url = wgServer + conf.wgScriptPath + engine.uri.replace( /\$1/g, encodeURIComponent( cleanKey ) ); this.makeCall( url, cb, engine, v, cleanKey ); } }, showSuggestions: function ( titles, dontAutocomplete, queryKey, engineName ) { this.text.readOnly = false; this.dab = null; this.showsList = false; if ( !this.list ) return; if ( noSuggestions ) { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( this.icon ) this.icon.style.display = 'none'; this.inputExists = true; // Default... return; } this.engineName = engineName; if ( engineName ) { if ( !this.engineSelector ) this.engineName = null; } else { if ( this.engineSelector ) this.engineSelector.style.display = 'none'; } if ( queryKey ) { if ( this.lastInput.indexOf( queryKey ) ) return; if ( this.lastQuery && this.lastInput.indexOf( this.lastQuery ) === 0 && this.lastQuery.length > queryKey.length ) return; } this.lastQuery = queryKey; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; v = ( HC.capitalizePageNames ? capitalize( v[ 0 ] ) : v[ 0 ] ); var vNormalized = v; var knownToExist = titles && titles.exists; var i; if ( titles ) { if ( titles.normalized && v.indexOf( queryKey ) === 0 ) { // We got back a different normalization than what is in the input field vNormalized = titles.normalized + v.substring( queryKey.length ); } var vLow = vNormalized.toLowerCase(); // Strip blacklisted categories if ( HC.blacklist ) { for ( i = 0; i < titles.length; i++ ) { if ( HC.blacklist.test( titles[ i ] ) ) { titles.splice( i, 1 ); i--; } } } titles.sort( function ( a, b ) { if ( a === b ) return 0; if ( a.indexOf( b ) === 0 ) return 1; // a begins with b: a > b if ( b.indexOf( a ) === 0 ) return -1; // b begins with a: a < b // Opensearch may return stuff not beginning with the search prefix! var prefixMatchA = ( a.indexOf( vNormalized ) === 0 ? 1 : 0 ); var prefixMatchB = ( b.indexOf( vNormalized ) === 0 ? 1 : 0 ); if ( prefixMatchA !== prefixMatchB ) return prefixMatchB - prefixMatchA; // Case-insensitive prefix match! var aLow = a.toLowerCase(), bLow = b.toLowerCase(); prefixMatchA = ( aLow.indexOf( vLow ) === 0 ? 1 : 0 ); prefixMatchB = ( bLow.indexOf( vLow ) === 0 ? 1 : 0 ); if ( prefixMatchA !== prefixMatchB ) return prefixMatchB - prefixMatchA; if ( a < b ) return -1; if ( b < a ) return 1; return 0; } ); // Remove duplicates and self-references for ( i = 0; i < titles.length; i++ ) { if ( i + 1 < titles.length && titles[ i ] === titles[ i + 1 ] || conf.wgNamespaceNumber === 14 && titles[ i ] === conf.wgTitle ) { titles.splice( i, 1 ); i--; } } } if ( !titles || !titles.length ) { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { if ( this.icon ) this.icon.src = HC.existsNo; this.inputExists = false; } return; } var firstTitle = titles[ 0 ]; var completed = this.autoComplete( firstTitle, v, vNormalized, key, dontAutocomplete ); var existing = completed || knownToExist || firstTitle === replaceShortcuts( v, HC.shortcuts ); if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { this.icon.src = ( existing ? HC.existsYes : HC.existsNo ); this.inputExists = existing; } if ( completed ) { this.lastInput = firstTitle; if ( titles.length === 1 ) { this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; return; } } // (Re-)fill the list while ( this.list.firstChild ) this.list.removeChild( this.list.firstChild ); for ( i = 0; i < titles.length; i++ ) { var opt = make( 'option' ); opt.appendChild( make( titles[ i ], true ) ); opt.selected = completed && ( i === 0 ); this.list.appendChild( opt ); } this.displayList(); }, displayList: function () { this.showsList = true; if ( !this.is_active ) { this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; return; } var nofItems = ( this.list.options.length > HC.listSize ? HC.listSize : this.list.options.length ); if ( nofItems <= 1 ) nofItems = 2; this.list.size = nofItems; this.list.style.align = is_rtl ? 'right' : 'left'; this.list.style.zIndex = 5; this.list.style.position = 'absolute'; // Compute initial list position. First the height. var anchor = is_rtl ? 'right' : 'left'; var listh = 0; if ( this.list.style.display === 'none' ) { // Off-screen display to get the height this.list.style.top = this.text.offsetTop + 'px'; this.list.style[ anchor ] = '-10000px'; this.list.style.display = ''; listh = this.list.offsetHeight; this.list.style.display = 'none'; } else { listh = this.list.offsetHeight; } // Approximate calculation of maximum list size var maxListHeight = listh; if ( nofItems < HC.listSize ) maxListHeight = ( listh / nofItems ) * HC.listSize; function viewport( what ) { if ( is_webkit && !document.evaluate ) { // Safari < 3.0 return window[ 'inner' + what ]; } var s = 'client' + what; if ( window.opera ) return document.body[ s ]; return ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; } function scroll_offset( what ) { var s = 'scroll' + what; var result = ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; if ( is_rtl && what === 'Left' ) { // RTL inconsistencies. // FF: 0 at the far right, then increasingly negative values. // IE >= 8: 0 at the far right, then increasingly positive values. // Webkit: scrollWidth - clientWidth at the far right, then down to zero. // Opera: don't know... if ( result < 0 ) result = -result; if ( !is_webkit ) result = scroll_offset( 'Width' ) - viewport( 'Width' ) - result; // Now all have webkit behavior, i.e. zero if at the leftmost edge. } return result; } function position( node ) { // Stripped-down simplified position function. It's good enough for our purposes. if ( node.getBoundingClientRect ) { var box = node.getBoundingClientRect(); return { x: Math.round( box.left + scroll_offset( 'Left' ) ), y: Math.round( box.top + scroll_offset( 'Top' ) ) }; } var t = 0, l = 0; do { t += ( node.offsetTop || 0 ); l += ( node.offsetLeft || 0 ); node = node.offsetParent; } while ( node ); return { x: l, y: t }; } var textPos = position( this.text ), nl = 0, nt = 0, offset = 0, // Opera 9.5 somehow has offsetWidth = 0 here?? Use the next best value... textBoxWidth = this.text.offsetWidth || this.text.clientWidth; if ( this.engineName ) { this.engineSelector.style.zIndex = 5; this.engineSelector.style.position = 'absolute'; this.engineSelector.style.width = textBoxWidth + 'px'; // Figure out the height of this selector: display it off-screen, then hide it again. if ( this.engineSelector.style.display === 'none' ) { this.engineSelector.style[ anchor ] = '-10000px'; this.engineSelector.style.top = '0'; this.engineSelector.style.display = ''; offset = this.engineSelector.offsetHeight; this.engineSelector.style.display = 'none'; } else { offset = this.engineSelector.offsetHeight; } this.engineSelector.style[ anchor ] = nl + 'px'; } if ( textPos.y < maxListHeight + offset + 1 ) { // The list might extend beyond the upper border of the page. Let's avoid that by placing it // below the input text field. nt = this.text.offsetHeight + offset + 1; if ( this.engineName ) this.engineSelector.style.top = this.text.offsetHeight + 'px'; } else { nt = -listh - offset - 1; if ( this.engineName ) this.engineSelector.style.top = -( offset + 1 ) + 'px'; } this.list.style.top = nt + 'px'; this.list.style.width = ''; // No fixed width (yet) this.list.style[ anchor ] = nl + 'px'; if ( this.engineName ) { this.selectEngine( this.engineName ); this.engineSelector.style.display = ''; } this.list.style.display = 'block'; // Set the width of the list if ( this.list.offsetWidth < textBoxWidth ) { this.list.style.width = textBoxWidth + 'px'; return; } // If the list is wider than the textbox: make sure it fits horizontally into the browser window var scroll = scroll_offset( 'Left' ); var view_w = viewport( 'Width' ); var w = this.list.offsetWidth; var l_pos = position( this.list ); var left = l_pos.x; var right = left + w; if ( left < scroll || right > scroll + view_w ) { if ( w > view_w ) { w = view_w; this.list.style.width = w + 'px'; if ( is_rtl ) left = right - w; else right = left + w; } var relative_offset = 0; if ( left < scroll ) relative_offset = scroll - left; else if ( right > scroll + view_w ) relative_offset = -( right - scroll - view_w ); if ( is_rtl ) relative_offset = -relative_offset; if ( relative_offset ) this.list.style[ anchor ] = ( nl + relative_offset ) + 'px'; } }, autoComplete: function ( newVal, actVal, normalizedActVal, key, dontModify ) { if ( newVal === actVal ) return true; if ( dontModify || this.ime || !this.canSelect() ) return false; // If we can't select properly or an IME composition is ongoing, autocompletion would be a major annoyance to the user. if ( newVal.indexOf( actVal ) ) { // Maybe it'll work with the normalized value (NFC)? if ( normalizedActVal && newVal.indexOf( normalizedActVal ) === 0 ) { if ( this.lastRealInput === actVal ) this.lastRealInput = normalizedActVal; actVal = normalizedActVal; } else { return false; } } // Actual input is a prefix of the new text. Fill in new text, selecting the newly added suffix // such that it can be easily removed by typing backspace if the suggestion is unwanted. this.text.focus(); this.text.value = newVal + key; this.setSelection( actVal.length, newVal.length ); return true; }, canSelect: function () { return this.text.setSelectionRange || this.text.createTextRange || this.text.selectionStart !== undefined && this.text.selectionEnd !== undefined; }, setSelection: function ( from, to ) { // this.text must be focused (at least on IE) if ( !this.text.value ) return; if ( this.text.setSelectionRange ) { // e.g. khtml this.text.setSelectionRange( from, to ); } else if ( this.text.selectionStart !== undefined ) { if ( from > this.text.selectionStart ) { this.text.selectionEnd = to; this.text.selectionStart = from; } else { this.text.selectionStart = from; this.text.selectionEnd = to; } } else if ( this.text.createTextRange ) { // IE var new_selection = this.text.createTextRange(); new_selection.move( 'character', from ); new_selection.moveEnd( 'character', to - from ); new_selection.select(); } }, getSelection: function () { var from = 0, to = 0; // this.text must be focused (at least on IE) if ( !this.text.value ) { // No text. } else if ( this.text.selectionStart !== undefined ) { from = this.text.selectionStart; to = this.text.selectionEnd; } else if ( document.selection && document.selection.createRange ) { // IE var rng = document.selection.createRange().duplicate(); if ( rng.parentElement() === this.text ) { try { var textRng = this.text.createTextRange(); textRng.move( 'character', 0 ); textRng.setEndPoint( 'EndToEnd', rng ); // We're in a single-line input box: no need to care about IE's strange // handling of line ends to = textRng.text.length; textRng.setEndPoint( 'EndToStart', rng ); from = textRng.text.length; } catch ( notFocused ) { from = this.text.value.length; to = from; // At end of text } } } return { start: from, end: to }; }, saveView: function () { this.lastSelection = this.getSelection(); }, processKey: function ( evt ) { var dir = 0; switch ( this.lastKey ) { case UP: dir = -1; break; case DOWN: dir = 1; break; case PGUP: dir = -HC.listSize; break; case PGDOWN: dir = HC.listSize; break; case ESC: // Inhibit default behavior (revert to last real input in FF: we do that ourselves) return evtKill( evt ); } if ( dir ) { if ( this.list.style.display !== 'none' ) { // List is visible, so there are suggestions this.highlightSuggestion( dir ); // Kill the event, otherwise some browsers (e.g., Firefox) may additionally treat an up-arrow // as "place the text cursor at the front", which we don't want here. return evtKill( evt ); } else if ( this.keyCount <= 1 && ( !this.callbackObj || this.callbackObj.callsMade === this.callbackObj.nofCalls ) ) { // If no suggestions displayed, get them, unless we're already getting them. this.textchange(); } } return true; }, highlightSuggestion: function ( dir ) { if ( noSuggestions || !this.list || this.list.style.display === 'none' ) return false; var curr = this.list.selectedIndex; var tgt = -1; if ( dir === 0 ) { if ( curr < 0 || curr >= this.list.options.length ) return false; tgt = curr; } else { tgt = curr < 0 ? 0 : curr + dir; tgt = tgt < 0 ? 0 : tgt; if ( tgt >= this.list.options.length ) tgt = this.list.options.length - 1; } if ( tgt !== curr || dir === 0 ) { if ( curr >= 0 && curr < this.list.options.length && dir !== 0 ) this.list.options[ curr ].selected = false; this.list.options[ tgt ].selected = true; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; var completed = this.autoComplete( this.list.options[ tgt ].text, this.lastRealInput, null, key, false ); if ( !completed || this.list.options[ tgt ].text === this.lastRealInput ) { this.text.value = this.list.options[ tgt ].text + key; if ( this.canSelect() ) this.setSelection( this.list.options[ tgt ].text.length, this.list.options[ tgt ].text.length ); } this.lastInput = this.list.options[ tgt ].text; this.inputExists = true; // Might be wrong if from a dab list... if ( this.icon ) this.icon.src = HC.existsYes; this.state = CategoryEditor.CHANGE_PENDING; } return true; }, resetKeySelection: function () { if ( noSuggestions || !this.list || this.list.style.display === 'none' ) return false; var curr = this.list.selectedIndex; if ( curr >= 0 && curr < this.list.options.length ) { this.list.options[ curr ].selected = false; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; // ESC is handled strangely by some browsers (e.g., FF); somehow it resets the input value before // our event handlers ever get a chance to run. var result = v[ 0 ] !== this.lastInput; if ( v[ 0 ] !== this.lastRealInput ) { this.text.value = this.lastRealInput + key; result = true; } this.lastInput = this.lastRealInput; return result; } return false; } }; // end CategoryEditor.prototype function initialize() { // User configurations: Do this here, called from the onload handler, so that users can // override it easily in their own user script files by just declaring variables. JSconfig // is some feature used at Wikimedia Commons. var config = ( window.JSconfig !== undefined && JSconfig.keys ) ? JSconfig.keys : {}; HC.dont_add_to_watchlist = ( window.hotcat_dont_add_to_watchlist !== undefined ? !!window.hotcat_dont_add_to_watchlist : ( config.HotCatDontAddToWatchlist !== undefined ? config.HotCatDontAddToWatchlist : HC.dont_add_to_watchlist ) ); HC.no_autocommit = ( window.hotcat_no_autocommit !== undefined ? !!window.hotcat_no_autocommit : ( config.HotCatNoAutoCommit !== undefined ? config.HotCatNoAutoCommit : // On talk namespace default autocommit off ( conf.wgNamespaceNumber % 2 ? true : HC.no_autocommit ) ) ); HC.del_needs_diff = ( window.hotcat_del_needs_diff !== undefined ? !!window.hotcat_del_needs_diff : ( config.HotCatDelNeedsDiff !== undefined ? config.HotCatDelNeedsDiff : HC.del_needs_diff ) ); HC.suggest_delay = window.hotcat_suggestion_delay || config.HotCatSuggestionDelay || HC.suggest_delay; HC.editbox_width = window.hotcat_editbox_width || config.HotCatEditBoxWidth || HC.editbox_width; HC.suggestions = window.hotcat_suggestions || config.HotCatSuggestions || HC.suggestions; if ( typeof HC.suggestions !== 'string' || !suggestionConfigs[ HC.suggestions ] ) HC.suggestions = 'combined'; HC.fixed_search = ( window.hotcat_suggestions_fixed !== undefined ? !!window.hotcat_suggestions_fixed : ( config.HotCatFixedSuggestions !== undefined ? config.HotCatFixedSuggestions : HC.fixed_search ) ); HC.single_minor = ( window.hotcat_single_changes_are_minor !== undefined ? !!window.hotcat_single_changes_are_minor : ( config.HotCatMinorSingleChanges !== undefined ? config.HotCatMinorSingleChanges : HC.single_minor ) ); HC.bg_changed = window.hotcat_changed_background || config.HotCatChangedBackground || HC.bg_changed; HC.use_up_down = ( window.hotcat_use_category_links !== undefined ? !!window.hotcat_use_category_links : ( config.HotCatUseCategoryLinks !== undefined ? config.HotCatUseCategoryLinks : HC.use_up_down ) ); HC.listSize = window.hotcat_list_size || config.HotCatListSize || HC.listSize; if ( conf.wgDBname !== 'commonswiki' ) HC.changeTag = config.HotCatChangeTag || ''; // The next whole shebang is needed, because manual tags get not submitted except of save if ( HC.changeTag ) { var eForm = document.editform, catRegExp = new RegExp( '^\\[\\[(' + HC.category_regexp + '):' ), oldTxt; // Returns true if minor change var isMinorChange = function () { var newTxt = eForm.wpTextbox1; if ( !newTxt ) return; newTxt = newTxt.value; var oldLines = oldTxt.match( /^.*$/gm ), newLines = newTxt.match( /^.*$/gm ), cArr; // changes var except = function ( aArr, bArr ) { var result = [], lArr, // larger sArr; // smaller if ( aArr.length < bArr.length ) { lArr = bArr; sArr = aArr; } else { lArr = aArr; sArr = bArr; } for ( var i = 0; i < lArr.length; i++ ) { var item = lArr[ i ]; var ind = $.inArray( item, sArr ); if ( ind === -1 ) result.push( item ); else sArr.splice( ind, 1 ); // don't check this item again } return result.concat( sArr ); }; cArr = except( oldLines, newLines ); if ( cArr.length ) { cArr = $.grep( cArr, function ( c ) { c = $.trim( c ); return ( c && !catRegExp.test( c ) ); } ); } if ( !cArr.length ) { oldTxt = newTxt; return true; } }; if ( conf.wgAction === 'submit' && conf.wgArticleId && eForm && eForm.wpSummary && document.getElementById( 'wikiDiff' ) ) { var sum = eForm.wpSummary, sumA = eForm.wpAutoSummary; if ( sum.value && sumA.value === HC.changeTag ) { // HotCat diff // MD5 hash of the empty string, as HotCat edit is based on empty sum sumA.value = sumA.value.replace( HC.changeTag, 'd41d8cd98f00b204e9800998ecf8427e' ); // Attr creation and event handling is not same in all (old) browsers so use $ var $ct = $( '<input type="hidden" name="wpChangeTags">' ).val( HC.changeTag ); $( eForm ).append( $ct ); oldTxt = eForm.wpTextbox1.value; $( '#wpSave' ).one( 'click', function () { if ( $ct.val() ) sum.value = sum.value.replace( ( HC.messages.using || HC.messages.prefix ), '' ); } ); var removeChangeTag = function () { $( eForm.wpTextbox1 ).add( sum ).one( 'input', function () { window.setTimeout( function () { if ( !isMinorChange() ) $ct.val( '' ); else removeChangeTag(); }, 500 ); } ); }; removeChangeTag(); } } } // Numeric input, make sure we have a numeric value HC.listSize = parseInt( HC.listSize, 10 ); if ( isNaN( HC.listSize ) || HC.listSize < 5 ) HC.listSize = 5; HC.listSize = Math.min( HC.listSize, 30 ); // Max size // Localize search engine names if ( HC.engine_names ) { for ( var key in HC.engine_names ) if ( suggestionConfigs[ key ] && HC.engine_names[ key ] ) suggestionConfigs[ key ].name = HC.engine_names[ key ]; } // Catch both native RTL and "faked" RTL through [[MediaWiki:Rtl.js]] is_rtl = hasClass( document.body, 'rtl' ); if ( !is_rtl ) { if ( document.defaultView && document.defaultView.getComputedStyle ) { // Gecko etc. is_rtl = document.defaultView.getComputedStyle( document.body, null ).getPropertyValue( 'direction' ); } else if ( document.body.currentStyle ) { // IE, has subtle differences to getComputedStyle is_rtl = document.body.currentStyle.direction; } else { // Not exactly right, but best effort is_rtl = document.body.style.direction; } is_rtl = ( is_rtl === 'rtl' ); } } function can_edit() { var container = null; switch ( mw.config.get( 'skin' ) ) { case 'cologneblue': container = document.getElementById( 'quickbar' ); /* fall through */ case 'standard': case 'nostalgia': if ( !container ) container = document.getElementById( 'topbar' ); var lks = container.getElementsByTagName( 'a' ); for ( var i = 0; i < lks.length; i++ ) { if ( param( 'title', lks[ i ].href ) === conf.wgPageName && param( 'action', lks[ i ].href ) === 'edit' ) { return true; } } return false; default: // all modern skins: return document.getElementById( 'ca-edit' ) !== null; } } // Legacy stuff function closeForm() { // Close all open editors without redirect resolution and other asynchronous stuff. for ( var i = 0; i < editors.length; i++ ) { var edit = editors[ i ]; if ( edit.state === CategoryEditor.OPEN ) { edit.cancel(); } else if ( edit.state === CategoryEditor.CHANGE_PENDING ) { edit.sanitizeInput(); var value = edit.text.value.split( '|' ); var key = null; if ( value.length > 1 ) key = value[ 1 ]; var v = value[ 0 ].replace( /_/g, ' ' ).replace( /^\s+|\s+$/g, '' ); if ( !v.length ) { edit.cancel(); } else { edit.currentCategory = v; edit.currentKey = key; edit.currentExists = this.inputExists; edit.close(); } } } } function setup_upload() { onUpload = true; // Add an empty category bar at the end of the table containing the description, and change the onsubmit handler. var ip = document.getElementById( 'mw-htmlform-description' ) || document.getElementById( 'wpDestFile' ); if ( !ip ) { ip = document.getElementById( 'wpDestFile' ); while ( ip && ip.nodeName.toLowerCase() !== 'table' ) ip = ip.parentNode; } if ( !ip ) return; var reupload = document.getElementById( 'wpForReUpload' ); var destFile = document.getElementById( 'wpDestFile' ); if ( ( reupload && !!reupload.value ) || ( destFile && ( destFile.disabled || destFile.readOnly ) ) ) { return; // re-upload form... } // Insert a table row with two fields (label and empty category bar) var labelCell = make( 'td' ); var lineCell = make( 'td' ); // Create the category line catLine = make( 'div' ); catLine.className = 'catlinks'; catLine.id = 'catlinks'; catLine.style.textAlign = is_rtl ? 'right' : 'left'; // We'll be inside a table row. Make sure that we don't have margins or strange borders. catLine.style.margin = '0'; catLine.style.border = 'none'; lineCell.appendChild( catLine ); // Create the label var label = null; if ( window.UFUI && window.UIElements && UFUI.getLabel instanceof Function ) { try { label = UFUI.getLabel( 'wpCategoriesUploadLbl' ); } catch ( ex ) { label = null; } } if ( !label ) { labelCell.id = 'hotcatLabel'; labelCell.appendChild( make( HC.categories, true ) ); } else { labelCell.id = 'hotcatLabelTranslated'; labelCell.appendChild( label ); } labelCell.className = 'mw-label'; labelCell.style.textAlign = 'right'; labelCell.style.verticalAlign = 'middle'; // Change the onsubmit handler var form = document.getElementById( 'upload' ) || document.getElementById( 'mw-upload-form' ); if ( form && ip && ip.insertRow ) { var newRow = ip.insertRow( -1 ); newRow.appendChild( labelCell ); newRow.appendChild( lineCell ); form.onsubmit = ( function ( oldSubmit ) { return function () { var do_submit = true; if ( oldSubmit ) { if ( typeof oldSubmit === 'string' ) { // eslint-disable-next-line no-eval do_submit = eval( oldSubmit ); } else if ( oldSubmit instanceof Function ) { do_submit = oldSubmit.apply( form, arguments ); } } if ( !do_submit ) return false; closeForm(); // Copy the categories var eb = document.getElementById( 'wpUploadDescription' ) || document.getElementById( 'wpDesc' ); var addedOne = false; for ( var i = 0; i < editors.length; i++ ) { var t = editors[ i ].currentCategory; if ( !t ) continue; var key = editors[ i ].currentKey; var new_cat = '[[' + HC.category_canonical + ':' + t + ( key ? '|' + key : '' ) + ']]'; // Only add if not already present var cleanedText = eb.value .replace( /<!--(\s|\S)*?-->/g, '' ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, '' ); if ( !find_category( cleanedText, t, true ) ) { eb.value += '\n' + new_cat; addedOne = true; } } if ( addedOne ) { // Remove "subst:unc" added by Flinfo if it didn't find categories eb.value = eb.value.replace( /\{\{subst:unc\}\}/g, '' ); } return true; }; }( form.onsubmit ) ); } } var cleanedText = null; function isOnPage( span ) { if ( span.firstChild.nodeType !== Node.ELEMENT_NODE ) return null; var catTitle = title( span.firstChild.getAttribute( 'href' ) ); if ( !catTitle ) return null; catTitle = catTitle.substr( catTitle.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); if ( HC.blacklist && HC.blacklist.test( catTitle ) ) return null; var result = { title: catTitle, match: [ '', '', '' ] }; if ( pageText === null ) return result; if ( cleanedText === null ) { cleanedText = pageText .replace( /<!--(\s|\S)*?-->/g, '' ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, '' ); } result.match = find_category( cleanedText, catTitle, true ); return result; } var initialized = false; var setupTimeout = null; function findByClass( scope, tag, className ) { var result = $( scope ).find( tag + '.' + className ); return ( result && result.length ) ? result[ 0 ] : null; } function errorAMC() { alert( 'An error occurred. Unable to setup HotCat' ); } function enableAMC() { var api = new mw.Api(); return api.saveOption( 'mf_amc_optin', '1' ).then( function ( r ) { if ( !r || r.options !== 'success' ) { errorAMC(); return; } if ( window.confirm( 'Please reload your page to use hotcat.' ) ) { location.reload(); } }, function () { errorAMC(); } ); } function showWarning( text ) { var warning = document.createElement( 'div' ); warning.setAttribute( 'style', 'padding: 20px; background: var(--wikt-palette-amber-0,orange); color: var(--wikt-palette-black,#333); font-weight: bold; margin-top: 20px;' ); warning.textContent = text; var btn = document.createElement( 'button' ); btn.classList.add( 'mw-ui-button', 'cdx-button' ); btn.style.display = 'block'; btn.textContent = 'Enable HotCat and AMC mode on this page'; btn.addEventListener( 'click', function () { enableAMC(); } ); warning.appendChild( btn ); document.getElementById( 'mw-content-text' ).appendChild( warning ); } function setup( additionalWork ) { if ( initialized ) return; initialized = true; if ( setupTimeout ) { window.clearTimeout( setupTimeout ); setupTimeout = null; } // Find the category bar, or create an empty one if there isn't one. Then add -/+- links after // each category, and add the + link. catLine = // Special:Upload catLine || document.getElementById( 'mw-normal-catlinks' ); var hiddenCats = document.getElementById( 'mw-hidden-catlinks' ); if ( !catLine ) { // Workaround for T24660 if ( mw.config.get('skin') === 'minerva' ) { if ( document.body.classList.contains('mw-mf-amc-disabled') ) { showWarning( 'HotCat requires AMC mode.' ); } } var footer = null; if ( !hiddenCats ) { footer = findByClass( document, 'div', 'printfooter' ); if ( !footer ) return; // Don't know where to insert the category line } catLine = make( 'div' ); catLine.id = 'mw-normal-catlinks'; catLine.style.textAlign = is_rtl ? 'right' : 'left'; // Add a label var label = make( 'a' ); label.href = conf.wgArticlePath.replace( '$1', 'Special:Categories' ); label.title = HC.categories; label.appendChild( make( HC.categories, true ) ); catLine.appendChild( label ); catLine.appendChild( make( ':', true ) ); // Insert the new category line var container = ( hiddenCats ? hiddenCats.parentNode : document.getElementById( 'catlinks' ) ); if ( !container ) { container = make( 'div' ); container.id = 'catlinks'; footer.parentNode.insertBefore( container, footer.nextSibling ); } container.className = 'catlinks noprint'; container.style.display = ''; if ( !hiddenCats ) container.appendChild( catLine ); else container.insertBefore( catLine, hiddenCats ); } // end if catLine exists if ( is_rtl ) catLine.dir = 'rtl'; // Create editors for all existing categories function createEditors( line, is_hidden ) { var i; var cats = line.getElementsByTagName( 'li' ); if ( cats.length ) { newDOM = true; line = cats[ 0 ].parentNode; } else { cats = line.getElementsByTagName( 'span' ); } // Copy cats, otherwise it'll also magically contain our added spans as it is a live collection! var copyCats = new Array( cats.length ); for ( i = 0; i < cats.length; i++ ) copyCats[ i ] = cats[ i ]; for ( i = 0; i < copyCats.length; i++ ) { var test = isOnPage( copyCats[ i ] ); if ( test !== null && test.match !== null && line ) { // eslint-disable-next-line no-new new CategoryEditor( line, copyCats[ i ], test.title, test.match[ 2 ], is_hidden ); } } return copyCats.length ? copyCats[ copyCats.length - 1 ] : null; } var lastSpan = createEditors( catLine, false ); // Create one to add a new category // eslint-disable-next-line no-new new CategoryEditor( newDOM ? catLine.getElementsByTagName( 'ul' )[ 0 ] : catLine, null, null, lastSpan !== null, false ); if ( !onUpload ) { if ( pageText !== null && hiddenCats ) { if ( is_rtl ) hiddenCats.dir = 'rtl'; createEditors( hiddenCats, true ); } // And finally add the "multi-mode" span. (Do this at the end, otherwise it ends up in the list above.) var enableMulti = make( 'span' ); enableMulti.className = 'noprint'; if ( is_rtl ) enableMulti.dir = 'rtl'; catLine.insertBefore( enableMulti, catLine.firstChild.nextSibling ); enableMulti.appendChild( make( '\xa0', true ) ); // nbsp multiSpan = make( 'span' ); enableMulti.appendChild( multiSpan ); multiSpan.innerHTML = '(<a>' + HC.addmulti + '</a>)'; var lk = multiSpan.getElementsByTagName( 'a' )[ 0 ]; lk.onclick = function ( evt ) { setMultiInput(); checkMultiInput(); return evtKill( evt ); }; lk.title = HC.multi_tooltip; lk.style.cursor = 'pointer'; } cleanedText = null; if ( additionalWork instanceof Function ) additionalWork(); mw.hook( 'hotcat.ready' ).fire(); // Execute registered callback functions $( 'body' ).trigger( 'hotcatSetupCompleted' ); } function createCommitForm() { if ( commitForm ) return; var formContainer = make( 'div' ); formContainer.style.display = 'none'; document.body.appendChild( formContainer ); formContainer.innerHTML = '<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="' + conf.wgScript + '?title=' + encodeURIComponent( conf.wgPageName ) + '&action=submit">' + '<input type="hidden" name="wpTextbox1">' + '<input type="hidden" name="model" value="' + conf.wgPageContentModel + '">' + '<input type="hidden" name="format" value="text/x-wiki">' + '<input type="hidden" name="wpSummary" value="">' + '<input type="checkbox" name="wpMinoredit" value="1">' + '<input type="checkbox" name="wpWatchthis" value="1">' + '<input type="hidden" name="wpAutoSummary" value="d41d8cd98f00b204e9800998ecf8427e">' + '<input type="hidden" name="wpEdittime">' + '<input type="hidden" name="wpStarttime">' + '<input type="hidden" name="wpDiff" value="wpDiff">' + '<input type="hidden" name="oldid" value="0">' + '<input type="hidden" name="wpIgnoreBlankSummary" value="1">' + '<input type="submit" name="hcCommit" value="hcCommit">' + '<input type="hidden" name="wpEditToken">' + '<input type="hidden" name="wpUltimateParam" value="1">' + '<input type="hidden" name="wpChangeTags">' + '<input type="hidden" value="ℳ𝒲♥𝓊𝓃𝒾𝒸ℴ𝒹ℯ" name="wpUnicodeCheck">' + '</form>'; commitForm = document.getElementById( 'hotcatCommitForm' ); } function getPage() { // We know we have an article here. if ( !conf.wgArticleId ) { // Doesn't exist yet. Disable on non-existing User pages -- might be a global user page. if ( conf.wgNamespaceNumber === 2 ) return; pageText = ''; pageTime = null; setup( createCommitForm ); } else { var url = wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&rawcontinue=&titles=' + encodeURIComponent( conf.wgPageName ) + '&prop=info%7Crevisions&rvprop=content%7Ctimestamp%7Cids&meta=siteinfo&rvlimit=1&rvstartid=' + conf.wgCurRevisionId; var s = make( 'script' ); s.src = url; HC.start = function ( json ) { setPage( json ); setup( createCommitForm ); }; document.getElementsByTagName( 'head' )[ 0 ].appendChild( s ); setupTimeout = window.setTimeout( function () { setup( createCommitForm ); }, 4000 ); // 4 sec, just in case getting the wikitext takes longer. } } function setState( state ) { var cats = state.split( '\n' ); if ( !cats.length ) return null; if ( initialized && editors.length === 1 && editors[ 0 ].isAddCategory ) { // Insert new spans and create new editors for them. var newSpans = []; var before = editors.length === 1 ? editors[ 0 ].span : null; var i; for ( i = 0; i < cats.length; i++ ) { if ( !cats[ i ].length ) continue; var cat = cats[ i ].split( '|' ); var key = cat.length > 1 ? cat[ 1 ] : null; cat = cat[ 0 ]; var lk = make( 'a' ); lk.href = wikiPagePath( HC.category_canonical + ':' + cat ); lk.appendChild( make( cat, true ) ); lk.title = cat; var span = make( 'span' ); span.appendChild( lk ); if ( !i ) catLine.insertBefore( make( ' ', true ), before ); catLine.insertBefore( span, before ); if ( before && i + 1 < cats.length ) parent.insertBefore( make( ' | ', true ), before ); newSpans.push( { element: span, title: cat, key: key } ); } // And change the last one... if ( before ) before.parentNode.insertBefore( make( ' | ', true ), before ); for ( i = 0; i < newSpans.length; i++ ) { // eslint-disable-next-line no-new new CategoryEditor( catLine, newSpans[ i ].element, newSpans[ i ].title, newSpans[ i ].key ); } } return null; } function getState() { var result = null; for ( var i = 0; i < editors.length; i++ ) { var text = editors[ i ].currentCategory; var key = editors[ i ].currentKey; if ( text && text.length ) { if ( key !== null ) text += '|' + key; if ( result === null ) result = text; else result += '\n' + text; } } return result; } function really_run() { en_wiktionary_get_langdata(function() { initialize(); if ( !HC.upload_disabled && conf.wgNamespaceNumber === -1 && conf.wgCanonicalSpecialPageName === 'Upload' && conf.wgUserName ) { setup_upload(); setup( function () { // Check for state restoration once the setup is done otherwise, but before signalling setup completion if ( window.UploadForm && UploadForm.previous_hotcat_state ) UploadForm.previous_hotcat_state = setState( UploadForm.previous_hotcat_state ); } ); } else { if ( !conf.wgIsArticle || conf.wgAction !== 'view' || param( 'diff' ) !== null || param( 'oldid' ) !== null || !can_edit() || HC.disable() ) return; getPage(); } }); } function run() { if ( HC.started ) return; HC.started = true; loadTrigger.register( really_run ); } // Export legacy functions window.hotcat_get_state = function () { return getState(); }; window.hotcat_set_state = function ( state ) { return setState( state ); }; window.hotcat_close_form = function () { closeForm(); }; HC.runWhenReady = function ( callback ) { // run user-registered code once HotCat is fully set up and ready. mw.hook( 'hotcat.ready' ).add( callback ); }; // Make sure we don't get conflicts with AjaxCategories (core development that should one day // replace HotCat). mw.config.set( 'disableAJAXCategories', true ); // Run as soon as possible. This varies depending on MediaWiki version; // window's 'load' event is always safe, but usually we can do better than that. if ( conf.wgCanonicalSpecialPageName !== 'Upload' ) { // Reload HotCat after (VE) edits (bug T103285) mw.hook( 'postEdit' ).add( function () { // Reset HotCat in case this is a soft reload (e.g. VisualEditor edit), unless the categories // were not re-rendered and our interface is still there (e.g. DiscussionTools edit) if ( document.querySelector( '#catlinks .hotcatlink' ) ) { return; } catLine = null; editors = []; initialized = false; HC.started = false; run(); } ); } // We can safely trigger just after user configuration is loaded. // Use always() instead of then() to also start HotCat if the user module has problems. $.when( mw.loader.using( 'user' ), $.ready ).always( run ); }( jQuery, mediaWiki ) ); // </nowiki> qp2yp9147ad7pkve4h3sqrco2yhn5th 89010 89009 2026-08-06T23:33:24Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-HotCat.js]] 89009 javascript text/javascript // {{documentation}} // See also: MediaWiki:Gadget-HotCat.js/local defaults //window.hotcat_translations_from_commons = true; // Make HotCat load its interface from the Commons (the default setting so no need to set it here) /** HotCat V2.43 en.wiktionary fork (with better support for en.wiktionary templates) upstream: https://commons.wikimedia.org/w/index.php?title=MediaWiki:Gadget-HotCat.js&oldid=818790002 The original script is hosted at [https://commons.wikimedia.org/wiki/MediaWiki:Gadget-HotCat.js]. See it for more information. License: Quadruple licensed, any of the following: GFDL GPL LGPL Creative Commons Attribution 3.0 (CC-BY-3.0) Requires MediaWiki >= MW 1.27. */ // <nowiki> /* eslint-disable vars-on-top, one-var, camelcase, no-alert, curly */ /* global jQuery, mediaWiki, UFUI, JSconfig, UploadForm */ /* jslint strict:false, nonew:false, bitwise:true */ ( function ( $, mw ) { // BEGINNING OF en.wiktionary EXTRA CODE var EN_WIKTIONARY_CONTENT_NAMESPACE = [0, 100, 118].indexOf(mw.config.get("wgNamespaceNumber")) >= 0; var EN_WIKTIONARY_TOPICS = ["C", "c", "topics", "top", "topic", "catlangcode"]; var EN_WIKTIONARY_CATLANGNAME = ["cln", "catlangname", "Cln"]; var EN_WIKTIONARY_CATEGORIZE = ["categorize", "cat"]; var EN_WIKTIONARY_PREFER_TOPICS_FOR_NEW_ADDITIONS = true; var EN_WIKTIONARY_PREFER_CATLANGNAME_FOR_NEW_ADDITIONS = true; function regexpEscape(string) { return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } function cleanUpText(wikitext) { return wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); } function en_wiktionary_find_category_allMatches(regexp, wikitext, data_key, data) { var copiedtext = cleanUpText(wikitext); var result = []; var curr_match = null; while ((curr_match = regexp.exec(copiedtext)) !== null) { var obj = { match: curr_match }; obj[data_key] = data; result.push(obj); } result.re = regexp; return result.length ? result : null; } function en_wiktionary_codeToCanonicalName(callback) { $.get({ "url": mw.util.wikiScript('index'), "data": { "action": "raw", "title": "Module:languages/code to canonical name.json" }, "cache": true }).then(function(r) { var parsedData; try { parsedData = JSON.parse(r); callback({ ok: true, data: parsedData }); } catch (e) { console.error(e); callback({ ok: false }); } }); } function en_wiktionary_populate_langdata(data) { data.langnames = []; data.name_to_code = {}; for (var key in data.code_to_name) { if (data.code_to_name.hasOwnProperty(key)) { var value = data.code_to_name[key]; data.langnames.push(value); data.name_to_code[value] = key; } } var escaped = data.langnames.map(regexpEscape); // sort from longest to shortest to ensure greedy alternation escaped.sort(function (a, b) { return b.length - a.length; }); data.catlangnameRegexp = "^(" + escaped.join("|") + ") (.+)"; } var EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY = "HotCat-en-wiktionary-language-data"; function en_wiktionary_cache_langdata(callback) { if (!window.sessionStorage) { callback(); return; } if (window.sessionStorage.hasOwnProperty(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY)) { try { var timeNow = new Date().getTime(); var data = JSON.parse(window.sessionStorage.getItem(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY)); if (timeNow < data.expiry) { EN_WIKTIONARY_LANGDATA = data.data; EN_WIKTIONARY_LANGDATA_READY = true; EN_WIKTIONARY_LANGDATA.catlangnameRegexpCompiled = null; callback(); return; } } catch (e) { } } en_wiktionary_codeToCanonicalName(function (r) { if (r.ok) { EN_WIKTIONARY_LANGDATA = {}; EN_WIKTIONARY_LANGDATA.code_to_name = r.data; en_wiktionary_populate_langdata(EN_WIKTIONARY_LANGDATA); } EN_WIKTIONARY_LANGDATA_READY = true; if (window.sessionStorage) window.sessionStorage.setItem(EN_WIKTIONARY_LANGUAGE_DATA_STORAGE_KEY, JSON.stringify({ expiry: new Date().getTime() + 30 * 60 * 1000, // expire in 30 minutes data: EN_WIKTIONARY_LANGDATA })); callback(); }); } var EN_WIKTIONARY_LANGDATA = null; var EN_WIKTIONARY_LANGDATA_READY = false; var EN_WIKTIONARY_LANGDATA_LOCK = false; var EN_WIKTIONARY_LANGDATA_QUEUE = []; function en_wiktionary_get_langdata(callback) { if (EN_WIKTIONARY_LANGDATA_READY) { callback(); } else { if (!EN_WIKTIONARY_LANGDATA_LOCK) { EN_WIKTIONARY_LANGDATA_LOCK = true; en_wiktionary_cache_langdata(function() { callback(); EN_WIKTIONARY_LANGDATA_QUEUE.forEach(function(fn) { fn(); }); }); return; } EN_WIKTIONARY_LANGDATA_QUEUE.push(callback); } } function EN_WIKTIONARY_TOPICS_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_TOPICS.join("|") + ")\\s*\\|\\s*" + lang + "\\s*\\|" + (bar_required ? "" : "?"); } function EN_WIKTIONARY_CATLANGNAME_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_CATLANGNAME.join("|") + ")\\s*\\|\\s*" + lang + "\\s*\\|" + (bar_required ? "" : "?"); } function EN_WIKTIONARY_CATEGORIZE_START(lang, bar_required) { return "\\{\\{\\s*(?:" + EN_WIKTIONARY_CATEGORIZE.join("|") + ")\\s*\\|\\s*" + (lang == true ? "(" : "") + "[a-z0-9-]+" + (lang == true ? ")" : "") + "\\s*\\|" + (bar_required ? "" : "?"); } var EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS = "[^}]*"; var EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER = "?(?<=\\|)"; var EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER = "(?=\\s*[\|\}])"; var EN_WIKTIONARY_TEMPLATE_END = "\\}\\}"; var EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE = "\\s*\\}\\}\n?"; function en_wiktionary_category_name_detect(category) { var topicsMatch = category.match(/^([a-z-]+):(.+)$/); if (topicsMatch) { return { type: "topics", lang: topicsMatch[1], topic: topicsMatch[2] }; } if (EN_WIKTIONARY_LANGDATA) { var data = EN_WIKTIONARY_LANGDATA; if (!data.catlangnameRegexpCompiled) { data.catlangnameRegexpCompiled = new RegExp(data.catlangnameRegexp); } var catlangnameMatch = category.match(data.catlangnameRegexpCompiled); if (catlangnameMatch && data.name_to_code[catlangnameMatch[1]]) { return { type: "catlangname", lang: data.name_to_code[catlangnameMatch[1]], topic: catlangnameMatch[2] }; } } return null; } function en_wiktionary_find_category(wikitext, category, once) { if (!EN_WIKTIONARY_CONTENT_NAMESPACE) return null; var catname = en_wiktionary_category_name_detect(category); var data, matched; if (catname) { if (catname.type == "topics") { var topicTemplateRegex = new RegExp( EN_WIKTIONARY_TOPICS_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(catname.topic) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); data = { lang: catname.lang, name: catname.topic }; if (once) { matched = topicTemplateRegex.exec(wikitext); if (matched) { matched.enWiktTopics = data; } return matched; } return en_wiktionary_find_category_allMatches(topicTemplateRegex, wikitext, "enWiktTopics", data); } else if (catname.type == "catlangname") { var clnTemplateRegex = new RegExp( EN_WIKTIONARY_CATLANGNAME_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(catname.topic) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); data = { lang: catname.lang, name: catname.topic }; if (once) { matched = clnTemplateRegex.exec(wikitext); if (matched) { matched.enWiktCatlangname = data; } return matched; } return en_wiktionary_find_category_allMatches(clnTemplateRegex, wikitext, "enWiktCatlangname", data); } } var catTemplateRegex = new RegExp(EN_WIKTIONARY_CATEGORIZE_START(true, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(category) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END, "g"); var catTemplateMatches = wikitext.match(catTemplateRegex); if (catTemplateMatches) { data = { lang: catTemplateMatches[1], name: category }; if (once) { if (catTemplateMatches) { catTemplateMatches.enWiktCategorize = data; } return catTemplateMatches; } catTemplateRegex.lastIndex = 0; return en_wiktionary_find_category_allMatches(catTemplateRegex, wikitext, "enWiktCategorize", data); } return null; } function en_wiktionary_is_special_match(match) { return !!(match.enWiktTopics || match.enWiktCatlangname || match.enWiktCategorize); } function en_wiktionary_three_to_two_split(wikitext, match) { var before, after, data, removeTopic; if (match.enWiktTopics) { // {{topics}}? data = match.enWiktTopics; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var topicTemplateRegex = new RegExp( EN_WIKTIONARY_TOPICS_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{topics}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_TOPICS_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(topicTemplateRegex, removeTopic)]; } else if (match.enWiktCatlangname) { // {{cln}}? data = match.enWiktCatlangname; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var clnTemplateRegex = new RegExp( EN_WIKTIONARY_CATLANGNAME_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{cln}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_CATLANGNAME_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(clnTemplateRegex, removeTopic)]; } else if (match.enWiktCategorize) { // {{cat}}? data = match.enWiktCategorize; before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index); var catTemplateRegex = new RegExp( EN_WIKTIONARY_CATEGORIZE_START(data.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_START_OF_PARAMETER + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + EN_WIKTIONARY_TEMPLATE_END + "\\s*?\n?"); removeTopic = function(inner) { // remove parameter from {{cln}} var remaining = inner.replace(new RegExp("\\|" + regexpEscape(data.name) + EN_WIKTIONARY_TEMPLATE_END_OF_PARAMETER), ""); // if it is now empty, remove it remaining = remaining.replace(new RegExp( EN_WIKTIONARY_CATEGORIZE_START(data.lang, false) + EN_WIKTIONARY_TEMPLATE_END_WITH_WHITESPACE), ""); return remaining; }; return [before, after.replace(catTemplateRegex, removeTopic)]; } before = wikitext.substring(0, match.match.index); after = wikitext.substring(match.match.index + match.match[0].length); return [before, after]; } function en_wiktionary_remove_category(wikitext, match) { var before_after = en_wiktionary_three_to_two_split(wikitext, match); return before_after[0] + before_after[1]; } function en_wiktionary_find_insertionpoint(wikitext, category) { var catname = en_wiktionary_category_name_detect(category); if (catname) { if (catname.lang) { var langname = catname.langname || (EN_WIKTIONARY_LANGDATA ? EN_WIKTIONARY_LANGDATA.code_to_name[catname.lang] : null); if (langname) { // try to put category under the language L2 var l2_heading_this = "^==\\s*" + regexpEscape(langname) + "\\s*==$"; var end_of_l2 = "\\n*(?:^----$)?\\n*^==(?!=)\\s*.*\\s*==$"; var clean_wikitext = cleanUpText(wikitext); var finalRegexp = "(" + l2_heading_this + "[\\s\\S]+?)" + end_of_l2; var match = new RegExp(finalRegexp, "m").exec(clean_wikitext); if (match) { var rawPoint = match.index + match[1].length; var noPreLine = false; if (wikitext.substring(rawPoint - 2, rawPoint) == "]]") { return { idx: rawPoint, onCat: true }; } var cookedPoint = rawPoint; if (wikitext.substring(cookedPoint - 3, cookedPoint) == "}}\n") { // if the preceding line has a topics/cln template, add noPreLine var i = cookedPoint - 2; while (i >= 0 && wikitext[i] !== '\n') { i--; } i += 2; var previousLine = wikitext.substring(i, cookedPoint - 1); if (previousLine.match(new RegExp("^\\{\\{(?:" + EN_WIKTIONARY_TOPICS.join("|") + "|" + EN_WIKTIONARY_CATLANGNAME.join("|") + ")\\|"))) { noPreLine = true; } } // hotfix: fix newline placement if (!noPreLine && wikitext.charAt(cookedPoint - 1) != "\n" && wikitext.substring(cookedPoint, cookedPoint + 2) == "\n\n") { ++cookedPoint; } return { idx: cookedPoint, onCat: false, noPreLine: noPreLine }; } else { var l2match = new RegExp(l2_heading_this, "m").exec(clean_wikitext); if (l2match) { // assuming there are no more L2s... var l2_regex = new RegExp("^==(?!=)\\s*.*\\s*==$", "gm"); l2_regex.lastIndex = l2match.index + l2match[0].length; var l2nextmatch = l2_regex.exec(clean_wikitext); if (!l2nextmatch) { // no more L2s return { idx: -1, onCat: false }; } } } } } } return null; // fallback } function en_wiktionary_add_category_hook(wikitext, category, cat_point) { var catname = en_wiktionary_category_name_detect(category); if (catname) { var match, splitPoint; if (catname.type == "topics") { // try to find the first language template that matches and // add the category there var topicTemplateRegex = new RegExp("(?:^|(?<=\\n))(" + EN_WIKTIONARY_TOPICS_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + ")" + EN_WIKTIONARY_TEMPLATE_END); match = topicTemplateRegex.exec(cleanUpText(wikitext)); if (match) { splitPoint = match.index + match[1].length; return wikitext.substring(0, splitPoint) + "|" + catname.topic + wikitext.substring(splitPoint); } } if (catname.type == "catlangname") { // try to find the first language template that matches and // add the category there var clnTemplateRegex = new RegExp("(?:^|(?<=\\n))(" + EN_WIKTIONARY_CATLANGNAME_START(catname.lang, true) + EN_WIKTIONARY_TEMPLATE_ANY_PARAMETERS + ")" + EN_WIKTIONARY_TEMPLATE_END); match = clnTemplateRegex.exec(cleanUpText(wikitext)); if (match) { splitPoint = match.index + match[1].length; return wikitext.substring(0, splitPoint) + "|" + catname.topic + wikitext.substring(splitPoint); } } } return null; // fallback } function en_wiktionary_add_category_string(category, onCat) { var catname = en_wiktionary_category_name_detect(category); if (catname) { if (catname.type == "topics" && EN_WIKTIONARY_PREFER_TOPICS_FOR_NEW_ADDITIONS && !onCat) { return "{{" + EN_WIKTIONARY_TOPICS[0] + "|" + catname.lang + "|" + catname.topic + "}}"; } if (catname.type == "catlangname" && EN_WIKTIONARY_PREFER_CATLANGNAME_FOR_NEW_ADDITIONS && !onCat) { return "{{" + EN_WIKTIONARY_CATLANGNAME[0] + "|" + catname.lang + "|" + catname.topic + "}}"; } } return null; // fallback } // END OF en.wiktionary EXTRA CODE // Don't use mw.config.get() as that takes a copy of the config, and so doesn't // account for values changing, e.g. wgCurRevisionId after a VE edit var conf = mw.config.values, // when running on mobile domain - do not use wgServer. wgServer = window.location.host.indexOf('.m.') > -1 ? '//' + window.location.host : mw.config.get( 'wgServer' ); // Guard against double inclusions (in old IE/Opera element ids become window properties) if ( ( window.HotCat && !window.HotCat.nodeName ) || conf.wgAction === 'edit' ) // Not on edit mode return; // Configuration stuff. var HC = window.HotCat = { // Localize these messages to the main language of your wiki. messages: { cat_removed: 'removed [[Category:$1]]', template_removed: 'removed {{[[Category:$1]]}}', cat_added: 'added [[Category:$1]]', cat_keychange: 'new key for [[Category:$1]]: "$2"', // $2 is the new key cat_notFound: 'Category "$1" not found', cat_exists: 'Category "$1" already exists; not added.', cat_resolved: ' (redirect [[Category:$1]] resolved)', uncat_removed: 'removed {{uncategorized}}', separator: '; ', // Some text to prefix to the edit summary. prefix: '', // Some text to append to the edit summary. Named 'using' for historical reasons. If you prefer // to have a marker at the front, use prefix and set this to the empty string. using: ' using [[Help:Gadget-HotCat|HotCat]]', // $1 is replaced by a number. If your language has several plural forms (c.f. [[:en:Dual (grammatical form)]]), // you can set this to an array of strings suitable for passing to mw.language.configPlural(). // If that function doesn't exist, HotCat will simply fall back to using the last // entry in the array. multi_change: '$1 categories', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. commit: 'Save', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. ok: 'OK', // Button text. Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. cancel: 'Cancel', // Localize to wgContentLanguage here; localize to wgUserLanguage in a subpage, // see localization hook below. multi_error: 'Could not retrieve the page text from the server. Therefore, your category changes ' + 'cannot be saved. We apologize for the inconvenience.', // Defaults to '[[' + category_canonical + ':$1]]'. Can be overridden if in the short edit summaries // not the standard category name should be used but, say, a shorter namespace alias. $1 is replaced // by a category name. short_catchange: null }, // Plural of category_canonical. categories: 'Categories', // Any category in this category is deemed a disambiguation category; i.e., a category that should not contain // any items, but that contains links to other categories where stuff should be categorized. If you don't have // that concept on your wiki, set it to null. Use blanks, not underscores. disambig_category: 'Disambiguation', // Any category in this category is deemed a (soft) redirect to some other category defined by a link // to another non-blacklisted category. If your wiki doesn't have soft category redirects, set this to null. // If a soft-redirected category contains more than one link to another non-blacklisted category, it's considered // a disambiguation category instead. redir_category: 'Category redirects', // The little modification links displayed after category names. U+2212 is a minus sign; U+2193 and U+2191 are // downward and upward pointing arrows. Do not use ↓ and ↑ in the code! links: { change: '(±)', remove: '(\u2212)', add: '(+)', restore: '(×)', undo: '(×)', down: '(\u2193)', up: '(\u2191)' }, changeTag: conf.wgUserName ? 'HotCat' : '', // if tag is missing, edit is rejected // The tooltips for the above links tooltips: { change: 'Modify', remove: 'Remove', add: 'Add a new category', restore: 'Undo changes', undo: 'Undo changes', down: 'Open for modifying and display subcategories', up: 'Open for modifying and display parent categories' }, // The HTML content of the "enter multi-mode" link at the front. addmulti: '<span>+<sup>+</sup></span>', // Tooltip for the "enter multi-mode" link multi_tooltip: 'Modify several categories', // Return true to disable HotCat. disable: function () { var ns = conf.wgNamespaceNumber; var nsIds = conf.wgNamespaceIds; return ( ns < 0 || // Special pages; Special:Upload is handled differently ns === 10 || // Templates ns === 828 || // Module (Lua) ns === 8 || // MediaWiki ns === 6 && !conf.wgArticleId || // Non-existing file pages ns === 2 && /\.(js|css)$/.test( conf.wgTitle ) || // User scripts nsIds && ( ns === nsIds.creator || ns === nsIds.timedtext || ns === nsIds.institution ) ); }, // A regexp matching a templates used to mark uncategorized pages, if your wiki does have that. // If not, set it to null. uncat_regexp: /\{\{\s*[Uu]ncategorized\s*[^}]*\}\}\s*(<!--.*?-->\s*)?/g, // The images used for the little indication icon. Should not need changing. existsYes: '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png', existsNo: '//upload.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png', // a list of categories which can be removed by removing a template // key: the category without namespace // value: A regexp matching the template name, again without namespace // If you don't have this at your wiki, or don't want this, set it to an empty object {}. template_categories: {}, // Names for the search engines engine_names: { searchindex: 'Search index', pagelist: 'Page list', combined: 'Combined search', subcat: 'Subcategories', parentcat: 'Parent categories' }, // Override the decision of whether HotCat should help users by automatically // capitalising the title in the user input text if the wiki has case-sensitive page names. // Basically, this will make an API query to check the MediaWiki configuration and HotCat then sets // this to true for most wikis, and to false on Wiktionary. // // You can set this directly if there is a problem with it. For example, Georgian Wikipedia (kawiki), // is known to have different capitalisation logic between MediaWiki PHP and JavaScript. As such, automatic // case changes in JavaScript by HotCat would be wrong. capitalizePageNames: null, // If upload_disabled is true, HotCat will not be used on the Upload form. upload_disabled: false, // Single regular expression matching blacklisted categories that cannot be changed or // added using HotCat. For instance /\bstubs?$/ (any category ending with the word "stub" // or "stubs"), or /(\bstubs?$)|\bmaintenance\b/ (stub categories and any category with the // word "maintenance" in its title. blacklist: null, // Stuff changeable by users: // Background for changed categories in multi-edit mode. Default is a very light salmon pink. bg_changed: '#FCA', // If true, HotCat will never automatically submit changes. HotCat will only open an edit page with // the changes; users must always save explicitly. no_autocommit: false, // If true, the "category deletion" link "(-)" will never save automatically but always show an // edit page where the user has to save the edit manually. Is false by default because that's the // traditional behavior. This setting overrides no_autocommit for "(-)" links. del_needs_diff: false, // Time, in milliseconds, that HotCat waits after a keystroke before making a request to the // server to get suggestions. suggest_delay: 100, // Default width, in characters, of the text input field. editbox_width: 40, // One of the engine_names above, to be used as the default suggestion engine. suggestions: 'combined', // If true, always use the default engine, and never display a selector. fixed_search: false, // If false, do not display the "up" and "down" links use_up_down: true, // Default list size listSize: 10, // If true, single category changes are marked as minor edits. If false, they're not. single_minor: true, // If true, never add a page to the user's watchlist. If false, pages get added to the watchlist if // the user has the "Add pages I edit to my watchlist" or the "Add pages I create to my watchlist" // options in his or her preferences set. dont_add_to_watchlist: false, shortcuts: null, addShortcuts: function ( map ) { if ( !map ) return; window.HotCat.shortcuts = window.HotCat.shortcuts || {}; for ( var k in map ) { if ( !map.hasOwnProperty( k ) || typeof k !== 'string' ) continue; var v = map[ k ]; if ( typeof v !== 'string' ) continue; k = k.replace( /^\s+|\s+$/g, '' ); v = v.replace( /^\s+|\s+$/g, '' ); if ( !k.length || !v.length ) continue; window.HotCat.shortcuts[ k ] = v; } } }; // More backwards compatibility. We have a few places where we test for the browser: once for // Safari < 3.0, and twice for WebKit (Chrome or Safari, any versions) var ua = navigator.userAgent.toLowerCase(); var is_webkit = /applewebkit\/\d+/.test( ua ) && ua.indexOf( 'spoofer' ) < 0; var cat_prefix = null; var noSuggestions = false; function LoadTrigger( needed ) { // Define methods in a closure so that self reference is available, // also allows method calls to be detached. var self = this; self.queue = []; self.needed = needed; self.register = function ( callback ) { if ( self.needed <= 0 ) callback(); // Execute directly else self.queue.push( callback ); }; self.loaded = function () { self.needed--; if ( self.needed === 0 ) { // Run queued callbacks once for ( var i = 0; i < self.queue.length; i++ ) self.queue[ i ](); self.queue = []; } }; } // Used to delay running the HotCat setup until /local_defaults and localizations have been loaded. var loadTrigger = new LoadTrigger( 2 ); function load( uri, callback ) { var s = document.createElement( 'script' ); s.src = uri; var called = false; s.onload = s.onerror = function () { if ( !called && callback ) { called = true; callback(); } if ( s.parentNode ) { s.parentNode.removeChild( s ); } }; document.head.appendChild( s ); } function loadJS( page, callback ) { load( wgServer + conf.wgScript + '?title=' + encodeURIComponent( page ) + '&action=raw&ctype=text/javascript', callback ); } function loadURI( href, callback ) { var url = href; if ( url.substring( 0, 2 ) === '//' ) url = window.location.protocol + url; else if ( url.substring( 0, 1 ) === '/' ) url = wgServer + url; load( url, callback ); } // Load local configurations, overriding the pre-set default values in the HotCat object above. This is always loaded // from the wiki where this script is executing, even if this script itself is hotlinked from Commons. This can // be used to change the default settings, or to provide localized interface texts for edit summaries and so on. loadJS( 'MediaWiki:Gadget-HotCat.js/local_defaults', loadTrigger.loaded ); // Load localized UI texts. These are the texts that HotCat displays on the page itself. Texts shown in edit summaries // should be localized in /local_defaults above. if ( conf.wgUserLanguage !== 'en' ) { // Lupo: somebody thought it would be a good idea to add this. So the default is true, and you have to set it to false // explicitly if you're not on Commons and don't want that. if ( window.hotcat_translations_from_commons === undefined ) window.hotcat_translations_from_commons = true; // Localization hook to localize HotCat messages, tooltips, and engine names for wgUserLanguage. if ( window.hotcat_translations_from_commons && wgServer.indexOf( '//commons' ) < 0 ) { loadURI( '//commons.wikimedia.org/w/index.php?title=' + 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage + '&action=raw&ctype=text/javascript', loadTrigger.loaded ); } else { // Load translations locally loadJS( 'MediaWiki:Gadget-HotCat.js/' + conf.wgUserLanguage, loadTrigger.loaded ); } } else { loadTrigger.loaded(); } // No further changes should be necessary here. // The following regular expression strings are used when searching for categories in wikitext. var wikiTextBlank = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+'; var wikiTextBlankRE = new RegExp( wikiTextBlank, 'g' ); // Regexp for handling blanks inside a category title or namespace name. // See http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/Title.php?revision=104051&view=markup#l2722 // See also http://www.fileformat.info/info/unicode/category/Zs/list.htm // MediaWiki collapses several contiguous blanks inside a page title to one single blank. It also replace a // number of special whitespace characters by simple blanks. And finally, blanks are treated as underscores. // Therefore, when looking for page titles in wikitext, we must handle all these cases. // Note: we _do_ include the horizontal tab in the above list, even though the MediaWiki software for some reason // appears to not handle it. The zero-width space \u200B is _not_ handled as a space inside titles by MW. var wikiTextBlankOrBidi = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200B\\u200E\\u200F\\u2028-\\u202F\\u205F\\u3000]*'; // Whitespace regexp for handling whitespace between link components. Including the horizontal tab, but not \n\r\f\v: // a link must be on one single line. // MediaWiki also removes Unicode bidi override characters in page titles (and namespace names) completely. // This is *not* handled, as it would require us to allow any of [\u200E\u200F\u202A-\u202E] between any two // characters inside a category link. It _could_ be done though... We _do_ handle strange spaces, including the // zero-width space \u200B, and bidi overrides between the components of a category link (adjacent to the colon, // or adjacent to and inside of "[[" and "]]"). // First auto-localize the regexps for the category and the template namespaces. var formattedNamespaces = conf.wgFormattedNamespaces; var namespaceIds = conf.wgNamespaceIds; function autoLocalize( namespaceNumber, fallback ) { function createRegexpStr( name ) { if ( !name || !name.length ) return ''; var regex_name = ''; for ( var i = 0; i < name.length; i++ ) { var initial = name.charAt( i ), ll = initial.toLowerCase(), ul = initial.toUpperCase(); if ( ll === ul ) regex_name += initial; else regex_name += '[' + ll + ul + ']'; } return regex_name .replace( /([\\^$.?*+()])/g, '\\$1' ) .replace( wikiTextBlankRE, wikiTextBlank ); } fallback = fallback.toLowerCase(); var canonical = formattedNamespaces[ String( namespaceNumber ) ].toLowerCase(); var regexp = createRegexpStr( canonical ); if ( fallback && canonical !== fallback ) regexp += '|' + createRegexpStr( fallback ); if ( namespaceIds ) { for ( var cat_name in namespaceIds ) { if ( typeof cat_name === 'string' && cat_name.toLowerCase() !== canonical && cat_name.toLowerCase() !== fallback && namespaceIds[ cat_name ] === namespaceNumber ) { regexp += '|' + createRegexpStr( cat_name ); } } } return regexp; } HC.category_canonical = formattedNamespaces[ '14' ]; HC.category_regexp = autoLocalize( 14, 'category' ); if ( formattedNamespaces[ '10' ] ) HC.template_regexp = autoLocalize( 10, 'template' ); // Utility functions. Yes, this duplicates some functionality that also exists in other places, but // to keep this whole stuff in a single file not depending on any other on-wiki JavaScripts, we re-do // these few operations here. function make( arg, literal ) { if ( !arg ) return null; return literal ? document.createTextNode( arg ) : document.createElement( arg ); } function param( name, uri ) { uri = uri || document.location.href; var re = new RegExp( '[&?]' + name + '=([^&#]*)' ); var m = re.exec( uri ); if ( m && m.length > 1 ) return decodeURIComponent( m[ 1 ] ); return null; } function title( href ) { if ( !href ) return null; var script = conf.wgScript + '?'; if ( href.indexOf( script ) === 0 || href.indexOf( wgServer + script ) === 0 || wgServer.substring( 0, 2 ) === '//' && href.indexOf( document.location.protocol + wgServer + script ) === 0 ) { // href="/w/index.php?title=..." return param( 'title', href ); } else { // href="/wiki/..." var prefix = conf.wgArticlePath.replace( '$1', '' ); if ( href.indexOf( prefix ) ) prefix = wgServer + prefix; // Fully expanded URL? if ( href.indexOf( prefix ) && prefix.substring( 0, 2 ) === '//' ) prefix = document.location.protocol + prefix; // Protocol-relative wgServer? if ( href.indexOf( prefix ) === 0 ) return decodeURIComponent( href.substring( prefix.length ) ); } return null; } function hasClass( elem, name ) { return ( ' ' + elem.className + ' ' ).indexOf( ' ' + name + ' ' ) >= 0; } function capitalize( str ) { if ( !str || !str.length ) return str; return str.substr( 0, 1 ).toUpperCase() + str.substr( 1 ); } function wikiPagePath( pageName ) { // Note: do not simply use encodeURI, it doesn't encode '&', which might break if wgArticlePath actually has the $1 in // a query parameter. return conf.wgArticlePath.replace( '$1', encodeURIComponent( pageName ).replace( /%3A/g, ':' ).replace( /%2F/g, '/' ) ); } function escapeRE( str ) { return str.replace( /([\\^$.?*+()[\]])/g, '\\$1' ); } function substituteFactory( options ) { options = options || {}; var lead = options.indicator || '$'; var indicator = escapeRE( lead ); var lbrace = escapeRE( options.lbrace || '{' ); var rbrace = escapeRE( options.rbrace || '}' ); var re; re = new RegExp( // $$ '(?:' + indicator + '(' + indicator + '))|' + // $0, $1 '(?:' + indicator + '(\\d+))|' + // ${key} '(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' + // $key (only if first char after $ is not $, digit, or { ) '(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)', 'g' ); // Replace $1, $2, or ${key1}, ${key2}, or $key1, $key2 by values from map. $$ is replaced by a single $. return function ( str, map ) { if ( !map ) return str; return str.replace( re, function ( match, prefix, idx, key, alpha ) { if ( prefix === lead ) return lead; var k = alpha || key || idx; var replacement = typeof map[ k ] === 'function' ? map[ k ]( match, k ) : map[ k ]; return typeof replacement === 'string' ? replacement : ( replacement || match ); } ); }; } var substitute = substituteFactory(); var replaceShortcuts = ( function () { var replaceHash = substituteFactory( { indicator: '#', lbrace: '[', rbrace: ']' } ); return function ( str, map ) { var s = replaceHash( str, map ); return HC.capitalizePageNames ? capitalize( s ) : s; }; }() ); // Text modification var findCatsRE = new RegExp( '\\[\\[' + wikiTextBlankOrBidi + '(?:' + HC.category_regexp + ')' + wikiTextBlankOrBidi + ':[^\\]]+\\]\\]', 'g' ); function replaceByBlanks( match ) { return match.replace( /(\s|\S)/g, ' ' ); // /./ doesn't match linebreaks. /(\s|\S)/ does. } function find_category( wikitext, category, once ) { var cat_regex = null; var result_hook = en_wiktionary_find_category(wikitext, category, once); if (result_hook) { return result_hook; } if ( HC.template_categories[ category ] ) { cat_regex = new RegExp( '\\{\\{' + wikiTextBlankOrBidi + '(' + HC.template_regexp + '(?=' + wikiTextBlankOrBidi + ':))?' + wikiTextBlankOrBidi + '(?:' + HC.template_categories[ category ] + ')' + wikiTextBlankOrBidi + '(\\|.*?)?\\}\\}', 'g' ); } else { var cat_name = escapeRE( category ); var initial = cat_name.substr( 0, 1 ); cat_regex = new RegExp( '\\[\\[' + wikiTextBlankOrBidi + '(' + HC.category_regexp + ')' + wikiTextBlankOrBidi + ':' + wikiTextBlankOrBidi + ( initial === '\\' || !HC.capitalizePageNames ? initial : '[' + initial.toUpperCase() + initial.toLowerCase() + ']' ) + cat_name.substring( 1 ).replace( wikiTextBlankRE, wikiTextBlank ) + wikiTextBlankOrBidi + '(\\|.*?)?\\]\\]', 'g' ); } if ( once ) return cat_regex.exec( wikitext ); var copiedtext = wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); var result = []; var curr_match = null; while ( ( curr_match = cat_regex.exec( copiedtext ) ) !== null ) { result.push( { match: curr_match } ); } result.re = cat_regex; return result; // An array containing all matches, with positions, in result[ i ].match } var interlanguageRE = null; function change_category( wikitext, toRemove, toAdd, key, is_hidden ) { function find_insertionpoint( wikitext, category ) { var copiedtext = wikitext .replace( /<!--(\s|\S)*?-->/g, replaceByBlanks ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, replaceByBlanks ); // Search in copiedtext to avoid that we insert inside an HTML comment or a nowiki "element". var result = en_wiktionary_find_insertionpoint( wikitext, category ); if (result) { return result; } var index = -1; findCatsRE.lastIndex = 0; while ( findCatsRE.exec( copiedtext ) !== null ) index = findCatsRE.lastIndex; if ( index < 0 ) { // Find the index of the first interlanguage link... var match = null; if ( !interlanguageRE ) { // Approximation without API: interlanguage links start with 2 to 3 lower case letters, optionally followed by // a sequence of groups consisting of a dash followed by one or more lower case letters. Exceptions are "simple" // and "tokipona". match = /((^|\n\r?)(\[\[\s*(([a-z]{2,3}(-[a-z]+)*)|simple|tokipona)\s*:[^\]]+\]\]\s*))+$/.exec( copiedtext ); } else { match = interlanguageRE.exec( copiedtext ); } if ( match ) index = match.index; return { idx: index, onCat: false }; } return { idx: index, onCat: index >= 0 }; } var summary = [], nameSpace = HC.category_canonical, cat_point = -1, // Position of removed category; keyChange = ( toRemove && toAdd && toRemove === toAdd && toAdd.length ), matches, noOnCatOverride = false; if ( key ) key = '|' + key; // Remove if ( toRemove && toRemove.length ) { matches = find_category( wikitext, toRemove ); if ( !matches || !matches.length ) { return { text: wikitext, summary: summary, error: HC.messages.cat_notFound.replace( /\$1/g, toRemove ) }; } else { var after = wikitext; for (var i = matches.length - 1; i > 0; i--) { after = en_wiktionary_remove_category(after, matches[i]); } var before_after = en_wiktionary_three_to_two_split(after, matches[0]); noOnCatOverride = en_wiktionary_is_special_match(matches[0]); var before = before_after[0]; after = before_after[1]; if ( toAdd ) { // nameSpace = matches[ 0 ].match[ 1 ] || nameSpace; Canonical namespace should be always preferred if ( key === null ) key = matches[ 0 ].match[ 2 ]; // Remember the category key, if any. } // Remove whitespace (properly): strip whitespace, but only up to the next line feed. // If we then have two linefeeds in a row, remove one. Otherwise, if we have two non- // whitespace characters, insert a blank. var i = before.length - 1; while ( i >= 0 && before.charAt( i ) !== '\n' && before.substr( i, 1 ).search( /\s/ ) >= 0 ) i--; var j = 0; while ( j < after.length && after.charAt( j ) !== '\n' && after.substr( j, 1 ).search( /\s/ ) >= 0 ) j++; if ( i >= 0 && before.charAt( i ) === '\n' && ( !after.length || j < after.length && after.charAt( j ) === '\n' ) ) i--; if ( i >= 0 ) before = before.substring( 0, i + 1 ); else before = ''; if ( j < after.length ) after = after.substring( j ); else after = ''; if ( before.length && before.substring( before.length - 1 ).search( /\S/ ) >= 0 && after.length && after.substr( 0, 1 ).search( /\S/ ) >= 0 ) { before += ' '; } cat_point = before.length; if ( cat_point === 0 && after.length && after.substr( 0, 1 ) === '\n' ) after = after.substr( 1 ); wikitext = before + after; if ( !keyChange ) { if ( HC.template_categories[ toRemove ] ) { summary.push( HC.messages.template_removed.replace( /\$1/g, toRemove ) ); } else { summary.push( HC.messages.cat_removed.replace( /\$1/g, toRemove ) ); } } } } // Add if ( toAdd && toAdd.length ) { matches = find_category( wikitext, toAdd ); if ( matches && matches.length ) { // Already exists return { text: wikitext, summary: summary, error: HC.messages.cat_exists.replace( /\$1/g, toAdd ) }; } else { var hooked = en_wiktionary_add_category_hook( wikitext, toAdd, cat_point ); if (hooked) { wikitext = hooked; summary.push( HC.messages.cat_added.replace( /\$1/g, toAdd ) ); } else { var onCat = false; var noPreLine = false; if ( cat_point < 0 ) { var point = find_insertionpoint ( wikitext, toAdd ); cat_point = point.idx; onCat = point.onCat; noPreLine = point.noPreLine; } else { onCat = true; } var newcatstring = en_wiktionary_add_category_string(toAdd, onCat && !noOnCatOverride) || ('[[' + nameSpace + ':' + toAdd + ( key || '' ) + ']]'); if ( cat_point >= 0 ) { var suffix = wikitext.substring( cat_point ); wikitext = wikitext.substring( 0, cat_point ) + ( cat_point > 0 && !noPreLine ? '\n' : '' ) + newcatstring + ( !onCat ? '\n' : '' ); if ( suffix.length && suffix.substr( 0, 1 ) !== '\n' ) wikitext += '\n' + suffix; else wikitext += suffix; } else { if ( wikitext.length && wikitext.substr( wikitext.length - 1, 1 ) !== '\n' ) wikitext += '\n'; wikitext += ( wikitext.length ? '\n' : '' ) + newcatstring; } if ( keyChange ) { var k = key || ''; if ( k.length ) k = k.substr( 1 ); summary.push( substitute( HC.messages.cat_keychange, [ null, toAdd, k ] ) ); } else { summary.push( HC.messages.cat_added.replace( /\$1/g, toAdd ) ); } if ( HC.uncat_regexp && !is_hidden ) { var txt = wikitext.replace( HC.uncat_regexp, '' ); // Remove "uncat" templates if ( txt.length !== wikitext.length ) { wikitext = txt; summary.push( HC.messages.uncat_removed ); } } } } } return { text: wikitext, summary: summary, error: null }; } // The real HotCat UI function evtKeys( e ) { /* eslint-disable no-bitwise */ var code = 0; if ( e.ctrlKey ) { // All modern browsers // Ctrl-click seems to be overloaded in FF/Mac (it opens a pop-up menu), so treat cmd-click // as a ctrl-click, too. if ( e.ctrlKey || e.metaKey ) code |= 1; if ( e.shiftKey ) code |= 2; } return code; } function evtKill( e ) { if ( e.preventDefault ) { e.preventDefault(); e.stopPropagation(); } else { e.cancelBubble = true; } return false; } var catLine = null, onUpload = false, editors = [], commitButton = null, commitForm = null, multiSpan = null, pageText = null, pageTime = null, pageWatched = false, watchCreate = false, watchEdit = false, minorEdits = false, editToken = null, is_rtl = false, serverTime = null, lastRevId = null, pageTextRevId = null, conflictingUser = null, newDOM = false; // true if MediaWiki serves the new UL-LI DOM for categories function CategoryEditor() { this.initialize.apply( this, arguments ); } function setPage( json ) { var startTime = null; if ( json && json.query ) { if ( json.query.pages ) { var page = json.query.pages[ !conf.wgArticleId ? '-1' : String( conf.wgArticleId ) ]; if ( page ) { if ( page.revisions && page.revisions.length ) { // Revisions are sorted by revision ID, hence [ 0 ] is the one we asked for, and possibly there's a [ 1 ] if we're // not on the latest revision (edit conflicts and such). pageText = page.revisions[ 0 ][ '*' ]; if ( page.revisions[ 0 ].timestamp ) pageTime = page.revisions[ 0 ].timestamp.replace( /\D/g, '' ); if ( page.revisions[ 0 ].revid ) pageTextRevId = page.revisions[ 0 ].revid; if ( page.revisions.length > 1 ) conflictingUser = page.revisions[ 1 ].user; } if ( page.lastrevid ) lastRevId = page.lastrevid; if ( page.starttimestamp ) startTime = page.starttimestamp.replace( /\D/g, '' ); pageWatched = typeof page.watched === 'string'; if ( json.query.tokens ) editToken = json.query.tokens.csrftoken; if ( page.langlinks && ( !json[ 'query-continue' ] || !json[ 'query-continue' ].langlinks ) ) { // We have interlanguage links, and we got them all. var re = ''; for ( var i = 0; i < page.langlinks.length; i++ ) re += ( i > 0 ? '|' : '' ) + page.langlinks[ i ].lang.replace( /([\\^$.?*+()])/g, '\\$1' ); if ( re.length ) interlanguageRE = new RegExp( '((^|\\n\\r?)(\\[\\[\\s*(' + re + ')\\s*:[^\\]]+\\]\\]\\s*))+$' ); } } } // Siteinfo if ( json.query.general ) { if ( json.query.general.time && !startTime ) startTime = json.query.general.time.replace( /\D/g, '' ); if ( HC.capitalizePageNames === null ) { // ResourceLoader's JSParser doesn't like .case, so override eslint. // eslint-disable-next-line dot-notation HC.capitalizePageNames = ( json.query.general[ 'case' ] === 'first-letter' ); } } serverTime = startTime; // Userinfo if ( json.query.userinfo && json.query.userinfo.options ) { watchCreate = !HC.dont_add_to_watchlist && json.query.userinfo.options.watchcreations === '1'; watchEdit = !HC.dont_add_to_watchlist && json.query.userinfo.options.watchdefault === '1'; minorEdits = json.query.userinfo.options.minordefault === 1; // If the user has the "All edits are minor" preference enabled, we should honor that // for single category changes, no matter what the site configuration is. if ( minorEdits ) HC.single_minor = true; } } } var saveInProgress = false; function initiateEdit( doEdit, failure ) { if ( saveInProgress ) return; saveInProgress = true; var oldButtonState; if ( commitButton ) { oldButtonState = commitButton.disabled; commitButton.disabled = true; } function fail() { saveInProgress = false; if ( commitButton ) commitButton.disabled = oldButtonState; failure.apply( this, arguments ); } // Must use Ajax here to get the user options and the edit token. $.getJSON( wgServer + conf.wgScriptPath + '/api.php?' + 'format=json&action=query&rawcontinue=&titles=' + encodeURIComponent( conf.wgPageName ) + '&prop=info%7Crevisions%7Clanglinks&inprop=watched&rvprop=content%7Ctimestamp%7Cids%7Cuser&lllimit=500' + '&rvlimit=2&rvdir=newer&rvstartid=' + conf.wgCurRevisionId + '&meta=siteinfo%7Cuserinfo%7Ctokens&type=csrf&uiprop=options', function ( json ) { setPage( json ); doEdit( fail ); } ).fail( function ( req ) { fail( req.status + ' ' + req.statusText ); } ); } function multiChangeMsg( count ) { var msg = HC.messages.multi_change; if ( typeof msg !== 'string' && msg.length ) if ( mw.language && mw.language.convertPlural ) { msg = mw.language.convertPlural( count, msg ); } else { msg = msg[ msg.length - 1 ]; } return substitute( msg, [ null, String( count ) ] ); } function currentTimestamp() { var now = new Date(); var ts = String( now.getUTCFullYear() ); function two( s ) { return s.substr( s.length - 2 ); } ts += two( '0' + ( now.getUTCMonth() + 1 ) ) + two( '0' + now.getUTCDate() ) + two( '00' + now.getUTCHours() ) + two( '00' + now.getUTCMinutes() ) + two( '00' + now.getUTCSeconds() ); return ts; } function performChanges( failure, singleEditor ) { if ( pageText === null ) { failure( HC.messages.multi_error ); return; } // Backwards compatibility after message change (added $2 to cat_keychange) if ( HC.messages.cat_keychange.indexOf( '$2' ) < 0 ) HC.messages.cat_keychange += '"$2"'; // More backwards-compatibility with earlier HotCat versions: if ( !HC.messages.short_catchange ) HC.messages.short_catchange = '[[' + HC.category_canonical + ':$1]]'; // Create a form and submit it. We don't use the edit API (api.php?action=edit) because // (a) sensibly reporting back errors like edit conflicts is always a hassle, and // (b) we want to show a diff for multi-edits anyway, and // (c) we want to trigger onsubmit events, allowing user code to intercept the edit. // Using the form, we can do (b) and (c), and we get (a) for free. And, of course, using the form // automatically reloads the page with the updated categories on a successful submit, which // we would have to do explicitly if we used the edit API. var action; // Normally, we don't have to care about edit conflicts. If some other user edited the page in the meantime, the // server will take care of it and merge the edit automatically or present an edit conflict screen. However, the // server suppresses edit conflicts with oneself. Hence, if we have a conflict, and the conflicting user is the // current user, then we set the "oldid" value and switch to diff, which gives the "you are editing an old version; // if you save, any more recent changes will be lost" screen. var selfEditConflict = ( lastRevId !== null && lastRevId !== conf.wgCurRevisionId || pageTextRevId !== null && pageTextRevId !== conf.wgCurRevisionId ) && conflictingUser && conflictingUser === conf.wgUserName; if ( singleEditor && !singleEditor.noCommit && !HC.no_autocommit && editToken && !selfEditConflict ) { // If we do have an edit conflict, but not with ourself, that's no reason not to attempt to save: the server side may actually be able to // merge the changes. We just need to make sure that we do present a diff view if it's a self edit conflict. commitForm.wpEditToken.value = editToken; action = commitForm.wpDiff; if ( action ) action.name = action.value = 'wpSave'; } else { action = commitForm.wpSave; if ( action ) action.name = action.value = 'wpDiff'; } var result = { text: pageText }, changed = [], added = [], deleted = [], changes = 0, toEdit = singleEditor ? [ singleEditor ] : editors, error = null, edit, i; for ( i = 0; i < toEdit.length; i++ ) { edit = toEdit[ i ]; if ( edit.state === CategoryEditor.CHANGED ) { result = change_category( result.text, edit.originalCategory, edit.currentCategory, edit.currentKey, edit.currentHidden ); if ( !result.error ) { changes++; if ( !edit.originalCategory || !edit.originalCategory.length ) { added.push( edit.currentCategory ); } else { changed.push( { from: edit.originalCategory, to: edit.currentCategory } ); } } else if ( error === null ) { error = result.error; } } else if ( edit.state === CategoryEditor.DELETED && edit.originalCategory && edit.originalCategory.length ) { result = change_category( result.text, edit.originalCategory, null, null, false ); if ( !result.error ) { changes++; deleted.push( edit.originalCategory ); } else if ( error === null ) { error = result.error; } } } if ( error !== null ) { // Do not commit if there were errors action = commitForm.wpSave; if ( action ) action.name = action.value = 'wpDiff'; } // Fill in the form and submit it commitForm.wpMinoredit.checked = minorEdits; commitForm.wpWatchthis.checked = !conf.wgArticleId && watchCreate || watchEdit || pageWatched; if ( conf.wgArticleId || !!singleEditor ) { // Prepare change-tag save if ( action && action.value === 'wpSave' ) { if ( HC.changeTag ) { commitForm.wpChangeTags.value = HC.changeTag; HC.messages.using = ''; HC.messages.prefix = ''; } } else { commitForm.wpAutoSummary.value = HC.changeTag; } if ( changes === 1 ) { if ( result.summary && result.summary.length ) commitForm.wpSummary.value = HC.messages.prefix + result.summary.join( HC.messages.separator ) + HC.messages.using; commitForm.wpMinoredit.checked = HC.single_minor || minorEdits; } else if ( changes ) { var summary = []; var shortSummary = []; // Deleted for ( i = 0; i < deleted.length; i++ ) summary.push( '−' + substitute( HC.messages.short_catchange, [ null, deleted[ i ] ] ) ); if ( deleted.length === 1 ) shortSummary.push( '−' + substitute( HC.messages.short_catchange, [ null, deleted[ 0 ] ] ) ); else if ( deleted.length ) shortSummary.push( '− ' + multiChangeMsg( deleted.length ) ); // Added for ( i = 0; i < added.length; i++ ) summary.push( '+' + substitute( HC.messages.short_catchange, [ null, added[ i ] ] ) ); if ( added.length === 1 ) shortSummary.push( '+' + substitute( HC.messages.short_catchange, [ null, added[ 0 ] ] ) ); else if ( added.length ) shortSummary.push( '+ ' + multiChangeMsg( added.length ) ); // Changed var arrow = is_rtl ? '\u2190' : '\u2192'; // left and right arrows. Don't use ← and → in the code. for ( i = 0; i < changed.length; i++ ) { if ( changed[ i ].from !== changed[ i ].to ) { summary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ i ].from ] ) + arrow + substitute( HC.messages.short_catchange, [ null, changed[ i ].to ] ) ); } else { summary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ i ].from ] ) ); } } if ( changed.length === 1 ) { if ( changed[ 0 ].from !== changed[ 0 ].to ) { shortSummary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].from ] ) + arrow + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].to ] ) ); } else { shortSummary.push( '±' + substitute( HC.messages.short_catchange, [ null, changed[ 0 ].from ] ) ); } } else if ( changed.length ) { shortSummary.push( '± ' + multiChangeMsg( changed.length ) ); } if ( summary.length ) { summary = summary.join( HC.messages.separator ); if ( summary.length > 200 - HC.messages.prefix.length - HC.messages.using.length ) summary = shortSummary.join( HC.messages.separator ); commitForm.wpSummary.value = HC.messages.prefix + summary + HC.messages.using; } } } commitForm.wpTextbox1.value = result.text; commitForm.wpStarttime.value = serverTime || currentTimestamp(); commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value; if ( selfEditConflict ) commitForm.oldid.value = String( pageTextRevId || conf.wgCurRevisionId ); // Submit the form in a way that triggers onsubmit events: commitForm.submit() doesn't. commitForm.hcCommit.click(); } function resolveOne( page, toResolve ) { var cats = page.categories, lks = page.links, is_dab = false, is_redir = typeof page.redirect === 'string', // Hard redirect? is_hidden = page.categoryinfo && typeof page.categoryinfo.hidden === 'string', is_missing = typeof page.missing === 'string', i; for ( i = 0; i < toResolve.length; i++ ) { if ( i && toResolve[ i ].dabInputCleaned !== page.title.substring( page.title.indexOf( ':' ) + 1 ) ) continue; // Note: the server returns in page an NFC normalized Unicode title. If our input was not NFC normalized, we may not find // any entry here. If we have only one editor to resolve (the most common case, I presume), we may simply skip the check. toResolve[ i ].currentHidden = is_hidden; toResolve[ i ].inputExists = !is_missing; toResolve[ i ].icon.src = ( is_missing ? HC.existsNo : HC.existsYes ); } if ( is_missing ) return; if ( !is_redir && cats && ( HC.disambig_category || HC.redir_category ) ) { for ( var c = 0; c < cats.length; c++ ) { var cat = cats[ c ].title; // Strip namespace prefix if ( cat ) { cat = cat.substring( cat.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); if ( cat === HC.disambig_category ) { is_dab = true; break; } else if ( cat === HC.redir_category ) { is_redir = true; break; } } } } if ( !is_redir && !is_dab ) return; if ( !lks || !lks.length ) return; var titles = []; for ( i = 0; i < lks.length; i++ ) { if ( // Category namespace -- always true since we ask only for the category links lks[ i ].ns === 14 && // Name not empty lks[ i ].title && lks[ i ].title.length ) { // Internal link to existing thingy. Extract the page name and remove the namespace. var match = lks[ i ].title; match = match.substring( match.indexOf( ':' ) + 1 ); // Exclude blacklisted categories. if ( !HC.blacklist || !HC.blacklist.test( match ) ) titles.push( match ); } } if ( !titles.length ) return; for ( i = 0; i < toResolve.length; i++ ) { if ( i && toResolve[ i ].dabInputCleaned !== page.title.substring( page.title.indexOf( ':' ) + 1 ) ) continue; toResolve[ i ].inputExists = true; // Might actually be wrong if it's a redirect pointing to a non-existing category toResolve[ i ].icon.src = HC.existsYes; if ( titles.length > 1 ) { toResolve[ i ].dab = titles; } else { toResolve[ i ].text.value = titles[ 0 ] + ( toResolve[ i ].currentKey !== null ? '|' + toResolve[ i ].currentKey : '' ); } } } function resolveRedirects( toResolve, params ) { if ( !params || !params.query || !params.query.pages ) return; for ( var p in params.query.pages ) resolveOne( params.query.pages[ p ], toResolve ); } function resolveMulti( toResolve, callback ) { var i; for ( i = 0; i < toResolve.length; i++ ) { toResolve[ i ].dab = null; toResolve[ i ].dabInput = toResolve[ i ].lastInput; } if ( noSuggestions ) { callback( toResolve ); return; } // Use %7C instead of |, otherwise Konqueror insists on re-encoding the arguments, resulting in doubly encoded // category names. (That is a bug in Konqueror. Other browsers don't have this problem.) var args = 'action=query&prop=info%7Clinks%7Ccategories%7Ccategoryinfo&plnamespace=14' + '&pllimit=' + ( toResolve.length * 10 ) + '&cllimit=' + ( toResolve.length * 10 ) + '&format=json&titles='; for ( i = 0; i < toResolve.length; i++ ) { var v = toResolve[ i ].dabInput; v = replaceShortcuts( v, HC.shortcuts ); toResolve[ i ].dabInputCleaned = v; args += encodeURIComponent( 'Category:' + v ); if ( i + 1 < toResolve.length ) args += '%7C'; } $.getJSON( wgServer + conf.wgScriptPath + '/api.php?' + args, function ( json ) { resolveRedirects( toResolve, json ); callback( toResolve ); } ).fail( function ( req ) { if ( !req ) noSuggestions = true; callback( toResolve ); } ); } function makeActive( which ) { if ( which.is_active ) return; for ( var i = 0; i < editors.length; i++ ) if ( editors[ i ] !== which ) editors[ i ].inactivate(); which.is_active = true; if ( which.dab ) { // eslint-disable-next-line no-use-before-define showDab( which ); } else { // Check for programmatic value changes. var expectedInput = which.lastRealInput || which.lastInput || ''; var actualValue = which.text.value || ''; if ( !expectedInput.length && actualValue.length || expectedInput.length && actualValue.indexOf( expectedInput ) ) { // Somehow the field's value appears to have changed, and which.lastSelection therefore is no longer valid. Try to set the // cursor at the end of the category, and do not display the old suggestion list. which.showsList = false; var v = actualValue.split( '|' ); which.lastRealInput = which.lastInput = v[ 0 ]; if ( v.length > 1 ) which.currentKey = v[ 1 ]; if ( which.lastSelection ) { which.lastSelection = { start: v[ 0 ].length, end: v[ 0 ].length }; } } if ( which.showsList ) which.displayList(); if ( which.lastSelection ) { if ( is_webkit ) { // WebKit (Safari, Chrome) has problems selecting inside focus() // See http://code.google.com/p/chromium/issues/detail?id=32865#c6 window.setTimeout( function () { which.setSelection( which.lastSelection.start, which.lastSelection.end ); }, 1 ); } else { which.setSelection( which.lastSelection.start, which.lastSelection.end ); } } } } function showDab( which ) { if ( !which.is_active ) { makeActive( which ); } else { which.showSuggestions( which.dab, false, null, null ); // do autocompletion, no key, no engine selector which.dab = null; } } function multiSubmit() { var toResolve = []; for ( var i = 0; i < editors.length; i++ ) if ( editors[ i ].state === CategoryEditor.CHANGE_PENDING || editors[ i ].state === CategoryEditor.OPEN ) toResolve.push( editors[ i ] ); if ( !toResolve.length ) { initiateEdit( function ( failure ) { performChanges( failure ); }, function ( msg ) { alert( msg ); } ); return; } resolveMulti( toResolve, function ( resolved ) { var firstDab = null; var dontChange = false; for ( var i = 0; i < resolved.length; i++ ) { if ( resolved[ i ].lastInput !== resolved[ i ].dabInput ) { // We didn't disable all the open editors, but we did asynchronous calls. It is // theoretically possible that the user changed something... dontChange = true; } else { if ( resolved[ i ].dab ) { if ( !firstDab ) firstDab = resolved[ i ]; } else { if ( resolved[ i ].acceptCheck( true ) ) resolved[ i ].commit(); } } } if ( firstDab ) { showDab( firstDab ); } else if ( !dontChange ) { initiateEdit( function ( failure ) { performChanges( failure ); }, function ( msg ) { alert( msg ); } ); } } ); } function setMultiInput() { if ( commitButton || onUpload ) return; commitButton = make( 'input' ); commitButton.type = 'button'; commitButton.value = HC.messages.commit; commitButton.onclick = multiSubmit; if ( multiSpan ) multiSpan.parentNode.replaceChild( commitButton, multiSpan ); else catLine.appendChild( commitButton ); } function checkMultiInput() { if ( !commitButton ) return; var hasChanges = false; for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { hasChanges = true; break; } } commitButton.disabled = !hasChanges; } var suggestionEngines = { opensearch: { uri: '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=Category:$1', // $1 = search term // Function to convert result of uri into an array of category names handler: function ( queryResult, queryKey ) { if ( queryResult && queryResult.length >= 2 ) { var key = queryResult[ 0 ].substring( queryResult[ 0 ].indexOf( ':' ) + 1 ); var titles = queryResult[ 1 ]; var exists = false; if ( !cat_prefix ) cat_prefix = new RegExp( '^(' + HC.category_regexp + '):' ); for ( var i = 0; i < titles.length; i++ ) { cat_prefix.lastIndex = 0; var m = cat_prefix.exec( titles[ i ] ); if ( m && m.length > 1 ) { titles[ i ] = titles[ i ].substring( titles[ i ].indexOf( ':' ) + 1 ); // rm namespace if ( key === titles[ i ] ) exists = true; } else { titles.splice( i, 1 ); // Nope, it's not a category after all. i--; } } titles.exists = exists; if ( queryKey !== key ) titles.normalized = key; // Remember the NFC normalized key we got back from the server return titles; } return null; } }, internalsearch: { uri: '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1&apprefix=$1', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.allpages ) { var titles = queryResult.query.allpages; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } return null; } }, exists: { uri: '/api.php?format=json&action=query&prop=info&titles=Category:$1', handler: function ( queryResult, queryKey ) { if ( queryResult && queryResult.query && queryResult.query.pages && !queryResult.query.pages[ -1 ] ) { // Should have exactly 1 for ( var p in queryResult.query.pages ) { var title = queryResult.query.pages[ p ].title; title = title.substring( title.indexOf( ':' ) + 1 ); var titles = [ title ]; titles.exists = true; if ( queryKey !== title ) titles.normalized = title; // NFC return titles; } } return null; } }, subcategories: { uri: '/api.php?format=json&action=query&list=categorymembers&cmtype=subcat&cmlimit=max&cmtitle=Category:$1', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.categorymembers ) { var titles = queryResult.query.categorymembers; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } return null; } }, parentcategories: { uri: '/api.php?format=json&action=query&prop=categories&titles=Category:$1&cllimit=max', handler: function ( queryResult ) { if ( queryResult && queryResult.query && queryResult.query.pages ) { for ( var p in queryResult.query.pages ) { if ( queryResult.query.pages[ p ].categories ) { var titles = queryResult.query.pages[ p ].categories; for ( var i = 0; i < titles.length; i++ ) titles[ i ] = titles[ i ].title.substring( titles[ i ].title.indexOf( ':' ) + 1 ); // rm namespace return titles; } } } return null; } } }; var suggestionConfigs = { searchindex: { name: 'Search index', engines: [ 'opensearch' ], cache: {}, show: true, temp: false, noCompletion: false }, pagelist: { name: 'Page list', engines: [ 'internalsearch', 'exists' ], cache: {}, show: true, temp: false, noCompletion: false }, combined: { name: 'Combined search', engines: [ 'opensearch', 'internalsearch' ], cache: {}, show: true, temp: false, noCompletion: false }, subcat: { name: 'Subcategories', engines: [ 'subcategories' ], cache: {}, show: true, temp: true, noCompletion: true }, parentcat: { name: 'Parent categories', engines: [ 'parentcategories' ], cache: {}, show: true, temp: true, noCompletion: true } }; CategoryEditor.UNCHANGED = 0; CategoryEditor.OPEN = 1; // Open, but no input yet CategoryEditor.CHANGE_PENDING = 2; // Open, some input made CategoryEditor.CHANGED = 3; CategoryEditor.DELETED = 4; // Support: IE6 // IE6 sometimes forgets to redraw the list when editors are opened or closed. // Adding/removing a dummy element helps, at least when opening editors. var dummyElement = make( '\xa0', true ); function forceRedraw() { if ( dummyElement.parentNode ) document.body.removeChild( dummyElement ); else document.body.appendChild( dummyElement ); } // Event keyCodes that we handle in the text input field/suggestion list. var BS = 8, TAB = 9, RET = 13, ESC = 27, SPACE = 32, PGUP = 33, PGDOWN = 34, UP = 38, DOWN = 40, DEL = 46, IME = 229; CategoryEditor.prototype = { initialize: function ( line, span, after, key, is_hidden ) { // If a span is given, 'after' is the category title, otherwise it may be an element after which to // insert the new span. 'key' is likewise overloaded; if a span is given, it is the category key (if // known), otherwise it is a boolean indicating whether a bar shall be prepended. if ( !span ) { this.isAddCategory = true; // Create add span and append to catLinks this.originalCategory = ''; this.originalKey = null; this.originalExists = false; if ( !newDOM ) { span = make( 'span' ); span.className = 'noprint'; if ( key ) { span.appendChild( make( ' | ', true ) ); if ( after ) { after.parentNode.insertBefore( span, after.nextSibling ); after = after.nextSibling; } else if (line) { line.appendChild( span ); } } else if ( line && line.firstChild ) { span.appendChild( make( ' ', true ) ); line.appendChild( span ); } } this.linkSpan = make( 'span' ); this.linkSpan.className = 'noprint nopopups hotcatlink'; var lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.open.bind( this ); lk.appendChild( make( HC.links.add, true ) ); lk.title = HC.tooltips.add; this.linkSpan.appendChild( lk ); span = make( newDOM ? 'li' : 'span' ); span.className = 'noprint'; if ( is_rtl ) span.dir = 'rtl'; span.appendChild( this.linkSpan ); if ( after ) { after.parentNode.insertBefore( span, after.nextSibling ); } else if ( line ) { line.appendChild( span ); } this.normalLinks = null; this.undelLink = null; this.catLink = null; } else { if ( is_rtl ) span.dir = 'rtl'; this.isAddCategory = false; this.catLink = span.firstChild; this.originalCategory = after; this.originalKey = ( key && key.length > 1 ) ? key.substr( 1 ) : null; // > 1 because it includes the leading bar this.originalExists = !hasClass( this.catLink, 'new' ); // Create change and del links this.makeLinkSpan(); if ( !this.originalExists && this.upDownLinks ) this.upDownLinks.style.display = 'none'; span.appendChild( this.linkSpan ); } this.originalHidden = is_hidden; this.line = line; this.engine = HC.suggestions; this.span = span; this.currentCategory = this.originalCategory; this.currentExists = this.originalExists; this.currentHidden = this.originalHidden; this.currentKey = this.originalKey; this.state = CategoryEditor.UNCHANGED; this.lastSavedState = CategoryEditor.UNCHANGED; this.lastSavedCategory = this.originalCategory; this.lastSavedKey = this.originalKey; this.lastSavedExists = this.originalExists; this.lastSavedHidden = this.originalHidden; if ( this.catLink && this.currentKey ) this.catLink.title = this.currentKey; editors[ editors.length ] = this; }, makeLinkSpan: function () { this.normalLinks = make( 'span' ); var lk = null; if ( this.originalCategory && this.originalCategory.length ) { lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.remove.bind( this ); lk.appendChild( make( HC.links.remove, true ) ); lk.title = HC.tooltips.remove; this.normalLinks.appendChild( make( ' ', true ) ); this.normalLinks.appendChild( lk ); } if ( !HC.template_categories[ this.originalCategory ] ) { lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.open.bind( this ); lk.appendChild( make( HC.links.change, true ) ); lk.title = HC.tooltips.change; this.normalLinks.appendChild( make( ' ', true ) ); this.normalLinks.appendChild( lk ); if ( !noSuggestions && HC.use_up_down ) { this.upDownLinks = make( 'span' ); lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.down.bind( this ); lk.appendChild( make( HC.links.down, true ) ); lk.title = HC.tooltips.down; this.upDownLinks.appendChild( make( ' ', true ) ); this.upDownLinks.appendChild( lk ); lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.up.bind( this ); lk.appendChild( make( HC.links.up, true ) ); lk.title = HC.tooltips.up; this.upDownLinks.appendChild( make( ' ', true ) ); this.upDownLinks.appendChild( lk ); this.normalLinks.appendChild( this.upDownLinks ); } } this.linkSpan = make( 'span' ); this.linkSpan.className = 'noprint nopopups hotcatlink'; this.linkSpan.appendChild( this.normalLinks ); this.undelLink = make( 'span' ); this.undelLink.className = 'nopopups hotcatlink'; this.undelLink.style.display = 'none'; lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.restore.bind( this ); lk.appendChild( make( HC.links.restore, true ) ); lk.title = HC.tooltips.restore; this.undelLink.appendChild( make( ' ', true ) ); this.undelLink.appendChild( lk ); this.linkSpan.appendChild( this.undelLink ); }, invokeSuggestions: function ( dont_autocomplete ) { if ( this.engine && suggestionConfigs[ this.engine ] && suggestionConfigs[ this.engine ].temp && !dont_autocomplete ) this.engine = HC.suggestions; // Reset to a search upon input this.state = CategoryEditor.CHANGE_PENDING; var self = this; window.setTimeout( function () { self.textchange( dont_autocomplete ); }, HC.suggest_delay ); }, makeForm: function () { var form = make( 'form' ); form.method = 'POST'; form.onsubmit = this.accept.bind( this ); this.form = form; var self = this; var text = make( 'input' ); text.type = 'text'; text.size = HC.editbox_width; if ( !noSuggestions ) { // Be careful here to handle IME input. This is browser/OS/IME dependent, but basically there are two mechanisms: // - Modern (DOM Level 3) browsers use compositionstart/compositionend events to signal composition; if the // composition is not canceled, there'll be a textInput event following. During a composition key events are // either all suppressed (FF/Gecko), or otherwise have keyDown === IME for all keys (Webkit). // - Webkit sends a textInput followed by keyDown === IME and a keyUp with the key that ended composition. // - Gecko doesn't send textInput but just a keyUp with the key that ended composition, without sending keyDown // first. Gecko doesn't send any keydown while IME is active. // - Older browsers signal composition by keyDown === IME for the first and subsequent keys for a composition. The // first keyDown !== IME is certainly after the end of the composition. Typically, composition end can also be // detected by a keyDown IME with a keyUp of space, tab, escape, or return. text.onkeyup = function ( evt ) { var key = evt.keyCode || 0; if ( self.ime && self.lastKey === IME && !self.usesComposition && ( key === TAB || key === RET || key === ESC || key === SPACE ) ) self.ime = false; if ( self.ime ) return true; if ( key === UP || key === DOWN || key === PGUP || key === PGDOWN ) { // In case a browser doesn't generate keypress events for arrow keys... if ( self.keyCount === 0 ) return self.processKey( evt ); } else { if ( key === ESC && self.lastKey !== IME ) { if ( !self.resetKeySelection() ) { // No undo of key selection: treat ESC as "cancel". self.cancel(); return; } } // Also do this for ESC as a workaround for Firefox bug 524360 // https://bugzilla.mozilla.org/show_bug.cgi?id=524360 self.invokeSuggestions( key === BS || key === DEL || key === ESC ); } return true; }; text.onkeydown = function ( evt ) { var key = evt.keyCode || 0; self.lastKey = key; self.keyCount = 0; // DOM Level < 3 IME input if ( !self.ime && key === IME && !self.usesComposition ) { // self.usesComposition catches browsers that may emit spurious keydown IME after a composition has ended self.ime = true; } else if ( self.ime && key !== IME && !( key >= 16 && key <= 20 || key >= 91 && key <= 93 || key === 144 ) ) { // Ignore control keys: ctrl, shift, alt, alt gr, caps lock, windows/apple cmd keys, num lock. Only the windows keys // terminate IME (apple cmd doesn't), but they also cause a blur, so it's OK to ignore them here. // Note: Safari 4 (530.17) propagates ESC out of an IME composition (observed at least on Win XP). self.ime = false; } if ( self.ime ) return true; // Handle return explicitly, to override the default form submission to be able to check for ctrl if ( key === RET ) return self.accept( evt ); // Inhibit default behavior of ESC (revert to last real input in FF: we do that ourselves) return ( key === ESC ) ? evtKill( evt ) : true; }; // And handle continued pressing of arrow keys text.onkeypress = function ( evt ) { self.keyCount++; return self.processKey( evt ); }; $( text ).on( 'focus', function () { makeActive( self ); } ); // On IE, blur events are asynchronous, and may thus arrive after the element has lost the focus. Since IE // can get the selection only while the element is active (has the focus), we may not always get the selection. // Therefore, use an IE-specific synchronous event on IE... // Don't test for text.selectionStart being defined; $( text ).on( ( text.onbeforedeactivate !== undefined && text.createTextRange ) ? 'beforedeactivate' : 'blur', this.saveView.bind( this ) ); // DOM Level 3 IME handling try { // Setting lastKey = IME provides a fake keyDown for Gecko's single keyUp after a cmposition. If we didn't do this, // cancelling a composition via ESC would also cancel and close the whole category input editor. $( text ).on( 'compositionstart', function () { self.lastKey = IME; self.usesComposition = true; self.ime = true; } ); $( text ).on( 'compositionend', function () { self.lastKey = IME; self.usesComposition = true; self.ime = false; } ); $( text ).on( 'textInput', function () { self.ime = false; self.invokeSuggestions( false ); } ); } catch ( any ) { // Just in case some browsers might produce exceptions with these DOM Level 3 events } $( text ).on( 'blur', function () { self.usesComposition = false; self.ime = false; } ); } this.text = text; this.icon = make( 'img' ); var list = null; if ( !noSuggestions ) { list = make( 'select' ); list.onclick = function () { if ( self.highlightSuggestion( 0 ) ) self.textchange( false, true ); }; list.ondblclick = function ( e ) { if ( self.highlightSuggestion( 0 ) ) self.accept( e ); }; list.onchange = function () { self.highlightSuggestion( 0 ); self.text.focus(); }; list.onkeyup = function ( evt ) { if ( evt.keyCode === ESC ) { self.resetKeySelection(); self.text.focus(); window.setTimeout( function () { self.textchange( true ); }, HC.suggest_delay ); } else if ( evt.keyCode === RET ) { self.accept( evt ); } }; if ( !HC.fixed_search ) { var engineSelector = make( 'select' ); for ( var key in suggestionConfigs ) { if ( suggestionConfigs[ key ].show ) { var opt = make( 'option' ); opt.value = key; if ( key === this.engine ) opt.selected = true; opt.appendChild( make( suggestionConfigs[ key ].name, true ) ); engineSelector.appendChild( opt ); } } engineSelector.onchange = function () { self.engine = self.engineSelector.options[ self.engineSelector.selectedIndex ].value; self.text.focus(); self.textchange( true, true ); // Don't autocomplete, force re-display of list }; this.engineSelector = engineSelector; } } this.list = list; function button_label( id, defaultText ) { var label = null; if ( onUpload && window.UFUI !== undefined && window.UIElements !== undefined && UFUI.getLabel instanceof Function ) { try { label = UFUI.getLabel( id, true ); // Extract the plain text. IE doesn't know that Node.TEXT_NODE === 3 while ( label && label.nodeType !== 3 ) label = label.firstChild; } catch ( ex ) { label = null; } } if ( !label || !label.data ) return defaultText; return label.data; } // Do not use type 'submit'; we cannot detect modifier keys if we do var OK = make( 'input' ); OK.type = 'button'; OK.value = button_label( 'wpOkUploadLbl', HC.messages.ok ); OK.onclick = this.accept.bind( this ); this.ok = OK; var cancel = make( 'input' ); cancel.type = 'button'; cancel.value = button_label( 'wpCancelUploadLbl', HC.messages.cancel ); cancel.onclick = this.cancel.bind( this ); this.cancelButton = cancel; var span = make( 'span' ); span.className = 'hotcatinput'; span.style.position = 'relative'; span.appendChild( text ); // Support: IE8, IE9 // Put some text into this span (a0 is nbsp) and make sure it always stays on the same // line as the input field, otherwise, IE8/9 miscalculates the height of the span and // then the engine selector may overlap the input field. span.appendChild( make( '\xa0', true ) ); span.style.whiteSpace = 'nowrap'; if ( list ) span.appendChild( list ); if ( this.engineSelector ) span.appendChild( this.engineSelector ); if ( !noSuggestions ) span.appendChild( this.icon ); span.appendChild( OK ); span.appendChild( cancel ); form.appendChild( span ); form.style.display = 'none'; this.span.appendChild( form ); }, display: function ( evt ) { if ( this.isAddCategory && !onUpload && this.line ) { // eslint-disable-next-line no-new new CategoryEditor( this.line, null, this.span, true ); // Create a new one } if ( !commitButton && !onUpload ) { for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { setMultiInput(); break; } } } if ( !this.form ) this.makeForm(); if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; this.currentCategory = this.lastSavedCategory; this.currentExists = this.lastSavedExists; this.currentHidden = this.lastSavedHidden; this.currentKey = this.lastSavedKey; this.icon.src = ( this.currentExists ? HC.existsYes : HC.existsNo ); this.text.value = this.currentCategory + ( this.currentKey !== null ? '|' + this.currentKey : '' ); this.originalState = this.state; this.lastInput = this.currentCategory; this.inputExists = this.currentExists; this.state = this.state === CategoryEditor.UNCHANGED ? CategoryEditor.OPEN : CategoryEditor.CHANGE_PENDING; this.lastSelection = { start: this.currentCategory.length, end: this.currentCategory.length }; this.showsList = false; // Display the form if ( this.catLink ) this.catLink.style.display = 'none'; this.linkSpan.style.display = 'none'; this.form.style.display = 'inline'; this.ok.disabled = false; // Kill the event before focussing, otherwise IE will kill the onfocus event! var result = evtKill( evt ); this.text.focus(); this.text.readOnly = false; checkMultiInput(); return result; }, show: function ( evt, engine, readOnly ) { var result = this.display( evt ); var v = this.lastSavedCategory; if ( !v.length ) return result; this.text.readOnly = !!readOnly; this.engine = engine; this.textchange( false, true ); // do autocompletion, force display of suggestions forceRedraw(); return result; }, open: function ( evt ) { return this.show( evt, ( this.engine && suggestionConfigs[ this.engine ].temp ) ? HC.suggestions : this.engine ); }, down: function ( evt ) { return this.show( evt, 'subcat', true ); }, up: function ( evt ) { return this.show( evt, 'parentcat' ); }, cancel: function () { if ( this.isAddCategory && !onUpload ) { this.removeEditor(); // We added a new adder when opening return; } // Close, re-display link this.inactivate(); this.form.style.display = 'none'; if ( this.catLink ) this.catLink.style.display = ''; this.linkSpan.style.display = ''; this.state = this.originalState; this.currentCategory = this.lastSavedCategory; this.currentKey = this.lastSavedKey; this.currentExists = this.lastSavedExists; this.currentHidden = this.lastSavedHidden; if ( this.catLink ) if ( this.currentKey && this.currentKey.length ) { this.catLink.title = this.currentKey; } else { this.catLink.title = ''; } if ( this.state === CategoryEditor.UNCHANGED ) { if ( this.catLink ) this.catLink.style.backgroundColor = 'transparent'; } else { if ( !onUpload ) { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } } checkMultiInput(); forceRedraw(); }, removeEditor: function () { if ( !newDOM ) { var next = this.span.nextSibling; if ( next ) next.parentNode.removeChild( next ); } if (this.span && this.span.parentNode) { this.span.parentNode.removeChild( this.span ); } for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ] === this ) { editors.splice( i, 1 ); break; } } checkMultiInput(); }, rollback: function ( evt ) { this.undoLink.parentNode.removeChild( this.undoLink ); this.undoLink = null; this.currentCategory = this.originalCategory; this.currentKey = this.originalKey; this.currentExists = this.originalExists; this.currentHidden = this.originalHidden; this.lastSavedCategory = this.originalCategory; this.lastSavedKey = this.originalKey; this.lastSavedExists = this.originalExists; this.lastSavedHidden = this.originalHidden; this.state = CategoryEditor.UNCHANGED; if ( !this.currentCategory || !this.currentCategory.length ) { // It was a newly added category. Remove the whole editor. this.removeEditor(); } else { // Redisplay the link... this.catLink.removeChild( this.catLink.firstChild ); this.catLink.appendChild( make( this.currentCategory, true ) ); this.catLink.href = wikiPagePath( HC.category_canonical + ':' + this.currentCategory ); this.catLink.title = this.currentKey || ''; this.catLink.className = this.currentExists ? '' : 'new'; this.catLink.style.backgroundColor = 'transparent'; if ( this.upDownLinks ) this.upDownLinks.style.display = this.currentExists ? '' : 'none'; checkMultiInput(); } return evtKill( evt ); }, inactivate: function () { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; this.is_active = false; }, acceptCheck: function ( dontCheck ) { this.sanitizeInput(); var value = this.text.value.split( '|' ); var key = null; if ( value.length > 1 ) key = value[ 1 ]; var v = value[ 0 ].replace( /_/g, ' ' ).replace( /^\s+|\s+$/g, '' ); if ( HC.capitalizePageNames ) v = capitalize( v ); this.lastInput = v; v = replaceShortcuts( v, HC.shortcuts ); if ( !v.length ) { this.cancel(); return false; } if ( !dontCheck && ( conf.wgNamespaceNumber === 14 && v === conf.wgTitle || HC.blacklist && HC.blacklist.test( v ) ) ) { this.cancel(); return false; } this.currentCategory = v; this.currentKey = key; this.currentExists = this.inputExists; return true; }, accept: function ( evt ) { // eslint-disable-next-line no-bitwise this.noCommit = ( evtKeys( evt ) & 1 ) !== 0; var result = evtKill( evt ); if ( this.acceptCheck() ) { var toResolve = [ this ]; var original = this.currentCategory; resolveMulti( toResolve, function ( resolved ) { if ( resolved[ 0 ].dab ) { showDab( resolved[ 0 ] ); } else { if ( resolved[ 0 ].acceptCheck( true ) ) { resolved[ 0 ].commit( ( resolved[ 0 ].currentCategory !== original ) ? HC.messages.cat_resolved.replace( /\$1/g, original ) : null ); } } } ); } return result; }, close: function () { if ( !this.catLink ) { // Create a catLink this.catLink = make( 'a' ); this.catLink.appendChild( make( 'foo', true ) ); this.catLink.style.display = 'none'; this.span.insertBefore( this.catLink, this.span.firstChild.nextSibling ); } this.catLink.removeChild( this.catLink.firstChild ); this.catLink.appendChild( make( this.currentCategory, true ) ); this.catLink.href = wikiPagePath( HC.category_canonical + ':' + this.currentCategory ); this.catLink.className = this.currentExists ? '' : 'new'; this.lastSavedCategory = this.currentCategory; this.lastSavedKey = this.currentKey; this.lastSavedExists = this.currentExists; this.lastSavedHidden = this.currentHidden; // Close form and redisplay category this.inactivate(); this.form.style.display = 'none'; this.catLink.title = this.currentKey || ''; this.catLink.style.display = ''; if ( this.isAddCategory ) { if ( onUpload && this.line ) { // eslint-disable-next-line no-new new CategoryEditor( this.line, null, this.span, true ); // Create a new one } this.isAddCategory = false; this.linkSpan.parentNode.removeChild( this.linkSpan ); this.makeLinkSpan(); this.span.appendChild( this.linkSpan ); } if ( !this.undoLink ) { // Append an undo link. var span = make( 'span' ); var lk = make( 'a' ); lk.href = '#catlinks'; lk.onclick = this.rollback.bind( this ); lk.appendChild( make( HC.links.undo, true ) ); lk.title = HC.tooltips.undo; span.appendChild( make( ' ', true ) ); span.appendChild( lk ); this.normalLinks.appendChild( span ); this.undoLink = span; if ( !onUpload ) { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } } if ( this.upDownLinks ) this.upDownLinks.style.display = this.lastSavedExists ? '' : 'none'; this.linkSpan.style.display = ''; this.state = CategoryEditor.CHANGED; checkMultiInput(); forceRedraw(); }, commit: function () { // Check again to catch problem cases after redirect resolution if ( ( this.currentCategory === this.originalCategory && ( this.currentKey === this.originalKey || this.currentKey === null && !this.originalKey.length ) ) || conf.wgNamespaceNumber === 14 && this.currentCategory === conf.wgTitle || HC.blacklist && HC.blacklist.test( this.currentCategory ) ) { this.cancel(); return; } this.close(); if ( !commitButton && !onUpload ) { var self = this; initiateEdit( function ( failure ) { performChanges( failure, self ); }, function ( msg ) { alert( msg ); } ); } }, remove: function ( evt ) { // eslint-disable-next-line no-bitwise this.doRemove( evtKeys( evt ) & 1 ); return evtKill( evt ); }, doRemove: function ( noCommit ) { if ( this.isAddCategory ) { // Empty input on adding a new category this.cancel(); return; } if ( !commitButton && !onUpload ) { for ( var i = 0; i < editors.length; i++ ) { if ( editors[ i ].state !== CategoryEditor.UNCHANGED ) { setMultiInput(); break; } } } if ( commitButton ) { this.catLink.title = ''; this.catLink.style.cssText += '; text-decoration : line-through !important;'; try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} this.originalState = this.state; this.state = CategoryEditor.DELETED; this.normalLinks.style.display = 'none'; this.undelLink.style.display = ''; checkMultiInput(); } else { if ( onUpload ) { // Remove this editor completely this.removeEditor(); } else { this.originalState = this.state; this.state = CategoryEditor.DELETED; this.noCommit = noCommit || HC.del_needs_diff; var self = this; initiateEdit( function ( failure ) { performChanges( failure, self ); }, function ( msg ) { self.state = self.originalState; alert( msg ); } ); } } }, restore: function ( evt ) { // Can occur only if we do have a commit button and are not on the upload form this.catLink.title = this.currentKey || ''; this.catLink.style.textDecoration = ''; this.state = this.originalState; if ( this.state === CategoryEditor.UNCHANGED ) { this.catLink.style.backgroundColor = 'transparent'; } else { try { this.catLink.style.backgroundColor = HC.bg_changed; } catch ( ex ) {} } this.normalLinks.style.display = ''; this.undelLink.style.display = 'none'; checkMultiInput(); return evtKill( evt ); }, // Internal operations selectEngine: function ( engineName ) { if ( !this.engineSelector ) return; for ( var i = 0; i < this.engineSelector.options.length; i++ ) this.engineSelector.options[ i ].selected = this.engineSelector.options[ i ].value === engineName; }, sanitizeInput: function () { var v = this.text.value || ''; v = v.replace( /^(\s|_)+/, '' ); // Trim leading blanks and underscores var re = new RegExp( '^(' + HC.category_regexp + '):' ); if ( re.test( v ) ) v = v.substring( v.indexOf( ':' ) + 1 ).replace( /^(\s|_)+/, '' ); v = v.replace(/\u200E$/, ''); // Trim ending left-to-right mark if ( HC.capitalizePageNames ) v = capitalize( v ); // Update the input field if needed, manually restoring the cursor afterwards // (but not the whole selection, so that further typing does not overwrite anything) if ( this.text.value !== null && this.text.value !== v ) { var cursorPos = this.text.selectionStart; this.text.value = v; this.text.setSelectionRange( cursorPos, cursorPos ); } }, makeCall: function ( url, callbackObj, engine, queryKey, cleanKey ) { var cb = callbackObj, e = engine, v = queryKey, z = cleanKey, thisObj = this; function done() { cb.callsMade++; if ( cb.callsMade === cb.nofCalls ) { if ( cb.exists ) cb.allTitles.exists = true; if ( cb.normalized ) cb.allTitles.normalized = cb.normalized; if ( !cb.dontCache && !suggestionConfigs[ cb.engineName ].cache[ z ] ) suggestionConfigs[ cb.engineName ].cache[ z ] = cb.allTitles; thisObj.text.readOnly = false; if ( !cb.cancelled ) thisObj.showSuggestions( cb.allTitles, cb.noCompletion, v, cb.engineName ); if ( cb === thisObj.callbackObj ) thisObj.callbackObj = null; cb = undefined; } } $.getJSON( url, function ( json ) { var titles = e.handler( json, z ); if ( titles && titles.length ) { if ( cb.allTitles === null ) cb.allTitles = titles; else cb.allTitles = cb.allTitles.concat( titles ); if ( titles.exists ) cb.exists = true; if ( titles.normalized ) cb.normalized = titles.normalized; } done(); } ).fail( function ( req ) { if ( !req ) noSuggestions = true; cb.dontCache = true; done(); } ); }, callbackObj: null, textchange: function ( dont_autocomplete, force ) { // Hide all other lists makeActive( this ); // Get input value, omit sort key, if any this.sanitizeInput(); var v = this.text.value; // Disregard anything after a pipe. var pipe = v.indexOf( '|' ); if ( pipe >= 0 ) { this.currentKey = v.substring( pipe + 1 ); v = v.substring( 0, pipe ); } else { this.currentKey = null; } if ( this.lastInput === v && !force ) return; // No change if ( this.lastInput !== v ) checkMultiInput(); this.lastInput = v; this.lastRealInput = v; // Mark blacklisted inputs. this.ok.disabled = v.length && HC.blacklist && HC.blacklist.test( v ); if ( noSuggestions ) { // No Ajax: just make sure the list is hidden if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( this.icon ) this.icon.style.display = 'none'; return; } if ( !v.length ) { this.showSuggestions( [] ); return; } var cleanKey = v.replace( /[\u200E\u200F\u202A-\u202E]/g, '' ).replace( wikiTextBlankRE, ' ' ); cleanKey = replaceShortcuts( cleanKey, HC.shortcuts ); cleanKey = cleanKey.replace( /^\s+|\s+$/g, '' ); if ( !cleanKey.length ) { this.showSuggestions( [] ); return; } if ( this.callbackObj ) this.callbackObj.cancelled = true; var engineName = suggestionConfigs[ this.engine ] ? this.engine : 'combined'; dont_autocomplete = dont_autocomplete || suggestionConfigs[ engineName ].noCompletion; if ( suggestionConfigs[ engineName ].cache[ cleanKey ] ) { this.showSuggestions( suggestionConfigs[ engineName ].cache[ cleanKey ], dont_autocomplete, v, engineName ); return; } var engines = suggestionConfigs[ engineName ].engines; this.callbackObj = { allTitles: null, callsMade: 0, nofCalls: engines.length, noCompletion: dont_autocomplete, engineName: engineName }; this.makeCalls( engines, this.callbackObj, v, cleanKey ); }, makeCalls: function ( engines, cb, v, cleanKey ) { for ( var j = 0; j < engines.length; j++ ) { var engine = suggestionEngines[ engines[ j ] ]; var url = wgServer + conf.wgScriptPath + engine.uri.replace( /\$1/g, encodeURIComponent( cleanKey ) ); this.makeCall( url, cb, engine, v, cleanKey ); } }, showSuggestions: function ( titles, dontAutocomplete, queryKey, engineName ) { this.text.readOnly = false; this.dab = null; this.showsList = false; if ( !this.list ) return; if ( noSuggestions ) { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( this.icon ) this.icon.style.display = 'none'; this.inputExists = true; // Default... return; } this.engineName = engineName; if ( engineName ) { if ( !this.engineSelector ) this.engineName = null; } else { if ( this.engineSelector ) this.engineSelector.style.display = 'none'; } if ( queryKey ) { if ( this.lastInput.indexOf( queryKey ) ) return; if ( this.lastQuery && this.lastInput.indexOf( this.lastQuery ) === 0 && this.lastQuery.length > queryKey.length ) return; } this.lastQuery = queryKey; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; v = ( HC.capitalizePageNames ? capitalize( v[ 0 ] ) : v[ 0 ] ); var vNormalized = v; var knownToExist = titles && titles.exists; var i; if ( titles ) { if ( titles.normalized && v.indexOf( queryKey ) === 0 ) { // We got back a different normalization than what is in the input field vNormalized = titles.normalized + v.substring( queryKey.length ); } var vLow = vNormalized.toLowerCase(); // Strip blacklisted categories if ( HC.blacklist ) { for ( i = 0; i < titles.length; i++ ) { if ( HC.blacklist.test( titles[ i ] ) ) { titles.splice( i, 1 ); i--; } } } titles.sort( function ( a, b ) { if ( a === b ) return 0; if ( a.indexOf( b ) === 0 ) return 1; // a begins with b: a > b if ( b.indexOf( a ) === 0 ) return -1; // b begins with a: a < b // Opensearch may return stuff not beginning with the search prefix! var prefixMatchA = ( a.indexOf( vNormalized ) === 0 ? 1 : 0 ); var prefixMatchB = ( b.indexOf( vNormalized ) === 0 ? 1 : 0 ); if ( prefixMatchA !== prefixMatchB ) return prefixMatchB - prefixMatchA; // Case-insensitive prefix match! var aLow = a.toLowerCase(), bLow = b.toLowerCase(); prefixMatchA = ( aLow.indexOf( vLow ) === 0 ? 1 : 0 ); prefixMatchB = ( bLow.indexOf( vLow ) === 0 ? 1 : 0 ); if ( prefixMatchA !== prefixMatchB ) return prefixMatchB - prefixMatchA; if ( a < b ) return -1; if ( b < a ) return 1; return 0; } ); // Remove duplicates and self-references for ( i = 0; i < titles.length; i++ ) { if ( i + 1 < titles.length && titles[ i ] === titles[ i + 1 ] || conf.wgNamespaceNumber === 14 && titles[ i ] === conf.wgTitle ) { titles.splice( i, 1 ); i--; } } } if ( !titles || !titles.length ) { if ( this.list ) this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { if ( this.icon ) this.icon.src = HC.existsNo; this.inputExists = false; } return; } var firstTitle = titles[ 0 ]; var completed = this.autoComplete( firstTitle, v, vNormalized, key, dontAutocomplete ); var existing = completed || knownToExist || firstTitle === replaceShortcuts( v, HC.shortcuts ); if ( engineName && suggestionConfigs[ engineName ] && !suggestionConfigs[ engineName ].temp ) { this.icon.src = ( existing ? HC.existsYes : HC.existsNo ); this.inputExists = existing; } if ( completed ) { this.lastInput = firstTitle; if ( titles.length === 1 ) { this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; return; } } // (Re-)fill the list while ( this.list.firstChild ) this.list.removeChild( this.list.firstChild ); for ( i = 0; i < titles.length; i++ ) { var opt = make( 'option' ); opt.appendChild( make( titles[ i ], true ) ); opt.selected = completed && ( i === 0 ); this.list.appendChild( opt ); } this.displayList(); }, displayList: function () { this.showsList = true; if ( !this.is_active ) { this.list.style.display = 'none'; if ( this.engineSelector ) this.engineSelector.style.display = 'none'; return; } var nofItems = ( this.list.options.length > HC.listSize ? HC.listSize : this.list.options.length ); if ( nofItems <= 1 ) nofItems = 2; this.list.size = nofItems; this.list.style.align = is_rtl ? 'right' : 'left'; this.list.style.zIndex = 5; this.list.style.position = 'absolute'; // Compute initial list position. First the height. var anchor = is_rtl ? 'right' : 'left'; var listh = 0; if ( this.list.style.display === 'none' ) { // Off-screen display to get the height this.list.style.top = this.text.offsetTop + 'px'; this.list.style[ anchor ] = '-10000px'; this.list.style.display = ''; listh = this.list.offsetHeight; this.list.style.display = 'none'; } else { listh = this.list.offsetHeight; } // Approximate calculation of maximum list size var maxListHeight = listh; if ( nofItems < HC.listSize ) maxListHeight = ( listh / nofItems ) * HC.listSize; function viewport( what ) { if ( is_webkit && !document.evaluate ) { // Safari < 3.0 return window[ 'inner' + what ]; } var s = 'client' + what; if ( window.opera ) return document.body[ s ]; return ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; } function scroll_offset( what ) { var s = 'scroll' + what; var result = ( document.documentElement ? document.documentElement[ s ] : 0 ) || document.body[ s ] || 0; if ( is_rtl && what === 'Left' ) { // RTL inconsistencies. // FF: 0 at the far right, then increasingly negative values. // IE >= 8: 0 at the far right, then increasingly positive values. // Webkit: scrollWidth - clientWidth at the far right, then down to zero. // Opera: don't know... if ( result < 0 ) result = -result; if ( !is_webkit ) result = scroll_offset( 'Width' ) - viewport( 'Width' ) - result; // Now all have webkit behavior, i.e. zero if at the leftmost edge. } return result; } function position( node ) { // Stripped-down simplified position function. It's good enough for our purposes. if ( node.getBoundingClientRect ) { var box = node.getBoundingClientRect(); return { x: Math.round( box.left + scroll_offset( 'Left' ) ), y: Math.round( box.top + scroll_offset( 'Top' ) ) }; } var t = 0, l = 0; do { t += ( node.offsetTop || 0 ); l += ( node.offsetLeft || 0 ); node = node.offsetParent; } while ( node ); return { x: l, y: t }; } var textPos = position( this.text ), nl = 0, nt = 0, offset = 0, // Opera 9.5 somehow has offsetWidth = 0 here?? Use the next best value... textBoxWidth = this.text.offsetWidth || this.text.clientWidth; if ( this.engineName ) { this.engineSelector.style.zIndex = 5; this.engineSelector.style.position = 'absolute'; this.engineSelector.style.width = textBoxWidth + 'px'; // Figure out the height of this selector: display it off-screen, then hide it again. if ( this.engineSelector.style.display === 'none' ) { this.engineSelector.style[ anchor ] = '-10000px'; this.engineSelector.style.top = '0'; this.engineSelector.style.display = ''; offset = this.engineSelector.offsetHeight; this.engineSelector.style.display = 'none'; } else { offset = this.engineSelector.offsetHeight; } this.engineSelector.style[ anchor ] = nl + 'px'; } if ( textPos.y < maxListHeight + offset + 1 ) { // The list might extend beyond the upper border of the page. Let's avoid that by placing it // below the input text field. nt = this.text.offsetHeight + offset + 1; if ( this.engineName ) this.engineSelector.style.top = this.text.offsetHeight + 'px'; } else { nt = -listh - offset - 1; if ( this.engineName ) this.engineSelector.style.top = -( offset + 1 ) + 'px'; } this.list.style.top = nt + 'px'; this.list.style.width = ''; // No fixed width (yet) this.list.style[ anchor ] = nl + 'px'; if ( this.engineName ) { this.selectEngine( this.engineName ); this.engineSelector.style.display = ''; } this.list.style.display = 'block'; // Set the width of the list if ( this.list.offsetWidth < textBoxWidth ) { this.list.style.width = textBoxWidth + 'px'; return; } // If the list is wider than the textbox: make sure it fits horizontally into the browser window var scroll = scroll_offset( 'Left' ); var view_w = viewport( 'Width' ); var w = this.list.offsetWidth; var l_pos = position( this.list ); var left = l_pos.x; var right = left + w; if ( left < scroll || right > scroll + view_w ) { if ( w > view_w ) { w = view_w; this.list.style.width = w + 'px'; if ( is_rtl ) left = right - w; else right = left + w; } var relative_offset = 0; if ( left < scroll ) relative_offset = scroll - left; else if ( right > scroll + view_w ) relative_offset = -( right - scroll - view_w ); if ( is_rtl ) relative_offset = -relative_offset; if ( relative_offset ) this.list.style[ anchor ] = ( nl + relative_offset ) + 'px'; } }, autoComplete: function ( newVal, actVal, normalizedActVal, key, dontModify ) { if ( newVal === actVal ) return true; if ( dontModify || this.ime || !this.canSelect() ) return false; // If we can't select properly or an IME composition is ongoing, autocompletion would be a major annoyance to the user. if ( newVal.indexOf( actVal ) ) { // Maybe it'll work with the normalized value (NFC)? if ( normalizedActVal && newVal.indexOf( normalizedActVal ) === 0 ) { if ( this.lastRealInput === actVal ) this.lastRealInput = normalizedActVal; actVal = normalizedActVal; } else { return false; } } // Actual input is a prefix of the new text. Fill in new text, selecting the newly added suffix // such that it can be easily removed by typing backspace if the suggestion is unwanted. this.text.focus(); this.text.value = newVal + key; this.setSelection( actVal.length, newVal.length ); return true; }, canSelect: function () { return this.text.setSelectionRange || this.text.createTextRange || this.text.selectionStart !== undefined && this.text.selectionEnd !== undefined; }, setSelection: function ( from, to ) { // this.text must be focused (at least on IE) if ( !this.text.value ) return; if ( this.text.setSelectionRange ) { // e.g. khtml this.text.setSelectionRange( from, to ); } else if ( this.text.selectionStart !== undefined ) { if ( from > this.text.selectionStart ) { this.text.selectionEnd = to; this.text.selectionStart = from; } else { this.text.selectionStart = from; this.text.selectionEnd = to; } } else if ( this.text.createTextRange ) { // IE var new_selection = this.text.createTextRange(); new_selection.move( 'character', from ); new_selection.moveEnd( 'character', to - from ); new_selection.select(); } }, getSelection: function () { var from = 0, to = 0; // this.text must be focused (at least on IE) if ( !this.text.value ) { // No text. } else if ( this.text.selectionStart !== undefined ) { from = this.text.selectionStart; to = this.text.selectionEnd; } else if ( document.selection && document.selection.createRange ) { // IE var rng = document.selection.createRange().duplicate(); if ( rng.parentElement() === this.text ) { try { var textRng = this.text.createTextRange(); textRng.move( 'character', 0 ); textRng.setEndPoint( 'EndToEnd', rng ); // We're in a single-line input box: no need to care about IE's strange // handling of line ends to = textRng.text.length; textRng.setEndPoint( 'EndToStart', rng ); from = textRng.text.length; } catch ( notFocused ) { from = this.text.value.length; to = from; // At end of text } } } return { start: from, end: to }; }, saveView: function () { this.lastSelection = this.getSelection(); }, processKey: function ( evt ) { var dir = 0; switch ( this.lastKey ) { case UP: dir = -1; break; case DOWN: dir = 1; break; case PGUP: dir = -HC.listSize; break; case PGDOWN: dir = HC.listSize; break; case ESC: // Inhibit default behavior (revert to last real input in FF: we do that ourselves) return evtKill( evt ); } if ( dir ) { if ( this.list.style.display !== 'none' ) { // List is visible, so there are suggestions this.highlightSuggestion( dir ); // Kill the event, otherwise some browsers (e.g., Firefox) may additionally treat an up-arrow // as "place the text cursor at the front", which we don't want here. return evtKill( evt ); } else if ( this.keyCount <= 1 && ( !this.callbackObj || this.callbackObj.callsMade === this.callbackObj.nofCalls ) ) { // If no suggestions displayed, get them, unless we're already getting them. this.textchange(); } } return true; }, highlightSuggestion: function ( dir ) { if ( noSuggestions || !this.list || this.list.style.display === 'none' ) return false; var curr = this.list.selectedIndex; var tgt = -1; if ( dir === 0 ) { if ( curr < 0 || curr >= this.list.options.length ) return false; tgt = curr; } else { tgt = curr < 0 ? 0 : curr + dir; tgt = tgt < 0 ? 0 : tgt; if ( tgt >= this.list.options.length ) tgt = this.list.options.length - 1; } if ( tgt !== curr || dir === 0 ) { if ( curr >= 0 && curr < this.list.options.length && dir !== 0 ) this.list.options[ curr ].selected = false; this.list.options[ tgt ].selected = true; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; var completed = this.autoComplete( this.list.options[ tgt ].text, this.lastRealInput, null, key, false ); if ( !completed || this.list.options[ tgt ].text === this.lastRealInput ) { this.text.value = this.list.options[ tgt ].text + key; if ( this.canSelect() ) this.setSelection( this.list.options[ tgt ].text.length, this.list.options[ tgt ].text.length ); } this.lastInput = this.list.options[ tgt ].text; this.inputExists = true; // Might be wrong if from a dab list... if ( this.icon ) this.icon.src = HC.existsYes; this.state = CategoryEditor.CHANGE_PENDING; } return true; }, resetKeySelection: function () { if ( noSuggestions || !this.list || this.list.style.display === 'none' ) return false; var curr = this.list.selectedIndex; if ( curr >= 0 && curr < this.list.options.length ) { this.list.options[ curr ].selected = false; // Get current input text var v = this.text.value.split( '|' ); var key = v.length > 1 ? '|' + v[ 1 ] : ''; // ESC is handled strangely by some browsers (e.g., FF); somehow it resets the input value before // our event handlers ever get a chance to run. var result = v[ 0 ] !== this.lastInput; if ( v[ 0 ] !== this.lastRealInput ) { this.text.value = this.lastRealInput + key; result = true; } this.lastInput = this.lastRealInput; return result; } return false; } }; // end CategoryEditor.prototype function initialize() { // User configurations: Do this here, called from the onload handler, so that users can // override it easily in their own user script files by just declaring variables. JSconfig // is some feature used at Wikimedia Commons. var config = ( window.JSconfig !== undefined && JSconfig.keys ) ? JSconfig.keys : {}; HC.dont_add_to_watchlist = ( window.hotcat_dont_add_to_watchlist !== undefined ? !!window.hotcat_dont_add_to_watchlist : ( config.HotCatDontAddToWatchlist !== undefined ? config.HotCatDontAddToWatchlist : HC.dont_add_to_watchlist ) ); HC.no_autocommit = ( window.hotcat_no_autocommit !== undefined ? !!window.hotcat_no_autocommit : ( config.HotCatNoAutoCommit !== undefined ? config.HotCatNoAutoCommit : // On talk namespace default autocommit off ( conf.wgNamespaceNumber % 2 ? true : HC.no_autocommit ) ) ); HC.del_needs_diff = ( window.hotcat_del_needs_diff !== undefined ? !!window.hotcat_del_needs_diff : ( config.HotCatDelNeedsDiff !== undefined ? config.HotCatDelNeedsDiff : HC.del_needs_diff ) ); HC.suggest_delay = window.hotcat_suggestion_delay || config.HotCatSuggestionDelay || HC.suggest_delay; HC.editbox_width = window.hotcat_editbox_width || config.HotCatEditBoxWidth || HC.editbox_width; HC.suggestions = window.hotcat_suggestions || config.HotCatSuggestions || HC.suggestions; if ( typeof HC.suggestions !== 'string' || !suggestionConfigs[ HC.suggestions ] ) HC.suggestions = 'combined'; HC.fixed_search = ( window.hotcat_suggestions_fixed !== undefined ? !!window.hotcat_suggestions_fixed : ( config.HotCatFixedSuggestions !== undefined ? config.HotCatFixedSuggestions : HC.fixed_search ) ); HC.single_minor = ( window.hotcat_single_changes_are_minor !== undefined ? !!window.hotcat_single_changes_are_minor : ( config.HotCatMinorSingleChanges !== undefined ? config.HotCatMinorSingleChanges : HC.single_minor ) ); HC.bg_changed = window.hotcat_changed_background || config.HotCatChangedBackground || HC.bg_changed; HC.use_up_down = ( window.hotcat_use_category_links !== undefined ? !!window.hotcat_use_category_links : ( config.HotCatUseCategoryLinks !== undefined ? config.HotCatUseCategoryLinks : HC.use_up_down ) ); HC.listSize = window.hotcat_list_size || config.HotCatListSize || HC.listSize; if ( conf.wgDBname !== 'commonswiki' ) HC.changeTag = config.HotCatChangeTag || ''; // The next whole shebang is needed, because manual tags get not submitted except of save if ( HC.changeTag ) { var eForm = document.editform, catRegExp = new RegExp( '^\\[\\[(' + HC.category_regexp + '):' ), oldTxt; // Returns true if minor change var isMinorChange = function () { var newTxt = eForm.wpTextbox1; if ( !newTxt ) return; newTxt = newTxt.value; var oldLines = oldTxt.match( /^.*$/gm ), newLines = newTxt.match( /^.*$/gm ), cArr; // changes var except = function ( aArr, bArr ) { var result = [], lArr, // larger sArr; // smaller if ( aArr.length < bArr.length ) { lArr = bArr; sArr = aArr; } else { lArr = aArr; sArr = bArr; } for ( var i = 0; i < lArr.length; i++ ) { var item = lArr[ i ]; var ind = $.inArray( item, sArr ); if ( ind === -1 ) result.push( item ); else sArr.splice( ind, 1 ); // don't check this item again } return result.concat( sArr ); }; cArr = except( oldLines, newLines ); if ( cArr.length ) { cArr = $.grep( cArr, function ( c ) { c = $.trim( c ); return ( c && !catRegExp.test( c ) ); } ); } if ( !cArr.length ) { oldTxt = newTxt; return true; } }; if ( conf.wgAction === 'submit' && conf.wgArticleId && eForm && eForm.wpSummary && document.getElementById( 'wikiDiff' ) ) { var sum = eForm.wpSummary, sumA = eForm.wpAutoSummary; if ( sum.value && sumA.value === HC.changeTag ) { // HotCat diff // MD5 hash of the empty string, as HotCat edit is based on empty sum sumA.value = sumA.value.replace( HC.changeTag, 'd41d8cd98f00b204e9800998ecf8427e' ); // Attr creation and event handling is not same in all (old) browsers so use $ var $ct = $( '<input type="hidden" name="wpChangeTags">' ).val( HC.changeTag ); $( eForm ).append( $ct ); oldTxt = eForm.wpTextbox1.value; $( '#wpSave' ).one( 'click', function () { if ( $ct.val() ) sum.value = sum.value.replace( ( HC.messages.using || HC.messages.prefix ), '' ); } ); var removeChangeTag = function () { $( eForm.wpTextbox1 ).add( sum ).one( 'input', function () { window.setTimeout( function () { if ( !isMinorChange() ) $ct.val( '' ); else removeChangeTag(); }, 500 ); } ); }; removeChangeTag(); } } } // Numeric input, make sure we have a numeric value HC.listSize = parseInt( HC.listSize, 10 ); if ( isNaN( HC.listSize ) || HC.listSize < 5 ) HC.listSize = 5; HC.listSize = Math.min( HC.listSize, 30 ); // Max size // Localize search engine names if ( HC.engine_names ) { for ( var key in HC.engine_names ) if ( suggestionConfigs[ key ] && HC.engine_names[ key ] ) suggestionConfigs[ key ].name = HC.engine_names[ key ]; } // Catch both native RTL and "faked" RTL through [[MediaWiki:Rtl.js]] is_rtl = hasClass( document.body, 'rtl' ); if ( !is_rtl ) { if ( document.defaultView && document.defaultView.getComputedStyle ) { // Gecko etc. is_rtl = document.defaultView.getComputedStyle( document.body, null ).getPropertyValue( 'direction' ); } else if ( document.body.currentStyle ) { // IE, has subtle differences to getComputedStyle is_rtl = document.body.currentStyle.direction; } else { // Not exactly right, but best effort is_rtl = document.body.style.direction; } is_rtl = ( is_rtl === 'rtl' ); } } function can_edit() { var container = null; switch ( mw.config.get( 'skin' ) ) { case 'cologneblue': container = document.getElementById( 'quickbar' ); /* fall through */ case 'standard': case 'nostalgia': if ( !container ) container = document.getElementById( 'topbar' ); var lks = container.getElementsByTagName( 'a' ); for ( var i = 0; i < lks.length; i++ ) { if ( param( 'title', lks[ i ].href ) === conf.wgPageName && param( 'action', lks[ i ].href ) === 'edit' ) { return true; } } return false; default: // all modern skins: return document.getElementById( 'ca-edit' ) !== null; } } // Legacy stuff function closeForm() { // Close all open editors without redirect resolution and other asynchronous stuff. for ( var i = 0; i < editors.length; i++ ) { var edit = editors[ i ]; if ( edit.state === CategoryEditor.OPEN ) { edit.cancel(); } else if ( edit.state === CategoryEditor.CHANGE_PENDING ) { edit.sanitizeInput(); var value = edit.text.value.split( '|' ); var key = null; if ( value.length > 1 ) key = value[ 1 ]; var v = value[ 0 ].replace( /_/g, ' ' ).replace( /^\s+|\s+$/g, '' ); if ( !v.length ) { edit.cancel(); } else { edit.currentCategory = v; edit.currentKey = key; edit.currentExists = this.inputExists; edit.close(); } } } } function setup_upload() { onUpload = true; // Add an empty category bar at the end of the table containing the description, and change the onsubmit handler. var ip = document.getElementById( 'mw-htmlform-description' ) || document.getElementById( 'wpDestFile' ); if ( !ip ) { ip = document.getElementById( 'wpDestFile' ); while ( ip && ip.nodeName.toLowerCase() !== 'table' ) ip = ip.parentNode; } if ( !ip ) return; var reupload = document.getElementById( 'wpForReUpload' ); var destFile = document.getElementById( 'wpDestFile' ); if ( ( reupload && !!reupload.value ) || ( destFile && ( destFile.disabled || destFile.readOnly ) ) ) { return; // re-upload form... } // Insert a table row with two fields (label and empty category bar) var labelCell = make( 'td' ); var lineCell = make( 'td' ); // Create the category line catLine = make( 'div' ); catLine.className = 'catlinks'; catLine.id = 'catlinks'; catLine.style.textAlign = is_rtl ? 'right' : 'left'; // We'll be inside a table row. Make sure that we don't have margins or strange borders. catLine.style.margin = '0'; catLine.style.border = 'none'; lineCell.appendChild( catLine ); // Create the label var label = null; if ( window.UFUI && window.UIElements && UFUI.getLabel instanceof Function ) { try { label = UFUI.getLabel( 'wpCategoriesUploadLbl' ); } catch ( ex ) { label = null; } } if ( !label ) { labelCell.id = 'hotcatLabel'; labelCell.appendChild( make( HC.categories, true ) ); } else { labelCell.id = 'hotcatLabelTranslated'; labelCell.appendChild( label ); } labelCell.className = 'mw-label'; labelCell.style.textAlign = 'right'; labelCell.style.verticalAlign = 'middle'; // Change the onsubmit handler var form = document.getElementById( 'upload' ) || document.getElementById( 'mw-upload-form' ); if ( form && ip && ip.insertRow ) { var newRow = ip.insertRow( -1 ); newRow.appendChild( labelCell ); newRow.appendChild( lineCell ); form.onsubmit = ( function ( oldSubmit ) { return function () { var do_submit = true; if ( oldSubmit ) { if ( typeof oldSubmit === 'string' ) { // eslint-disable-next-line no-eval do_submit = eval( oldSubmit ); } else if ( oldSubmit instanceof Function ) { do_submit = oldSubmit.apply( form, arguments ); } } if ( !do_submit ) return false; closeForm(); // Copy the categories var eb = document.getElementById( 'wpUploadDescription' ) || document.getElementById( 'wpDesc' ); var addedOne = false; for ( var i = 0; i < editors.length; i++ ) { var t = editors[ i ].currentCategory; if ( !t ) continue; var key = editors[ i ].currentKey; var new_cat = '[[' + HC.category_canonical + ':' + t + ( key ? '|' + key : '' ) + ']]'; // Only add if not already present var cleanedText = eb.value .replace( /<!--(\s|\S)*?-->/g, '' ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, '' ); if ( !find_category( cleanedText, t, true ) ) { eb.value += '\n' + new_cat; addedOne = true; } } if ( addedOne ) { // Remove "subst:unc" added by Flinfo if it didn't find categories eb.value = eb.value.replace( /\{\{subst:unc\}\}/g, '' ); } return true; }; }( form.onsubmit ) ); } } var cleanedText = null; function isOnPage( span ) { if ( span.firstChild.nodeType !== Node.ELEMENT_NODE ) return null; var catTitle = title( span.firstChild.getAttribute( 'href' ) ); if ( !catTitle ) return null; catTitle = catTitle.substr( catTitle.indexOf( ':' ) + 1 ).replace( /_/g, ' ' ); if ( HC.blacklist && HC.blacklist.test( catTitle ) ) return null; var result = { title: catTitle, match: [ '', '', '' ] }; if ( pageText === null ) return result; if ( cleanedText === null ) { cleanedText = pageText .replace( /<!--(\s|\S)*?-->/g, '' ) .replace( /<nowiki>(\s|\S)*?<\/nowiki>/g, '' ); } result.match = find_category( cleanedText, catTitle, true ); return result; } var initialized = false; var setupTimeout = null; function findByClass( scope, tag, className ) { var result = $( scope ).find( tag + '.' + className ); return ( result && result.length ) ? result[ 0 ] : null; } function errorAMC() { alert( 'An error occurred. Unable to setup HotCat' ); } function enableAMC() { var api = new mw.Api(); return api.saveOption( 'mf_amc_optin', '1' ).then( function ( r ) { if ( !r || r.options !== 'success' ) { errorAMC(); return; } if ( window.confirm( 'Please reload your page to use hotcat.' ) ) { location.reload(); } }, function () { errorAMC(); } ); } function showWarning( text ) { var warning = document.createElement( 'div' ); warning.setAttribute( 'style', 'padding: 20px; background: var(--wikt-palette-amber-0,orange); color: var(--wikt-palette-black,#333); font-weight: bold; margin-top: 20px;' ); warning.textContent = text; var btn = document.createElement( 'button' ); btn.classList.add( 'mw-ui-button', 'cdx-button' ); btn.style.display = 'block'; btn.textContent = 'Enable HotCat and AMC mode on this page'; btn.addEventListener( 'click', function () { enableAMC(); } ); warning.appendChild( btn ); document.getElementById( 'mw-content-text' ).appendChild( warning ); } function setup( additionalWork ) { if ( initialized ) return; initialized = true; if ( setupTimeout ) { window.clearTimeout( setupTimeout ); setupTimeout = null; } // Find the category bar, or create an empty one if there isn't one. Then add -/+- links after // each category, and add the + link. catLine = // Special:Upload catLine || document.getElementById( 'mw-normal-catlinks' ); var hiddenCats = document.getElementById( 'mw-hidden-catlinks' ); if ( !catLine ) { // Workaround for T24660 if ( mw.config.get('skin') === 'minerva' ) { if ( document.body.classList.contains('mw-mf-amc-disabled') ) { showWarning( 'HotCat requires AMC mode.' ); } } var footer = null; if ( !hiddenCats ) { footer = findByClass( document, 'div', 'printfooter' ); if ( !footer ) return; // Don't know where to insert the category line } catLine = make( 'div' ); catLine.id = 'mw-normal-catlinks'; catLine.style.textAlign = is_rtl ? 'right' : 'left'; // Add a label var label = make( 'a' ); label.href = conf.wgArticlePath.replace( '$1', 'Special:Categories' ); label.title = HC.categories; label.appendChild( make( HC.categories, true ) ); catLine.appendChild( label ); catLine.appendChild( make( ':', true ) ); // Insert the new category line var container = ( hiddenCats ? hiddenCats.parentNode : document.getElementById( 'catlinks' ) ); if ( !container ) { container = make( 'div' ); container.id = 'catlinks'; footer.parentNode.insertBefore( container, footer.nextSibling ); } container.className = 'catlinks noprint'; container.style.display = ''; if ( !hiddenCats ) container.appendChild( catLine ); else container.insertBefore( catLine, hiddenCats ); } // end if catLine exists if ( is_rtl ) catLine.dir = 'rtl'; // Create editors for all existing categories function createEditors( line, is_hidden ) { var i; var cats = line.getElementsByTagName( 'li' ); if ( cats.length ) { newDOM = true; line = cats[ 0 ].parentNode; } else { cats = line.getElementsByTagName( 'span' ); } // Copy cats, otherwise it'll also magically contain our added spans as it is a live collection! var copyCats = new Array( cats.length ); for ( i = 0; i < cats.length; i++ ) copyCats[ i ] = cats[ i ]; for ( i = 0; i < copyCats.length; i++ ) { var test = isOnPage( copyCats[ i ] ); if ( test !== null && test.match !== null && line ) { // eslint-disable-next-line no-new new CategoryEditor( line, copyCats[ i ], test.title, test.match[ 2 ], is_hidden ); } } return copyCats.length ? copyCats[ copyCats.length - 1 ] : null; } var lastSpan = createEditors( catLine, false ); // Create one to add a new category // eslint-disable-next-line no-new new CategoryEditor( newDOM ? catLine.getElementsByTagName( 'ul' )[ 0 ] : catLine, null, null, lastSpan !== null, false ); if ( !onUpload ) { if ( pageText !== null && hiddenCats ) { if ( is_rtl ) hiddenCats.dir = 'rtl'; createEditors( hiddenCats, true ); } // And finally add the "multi-mode" span. (Do this at the end, otherwise it ends up in the list above.) var enableMulti = make( 'span' ); enableMulti.className = 'noprint'; if ( is_rtl ) enableMulti.dir = 'rtl'; catLine.insertBefore( enableMulti, catLine.firstChild.nextSibling ); enableMulti.appendChild( make( '\xa0', true ) ); // nbsp multiSpan = make( 'span' ); enableMulti.appendChild( multiSpan ); multiSpan.innerHTML = '(<a>' + HC.addmulti + '</a>)'; var lk = multiSpan.getElementsByTagName( 'a' )[ 0 ]; lk.onclick = function ( evt ) { setMultiInput(); checkMultiInput(); return evtKill( evt ); }; lk.title = HC.multi_tooltip; lk.style.cursor = 'pointer'; } cleanedText = null; if ( additionalWork instanceof Function ) additionalWork(); mw.hook( 'hotcat.ready' ).fire(); // Execute registered callback functions $( 'body' ).trigger( 'hotcatSetupCompleted' ); } function createCommitForm() { if ( commitForm ) return; var formContainer = make( 'div' ); formContainer.style.display = 'none'; document.body.appendChild( formContainer ); formContainer.innerHTML = '<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="' + conf.wgScript + '?title=' + encodeURIComponent( conf.wgPageName ) + '&action=submit">' + '<input type="hidden" name="wpTextbox1">' + '<input type="hidden" name="model" value="' + conf.wgPageContentModel + '">' + '<input type="hidden" name="format" value="text/x-wiki">' + '<input type="hidden" name="wpSummary" value="">' + '<input type="checkbox" name="wpMinoredit" value="1">' + '<input type="checkbox" name="wpWatchthis" value="1">' + '<input type="hidden" name="wpAutoSummary" value="d41d8cd98f00b204e9800998ecf8427e">' + '<input type="hidden" name="wpEdittime">' + '<input type="hidden" name="wpStarttime">' + '<input type="hidden" name="wpDiff" value="wpDiff">' + '<input type="hidden" name="oldid" value="0">' + '<input type="hidden" name="wpIgnoreBlankSummary" value="1">' + '<input type="submit" name="hcCommit" value="hcCommit">' + '<input type="hidden" name="wpEditToken">' + '<input type="hidden" name="wpUltimateParam" value="1">' + '<input type="hidden" name="wpChangeTags">' + '<input type="hidden" value="ℳ𝒲♥𝓊𝓃𝒾𝒸ℴ𝒹ℯ" name="wpUnicodeCheck">' + '</form>'; commitForm = document.getElementById( 'hotcatCommitForm' ); } function getPage() { // We know we have an article here. if ( !conf.wgArticleId ) { // Doesn't exist yet. Disable on non-existing User pages -- might be a global user page. if ( conf.wgNamespaceNumber === 2 ) return; pageText = ''; pageTime = null; setup( createCommitForm ); } else { var url = wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&rawcontinue=&titles=' + encodeURIComponent( conf.wgPageName ) + '&prop=info%7Crevisions&rvprop=content%7Ctimestamp%7Cids&meta=siteinfo&rvlimit=1&rvstartid=' + conf.wgCurRevisionId; var s = make( 'script' ); s.src = url; HC.start = function ( json ) { setPage( json ); setup( createCommitForm ); }; document.getElementsByTagName( 'head' )[ 0 ].appendChild( s ); setupTimeout = window.setTimeout( function () { setup( createCommitForm ); }, 4000 ); // 4 sec, just in case getting the wikitext takes longer. } } function setState( state ) { var cats = state.split( '\n' ); if ( !cats.length ) return null; if ( initialized && editors.length === 1 && editors[ 0 ].isAddCategory ) { // Insert new spans and create new editors for them. var newSpans = []; var before = editors.length === 1 ? editors[ 0 ].span : null; var i; for ( i = 0; i < cats.length; i++ ) { if ( !cats[ i ].length ) continue; var cat = cats[ i ].split( '|' ); var key = cat.length > 1 ? cat[ 1 ] : null; cat = cat[ 0 ]; var lk = make( 'a' ); lk.href = wikiPagePath( HC.category_canonical + ':' + cat ); lk.appendChild( make( cat, true ) ); lk.title = cat; var span = make( 'span' ); span.appendChild( lk ); if ( !i ) catLine.insertBefore( make( ' ', true ), before ); catLine.insertBefore( span, before ); if ( before && i + 1 < cats.length ) parent.insertBefore( make( ' | ', true ), before ); newSpans.push( { element: span, title: cat, key: key } ); } // And change the last one... if ( before ) before.parentNode.insertBefore( make( ' | ', true ), before ); for ( i = 0; i < newSpans.length; i++ ) { // eslint-disable-next-line no-new new CategoryEditor( catLine, newSpans[ i ].element, newSpans[ i ].title, newSpans[ i ].key ); } } return null; } function getState() { var result = null; for ( var i = 0; i < editors.length; i++ ) { var text = editors[ i ].currentCategory; var key = editors[ i ].currentKey; if ( text && text.length ) { if ( key !== null ) text += '|' + key; if ( result === null ) result = text; else result += '\n' + text; } } return result; } function really_run() { en_wiktionary_get_langdata(function() { initialize(); if ( !HC.upload_disabled && conf.wgNamespaceNumber === -1 && conf.wgCanonicalSpecialPageName === 'Upload' && conf.wgUserName ) { setup_upload(); setup( function () { // Check for state restoration once the setup is done otherwise, but before signalling setup completion if ( window.UploadForm && UploadForm.previous_hotcat_state ) UploadForm.previous_hotcat_state = setState( UploadForm.previous_hotcat_state ); } ); } else { if ( !conf.wgIsArticle || conf.wgAction !== 'view' || param( 'diff' ) !== null || param( 'oldid' ) !== null || !can_edit() || HC.disable() ) return; getPage(); } }); } function run() { if ( HC.started ) return; HC.started = true; loadTrigger.register( really_run ); } // Export legacy functions window.hotcat_get_state = function () { return getState(); }; window.hotcat_set_state = function ( state ) { return setState( state ); }; window.hotcat_close_form = function () { closeForm(); }; HC.runWhenReady = function ( callback ) { // run user-registered code once HotCat is fully set up and ready. mw.hook( 'hotcat.ready' ).add( callback ); }; // Make sure we don't get conflicts with AjaxCategories (core development that should one day // replace HotCat). mw.config.set( 'disableAJAXCategories', true ); // Run as soon as possible. This varies depending on MediaWiki version; // window's 'load' event is always safe, but usually we can do better than that. if ( conf.wgCanonicalSpecialPageName !== 'Upload' ) { // Reload HotCat after (VE) edits (bug T103285) mw.hook( 'postEdit' ).add( function () { // Reset HotCat in case this is a soft reload (e.g. VisualEditor edit), unless the categories // were not re-rendered and our interface is still there (e.g. DiscussionTools edit) if ( document.querySelector( '#catlinks .hotcatlink' ) ) { return; } catLine = null; editors = []; initialized = false; HC.started = false; run(); } ); } // We can safely trigger just after user configuration is loaded. // Use always() instead of then() to also start HotCat if the user module has problems. $.when( mw.loader.using( 'user' ), $.ready ).always( run ); }( jQuery, mediaWiki ) ); // </nowiki> qp2yp9147ad7pkve4h3sqrco2yhn5th MediaWiki:Gadget-FastRevert.js 8 18004 89011 2021-12-14T04:07:21Z en>Erutuon 0 add revert link next to bottom edit 89011 javascript text/javascript /** ************* FastRevert ******************* * Allows one to restore an old version * * * * Author: Quentinv57, for Wikimedia * * -- 06 Feb. 2010 -- * ******************************************** */ $( document ).ready( function () { if (mw.util.getParamValue('action') === 'history') { var chemin = '//en.wiktionary.org/w/index.php?action=edit&retablir'; var pageHistory = document.getElementById('pagehistory'); pageHistory = pageHistory && pageHistory.getElementsByTagName('li'); var prevUser; for (var i = 0; i < pageHistory.length; i++) { var li = pageHistory[i]; var oldid = li.dataset.mwRevid; // data-mw-revid="..." var userLink = li.querySelector(".history-user .mw-userlink"); // Get inside of bdi tag if it's present. while (userLink.firstElementChild) { userLink = userLink.firstElementChild; } var username = userLink.textContent; if (i !== 0) { var revertLink = document.createElement( "a" ); revertLink.href = chemin + '&oldid=' + oldid + '&user=' + username + '&user2=' + prevUser; revertLink.appendChild( document.createTextNode( "FastRevert" ) ); li.appendChild( document.createTextNode( " \u2014 (" ) ); li.appendChild( revertLink ); li.appendChild( document.createTextNode( ")" ) ); } prevUser = username; } } else if (location.href.match(/&retablir&/)) { var user2 = mw.util.getParamValue('user2'); var message = prompt( 'What message do you want to leave?', 'Reverted edits by [[Special:Contributions/' + user2 + '|' + user2 + ']]' ); var user = mw.util.getParamValue('user'); document.getElementById('wpSummary').value = (message ? message + '; ' : '') + 'Restore to version ' + mw.util.getParamValue('oldid') + ' by [[Special:Contributions/' + user + '|' + user + ']]'; if (message != null) document.getElementById('editform').submit(); } }); 4v10c32kaz8zwq5wmz28zdpaglqxslq 89012 89011 2026-08-06T23:33:33Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-FastRevert.js]] 89011 javascript text/javascript /** ************* FastRevert ******************* * Allows one to restore an old version * * * * Author: Quentinv57, for Wikimedia * * -- 06 Feb. 2010 -- * ******************************************** */ $( document ).ready( function () { if (mw.util.getParamValue('action') === 'history') { var chemin = '//en.wiktionary.org/w/index.php?action=edit&retablir'; var pageHistory = document.getElementById('pagehistory'); pageHistory = pageHistory && pageHistory.getElementsByTagName('li'); var prevUser; for (var i = 0; i < pageHistory.length; i++) { var li = pageHistory[i]; var oldid = li.dataset.mwRevid; // data-mw-revid="..." var userLink = li.querySelector(".history-user .mw-userlink"); // Get inside of bdi tag if it's present. while (userLink.firstElementChild) { userLink = userLink.firstElementChild; } var username = userLink.textContent; if (i !== 0) { var revertLink = document.createElement( "a" ); revertLink.href = chemin + '&oldid=' + oldid + '&user=' + username + '&user2=' + prevUser; revertLink.appendChild( document.createTextNode( "FastRevert" ) ); li.appendChild( document.createTextNode( " \u2014 (" ) ); li.appendChild( revertLink ); li.appendChild( document.createTextNode( ")" ) ); } prevUser = username; } } else if (location.href.match(/&retablir&/)) { var user2 = mw.util.getParamValue('user2'); var message = prompt( 'What message do you want to leave?', 'Reverted edits by [[Special:Contributions/' + user2 + '|' + user2 + ']]' ); var user = mw.util.getParamValue('user'); document.getElementById('wpSummary').value = (message ? message + '; ' : '') + 'Restore to version ' + mw.util.getParamValue('oldid') + ' by [[Special:Contributions/' + user + '|' + user + ']]'; if (message != null) document.getElementById('editform').submit(); } }); 4v10c32kaz8zwq5wmz28zdpaglqxslq MediaWiki:Gadget-ChangesByLanguage.js 8 18005 89013 2024-01-17T04:58:37Z en>This, that and the other 0 make the gadget aware of the "new" recent changes 89013 javascript text/javascript ( [ "Recentchanges", "Watchlist", "Recentchangeslinked" ] ).indexOf( mw.config.get( "wgCanonicalSpecialPageName" ) ) !== -1 && $( function () { var diffLinksSelector = ".mw-changeslist .special li > .mw-changeslist-line-inner > a:first-child, .mw-enhanced-rc .mw-title + a, .mw-enhanced-rc-nested a[tabindex] + a"; var getRevisions = ( function () { var revRequests = {}, pRequests = {}; function sendRequests( requests, isPageid ) { var pendingReqs = []; $.each( requests, function ( i, req ) { if ( !req.status ) { pendingReqs.push( i ); req.status = 1; } } ); for ( var i = 0; i < pendingReqs.length; i += 50 ) { var query = { action: 'query', prop: 'revisions', rvprop: 'content|ids', maxage: 60 * 60 * 12, smaxage: 60 * 60 * 12 }; query[ isPageid ? 'pageids' : 'revids' ] = pendingReqs.slice( i, i + 50 ).join( '|' ); ( new mw.Api() ).get( query ).done( function ( results ) { $.each( results.query.pages, function ( id, revision ) { $.each( revision.revisions, function ( i, rev ) { var rid = isPageid ? id : rev.revid, result = requests[ rid ].result = rev[ '*' ]; requests[ rid ].status = 2; $.each( requests[ rid ], function ( i, callback ) { callback( result ); } ); } ); } ); } ); } } return function getRevisions( id, callback, isPageid ) { if ( id ) { var requests = isPageid ? pRequests : revRequests, req = requests[ id ] || ( requests[ id ] = [] ); if ( callback ) { if ( !req.status || req.status === 1 ) { req.push( callback ); } else { callback( req.result ); } } } else { sendRequests( pRequests, true ); sendRequests( revRequests, false ); } return getRevisions; }; } )(); function getSection( content, language ) { var start = content.indexOf( '==' + language + '==' ), end = content.substr( start ).search( /$|\n==[^=]/ ); if ( start === -1 ) { return false; } else { return content .substr( start, end ) // Don't count a new section being added below as a change. .replace( /[\n \-]+$/g, '' ) // Filter out translations sections. .replace( /(\{\{(?:check)?trans-top[^\}]*\}\})[\s\S]*?(?=\{\{(?:check)?trans-bottom\}\})/g, '$1' ); } } function getTranslations( content, language ) { var t = content .match( new RegExp( '\n[\\*\\:]+\\s*' + language + ': [^\n]+', 'g' ) ); return t ? t.join( '\n' ) : ''; } function getLanguage() { return languageData .split( /\s*[,|]\s*/g) // Remove empty strings .filter( function ( x ) { return x; } ); } function hideFiltered() { if ( !languages || !languages.length ) { return; } $( diffLinksSelector ).each( function( i, diffLink ) { var href = diffLink.href, oldid = mw.util.getParamValue( "oldid", href ), curid = mw.util.getParamValue( "diff", href ), title = mw.util.getParamValue( "title", href ); if ( title && !title.includes( ":" ) && oldid && curid ) { getRevisions( curid ); getRevisions( oldid, function ( oldRevision ) { getRevisions( curid, function ( curRevision ) { var show = languages.some( function ( language ) { var oldSection = getSection( oldRevision, language ), newSection = getSection( curRevision, language ); if ( oldSection !== newSection ) { return true; } else if ( getTranslations( oldRevision, language ) !== getTranslations( curRevision, language ) ) { return true; } } ); if ( !show ) { diffLink.parentNode.parentNode.style.display = 'none'; } } ); } ); } } ); // Newly created pages, without diff links. $( '.newpage' ).prev().prev().each( function ( i, histLink ) { var href = histLink.href, curid = mw.util.getParamValue( "curid", href ); getRevisions( curid, function ( curRevision ) { var show = languages.some( function ( language ) { if ( getSection( curRevision, language ) || getTranslations( curRevision, language ) ) { return true; } } ); if ( !show ) { histLink.parentNode.parentNode.style.display = 'none'; } }, true ); } ); // Send the API requests. getRevisions(); } function showAll() { $( '.mw-changeslist .special li' ).show(); } // Settings var options = document.querySelector( "#mw-watchlist-options, .rcoptions, .mw-rcfilters-head" ), optionsDiv = document.createElement( "div" ), input, languages, languageData, isEnhanced = $( '.mw-enhanced-rc, .mw-rcfilters-head' ).length; if ( options ) { options.appendChild( document.createElement( "hr" ) ).style.margin = "8px 0"; if ( isEnhanced ) { // If "Enhanced recent changes" is enabled, this script doesn't work. optionsDiv.appendChild( document.createTextNode( '(The "Recent changes by language" gadget requires the "Use non-JavaScript interface" preference to be ON and the "Group changes by page" preference to be OFF.)' ) ); options.appendChild( optionsDiv ); } else { optionsDiv.appendChild( document.createTextNode( 'Languages: ' ) ); input = optionsDiv.appendChild( document.createElement( 'input' ) ); languageData = ( input.value = ( localStorage[ 'YR-rcbl' ] || '' ) ); languages = getLanguage(); input.onkeydown = input.onkeyup = function ( e ) { languageData = localStorage[ 'YR-rcbl' ] = this.value; if ( e.keyCode === 13 && e.type === 'keydown' ) { languages = getLanguage(); showAll(); hideFiltered(); e.preventDefault && e.preventDefault(); return false; } }; input.onblur = function () { languageData = localStorage[ 'YR-rcbl' ] = this.value; languages = getLanguage(); showAll(); hideFiltered(); }; options.appendChild( optionsDiv ); // Run hideFiltered(); } } } ); jn2ameweu3sqdms3gimerf9lemwt7k7 89014 89013 2026-08-06T23:33:41Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-ChangesByLanguage.js]] 89013 javascript text/javascript ( [ "Recentchanges", "Watchlist", "Recentchangeslinked" ] ).indexOf( mw.config.get( "wgCanonicalSpecialPageName" ) ) !== -1 && $( function () { var diffLinksSelector = ".mw-changeslist .special li > .mw-changeslist-line-inner > a:first-child, .mw-enhanced-rc .mw-title + a, .mw-enhanced-rc-nested a[tabindex] + a"; var getRevisions = ( function () { var revRequests = {}, pRequests = {}; function sendRequests( requests, isPageid ) { var pendingReqs = []; $.each( requests, function ( i, req ) { if ( !req.status ) { pendingReqs.push( i ); req.status = 1; } } ); for ( var i = 0; i < pendingReqs.length; i += 50 ) { var query = { action: 'query', prop: 'revisions', rvprop: 'content|ids', maxage: 60 * 60 * 12, smaxage: 60 * 60 * 12 }; query[ isPageid ? 'pageids' : 'revids' ] = pendingReqs.slice( i, i + 50 ).join( '|' ); ( new mw.Api() ).get( query ).done( function ( results ) { $.each( results.query.pages, function ( id, revision ) { $.each( revision.revisions, function ( i, rev ) { var rid = isPageid ? id : rev.revid, result = requests[ rid ].result = rev[ '*' ]; requests[ rid ].status = 2; $.each( requests[ rid ], function ( i, callback ) { callback( result ); } ); } ); } ); } ); } } return function getRevisions( id, callback, isPageid ) { if ( id ) { var requests = isPageid ? pRequests : revRequests, req = requests[ id ] || ( requests[ id ] = [] ); if ( callback ) { if ( !req.status || req.status === 1 ) { req.push( callback ); } else { callback( req.result ); } } } else { sendRequests( pRequests, true ); sendRequests( revRequests, false ); } return getRevisions; }; } )(); function getSection( content, language ) { var start = content.indexOf( '==' + language + '==' ), end = content.substr( start ).search( /$|\n==[^=]/ ); if ( start === -1 ) { return false; } else { return content .substr( start, end ) // Don't count a new section being added below as a change. .replace( /[\n \-]+$/g, '' ) // Filter out translations sections. .replace( /(\{\{(?:check)?trans-top[^\}]*\}\})[\s\S]*?(?=\{\{(?:check)?trans-bottom\}\})/g, '$1' ); } } function getTranslations( content, language ) { var t = content .match( new RegExp( '\n[\\*\\:]+\\s*' + language + ': [^\n]+', 'g' ) ); return t ? t.join( '\n' ) : ''; } function getLanguage() { return languageData .split( /\s*[,|]\s*/g) // Remove empty strings .filter( function ( x ) { return x; } ); } function hideFiltered() { if ( !languages || !languages.length ) { return; } $( diffLinksSelector ).each( function( i, diffLink ) { var href = diffLink.href, oldid = mw.util.getParamValue( "oldid", href ), curid = mw.util.getParamValue( "diff", href ), title = mw.util.getParamValue( "title", href ); if ( title && !title.includes( ":" ) && oldid && curid ) { getRevisions( curid ); getRevisions( oldid, function ( oldRevision ) { getRevisions( curid, function ( curRevision ) { var show = languages.some( function ( language ) { var oldSection = getSection( oldRevision, language ), newSection = getSection( curRevision, language ); if ( oldSection !== newSection ) { return true; } else if ( getTranslations( oldRevision, language ) !== getTranslations( curRevision, language ) ) { return true; } } ); if ( !show ) { diffLink.parentNode.parentNode.style.display = 'none'; } } ); } ); } } ); // Newly created pages, without diff links. $( '.newpage' ).prev().prev().each( function ( i, histLink ) { var href = histLink.href, curid = mw.util.getParamValue( "curid", href ); getRevisions( curid, function ( curRevision ) { var show = languages.some( function ( language ) { if ( getSection( curRevision, language ) || getTranslations( curRevision, language ) ) { return true; } } ); if ( !show ) { histLink.parentNode.parentNode.style.display = 'none'; } }, true ); } ); // Send the API requests. getRevisions(); } function showAll() { $( '.mw-changeslist .special li' ).show(); } // Settings var options = document.querySelector( "#mw-watchlist-options, .rcoptions, .mw-rcfilters-head" ), optionsDiv = document.createElement( "div" ), input, languages, languageData, isEnhanced = $( '.mw-enhanced-rc, .mw-rcfilters-head' ).length; if ( options ) { options.appendChild( document.createElement( "hr" ) ).style.margin = "8px 0"; if ( isEnhanced ) { // If "Enhanced recent changes" is enabled, this script doesn't work. optionsDiv.appendChild( document.createTextNode( '(The "Recent changes by language" gadget requires the "Use non-JavaScript interface" preference to be ON and the "Group changes by page" preference to be OFF.)' ) ); options.appendChild( optionsDiv ); } else { optionsDiv.appendChild( document.createTextNode( 'Languages: ' ) ); input = optionsDiv.appendChild( document.createElement( 'input' ) ); languageData = ( input.value = ( localStorage[ 'YR-rcbl' ] || '' ) ); languages = getLanguage(); input.onkeydown = input.onkeyup = function ( e ) { languageData = localStorage[ 'YR-rcbl' ] = this.value; if ( e.keyCode === 13 && e.type === 'keydown' ) { languages = getLanguage(); showAll(); hideFiltered(); e.preventDefault && e.preventDefault(); return false; } }; input.onblur = function () { languageData = localStorage[ 'YR-rcbl' ] = this.value; languages = getLanguage(); showAll(); hideFiltered(); }; options.appendChild( optionsDiv ); // Run hideFiltered(); } } } ); jn2ameweu3sqdms3gimerf9lemwt7k7 MediaWiki:Gadget-DefSideBoxes.js 8 18006 89015 2025-09-17T01:08:42Z en>Ioaxxere 0 Polyfill deprecated function newNode 89015 javascript text/javascript // Newer version of User:Yair rand/editor.js // <nowiki> // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** var autoTranslitScripts = { "Geor": true }; window.makedefsidebox = function(q) { function clickiconfunction() { var moreoptions, originalHeight, buttons; function uncollapse() { $(moreoptions).slideUp(); $("body").off("click", uncollapse); } editdefinition(q); if ($('>.addusexbutton', q).length === 0) { buttons = q.insertBefore(newNode('div', { 'class': 'addusexbutton' }, newNode('a', '+Add example sentence', { 'click': function() { setupusexadder(q); } }), newNode('a', '+Add quotation', { 'click': function() { setupquoteadder(q); } }), newNode('a', 'More ►', { 'click': function() { $(moreoptions).slideDown(); setTimeout(function() { $("body").click(uncollapse); }, 16); } }), newNode('span', { 'style': 'display:inline-block;' }, moreoptions = newNode('ul', newNode('li', q.className ? newNode('a', 'Edit gloss', { 'click': function() { editgloss(q); } }) : newNode('a', 'Add gloss', { 'click': function() { addgloss(q); } })), newNode('li', newNode('a', q.className ? undefined : { 'class': 'DSBinactive', 'title': 'Please add a gloss before adding synonyms.' }, { 'click': function() { setupnymadder(q, "Synonyms"); } }, 'Add synonyms')), newNode('li', newNode('a', q.className ? undefined : { 'class': 'DSBinactive', 'title': 'Please add a gloss before adding antonyms.' }, { 'click': function() { setupnymadder(q, "Antonyms"); } }, 'Add antonyms')), newNode('li', newNode('a', { 'href': mw.config.get('wgScript') + '?title=User_talk:Yair_rand/editor2.js&action=edit&section=new' }, 'Give feedback on this tool')), newNode('li', newNode('a', { click: function() { $.cookie("DisableYREdit", 1, { path: '/' }); location.href = location.href; } }, 'Disable this tool'))))), $('>dl,>ul,>ol', q)[0] || null); } } q.insertBefore( newNode('span', { 'class': 'defEditButton' }, newNode('span', { 'click': clickiconfunction, 'title': 'Edit' })), q.firstChild); return clickiconfunction; } function setupusexadder(qq) { var x, y; var usexform; var findsubdef = (qq.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "") + (qq.parentNode.parentNode.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "") editor = new Editor() findlang(qq.parentNode, function(findlang_) { var findscript = (new LangMetadata()).getScripts(findlang_), selectedscript = findscript[0] || "Latn"; if (qq.getElementsByTagName('dl')[0] && qq.getElementsByTagName('dl')[0].parentNode == qq) x = qq.getElementsByTagName('dl')[0]; else if ($(">ul", qq).length > 0) x = qq.insertBefore(newNode('dl'), $(">ul", qq)[0]); else x = qq.appendChild(newNode('dl')); x.appendChild(y = newNode('dd')) new AdderWrapper(new Editor(), { 'createForm': function() { var x, i = 0, y = function() { selectedscript = this.value; usexform.getElementsByTagName('dd')[0].style.display = this.value == 'Latn' ? 'none' : 'block' } if (findscript.length > 1) { for (x = newNode('select', { 'name': 'script', 'change': y }); i < findscript.length; i++) { x.appendChild(newNode('option', { 'value': findscript[i] }, findscript[i])) } } else { x = newNode('input', { 'name': 'script', 'value': findscript[0] || "Latn", 'style': "width:50px;", 'change': y }) } return usexform = newNode('form', { 'style': 'display:inline;' }, newNode('input', { 'size': 100, 'placeholder': 'Example sentence', 'name': 'examplesentence' }), newNode('span', { 'style': 'display:' + (findscript.length == 1 ? "none" : "inline") + ";" }, 'Script: ', x), newNode('div', { 'class': "DSBRedButton", 'click': function() { usexform.style.display = 'none' } }, newNode('div', 'Cancel')), newNode('div', { 'class': "DSBGreenButton", 'click': function() { usexform.onsubmit() } }, newNode('div', "Preview ►")), newNode('input', { 'type': 'submit', 'style': 'visibility:hidden;width:0px;' }), newNode('dl', (findlang_ == "en" ? { 'style': 'display:none;' } : ''), newNode('dd', 'Transliteration: ', ((findscript[0] == 'Latn' || !findscript[0]) ? { 'style': 'display:none;' } : ''), newNode('input', { 'size': '100px', name: 'transliteration' })), newNode('dd', 'Translation: ', newNode('input', { 'size': '100px', name: 'translation' })))) }, 'fields': { 'examplesentence': function(txt, error) { return util.validateNoWikisyntax('example sentence', true)(txt, error) }, 'transliteration': function(txt, error) { return txt || ''; }, 'translation': function(txt, error) { if (findlang_ != "en") { return util.validateNoWikisyntax('translation', true)(txt, error); } return ''; }, 'script': util.validateNoWikisyntax('script', true) }, 'onsubmit': function(values, render) { var renderWikitext = ""; if (findlang_ === "en") renderWikitext = "''" + values.examplesentence + "''"; else { renderWikitext = "{" + "{ux|" + findlang_ + "|" + values.examplesentence + "|" + values.translation; if (values.script) { renderWikitext += "|sc=" + values.script; if (!(values.script in autoTranslitScripts) && values.transliteration) renderWikitext += "|tr=" + values.transliteration; } renderWikitext += "}}"; } render(renderWikitext, function(newhtml) { var findnumberofheaders = findnumberofheaders_(qq); var findnumberofdefs = findnumberofdefs_(qq); var usextobeadded = newNode('span') usextobeadded.innerHTML = newhtml.replace(/<p>|<\/p>/g, ''); editor.addEdit({ edit: function(wikitext) { var usexWikitext = renderWikitext; wikitext = wikitext.replace(RegExp( "(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?)\n(?!#" + findsubdef + ":)|$"), "$1\n#" + findsubdef + ":" + usexWikitext + "\n"); ccc = wikitext; return wikitext; }, redo: function() { usexform.parentNode.appendChild(usextobeadded); usextobeadded.style.display = 'block'; usexform.style.display = "none"; y.style.display = 'block' }, undo: function() { usexform.parentNode.removeChild(usextobeadded); usexform.style.display = "inline"; }, summary: "+usex: " + values.examplesentence }, usextobeadded) }) } }, y) usexform.firstChild.focus() }) } window.editdefinition = function(qq) { (new Editor).withCurrentText(function(wikitext) { if (qq.YREditing) { return } qq.YREditing = true; var findnumberofheaders = findnumberofheaders_(qq), findnumberofdefs = findnumberofdefs_(qq) var temporarydefholder = qq.insertBefore(newNode('span', { 'style': 'display:none;' }), qq.childNodes[1].nodeName.toLowerCase() != "form" ? qq.childNodes[1] : qq.childNodes[2]) while (qq.childNodes[3] && qq.childNodes[3].nodeName != "DL" && qq.childNodes[3].nodeName != "UL" && qq.childNodes[3].nodeName != "OL" && qq.childNodes[3].className != "HQToggle" && qq.childNodes[3].className != "addusexbutton") temporarydefholder.appendChild(qq.childNodes[3]); if (qq.childNodes[2] != temporarydefholder) temporarydefholder.insertBefore(qq.childNodes[2], temporarydefholder.firstChild); var defform var olddef = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?)"), '').match(/^(\{\{senseid\|[^\}]*\}\})?\s?(.*)/)[2] new AdderWrapper(new Editor(), { 'createForm': function() { return defform = newNode('form', { 'style': 'width:100%;display:inline-block;margin-bottom:-6px;' }, newNode('table', { 'style': 'width:100%;' }, newNode('tr', newNode('td', newNode('input', { 'style': 'height:17px;width:100%;', 'name': 'definition', 'size': 80, 'value': olddef }) // newNode('input',{type:'submit',value:'Preview'}), // newNode('input',{type:'button',value:'Cancel',click:function(){temporarydefholder.style.display='inline';defform.style.display='none';qq.YREditing = false}}) ), newNode('td', { 'style': 'white-space:nowrap;' }, newNode('div', { 'class': "DSBRedButton" }, newNode('div', { click: function() { temporarydefholder.style.display = 'inline'; defform.style.display = 'none'; qq.YREditing = false } }, "Discard Changes")), newNode('div', { 'class': "DSBGreenButton" }, newNode('div', { click: function() { defform.onsubmit() } }, "Preview Changes ►")))))) }, 'fields': { 'definition': function(txt, error) { return txt || error("Please specify a definition.") } }, 'onsubmit': function(values, render) { render(values.definition, function(newhtml) { editor = new Editor() var findnumberofdefs = findnumberofdefs_(qq) // apparently this is sometimes necessary var addedspan = newNode('span') addedspan.innerHTML = newhtml var updatecatscallback; editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?(\{\{senseid\\|[^\}]*\}\})*?)(?!{" + "{senseid\\|).*"), "$1" + values.definition); ccc = wikitext; return wikitext }, redo: function() { defform.parentNode.insertBefore(addedspan, defform); defform.style.display = temporarydefholder.style.display = 'none'; updatecatscallback = window.tabbedLanguages && updateCategories(findtopli(defform.parentNode).parentNode.parentNode, values.definition, olddef) qq.YREditing = false; }, undo: function() { defform.parentNode.removeChild(addedspan); defform.style.display = "inline"; defform.firstChild.firstChild.firstChild.firstChild.value = olddef; updatecatscallback && updatecatscallback(); qq.YREditing = true; }, summary: "def: " + values.definition }, addedspan) }) } }, qq, qq.childNodes[1].nodeName.toLowerCase() != "form" ? qq.childNodes[1] : qq.childNodes[2]) }) } function findtopli(li) { for (; li.parentNode.parentNode.nodeName.toLowerCase() == "li";) { li = li.parentNode.parentNode; } return li; } function findnumberofheaders_(tosearchfrom) { tosearchfrom = findtopli(tosearchfrom).parentNode; while (!tosearchfrom.nodeName.match(/^h\d$/i)) tosearchfrom = tosearchfrom.previousSibling; return Number(tosearchfrom.lastChild.getElementsByTagName('a')[0].href.match(/\d*$/)) } function findnumberofdefs_(tosearchfrom) { var findnumberofdefs = [], tosearchfrom_, findnumberofpredefs = 0, result; // subdefinitions while (tosearchfrom.nodeName.toLowerCase() == "li") { tosearchfrom_ = tosearchfrom; findnumberofdefs.splice(0, 0, 0); while (tosearchfrom) { if (tosearchfrom.nodeName.toLowerCase() == "li") findnumberofdefs[0]++; tosearchfrom = tosearchfrom.previousSibling; } tosearchfrom = tosearchfrom_.parentNode.parentNode; } // in case of any def lists before the current def list under the same header for (tosearchfrom_ = tosearchfrom_.parentNode.previousSibling; !tosearchfrom_.nodeName.match(/^h\d$/i); tosearchfrom_ = tosearchfrom_.previousSibling) { if (tosearchfrom_.nodeName.toLowerCase() == "ol") findnumberofpredefs += 1; } result = "([\\s\\S]*?\n#[\\s\\S]*?\n(?!#)){" + findnumberofpredefs + "}"; for (var i = 0; i < findnumberofdefs.length; i++) { result += "([\\s\\S]*?\n" + Array(i + 2).join("#") + "(?![:*#])){" + findnumberofdefs[i] + "}"; } return result; } function findlang(tosearchfrom, callback) { var tosearchfrom_, findlang__ if (tosearchfrom.parentNode.nodeName.toLowerCase() == "li") tosearchfrom = findtopli(tosearchfrom.parentNode).parentNode; if (tosearchfrom.parentNode.className == "languageContainer") { if (tosearchfrom.parentNode.id == "Englishcontainer") return callback("en"); } else { tosearchfrom_ = tosearchfrom; while (tosearchfrom_.nodeName.toLowerCase() != "h2") tosearchfrom_ = tosearchfrom_.previousSibling; if (tosearchfrom_.lastChild.innerHTML == "English") return callback("en"); } tosearchfrom_ = tosearchfrom; while (tosearchfrom_ && !/^h\d$/i.test(tosearchfrom_.nodeName) && tosearchfrom_.className != "fakeheader") tosearchfrom_ = tosearchfrom_.previousSibling; while (tosearchfrom_ && tosearchfrom_.nodeName.toLowerCase() != "p" && tosearchfrom_.className != "fakeheader") tosearchfrom_ = tosearchfrom_.nextSibling; if (tosearchfrom_ && tosearchfrom_.className != "fakeheader" && tosearchfrom_.firstChild && (tosearchfrom_.firstChild.lang || (tosearchfrom_.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.lang) || (tosearchfrom_.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.firstChild.lang))) { return callback(tosearchfrom_.firstChild.lang || tosearchfrom_.firstChild.firstChild.lang || tosearchfrom_.firstChild.firstChild.firstChild.lang) } if (tosearchfrom.parentNode.className == "languageContainer") findlang__ = tosearchfrom.parentNode.id.split("container")[0]; else { while (tosearchfrom.nodeName.toLowerCase() != "h2") tosearchfrom = tosearchfrom.previousSibling; findlang__ = (findlang__ = tosearchfrom.getElementsByTagName("span")[0]).innerText || findlang__.textContent } window.languagecodefinder_preload = window.languagecodefinder_preload || mw.loader.getScript('https://en.wiktionary.org/w/index.php?title=User:Yair_rand/languagecodefinder.js&action=raw&ctype=text/javascript'); window.languagecodefinder_preload.always( function() { window.languagenametocode && languagenametocode[findlang__] && callback(languagenametocode[findlang__]) }); } function setupquoteadder(q) { findlang(q.parentNode, function(findlang_) { var z; if (!$(".HQToggle a", q)[0]) { z = q.appendChild(document.createElement("ul")) setupHiddenQuotes(q); } else { z = $(">ul", q)[0]; } if (z.style.display == 'none') { $(".HQToggle a", q).click(); } var zz = z.appendChild(document.createElement("li")), quoteform; var findsubdef = q.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "", editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return quoteform = newNode('form', { 'style': 'display:inline;' }, 'Year: ', newNode('input', { 'name': 'year', 'size': 4 }), ' Author: ', newNode('input', { 'name': 'author', 'size': 20 }), ' Source title: ', newNode('input', { 'name': 'source', 'size': 20 }), ' Publisher: ', newNode('input', { 'name': 'publisher', 'size': 20 }), ' Page(s): ', newNode('input', { 'name': 'page', 'size': 5 }), newNode('dl', newNode('dd', 'Quotation: ', newNode('input', { 'name': 'quotation', 'size': 40 }), newNode('div', { 'class': "DSBRedButton", 'click': function() { z.removeChild(zz) } }, newNode('div', 'Cancel')), newNode('div', { 'class': "DSBGreenButton", 'click': function() { quoteform.onsubmit() } }, newNode('div', "Preview ►")), newNode('input', { 'type': 'submit', 'style': 'visibility:hidden;width:0px;' }), newNode('dl', { 'style': 'display:' + (findlang_ == "en" ? "none" : "block") }, newNode('dd', 'Translation: ', newNode('input', { 'size': 40, 'name': 'translation' })))))) }, 'fields': { 'quotation': util.validateNoWikisyntax('quotation', true), 'year': util.validateNoWikisyntax('year', true), 'author': function(t) { return t }, 'source': function(t) { return t ? ", ''" + t + "''" : '' }, 'publisher': function(t) { return t ? ", " + t : '' }, 'page': function(t) { return t ? (/\-/.test(t) ? "pages " + t : "page " + t) : t }, 'translation': function(t) { return t } }, 'onsubmit': function(values, render) { var topline = "'''" + values.year + "'''" + (values.author ? ", " + values.author : '') + values.source + values.publisher + (values.page ? ", " + values.page : '') render(topline + "\n:" + values.quotation + (values.translation ? "\n:" + values.translation : ""), function(newhtml) { var findnumberofheaders = findnumberofheaders_(q), findnumberofdefs = findnumberofdefs_(q), quotetobeadded = newNode('span', { 'style': 'display:block;' }); quotetobeadded.innerHTML = newhtml.replace(/\<p\>|\<\/p\>/g, ''); editor.addEdit({ 'edit': function(wikitext) { return ccc = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?)\n(?!#" + findsubdef + "[:\*])|$"), "$1\n#" + findsubdef + "*" + topline + "\n#" + findsubdef + "*:" + values.quotation + (values.translation ? "\n#" + findsubdef + "*:" + values.translation : '') + '\n') }, 'redo': function() { quoteform.style.display = 'none'; quotetobeadded.style.display = 'block'; zz.appendChild(quotetobeadded) }, 'undo': function() { quoteform.style.display = 'inline'; zz.removeChild(quotetobeadded) }, 'summary': '+quote: "' + values.quotation + '"- ' + values.source }, quotetobeadded) }) } }, zz) }) } window.addPOSHeader = function(cancelhover) { var bodyContent = $(".mw-content-ltr")[0]; if (!defeditoptions.addingPOS) { defeditoptions.addingPOS = true; editor = new Editor() var headerLevel = (window.languageContainers && languageContainers[currentLanguageTab] && languageContainers[currentLanguageTab].firstChild) || bodyContent.firstChild; var ii; var temp, temp_; var theform; var findnumberofheaders; var addedwikitext; var prefakeheaders; var currentFocus; var langNames = [], docLink, docExists = {}; if (window.loadedTabs) { langNames = tabbedLanguages; } else { mw.util.$content.find("h2>.mw-headline").each(function() { langNames.push($(this).text()) }) } var langNameCodes; new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:languages/javascript-interface|GetAllData}}", "prop": "wikitext" }).done(function(r){ if(r.expandtemplates && r.expandtemplates.wikitext){ langNameCodes = JSON.parse(r.expandtemplates.wikitext); } }); function updateDocLink() { var pos = theform.getElementsByTagName("input")[0].value; pos = (({ Adjective: "adj", Adverb: "adv", Interjection: "interj", Preposition: "prep", Pronoun: "pron", Conjunction: "con", Contraction: "cont", Determiner: "det" })[pos] || pos.toLowerCase()); if (!langNameCodes || !pos || !theform.getElementsByTagName("input")[0].value) { return; } var currentLang = window.loadedTabs ? theform.parentNode.id.split("container")[0] : (function() { for (var s = theform; s && s.nodeName != "H2"; s = s.previousSibling); return s && s.lastChild && (s.lastChild.innerText || s.lastChild.textContent) })(); var docName = langNameCodes[currentLang] + "-" + pos; if (docExists[docName] === false) { return docLink.style.display = 'none'; } if (docExists[docName] === true) { docLink.style.display = 'inline'; docLink.href = mw.config.get("wgArticlePath").replace("$1", "Template:" + docName + "/doc"); return; } if (docExists[docName] === 'l') { docLink.style.display = 'none'; return; } docExists[docName] = 'l'; new mw.Api().get({ action: 'query', prop: 'info', titles: 'Template:' + docName + '/documentation' }).then(function(r) { docExists[docName] = r.query.pages.length == 1; updateDocLink(); }); } var poslist = '\nNoun\nVerb\nAdjective\nAdverb\nPronoun\nConjunction\nInterjection\nPreposition\nProper noun\nArticle\nPrepositional phrase\nAcronym\nAbbreviation\nInitialism\nContraction\nPrefix\nSuffix\nSymbol\nLetter\nLigature\nIdiom\nPhrase\nNumber\nNumeral\nCardinal number\nOrdinal number\nCardinal numeral\nOrdinal numeral\nPersonal pronoun\nDeterminer\nDemonstrative determiner\nClitic\nInfix\nInterfix\nAffix\nCircumfix\nCircumposition\nCounter\nKanji\nKanji reading\nHanja reading\nHirigana letter\nKatakana letter\nPinyin\nHan character\nHanzi\nHanja\nProverb\nExpression\nParticle\nInfinitive particle\nPossesive adjective\nPostposition\nPhrasal verb\nParticiple\nGerund\nInterrogative auxiliary verb\nPronominal adverb\nAdnominal\nAbstract pronoun\nConjunction particle\nCombining form\nRoot\nPinyin syllable\nSyllable\nHirigana character\nKatakana character\nJyutping syllable\nGismu\nLujvo\nBrivla\nClassifier\nPredicative\nMeasure word\nCorrelative\nPreverb\nPrenoun\nNoun stem\nNoun class\nCombined-kana character\nCmavo\n'; while (headerLevel.nextSibling) { if (/^h[34]$/i.test(headerLevel.nodeName) && !/Etymology|Pronunciation|Alternative\sforms/.test(headerLevel.innerHTML)) { headerLevel = headerLevel.nodeName.toLowerCase(); break; } headerLevel = headerLevel.nextSibling } currentBoxToBeAdded = newNode('div', { 'style': 'position:fixed;top:500px;' }) new AdderWrapper(editor, { createForm: function() { return theform = newNode('form', currentFocus = newNode('input', { 'style': 'font-size: 0.8em;font-size: ' + ((headerLevel == 'h3') ? '132%' : '116%') + ';font-weight: bold;font-family: sans-serif;width:auto;', 'placeholder': 'Part of speech', 'rows': 1, 'name': 'pos', focus: function() { currentFocus = this } }), newNode('input', { 'type': 'submit', 'value': 'Preview' }), newNode('input', { 'type': 'button', 'value': 'Cancel', click: function() { theform.style.display = 'none'; hoverNewPOS(null); defeditoptions.addingPOS = false; document.onmousemove = null; document.body.style.cursor = ''; } }), newNode('br'), newNode('input', { 'style': 'width:300px;font-family:monospace;', 'placeholder': '{\{head}}', 'name': 'inflline', focus: function() { currentFocus = this } }), docLink = newNode('a', { style: "margin-left:5px;display:none;", 'target': '_blank' }, "Help?"), newNode('ol', newNode('li', newNode('input', { 'size': 100, 'disabled': 'disabled' })))) }, fields: { 'pos': function(txt, error) { return poslist.indexOf('\n' + txt + '\n') > -1 ? txt : error('Please select a valid part of speech.') }, 'inflline': function(txt, error) { return txt || "{" + "{head}}" } }, onsubmit: function(values, render) { addedwikitext = '{' + '{subst:=}}==' + (headerLevel == 'h4' ? '=' : '') + values.pos + (headerLevel == 'h4' ? '=' : '') + '===\n' + values.inflline hoverNewPOS(null); document.onmousemove = null; defeditoptions.addingPOS = false; document.body.style.cursor = ''; render(addedwikitext, function(res) { theform.style.display = 'none' temp = document.createDocumentFragment(); temp.appendChild(temp_ = newNode('div', { 'class': 'fakeheader' })); temp_.innerHTML = res; temp.appendChild(newNode('ol', newNode('li', ' ', newNode('span')))); theform.parentNode.insertBefore(temp, theform); prefakeheaders = 0 findnumberofheaders = theform.previousSibling.previousSibling; while (true) { if (findnumberofheaders.previousSibling) { findnumberofheaders = findnumberofheaders.previousSibling; if (/h[2-6]/i.test(findnumberofheaders.nodeName)) { findnumberofheaders = Number(findnumberofheaders.lastChild.getElementsByTagName('a')[0].href.split("section=")[1]); break; } findnumberofheaders.className == 'fakeheader' && prefakeheaders++; } else { findnumberofheaders.parentNode.insertBefore(newNode('h2', languageHeaderEditButtons[currentLanguageTab].cloneNode(true), { 'style': 'display:none;' }), findnumberofheaders); } } var updatecatscallback; editor.addEdit({ 'edit': function(wikitext) { return ccc = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}([\\s\\S]*?\n\\{\\{subst:\\=\\}\\}==" + (headerLevel == 'h4' ? '=' : '') + "[^=]){" + prefakeheaders + "}[\\s\\S]*?(?=(\n=|\n----|\n\\{\\{subst:\\=\\}\\}==" + (headerLevel == 'h4' ? '=' : '') + "[^=]|$)))"), "$1\n" + addedwikitext + "\n\n# {" + "{rfdef}}\n") }, 'redo': function() { theform.style.display = 'none'; theform.parentNode.insertBefore(temp, theform); updatecatscallback = window.tabbedLanguages && updateCategories(theform.parentNode, addedwikitext) }, 'undo': function() { theform.style.display = 'block'; temp.appendChild(temp_); temp.appendChild(theform.previousSibling); updatecatscallback && updatecatscallback() }, 'summary': '+pos ' + values.pos }, temp_) makedefsidebox(theform.previousSibling.firstChild)(); editor.withCurrentText(function() { theform.previousSibling.getElementsByTagName('input')[0].value = ''; theform.previousSibling.getElementsByTagName('input')[0].focus() }) }) } }, currentBoxToBeAdded) cancelhover || setUpBoxToBeAdded(); theform.firstChild.focus() function hoverNewPOS(thefunction) { for (var ii = bodyContent.getElementsByTagName(headerLevel), i = 0; i < ii.length; i++) { if (!/^Etymology|Pronunciation|Alternative\sforms$/.test(ii[i].firstChild.innerHTML))(ii[i].parentNode.className == 'fakeheader' ? ii[i].parentNode : ii[i]).onmouseover = thefunction; } if (window.tabbedLanguages) { for (var i = 0; i < languageContainers.length; i++) languageContainers[i].lastChild.onmouseover = thefunction; } else { ii = bodyContent.getElementsByTagName('hr'); for (var i = 0; i < ii.length; i++) ii[i].onmouseover = thefunction; } } function hoverNewPOS_() { currentBoxToBeAdded.style.display = 'none'; this.parentNode.insertBefore(theform, this); currentFocus.focus(); updateDocLink() } cancelhover || hoverNewPOS(hoverNewPOS_); // autocomplete pos field theform.firstChild.onkeydown = function(e) { if ((e || event).keyCode == 9) { theform.getElementsByTagName("input")[3].focus(); return false } } theform.firstChild.onkeyup = function(e) { if (this.value[0] != this.value.charAt(0).toUpperCase()) this.value = this.value.charAt(0).toUpperCase() + this.value.substr(1); e = (e || event).keyCode; if (!(e >= 33 && e <= 40) && e != 8 && e != 46 && e != 27 && e != 16 && this.value) { if (poslist.indexOf('\n' + this.value) > -1) { if (this.setSelectionRange) this.setSelectionRange([this.value.length, this.value = poslist.match(RegExp(this.value + "[^\n]*"))][0], this.value.length); else if (this.createTextRange) { var z = this.createTextRange(); z.moveEnd('character', 0 - z.move('character', [this.value.length, this.value = poslist.match(RegExp(this.value + "[^\n]*"))][0]) + this.value.length); z.select() } } updateDocLink() } } } } window.updateCategories = function(container, newvalue, oldvalue) { var addedCategories = [], removedCategories = [] new mw.Api().get({ action: "parse", prop: "categorieshtml", title: mw.config.get('wgPageName'), text: newvalue }).then(function(r) { var e = r.parse.categorieshtml['*'].match(/\<li.*?\/li\>/g); var d = container.lastChild.lastChild; var f = document.createElement('ul'); for (var i = 0; e && i < e.length; i++) { f.innerHTML = e[i]; if (d.innerHTML.indexOf(f.firstChild.innerHTML) == -1) { addedCategories.push(d.insertBefore(f.lastChild, d.lastChild)) } } oldvalue && new mw.Api().get({ action: "parse", prop: "categorieshtml", title: mw.config.get('wgPageName'), text: oldvalue }).then(function(o) { e = o.parse.categorieshtml['*'].match(/\<li.*?\/li\>/g) for (var i = 0; e && i < e.length; i++) { f.innerHTML = e[i]; if (r.parse.categorieshtml['*'].indexOf(f.firstChild.innerHTML) == -1 && d.innerHTML.indexOf(f.firstChild.innerHTML) != -1) { var lis = d.getElementsByTagName('li') for (var ii = 0; ii < lis.length; ii++) { if (lis[ii].firstChild.innerHTML == f.firstChild.firstChild.innerHTML) { removedCategories.push(lis[ii]); lis[ii].style.display = 'none'; break; } } } } }) }); return function() { for (var i = 0; i < addedCategories.length; i++) { container.lastChild.lastChild.removeChild(addedCategories[i]) } for (var i = 0; i < removedCategories.length; i++) { removedCategories[i].style.display = ''; } } } function addgloss(qq) { var senseidform; findlang(qq.parentNode, function(findlang_) { if (qq.addinggloss) { return } qq.addinggloss = true; editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return senseidform = newNode('form', { 'style': 'display:inline; padding-right:20px;' }, newNode('input', { 'size': 30, 'name': 'senseid' }), newNode('input', { 'type': 'submit', 'value': 'Add' }), newNode('input', { 'type': 'button', 'value': 'Cancel', 'click': function() { qq.removeChild(senseidform); qq.addinggloss = false } }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!')) }, 'fields': { 'senseid': util.validateNoWikisyntax('gloss', true) }, 'onsubmit': function(values) { var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq) senseidform.lastChild.innerHTML = ''; var nymB = qq.getElementsByTagName('li')[1] editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ") ?"), "$1{" + "{senseid|" + findlang_ + "|" + values.senseid + "}}"); return ccc = wikitext; }, redo: function() { senseidform.style.display = "none"; $([nymB.firstChild, nymB.nextSibling.firstChild]).removeClass('DSBinactive'); nymB.firstChild.title = nymB.nextSibling.firstChild.title = '' }, undo: function() { senseidform.style.display = "inline"; $([nymB.firstChild, nymB.nextSibling.firstChild]).addClass('DSBinactive'); nymB.firstChild.title = 'Please add a gloss before adding synonyms.'; nymB.nextSibling.firstChild.title = 'Please add a gloss before adding antonyms.' }, summary: "+senseid: " + values.senseid }) } }, qq, qq.childNodes[1]) senseidform.firstChild.focus() editor.withCurrentText(function(wikitext) { wikitext = wikitext.match("==" + (window.loadedTabs ? tabbedLanguages[currentLanguageTab] : $(findtopli(qq).parentNode).prevUntil("h2").eq(-1).prev().find(".mw-headline").text()) + "==\n[\\s\\S]+?(----|$)")[0]; if (!wikitext) return; var senses = '', matches = wikitext.match(/(\{\{sense\||\{\{trans-top\|)[^\}]+(?=\}\})/g) if (!matches) return; for (var ms = 0; ms < matches.length; ms++) { senses += "\n" + matches[ms].split("|")[1] } if (!senses) return; senseidform.firstChild.onkeyup = function(e) { e = (e || event).keyCode; if (!(e >= 33 && e <= 40) && e != 8 && e != 46 && e != 27 && e != 16 && this.value) { if (senses.indexOf('\n' + this.value) > -1) { if (this.setSelectionRange) this.setSelectionRange([this.value.length, this.value = senses.match(RegExp("\n" + this.value + "[^\n]*")).toString().substr(1)][0], this.value.length); else if (this.createTextRange) { var z = this.createTextRange(); z.moveEnd('character', 0 - z.move('character', [this.value.length, this.value = senses.match(RegExp("\n" + this.value + "[^\n]*")).toString().substr(1)][0]) + this.value.length); z.select() } } } } }) }) } function editgloss(qq) { editor = new Editor() editor.withCurrentText(function(wikitext) { if (qq.editinggloss) { return } qq.editinggloss = true; var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq) var senseidform; var oldsenseid; new AdderWrapper(editor, { 'createForm': function() { var thisId = "a" + String(Math.random()).replace(".", "") oldsenseid = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?)"), '').match(/^\{\{senseid\|[^\\|]*\|([^\}]*)/)[1] return senseidform = newNode('form', { 'style': 'display:inline; padding-right:20px; ' }, newNode('input', { 'size': 30, 'name': 'senseid', 'value': oldsenseid }), newNode('input', { 'type': 'checkbox', 'id': thisId, 'name': 'changematching', style: 'display:' + (window.tabbedLanguages ? 'inline' : 'none') }), newNode('label', { 'for': thisId, style: 'display:' + (window.tabbedLanguages ? 'inline' : 'none') }, 'Edit matching glosses'), newNode('input', { 'type': 'submit', 'value': 'Change' }), newNode('input', { 'type': 'button', 'value': 'Cancel', 'click': function() { qq.editinggloss = false; qq.removeChild(senseidform); } }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!')) }, 'fields': { 'senseid': util.validateNoWikisyntax('gloss', true), 'changematching': 'checkbox' }, 'onsubmit': function(values) { var ttables = [], sensetemps = [], backups = []; if (values.changematching) { ttables = jQuery(".NavHead", languageContainers[currentLanguageTab]).filter(function() { if (this.parentNode.getElementsByTagName("table")[0].className != "translations") return false; for (var i = 0; i < this.childNodes.length; i++) { if (this.childNodes[i].nodeType == 3 || this.childNodes[i].className == 'wt-edit-recurse') { return (this.childNodes[i].nodeValue || this.childNodes[i].innerHTML) == oldsenseid; } } }) sensetemps = jQuery(".qualifier-content", languageContainers[currentLanguageTab]).filter(function() { return this.parentNode.nextSibling.nextSibling.className == "ib-colon" && this.innerHTML == oldsenseid; }) } editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?(\{\{senseid\\|[^\\|]*\\|))[^\}]*"), "$1" + values.senseid); if (values.changematching) { var asd = wikitext.match('==' + tabbedLanguages[currentLanguageTab] + '==\n[\\s\\S]+?(\n==[^=]|$)'); wikitext = wikitext.replace(asd[0], asd[0].replace(RegExp("\\{\\{(sense|trans-top)\\|" + oldsenseid + "\\}\\}", "g"), "{\{$1\|" + values.senseid + "}}")) } return ccc = wikitext }, redo: function() { senseidform.style.display = "none"; for (var i = 0; i < ttables.length; i++) { backups.push(document.createDocumentFragment()); while (ttables[i].childNodes[1]) { backups[backups.length - 1].appendChild(ttables[i].childNodes[1]); } ttables[i].appendChild(document.createTextNode(values.senseid)) } for (var i = 0; i < sensetemps.length; i++) { backups.push(document.createDocumentFragment()); backups[backups.length - 1].appendChild(sensetemps[i].firstChild); sensetemps[i].appendChild(document.createTextNode(values.senseid)) } }, undo: function() { senseidform.style.display = "inline"; for (var i = 0; i < ttables.length; i++) { ttables[i].removeChild(ttables[i].childNodes[1]); ttables[i].appendChild(backups.shift()) } for (var i = 0; i < sensetemps.length; i++) { sensetemps[i].removeChild(sensetemps[i].firstChild) sensetemps[i].appendChild(backups.shift()) } }, summary: "senseid: " + values.senseid }) } }, qq, qq.childNodes[1]) senseidform.firstChild.focus() }) } function setupnymadder(qq, nymtype) { var passtheseheaders = "Usage notes|Inflection|Conjugation|Declension|Quotations", nymtypelist = ["Synonyms", "Antonyms", "Hypernyms", "Hyponyms", "Meronyms", "Holonyms"] for (var x = 0; nymtypelist[x] != nymtype; x++) passtheseheaders += "|" + nymtypelist[x]; if (qq.parentNode.parentNode.nodeName.toLowerCase() == "li") qq = qq.parentNode.parentNode; var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq.parentNode.getElementsByTagName('li')[0]) for (var findheaderlevel = qq.parentNode; !/^h\d$/i.test(findheaderlevel.nodeName); findheaderlevel = findheaderlevel.previousSibling); findheaderlevel = Number(findheaderlevel.nodeName.match(/\d/)); var senseidencoded = [] editor = new Editor() editor.withCurrentText(function(wikitext) { // Find nym header, or add it if it doesn't exist var qqq = qq.parentNode; while (!((qqq.className == "fakesubheader" || /h\d/i.test(qqq.nodeName)) && !qqq.innerHTML.match(passtheseheaders) || qqq.className == "printfooter" || qqq.className == "fakeheader" || qqq.className == "catlinks")) { qqq = qqq.nextSibling } if (!qqq.innerHTML.match(nymtype)) { qqq = qqq.parentNode.insertBefore(newNode('div', { 'class': 'fakesubheader' }, newNode('h' + (findheaderlevel + 1), nymtype)), qqq); } // relevant vars: // findheaderlevel is the the headerlevel of the most recent header above the ol // qq is still the li itself // qqq is the (possibly newly added) nym header // find all relevant senseids, make an array of them, the whole template in each var senseid = wikitext.replace( RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ")"), '').replace(/\n\n[\s\S]*$/, '').match(/\{\{senseid\|[^\\|]*\|[^\}]*/g) if (!senseid) { alert("No glosses were found. Click \"Add gloss\" to attach a gloss to the definition before adding " + nymtype.toLowerCase() + "."); return } // run through senseids, checking for a corresponding span id'd nymtype-langcode-id, adding them encased in an li in a soon-to-be-parsed temp variable if not found, otherwise suppressing new form creation temp = "" var nymformexists = [] for (var i = 0; i < senseid.length; i++) { if (document.getElementById(senseidencoded[i] = nymtype + "-" + encodeURIComponent(senseid[i].split("|")[1] + "-" + senseid[i].split("|")[2]).replace(/%20/g, '_').replace(/%3A/g, ':').replace(/%/g, '.'))) { nymformexists[i] = true } else { temp += "* {" + "{sense|" + senseid[i].split("|")[2] + "}} <span id='" + nymtype + "-" + senseid[i].split("|")[1] + "-" + senseid[i].split("|")[2] + "'></span>\n" } } new mw.Api().parse(temp, { title: mw.config.get('wgPageName'), pst: true, //pst makes subst work as expected disablelimitreport: true }).then(function(res) { var qqqq = newNode('span') qqqq.innerHTML = res qqqq = qqq.parentNode.insertBefore(qqqq.firstChild, qqq.nextSibling) // the ul containing the form-holder spans, right below the nym header for (var i = 0; i < senseid.length; i++) { if (!nymformexists[i]) { setupnymadder2(i, senseid, wikitext) } } if (qqqq.getElementsByTagName && qqqq.getElementsByTagName('li').length == 0) { qqqq.parentNode.removeChild(qqqq) } scroll(0, jQuery(qqq).offset().top) }); }) function setupnymadder2(i, senseid, wikitext) { var nymtype2 = nymtype.slice(0, -1).toLowerCase() var x = document.getElementById(senseidencoded[i]); var theform new AdderWrapper(editor, { 'createForm': function() { return theform = newNode('form', { 'style': 'display:inline;' }, newNode('input', { 'name': 'nym' }), newNode('input', { 'value': 'Add', 'type': 'submit' })) }, 'fields': { 'nym': util.validateNoWikisyntax(nymtype2, true) }, 'onsubmit': function(values, render) { theform.getElementsByTagName('input')[0].value = "" var firstnym = !theform.parentNode.parentNode.getElementsByTagName('a')[0] var addedwikitext = (firstnym ? '' : ', ') + "{" + "{l|" + senseid[i].split("|")[1] + "|" + values.nym + "}}" render(addedwikitext, function(res2) { var nodeToInsert = newNode('span') nodeToInsert.innerHTML = res2 editor.addEdit({ edit: function(wikitext) { // unindent findnumberofdefs = findnumberofdefs_(qq.parentNode.getElementsByTagName('li')[0]) if (wikitext.substr(wikitext.length - 1, 1) != "\n") { wikitext += "\n" } if (!wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ")"), '').replace(RegExp("(\n(=|\\{\\{subst:=\\}\\})={" + (findheaderlevel - 1) + "}[^=][\\s\\S]*$)"), '').match(RegExp(nymtype + "={" + findheaderlevel + "}"))) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?(\n(?=(\\{\\{subst:=\\}\\}|=)=+(?=[^=])(?!(" + passtheseheaders + ")))|$))"), "$1{" + "{subst:=}}===" + (findheaderlevel == 4 ? "=" : "") + nymtype + (findheaderlevel == 4 ? "=" : "") + "====\n\n") } if (firstnym) { var passthesesenseids = []; for (var ii = 0; ii < i; ii++) { passthesesenseids.push("\\* \\{\\{sense\\|" + senseid[ii].split("|")[2] + "\\}\\}") } wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?=" + nymtype + "=+[\\s\\S]*?\n" + (passthesesenseids.length > 0 ? "(?!(" + passthesesenseids.join("|") + ")))" : ")")), "$1* {" + "{sense|" + senseid[i].split("|")[2] + "}} " + addedwikitext + "\n") } else { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}[\\s\\S]*?=" + nymtype + "=+[\\s\\S]*?\\{\\{sense\\|" + senseid[i].split("|")[2] + "\\}\\}.*)"), "$1" + addedwikitext) } return ccc = wikitext; }, redo: function() { theform.parentNode.parentNode.insertBefore(nodeToInsert, theform.parentNode) }, undo: function() { theform.parentNode.parentNode.removeChild(nodeToInsert) }, summary: "+" + nymtype2 + " [[" + values.nym + "]]" }, nodeToInsert) }) } }, x) // sort the lis var passthesesenseids = []; for (var ii = 0; ii < i; ii++) { passthesesenseids.push(senseid[ii].split("|")[2]) } for (var xx = x.parentNode.parentNode.nextSibling; xx.nextSibling && !/h\d/i.test(xx.nodeName) && xx.className != "fakesubheader" && xx.nodeName.toUpperCase() != "UL"; xx = xx.nextSibling); if (xx.nodeName.toUpperCase() == "UL") { var xxx = xx.getElementsByTagName('li') for (var xxxx = xxx.length; xxxx--;) { var xxxxx = xxx[xxxx].getElementsByTagName("span")[3] if (xxxxx && xxxxx.innerHTML == senseid[i].split("|")[2]) { x.parentNode.parentNode.removeChild(x.parentNode); xxx[xxxx].appendChild(x); break; } if (xxxxx && passthesesenseids.length && RegExp(passthesesenseids.join("|")).test(xxxxx.innerHTML)) { xxx[xxxx + 1] ? xx.insertBefore(x.parentNode, xxx[xxxx]) : xx.appendChild(x.parentNode); break; } } if (xxxx == -1) { xx.insertBefore(x.parentNode, xx.firstChild) } } } } jQuery(document).ready(function() { var disablebutton = document.getElementById('YRDefsideboxes-disable-button'); if (disablebutton) { disablebutton.innerHTML = ""; var toggle = newNode('span', { click: function() { if ($.cookie("DisableYREdit")) { $.cookie("DisableYREdit", null, { path: "/" }) toggle.innerHTML = "Disable definition editing options." } else { $.cookie("DisableYREdit", 1, { expires: 30, path: "/" }) toggle.innerHTML = "Enable definition editing options." } } }, ($.cookie("DisableYREdit") ? "Enable" : "Disable") + " definition editing options.") disablebutton.appendChild(toggle); } if (mw.config.get('wgAction') == 'view' && (mw.config.get('wgNamespaceNumber') == 0 || mw.config.get('wgPageName') == "Wiktionary:Sandbox") && !/&printable=yes|&diff=|&oldid=/.test(window.location.search) && !$.cookie("DisableYREdit") && !window.DisableYREdit && !window.loadedYREdit) { window.loadedYREdit = true; for (var ols = document.getElementsByTagName('ol'), ii = 0; ii < ols.length; ii++) { if (ols[ii].className != "references") { for (var lis = ols[ii].getElementsByTagName('li'), i = 0; i < lis.length; i++) { if (lis[i].parentNode == ols[ii] && ols[ii].parentNode.parentNode.nodeName != "UL") makedefsidebox(lis[i]); } } } mw.util.addPortletLink('p-tb', 'javascript:addPOSHeader()', 'Add part of speech'); defsidebuttons = [0] defeditoptions = { addingPOS: false } } }) // </nowiki> 8oh79o98tyjo7ss59excfxpgp5m9e4o 89016 89015 2026-08-06T23:33:51Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-DefSideBoxes.js]] 89015 javascript text/javascript // Newer version of User:Yair rand/editor.js // <nowiki> // ******** imported from [[MediaWiki:Gadget-LegacyScriptsNewNode.js]] ******** var newNode = window.newNode = function newNode(tagname) { var node = document.createElement(tagname); for (var i = 1; i < arguments.length; i++) { var argument = arguments[i]; if (typeof argument == 'string') { //Text node.appendChild(document.createTextNode(argument)); } else if (typeof argument == 'object') { if (argument instanceof Node) { // If it is a DOM Node node.appendChild(argument); } else { // Attributes (hopefully) for (var j in argument) { if (j === 'class') { // Classname different because... node.className = argument[j]; } else if (j == 'style') { // Style is special node.style.cssText = argument[j]; } else if (typeof argument[j] == 'function') { // Basic event handlers node.addEventListener(j, argument[j], false); } else { node.setAttribute(j, argument[j]); //Normal attributes } } } } } return node; }; // **************************************************************************** var autoTranslitScripts = { "Geor": true }; window.makedefsidebox = function(q) { function clickiconfunction() { var moreoptions, originalHeight, buttons; function uncollapse() { $(moreoptions).slideUp(); $("body").off("click", uncollapse); } editdefinition(q); if ($('>.addusexbutton', q).length === 0) { buttons = q.insertBefore(newNode('div', { 'class': 'addusexbutton' }, newNode('a', '+Add example sentence', { 'click': function() { setupusexadder(q); } }), newNode('a', '+Add quotation', { 'click': function() { setupquoteadder(q); } }), newNode('a', 'More ►', { 'click': function() { $(moreoptions).slideDown(); setTimeout(function() { $("body").click(uncollapse); }, 16); } }), newNode('span', { 'style': 'display:inline-block;' }, moreoptions = newNode('ul', newNode('li', q.className ? newNode('a', 'Edit gloss', { 'click': function() { editgloss(q); } }) : newNode('a', 'Add gloss', { 'click': function() { addgloss(q); } })), newNode('li', newNode('a', q.className ? undefined : { 'class': 'DSBinactive', 'title': 'Please add a gloss before adding synonyms.' }, { 'click': function() { setupnymadder(q, "Synonyms"); } }, 'Add synonyms')), newNode('li', newNode('a', q.className ? undefined : { 'class': 'DSBinactive', 'title': 'Please add a gloss before adding antonyms.' }, { 'click': function() { setupnymadder(q, "Antonyms"); } }, 'Add antonyms')), newNode('li', newNode('a', { 'href': mw.config.get('wgScript') + '?title=User_talk:Yair_rand/editor2.js&action=edit&section=new' }, 'Give feedback on this tool')), newNode('li', newNode('a', { click: function() { $.cookie("DisableYREdit", 1, { path: '/' }); location.href = location.href; } }, 'Disable this tool'))))), $('>dl,>ul,>ol', q)[0] || null); } } q.insertBefore( newNode('span', { 'class': 'defEditButton' }, newNode('span', { 'click': clickiconfunction, 'title': 'Edit' })), q.firstChild); return clickiconfunction; } function setupusexadder(qq) { var x, y; var usexform; var findsubdef = (qq.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "") + (qq.parentNode.parentNode.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "") editor = new Editor() findlang(qq.parentNode, function(findlang_) { var findscript = (new LangMetadata()).getScripts(findlang_), selectedscript = findscript[0] || "Latn"; if (qq.getElementsByTagName('dl')[0] && qq.getElementsByTagName('dl')[0].parentNode == qq) x = qq.getElementsByTagName('dl')[0]; else if ($(">ul", qq).length > 0) x = qq.insertBefore(newNode('dl'), $(">ul", qq)[0]); else x = qq.appendChild(newNode('dl')); x.appendChild(y = newNode('dd')) new AdderWrapper(new Editor(), { 'createForm': function() { var x, i = 0, y = function() { selectedscript = this.value; usexform.getElementsByTagName('dd')[0].style.display = this.value == 'Latn' ? 'none' : 'block' } if (findscript.length > 1) { for (x = newNode('select', { 'name': 'script', 'change': y }); i < findscript.length; i++) { x.appendChild(newNode('option', { 'value': findscript[i] }, findscript[i])) } } else { x = newNode('input', { 'name': 'script', 'value': findscript[0] || "Latn", 'style': "width:50px;", 'change': y }) } return usexform = newNode('form', { 'style': 'display:inline;' }, newNode('input', { 'size': 100, 'placeholder': 'Example sentence', 'name': 'examplesentence' }), newNode('span', { 'style': 'display:' + (findscript.length == 1 ? "none" : "inline") + ";" }, 'Script: ', x), newNode('div', { 'class': "DSBRedButton", 'click': function() { usexform.style.display = 'none' } }, newNode('div', 'Cancel')), newNode('div', { 'class': "DSBGreenButton", 'click': function() { usexform.onsubmit() } }, newNode('div', "Preview ►")), newNode('input', { 'type': 'submit', 'style': 'visibility:hidden;width:0px;' }), newNode('dl', (findlang_ == "en" ? { 'style': 'display:none;' } : ''), newNode('dd', 'Transliteration: ', ((findscript[0] == 'Latn' || !findscript[0]) ? { 'style': 'display:none;' } : ''), newNode('input', { 'size': '100px', name: 'transliteration' })), newNode('dd', 'Translation: ', newNode('input', { 'size': '100px', name: 'translation' })))) }, 'fields': { 'examplesentence': function(txt, error) { return util.validateNoWikisyntax('example sentence', true)(txt, error) }, 'transliteration': function(txt, error) { return txt || ''; }, 'translation': function(txt, error) { if (findlang_ != "en") { return util.validateNoWikisyntax('translation', true)(txt, error); } return ''; }, 'script': util.validateNoWikisyntax('script', true) }, 'onsubmit': function(values, render) { var renderWikitext = ""; if (findlang_ === "en") renderWikitext = "''" + values.examplesentence + "''"; else { renderWikitext = "{" + "{ux|" + findlang_ + "|" + values.examplesentence + "|" + values.translation; if (values.script) { renderWikitext += "|sc=" + values.script; if (!(values.script in autoTranslitScripts) && values.transliteration) renderWikitext += "|tr=" + values.transliteration; } renderWikitext += "}}"; } render(renderWikitext, function(newhtml) { var findnumberofheaders = findnumberofheaders_(qq); var findnumberofdefs = findnumberofdefs_(qq); var usextobeadded = newNode('span') usextobeadded.innerHTML = newhtml.replace(/<p>|<\/p>/g, ''); editor.addEdit({ edit: function(wikitext) { var usexWikitext = renderWikitext; wikitext = wikitext.replace(RegExp( "(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?)\n(?!#" + findsubdef + ":)|$"), "$1\n#" + findsubdef + ":" + usexWikitext + "\n"); ccc = wikitext; return wikitext; }, redo: function() { usexform.parentNode.appendChild(usextobeadded); usextobeadded.style.display = 'block'; usexform.style.display = "none"; y.style.display = 'block' }, undo: function() { usexform.parentNode.removeChild(usextobeadded); usexform.style.display = "inline"; }, summary: "+usex: " + values.examplesentence }, usextobeadded) }) } }, y) usexform.firstChild.focus() }) } window.editdefinition = function(qq) { (new Editor).withCurrentText(function(wikitext) { if (qq.YREditing) { return } qq.YREditing = true; var findnumberofheaders = findnumberofheaders_(qq), findnumberofdefs = findnumberofdefs_(qq) var temporarydefholder = qq.insertBefore(newNode('span', { 'style': 'display:none;' }), qq.childNodes[1].nodeName.toLowerCase() != "form" ? qq.childNodes[1] : qq.childNodes[2]) while (qq.childNodes[3] && qq.childNodes[3].nodeName != "DL" && qq.childNodes[3].nodeName != "UL" && qq.childNodes[3].nodeName != "OL" && qq.childNodes[3].className != "HQToggle" && qq.childNodes[3].className != "addusexbutton") temporarydefholder.appendChild(qq.childNodes[3]); if (qq.childNodes[2] != temporarydefholder) temporarydefholder.insertBefore(qq.childNodes[2], temporarydefholder.firstChild); var defform var olddef = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?)"), '').match(/^(\{\{senseid\|[^\}]*\}\})?\s?(.*)/)[2] new AdderWrapper(new Editor(), { 'createForm': function() { return defform = newNode('form', { 'style': 'width:100%;display:inline-block;margin-bottom:-6px;' }, newNode('table', { 'style': 'width:100%;' }, newNode('tr', newNode('td', newNode('input', { 'style': 'height:17px;width:100%;', 'name': 'definition', 'size': 80, 'value': olddef }) // newNode('input',{type:'submit',value:'Preview'}), // newNode('input',{type:'button',value:'Cancel',click:function(){temporarydefholder.style.display='inline';defform.style.display='none';qq.YREditing = false}}) ), newNode('td', { 'style': 'white-space:nowrap;' }, newNode('div', { 'class': "DSBRedButton" }, newNode('div', { click: function() { temporarydefholder.style.display = 'inline'; defform.style.display = 'none'; qq.YREditing = false } }, "Discard Changes")), newNode('div', { 'class': "DSBGreenButton" }, newNode('div', { click: function() { defform.onsubmit() } }, "Preview Changes ►")))))) }, 'fields': { 'definition': function(txt, error) { return txt || error("Please specify a definition.") } }, 'onsubmit': function(values, render) { render(values.definition, function(newhtml) { editor = new Editor() var findnumberofdefs = findnumberofdefs_(qq) // apparently this is sometimes necessary var addedspan = newNode('span') addedspan.innerHTML = newhtml var updatecatscallback; editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?(\{\{senseid\\|[^\}]*\}\})*?)(?!{" + "{senseid\\|).*"), "$1" + values.definition); ccc = wikitext; return wikitext }, redo: function() { defform.parentNode.insertBefore(addedspan, defform); defform.style.display = temporarydefholder.style.display = 'none'; updatecatscallback = window.tabbedLanguages && updateCategories(findtopli(defform.parentNode).parentNode.parentNode, values.definition, olddef) qq.YREditing = false; }, undo: function() { defform.parentNode.removeChild(addedspan); defform.style.display = "inline"; defform.firstChild.firstChild.firstChild.firstChild.value = olddef; updatecatscallback && updatecatscallback(); qq.YREditing = true; }, summary: "def: " + values.definition }, addedspan) }) } }, qq, qq.childNodes[1].nodeName.toLowerCase() != "form" ? qq.childNodes[1] : qq.childNodes[2]) }) } function findtopli(li) { for (; li.parentNode.parentNode.nodeName.toLowerCase() == "li";) { li = li.parentNode.parentNode; } return li; } function findnumberofheaders_(tosearchfrom) { tosearchfrom = findtopli(tosearchfrom).parentNode; while (!tosearchfrom.nodeName.match(/^h\d$/i)) tosearchfrom = tosearchfrom.previousSibling; return Number(tosearchfrom.lastChild.getElementsByTagName('a')[0].href.match(/\d*$/)) } function findnumberofdefs_(tosearchfrom) { var findnumberofdefs = [], tosearchfrom_, findnumberofpredefs = 0, result; // subdefinitions while (tosearchfrom.nodeName.toLowerCase() == "li") { tosearchfrom_ = tosearchfrom; findnumberofdefs.splice(0, 0, 0); while (tosearchfrom) { if (tosearchfrom.nodeName.toLowerCase() == "li") findnumberofdefs[0]++; tosearchfrom = tosearchfrom.previousSibling; } tosearchfrom = tosearchfrom_.parentNode.parentNode; } // in case of any def lists before the current def list under the same header for (tosearchfrom_ = tosearchfrom_.parentNode.previousSibling; !tosearchfrom_.nodeName.match(/^h\d$/i); tosearchfrom_ = tosearchfrom_.previousSibling) { if (tosearchfrom_.nodeName.toLowerCase() == "ol") findnumberofpredefs += 1; } result = "([\\s\\S]*?\n#[\\s\\S]*?\n(?!#)){" + findnumberofpredefs + "}"; for (var i = 0; i < findnumberofdefs.length; i++) { result += "([\\s\\S]*?\n" + Array(i + 2).join("#") + "(?![:*#])){" + findnumberofdefs[i] + "}"; } return result; } function findlang(tosearchfrom, callback) { var tosearchfrom_, findlang__ if (tosearchfrom.parentNode.nodeName.toLowerCase() == "li") tosearchfrom = findtopli(tosearchfrom.parentNode).parentNode; if (tosearchfrom.parentNode.className == "languageContainer") { if (tosearchfrom.parentNode.id == "Englishcontainer") return callback("en"); } else { tosearchfrom_ = tosearchfrom; while (tosearchfrom_.nodeName.toLowerCase() != "h2") tosearchfrom_ = tosearchfrom_.previousSibling; if (tosearchfrom_.lastChild.innerHTML == "English") return callback("en"); } tosearchfrom_ = tosearchfrom; while (tosearchfrom_ && !/^h\d$/i.test(tosearchfrom_.nodeName) && tosearchfrom_.className != "fakeheader") tosearchfrom_ = tosearchfrom_.previousSibling; while (tosearchfrom_ && tosearchfrom_.nodeName.toLowerCase() != "p" && tosearchfrom_.className != "fakeheader") tosearchfrom_ = tosearchfrom_.nextSibling; if (tosearchfrom_ && tosearchfrom_.className != "fakeheader" && tosearchfrom_.firstChild && (tosearchfrom_.firstChild.lang || (tosearchfrom_.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.lang) || (tosearchfrom_.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.firstChild && tosearchfrom_.firstChild.firstChild.firstChild.lang))) { return callback(tosearchfrom_.firstChild.lang || tosearchfrom_.firstChild.firstChild.lang || tosearchfrom_.firstChild.firstChild.firstChild.lang) } if (tosearchfrom.parentNode.className == "languageContainer") findlang__ = tosearchfrom.parentNode.id.split("container")[0]; else { while (tosearchfrom.nodeName.toLowerCase() != "h2") tosearchfrom = tosearchfrom.previousSibling; findlang__ = (findlang__ = tosearchfrom.getElementsByTagName("span")[0]).innerText || findlang__.textContent } window.languagecodefinder_preload = window.languagecodefinder_preload || mw.loader.getScript('https://en.wiktionary.org/w/index.php?title=User:Yair_rand/languagecodefinder.js&action=raw&ctype=text/javascript'); window.languagecodefinder_preload.always( function() { window.languagenametocode && languagenametocode[findlang__] && callback(languagenametocode[findlang__]) }); } function setupquoteadder(q) { findlang(q.parentNode, function(findlang_) { var z; if (!$(".HQToggle a", q)[0]) { z = q.appendChild(document.createElement("ul")) setupHiddenQuotes(q); } else { z = $(">ul", q)[0]; } if (z.style.display == 'none') { $(".HQToggle a", q).click(); } var zz = z.appendChild(document.createElement("li")), quoteform; var findsubdef = q.parentNode.parentNode.nodeName.toLowerCase() == "li" ? "#" : "", editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return quoteform = newNode('form', { 'style': 'display:inline;' }, 'Year: ', newNode('input', { 'name': 'year', 'size': 4 }), ' Author: ', newNode('input', { 'name': 'author', 'size': 20 }), ' Source title: ', newNode('input', { 'name': 'source', 'size': 20 }), ' Publisher: ', newNode('input', { 'name': 'publisher', 'size': 20 }), ' Page(s): ', newNode('input', { 'name': 'page', 'size': 5 }), newNode('dl', newNode('dd', 'Quotation: ', newNode('input', { 'name': 'quotation', 'size': 40 }), newNode('div', { 'class': "DSBRedButton", 'click': function() { z.removeChild(zz) } }, newNode('div', 'Cancel')), newNode('div', { 'class': "DSBGreenButton", 'click': function() { quoteform.onsubmit() } }, newNode('div', "Preview ►")), newNode('input', { 'type': 'submit', 'style': 'visibility:hidden;width:0px;' }), newNode('dl', { 'style': 'display:' + (findlang_ == "en" ? "none" : "block") }, newNode('dd', 'Translation: ', newNode('input', { 'size': 40, 'name': 'translation' })))))) }, 'fields': { 'quotation': util.validateNoWikisyntax('quotation', true), 'year': util.validateNoWikisyntax('year', true), 'author': function(t) { return t }, 'source': function(t) { return t ? ", ''" + t + "''" : '' }, 'publisher': function(t) { return t ? ", " + t : '' }, 'page': function(t) { return t ? (/\-/.test(t) ? "pages " + t : "page " + t) : t }, 'translation': function(t) { return t } }, 'onsubmit': function(values, render) { var topline = "'''" + values.year + "'''" + (values.author ? ", " + values.author : '') + values.source + values.publisher + (values.page ? ", " + values.page : '') render(topline + "\n:" + values.quotation + (values.translation ? "\n:" + values.translation : ""), function(newhtml) { var findnumberofheaders = findnumberofheaders_(q), findnumberofdefs = findnumberofdefs_(q), quotetobeadded = newNode('span', { 'style': 'display:block;' }); quotetobeadded.innerHTML = newhtml.replace(/\<p\>|\<\/p\>/g, ''); editor.addEdit({ 'edit': function(wikitext) { return ccc = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?)\n(?!#" + findsubdef + "[:\*])|$"), "$1\n#" + findsubdef + "*" + topline + "\n#" + findsubdef + "*:" + values.quotation + (values.translation ? "\n#" + findsubdef + "*:" + values.translation : '') + '\n') }, 'redo': function() { quoteform.style.display = 'none'; quotetobeadded.style.display = 'block'; zz.appendChild(quotetobeadded) }, 'undo': function() { quoteform.style.display = 'inline'; zz.removeChild(quotetobeadded) }, 'summary': '+quote: "' + values.quotation + '"- ' + values.source }, quotetobeadded) }) } }, zz) }) } window.addPOSHeader = function(cancelhover) { var bodyContent = $(".mw-content-ltr")[0]; if (!defeditoptions.addingPOS) { defeditoptions.addingPOS = true; editor = new Editor() var headerLevel = (window.languageContainers && languageContainers[currentLanguageTab] && languageContainers[currentLanguageTab].firstChild) || bodyContent.firstChild; var ii; var temp, temp_; var theform; var findnumberofheaders; var addedwikitext; var prefakeheaders; var currentFocus; var langNames = [], docLink, docExists = {}; if (window.loadedTabs) { langNames = tabbedLanguages; } else { mw.util.$content.find("h2>.mw-headline").each(function() { langNames.push($(this).text()) }) } var langNameCodes; new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:languages/javascript-interface|GetAllData}}", "prop": "wikitext" }).done(function(r){ if(r.expandtemplates && r.expandtemplates.wikitext){ langNameCodes = JSON.parse(r.expandtemplates.wikitext); } }); function updateDocLink() { var pos = theform.getElementsByTagName("input")[0].value; pos = (({ Adjective: "adj", Adverb: "adv", Interjection: "interj", Preposition: "prep", Pronoun: "pron", Conjunction: "con", Contraction: "cont", Determiner: "det" })[pos] || pos.toLowerCase()); if (!langNameCodes || !pos || !theform.getElementsByTagName("input")[0].value) { return; } var currentLang = window.loadedTabs ? theform.parentNode.id.split("container")[0] : (function() { for (var s = theform; s && s.nodeName != "H2"; s = s.previousSibling); return s && s.lastChild && (s.lastChild.innerText || s.lastChild.textContent) })(); var docName = langNameCodes[currentLang] + "-" + pos; if (docExists[docName] === false) { return docLink.style.display = 'none'; } if (docExists[docName] === true) { docLink.style.display = 'inline'; docLink.href = mw.config.get("wgArticlePath").replace("$1", "Template:" + docName + "/doc"); return; } if (docExists[docName] === 'l') { docLink.style.display = 'none'; return; } docExists[docName] = 'l'; new mw.Api().get({ action: 'query', prop: 'info', titles: 'Template:' + docName + '/documentation' }).then(function(r) { docExists[docName] = r.query.pages.length == 1; updateDocLink(); }); } var poslist = '\nNoun\nVerb\nAdjective\nAdverb\nPronoun\nConjunction\nInterjection\nPreposition\nProper noun\nArticle\nPrepositional phrase\nAcronym\nAbbreviation\nInitialism\nContraction\nPrefix\nSuffix\nSymbol\nLetter\nLigature\nIdiom\nPhrase\nNumber\nNumeral\nCardinal number\nOrdinal number\nCardinal numeral\nOrdinal numeral\nPersonal pronoun\nDeterminer\nDemonstrative determiner\nClitic\nInfix\nInterfix\nAffix\nCircumfix\nCircumposition\nCounter\nKanji\nKanji reading\nHanja reading\nHirigana letter\nKatakana letter\nPinyin\nHan character\nHanzi\nHanja\nProverb\nExpression\nParticle\nInfinitive particle\nPossesive adjective\nPostposition\nPhrasal verb\nParticiple\nGerund\nInterrogative auxiliary verb\nPronominal adverb\nAdnominal\nAbstract pronoun\nConjunction particle\nCombining form\nRoot\nPinyin syllable\nSyllable\nHirigana character\nKatakana character\nJyutping syllable\nGismu\nLujvo\nBrivla\nClassifier\nPredicative\nMeasure word\nCorrelative\nPreverb\nPrenoun\nNoun stem\nNoun class\nCombined-kana character\nCmavo\n'; while (headerLevel.nextSibling) { if (/^h[34]$/i.test(headerLevel.nodeName) && !/Etymology|Pronunciation|Alternative\sforms/.test(headerLevel.innerHTML)) { headerLevel = headerLevel.nodeName.toLowerCase(); break; } headerLevel = headerLevel.nextSibling } currentBoxToBeAdded = newNode('div', { 'style': 'position:fixed;top:500px;' }) new AdderWrapper(editor, { createForm: function() { return theform = newNode('form', currentFocus = newNode('input', { 'style': 'font-size: 0.8em;font-size: ' + ((headerLevel == 'h3') ? '132%' : '116%') + ';font-weight: bold;font-family: sans-serif;width:auto;', 'placeholder': 'Part of speech', 'rows': 1, 'name': 'pos', focus: function() { currentFocus = this } }), newNode('input', { 'type': 'submit', 'value': 'Preview' }), newNode('input', { 'type': 'button', 'value': 'Cancel', click: function() { theform.style.display = 'none'; hoverNewPOS(null); defeditoptions.addingPOS = false; document.onmousemove = null; document.body.style.cursor = ''; } }), newNode('br'), newNode('input', { 'style': 'width:300px;font-family:monospace;', 'placeholder': '{\{head}}', 'name': 'inflline', focus: function() { currentFocus = this } }), docLink = newNode('a', { style: "margin-left:5px;display:none;", 'target': '_blank' }, "Help?"), newNode('ol', newNode('li', newNode('input', { 'size': 100, 'disabled': 'disabled' })))) }, fields: { 'pos': function(txt, error) { return poslist.indexOf('\n' + txt + '\n') > -1 ? txt : error('Please select a valid part of speech.') }, 'inflline': function(txt, error) { return txt || "{" + "{head}}" } }, onsubmit: function(values, render) { addedwikitext = '{' + '{subst:=}}==' + (headerLevel == 'h4' ? '=' : '') + values.pos + (headerLevel == 'h4' ? '=' : '') + '===\n' + values.inflline hoverNewPOS(null); document.onmousemove = null; defeditoptions.addingPOS = false; document.body.style.cursor = ''; render(addedwikitext, function(res) { theform.style.display = 'none' temp = document.createDocumentFragment(); temp.appendChild(temp_ = newNode('div', { 'class': 'fakeheader' })); temp_.innerHTML = res; temp.appendChild(newNode('ol', newNode('li', ' ', newNode('span')))); theform.parentNode.insertBefore(temp, theform); prefakeheaders = 0 findnumberofheaders = theform.previousSibling.previousSibling; while (true) { if (findnumberofheaders.previousSibling) { findnumberofheaders = findnumberofheaders.previousSibling; if (/h[2-6]/i.test(findnumberofheaders.nodeName)) { findnumberofheaders = Number(findnumberofheaders.lastChild.getElementsByTagName('a')[0].href.split("section=")[1]); break; } findnumberofheaders.className == 'fakeheader' && prefakeheaders++; } else { findnumberofheaders.parentNode.insertBefore(newNode('h2', languageHeaderEditButtons[currentLanguageTab].cloneNode(true), { 'style': 'display:none;' }), findnumberofheaders); } } var updatecatscallback; editor.addEdit({ 'edit': function(wikitext) { return ccc = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}([\\s\\S]*?\n\\{\\{subst:\\=\\}\\}==" + (headerLevel == 'h4' ? '=' : '') + "[^=]){" + prefakeheaders + "}[\\s\\S]*?(?=(\n=|\n----|\n\\{\\{subst:\\=\\}\\}==" + (headerLevel == 'h4' ? '=' : '') + "[^=]|$)))"), "$1\n" + addedwikitext + "\n\n# {" + "{rfdef}}\n") }, 'redo': function() { theform.style.display = 'none'; theform.parentNode.insertBefore(temp, theform); updatecatscallback = window.tabbedLanguages && updateCategories(theform.parentNode, addedwikitext) }, 'undo': function() { theform.style.display = 'block'; temp.appendChild(temp_); temp.appendChild(theform.previousSibling); updatecatscallback && updatecatscallback() }, 'summary': '+pos ' + values.pos }, temp_) makedefsidebox(theform.previousSibling.firstChild)(); editor.withCurrentText(function() { theform.previousSibling.getElementsByTagName('input')[0].value = ''; theform.previousSibling.getElementsByTagName('input')[0].focus() }) }) } }, currentBoxToBeAdded) cancelhover || setUpBoxToBeAdded(); theform.firstChild.focus() function hoverNewPOS(thefunction) { for (var ii = bodyContent.getElementsByTagName(headerLevel), i = 0; i < ii.length; i++) { if (!/^Etymology|Pronunciation|Alternative\sforms$/.test(ii[i].firstChild.innerHTML))(ii[i].parentNode.className == 'fakeheader' ? ii[i].parentNode : ii[i]).onmouseover = thefunction; } if (window.tabbedLanguages) { for (var i = 0; i < languageContainers.length; i++) languageContainers[i].lastChild.onmouseover = thefunction; } else { ii = bodyContent.getElementsByTagName('hr'); for (var i = 0; i < ii.length; i++) ii[i].onmouseover = thefunction; } } function hoverNewPOS_() { currentBoxToBeAdded.style.display = 'none'; this.parentNode.insertBefore(theform, this); currentFocus.focus(); updateDocLink() } cancelhover || hoverNewPOS(hoverNewPOS_); // autocomplete pos field theform.firstChild.onkeydown = function(e) { if ((e || event).keyCode == 9) { theform.getElementsByTagName("input")[3].focus(); return false } } theform.firstChild.onkeyup = function(e) { if (this.value[0] != this.value.charAt(0).toUpperCase()) this.value = this.value.charAt(0).toUpperCase() + this.value.substr(1); e = (e || event).keyCode; if (!(e >= 33 && e <= 40) && e != 8 && e != 46 && e != 27 && e != 16 && this.value) { if (poslist.indexOf('\n' + this.value) > -1) { if (this.setSelectionRange) this.setSelectionRange([this.value.length, this.value = poslist.match(RegExp(this.value + "[^\n]*"))][0], this.value.length); else if (this.createTextRange) { var z = this.createTextRange(); z.moveEnd('character', 0 - z.move('character', [this.value.length, this.value = poslist.match(RegExp(this.value + "[^\n]*"))][0]) + this.value.length); z.select() } } updateDocLink() } } } } window.updateCategories = function(container, newvalue, oldvalue) { var addedCategories = [], removedCategories = [] new mw.Api().get({ action: "parse", prop: "categorieshtml", title: mw.config.get('wgPageName'), text: newvalue }).then(function(r) { var e = r.parse.categorieshtml['*'].match(/\<li.*?\/li\>/g); var d = container.lastChild.lastChild; var f = document.createElement('ul'); for (var i = 0; e && i < e.length; i++) { f.innerHTML = e[i]; if (d.innerHTML.indexOf(f.firstChild.innerHTML) == -1) { addedCategories.push(d.insertBefore(f.lastChild, d.lastChild)) } } oldvalue && new mw.Api().get({ action: "parse", prop: "categorieshtml", title: mw.config.get('wgPageName'), text: oldvalue }).then(function(o) { e = o.parse.categorieshtml['*'].match(/\<li.*?\/li\>/g) for (var i = 0; e && i < e.length; i++) { f.innerHTML = e[i]; if (r.parse.categorieshtml['*'].indexOf(f.firstChild.innerHTML) == -1 && d.innerHTML.indexOf(f.firstChild.innerHTML) != -1) { var lis = d.getElementsByTagName('li') for (var ii = 0; ii < lis.length; ii++) { if (lis[ii].firstChild.innerHTML == f.firstChild.firstChild.innerHTML) { removedCategories.push(lis[ii]); lis[ii].style.display = 'none'; break; } } } } }) }); return function() { for (var i = 0; i < addedCategories.length; i++) { container.lastChild.lastChild.removeChild(addedCategories[i]) } for (var i = 0; i < removedCategories.length; i++) { removedCategories[i].style.display = ''; } } } function addgloss(qq) { var senseidform; findlang(qq.parentNode, function(findlang_) { if (qq.addinggloss) { return } qq.addinggloss = true; editor = new Editor(); new AdderWrapper(editor, { 'createForm': function() { return senseidform = newNode('form', { 'style': 'display:inline; padding-right:20px;' }, newNode('input', { 'size': 30, 'name': 'senseid' }), newNode('input', { 'type': 'submit', 'value': 'Add' }), newNode('input', { 'type': 'button', 'value': 'Cancel', 'click': function() { qq.removeChild(senseidform); qq.addinggloss = false } }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!')) }, 'fields': { 'senseid': util.validateNoWikisyntax('gloss', true) }, 'onsubmit': function(values) { var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq) senseidform.lastChild.innerHTML = ''; var nymB = qq.getElementsByTagName('li')[1] editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ") ?"), "$1{" + "{senseid|" + findlang_ + "|" + values.senseid + "}}"); return ccc = wikitext; }, redo: function() { senseidform.style.display = "none"; $([nymB.firstChild, nymB.nextSibling.firstChild]).removeClass('DSBinactive'); nymB.firstChild.title = nymB.nextSibling.firstChild.title = '' }, undo: function() { senseidform.style.display = "inline"; $([nymB.firstChild, nymB.nextSibling.firstChild]).addClass('DSBinactive'); nymB.firstChild.title = 'Please add a gloss before adding synonyms.'; nymB.nextSibling.firstChild.title = 'Please add a gloss before adding antonyms.' }, summary: "+senseid: " + values.senseid }) } }, qq, qq.childNodes[1]) senseidform.firstChild.focus() editor.withCurrentText(function(wikitext) { wikitext = wikitext.match("==" + (window.loadedTabs ? tabbedLanguages[currentLanguageTab] : $(findtopli(qq).parentNode).prevUntil("h2").eq(-1).prev().find(".mw-headline").text()) + "==\n[\\s\\S]+?(----|$)")[0]; if (!wikitext) return; var senses = '', matches = wikitext.match(/(\{\{sense\||\{\{trans-top\|)[^\}]+(?=\}\})/g) if (!matches) return; for (var ms = 0; ms < matches.length; ms++) { senses += "\n" + matches[ms].split("|")[1] } if (!senses) return; senseidform.firstChild.onkeyup = function(e) { e = (e || event).keyCode; if (!(e >= 33 && e <= 40) && e != 8 && e != 46 && e != 27 && e != 16 && this.value) { if (senses.indexOf('\n' + this.value) > -1) { if (this.setSelectionRange) this.setSelectionRange([this.value.length, this.value = senses.match(RegExp("\n" + this.value + "[^\n]*")).toString().substr(1)][0], this.value.length); else if (this.createTextRange) { var z = this.createTextRange(); z.moveEnd('character', 0 - z.move('character', [this.value.length, this.value = senses.match(RegExp("\n" + this.value + "[^\n]*")).toString().substr(1)][0]) + this.value.length); z.select() } } } } }) }) } function editgloss(qq) { editor = new Editor() editor.withCurrentText(function(wikitext) { if (qq.editinggloss) { return } qq.editinggloss = true; var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq) var senseidform; var oldsenseid; new AdderWrapper(editor, { 'createForm': function() { var thisId = "a" + String(Math.random()).replace(".", "") oldsenseid = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?)"), '').match(/^\{\{senseid\|[^\\|]*\|([^\}]*)/)[1] return senseidform = newNode('form', { 'style': 'display:inline; padding-right:20px; ' }, newNode('input', { 'size': 30, 'name': 'senseid', 'value': oldsenseid }), newNode('input', { 'type': 'checkbox', 'id': thisId, 'name': 'changematching', style: 'display:' + (window.tabbedLanguages ? 'inline' : 'none') }), newNode('label', { 'for': thisId, style: 'display:' + (window.tabbedLanguages ? 'inline' : 'none') }, 'Edit matching glosses'), newNode('input', { 'type': 'submit', 'value': 'Change' }), newNode('input', { 'type': 'button', 'value': 'Cancel', 'click': function() { qq.editinggloss = false; qq.removeChild(senseidform); } }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!')) }, 'fields': { 'senseid': util.validateNoWikisyntax('gloss', true), 'changematching': 'checkbox' }, 'onsubmit': function(values) { var ttables = [], sensetemps = [], backups = []; if (values.changematching) { ttables = jQuery(".NavHead", languageContainers[currentLanguageTab]).filter(function() { if (this.parentNode.getElementsByTagName("table")[0].className != "translations") return false; for (var i = 0; i < this.childNodes.length; i++) { if (this.childNodes[i].nodeType == 3 || this.childNodes[i].className == 'wt-edit-recurse') { return (this.childNodes[i].nodeValue || this.childNodes[i].innerHTML) == oldsenseid; } } }) sensetemps = jQuery(".qualifier-content", languageContainers[currentLanguageTab]).filter(function() { return this.parentNode.nextSibling.nextSibling.className == "ib-colon" && this.innerHTML == oldsenseid; }) } editor.addEdit({ edit: function(wikitext) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "\\s?(\{\{senseid\\|[^\\|]*\\|))[^\}]*"), "$1" + values.senseid); if (values.changematching) { var asd = wikitext.match('==' + tabbedLanguages[currentLanguageTab] + '==\n[\\s\\S]+?(\n==[^=]|$)'); wikitext = wikitext.replace(asd[0], asd[0].replace(RegExp("\\{\\{(sense|trans-top)\\|" + oldsenseid + "\\}\\}", "g"), "{\{$1\|" + values.senseid + "}}")) } return ccc = wikitext }, redo: function() { senseidform.style.display = "none"; for (var i = 0; i < ttables.length; i++) { backups.push(document.createDocumentFragment()); while (ttables[i].childNodes[1]) { backups[backups.length - 1].appendChild(ttables[i].childNodes[1]); } ttables[i].appendChild(document.createTextNode(values.senseid)) } for (var i = 0; i < sensetemps.length; i++) { backups.push(document.createDocumentFragment()); backups[backups.length - 1].appendChild(sensetemps[i].firstChild); sensetemps[i].appendChild(document.createTextNode(values.senseid)) } }, undo: function() { senseidform.style.display = "inline"; for (var i = 0; i < ttables.length; i++) { ttables[i].removeChild(ttables[i].childNodes[1]); ttables[i].appendChild(backups.shift()) } for (var i = 0; i < sensetemps.length; i++) { sensetemps[i].removeChild(sensetemps[i].firstChild) sensetemps[i].appendChild(backups.shift()) } }, summary: "senseid: " + values.senseid }) } }, qq, qq.childNodes[1]) senseidform.firstChild.focus() }) } function setupnymadder(qq, nymtype) { var passtheseheaders = "Usage notes|Inflection|Conjugation|Declension|Quotations", nymtypelist = ["Synonyms", "Antonyms", "Hypernyms", "Hyponyms", "Meronyms", "Holonyms"] for (var x = 0; nymtypelist[x] != nymtype; x++) passtheseheaders += "|" + nymtypelist[x]; if (qq.parentNode.parentNode.nodeName.toLowerCase() == "li") qq = qq.parentNode.parentNode; var findnumberofheaders = findnumberofheaders_(qq) var findnumberofdefs = findnumberofdefs_(qq.parentNode.getElementsByTagName('li')[0]) for (var findheaderlevel = qq.parentNode; !/^h\d$/i.test(findheaderlevel.nodeName); findheaderlevel = findheaderlevel.previousSibling); findheaderlevel = Number(findheaderlevel.nodeName.match(/\d/)); var senseidencoded = [] editor = new Editor() editor.withCurrentText(function(wikitext) { // Find nym header, or add it if it doesn't exist var qqq = qq.parentNode; while (!((qqq.className == "fakesubheader" || /h\d/i.test(qqq.nodeName)) && !qqq.innerHTML.match(passtheseheaders) || qqq.className == "printfooter" || qqq.className == "fakeheader" || qqq.className == "catlinks")) { qqq = qqq.nextSibling } if (!qqq.innerHTML.match(nymtype)) { qqq = qqq.parentNode.insertBefore(newNode('div', { 'class': 'fakesubheader' }, newNode('h' + (findheaderlevel + 1), nymtype)), qqq); } // relevant vars: // findheaderlevel is the the headerlevel of the most recent header above the ol // qq is still the li itself // qqq is the (possibly newly added) nym header // find all relevant senseids, make an array of them, the whole template in each var senseid = wikitext.replace( RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ")"), '').replace(/\n\n[\s\S]*$/, '').match(/\{\{senseid\|[^\\|]*\|[^\}]*/g) if (!senseid) { alert("No glosses were found. Click \"Add gloss\" to attach a gloss to the definition before adding " + nymtype.toLowerCase() + "."); return } // run through senseids, checking for a corresponding span id'd nymtype-langcode-id, adding them encased in an li in a soon-to-be-parsed temp variable if not found, otherwise suppressing new form creation temp = "" var nymformexists = [] for (var i = 0; i < senseid.length; i++) { if (document.getElementById(senseidencoded[i] = nymtype + "-" + encodeURIComponent(senseid[i].split("|")[1] + "-" + senseid[i].split("|")[2]).replace(/%20/g, '_').replace(/%3A/g, ':').replace(/%/g, '.'))) { nymformexists[i] = true } else { temp += "* {" + "{sense|" + senseid[i].split("|")[2] + "}} <span id='" + nymtype + "-" + senseid[i].split("|")[1] + "-" + senseid[i].split("|")[2] + "'></span>\n" } } new mw.Api().parse(temp, { title: mw.config.get('wgPageName'), pst: true, //pst makes subst work as expected disablelimitreport: true }).then(function(res) { var qqqq = newNode('span') qqqq.innerHTML = res qqqq = qqq.parentNode.insertBefore(qqqq.firstChild, qqq.nextSibling) // the ul containing the form-holder spans, right below the nym header for (var i = 0; i < senseid.length; i++) { if (!nymformexists[i]) { setupnymadder2(i, senseid, wikitext) } } if (qqqq.getElementsByTagName && qqqq.getElementsByTagName('li').length == 0) { qqqq.parentNode.removeChild(qqqq) } scroll(0, jQuery(qqq).offset().top) }); }) function setupnymadder2(i, senseid, wikitext) { var nymtype2 = nymtype.slice(0, -1).toLowerCase() var x = document.getElementById(senseidencoded[i]); var theform new AdderWrapper(editor, { 'createForm': function() { return theform = newNode('form', { 'style': 'display:inline;' }, newNode('input', { 'name': 'nym' }), newNode('input', { 'value': 'Add', 'type': 'submit' })) }, 'fields': { 'nym': util.validateNoWikisyntax(nymtype2, true) }, 'onsubmit': function(values, render) { theform.getElementsByTagName('input')[0].value = "" var firstnym = !theform.parentNode.parentNode.getElementsByTagName('a')[0] var addedwikitext = (firstnym ? '' : ', ') + "{" + "{l|" + senseid[i].split("|")[1] + "|" + values.nym + "}}" render(addedwikitext, function(res2) { var nodeToInsert = newNode('span') nodeToInsert.innerHTML = res2 editor.addEdit({ edit: function(wikitext) { // unindent findnumberofdefs = findnumberofdefs_(qq.parentNode.getElementsByTagName('li')[0]) if (wikitext.substr(wikitext.length - 1, 1) != "\n") { wikitext += "\n" } if (!wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + ")"), '').replace(RegExp("(\n(=|\\{\\{subst:=\\}\\})={" + (findheaderlevel - 1) + "}[^=][\\s\\S]*$)"), '').match(RegExp(nymtype + "={" + findheaderlevel + "}"))) { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?(\n(?=(\\{\\{subst:=\\}\\}|=)=+(?=[^=])(?!(" + passtheseheaders + ")))|$))"), "$1{" + "{subst:=}}===" + (findheaderlevel == 4 ? "=" : "") + nymtype + (findheaderlevel == 4 ? "=" : "") + "====\n\n") } if (firstnym) { var passthesesenseids = []; for (var ii = 0; ii < i; ii++) { passthesesenseids.push("\\* \\{\\{sense\\|" + senseid[ii].split("|")[2] + "\\}\\}") } wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}" + findnumberofdefs + "[\\s\\S]*?=" + nymtype + "=+[\\s\\S]*?\n" + (passthesesenseids.length > 0 ? "(?!(" + passthesesenseids.join("|") + ")))" : ")")), "$1* {" + "{sense|" + senseid[i].split("|")[2] + "}} " + addedwikitext + "\n") } else { wikitext = wikitext.replace(RegExp("(^[\\s\\S]*?((^|\n)=[\\s\\S]*?){" + findnumberofheaders + "}[\\s\\S]*?=" + nymtype + "=+[\\s\\S]*?\\{\\{sense\\|" + senseid[i].split("|")[2] + "\\}\\}.*)"), "$1" + addedwikitext) } return ccc = wikitext; }, redo: function() { theform.parentNode.parentNode.insertBefore(nodeToInsert, theform.parentNode) }, undo: function() { theform.parentNode.parentNode.removeChild(nodeToInsert) }, summary: "+" + nymtype2 + " [[" + values.nym + "]]" }, nodeToInsert) }) } }, x) // sort the lis var passthesesenseids = []; for (var ii = 0; ii < i; ii++) { passthesesenseids.push(senseid[ii].split("|")[2]) } for (var xx = x.parentNode.parentNode.nextSibling; xx.nextSibling && !/h\d/i.test(xx.nodeName) && xx.className != "fakesubheader" && xx.nodeName.toUpperCase() != "UL"; xx = xx.nextSibling); if (xx.nodeName.toUpperCase() == "UL") { var xxx = xx.getElementsByTagName('li') for (var xxxx = xxx.length; xxxx--;) { var xxxxx = xxx[xxxx].getElementsByTagName("span")[3] if (xxxxx && xxxxx.innerHTML == senseid[i].split("|")[2]) { x.parentNode.parentNode.removeChild(x.parentNode); xxx[xxxx].appendChild(x); break; } if (xxxxx && passthesesenseids.length && RegExp(passthesesenseids.join("|")).test(xxxxx.innerHTML)) { xxx[xxxx + 1] ? xx.insertBefore(x.parentNode, xxx[xxxx]) : xx.appendChild(x.parentNode); break; } } if (xxxx == -1) { xx.insertBefore(x.parentNode, xx.firstChild) } } } } jQuery(document).ready(function() { var disablebutton = document.getElementById('YRDefsideboxes-disable-button'); if (disablebutton) { disablebutton.innerHTML = ""; var toggle = newNode('span', { click: function() { if ($.cookie("DisableYREdit")) { $.cookie("DisableYREdit", null, { path: "/" }) toggle.innerHTML = "Disable definition editing options." } else { $.cookie("DisableYREdit", 1, { expires: 30, path: "/" }) toggle.innerHTML = "Enable definition editing options." } } }, ($.cookie("DisableYREdit") ? "Enable" : "Disable") + " definition editing options.") disablebutton.appendChild(toggle); } if (mw.config.get('wgAction') == 'view' && (mw.config.get('wgNamespaceNumber') == 0 || mw.config.get('wgPageName') == "Wiktionary:Sandbox") && !/&printable=yes|&diff=|&oldid=/.test(window.location.search) && !$.cookie("DisableYREdit") && !window.DisableYREdit && !window.loadedYREdit) { window.loadedYREdit = true; for (var ols = document.getElementsByTagName('ol'), ii = 0; ii < ols.length; ii++) { if (ols[ii].className != "references") { for (var lis = ols[ii].getElementsByTagName('li'), i = 0; i < lis.length; i++) { if (lis[i].parentNode == ols[ii] && ols[ii].parentNode.parentNode.nodeName != "UL") makedefsidebox(lis[i]); } } } mw.util.addPortletLink('p-tb', 'javascript:addPOSHeader()', 'Add part of speech'); defsidebuttons = [0] defeditoptions = { addingPOS: false } } }) // </nowiki> 8oh79o98tyjo7ss59excfxpgp5m9e4o MediaWiki:Gadget-DefSideBoxes.css 8 18007 89017 2012-10-22T17:39:09Z en>Yair rand 0 89017 css text/css .defEditButton { position: absolute; margin-left: -45px; width: 45px; height: 20px; } ol li:hover .defEditButton span { opacity: 1; filter: alpha(opacity=100); } .defEditButton span { display: block; margin-top: 3px; margin-left: 10px; cursor: pointer; height: 10px; width: 10px; opacity: 0; filter: alpha(opacity=0); transition: opacity .15s; -webkit-transition: opacity .15s; -moz-transition: opacity .15s; -o-transition: opacity .15s; background-image: url(//upload.wikimedia.org/wikipedia/commons/d/d3/InterlanguageLinks-Asset-Pencil.gif); } .defEditButton span:hover { background-image: url(//upload.wikimedia.org/wikipedia/commons/d/d1/InterlanguageLinks-Asset-Pencil-Hover.gif) } .addusexbutton { padding-left: 15px; margin-top: 0px; overflow: hidden; -webkit-transition: all 0.3s 0.3s; -moz-transition: all 0.3s 0.3s; -ms-transition: all 0.3s 0.3s; -o-transition: all 0.3s 0.3s; transition: all 0.3s 0.3s; height: 0px; } li:hover>.addusexbutton { margin-top: -4px; height: 19px; } .addusexbutton>a { vertical-align: top; cursor: pointer; font-size: 10px; } .addusexbutton>a+a { margin-left: 15px } .addusexbutton li a { display: block; cursor: pointer; } .addusexbutton li a.DSBinactive { color: #AAAAAA; cursor: default; } .addusexbutton ul { display: none; position: absolute; background-color: #FFFFFF; border: 1px solid #AAA; list-style: none; padding: 1px 10px; margin: -12px 0 0 5px; } .DSBRedButton, .DSBGreenButton { display: inline-block; padding: 0px; border-radius: 5px; border: #9D9D9D solid 1px; } .DSBRedButton { margin-right: 5px; margin-left: 3px; } .DSBRedButton div, .DSBGreenButton div { padding: 1px 5px; display: inline-block; font-size: 14px; color: white; font-weight: bold; border-radius: 5px; cursor: pointer; } .DSBRedButton div { border-left: 1px solid #CA0000; border-top: 1px solid #CA0000; background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #C70000),color-stop(1, #7A0000)); background: -moz-linear-gradient(top, #C70000, #7A0000); background: -o-linear-gradient(top, #C70000, #7A0000); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#C70000', endColorstr='#7A0000'); -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#C70000', endColorstr='#7A0000'); background-color: #C70000; } .DSBGreenButton div { border-left: 1px solid #3BB677; border-top: 1px solid #3BB677; background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #3BB475),color-stop(1, #246E48)); background: -moz-linear-gradient(top, #3BB475, #246E48); background: -o-linear-gradient(top, #3BB475, #246E48); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3BB475', endColorstr='#246E48'); -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3BB475', endColorstr='#246E48'); background-color: #3BB475; } mv6bxcbnp2yxxg7t6oodkz7m84s05xd 89018 89017 2026-08-06T23:33:56Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-DefSideBoxes.css]] 89017 css text/css .defEditButton { position: absolute; margin-left: -45px; width: 45px; height: 20px; } ol li:hover .defEditButton span { opacity: 1; filter: alpha(opacity=100); } .defEditButton span { display: block; margin-top: 3px; margin-left: 10px; cursor: pointer; height: 10px; width: 10px; opacity: 0; filter: alpha(opacity=0); transition: opacity .15s; -webkit-transition: opacity .15s; -moz-transition: opacity .15s; -o-transition: opacity .15s; background-image: url(//upload.wikimedia.org/wikipedia/commons/d/d3/InterlanguageLinks-Asset-Pencil.gif); } .defEditButton span:hover { background-image: url(//upload.wikimedia.org/wikipedia/commons/d/d1/InterlanguageLinks-Asset-Pencil-Hover.gif) } .addusexbutton { padding-left: 15px; margin-top: 0px; overflow: hidden; -webkit-transition: all 0.3s 0.3s; -moz-transition: all 0.3s 0.3s; -ms-transition: all 0.3s 0.3s; -o-transition: all 0.3s 0.3s; transition: all 0.3s 0.3s; height: 0px; } li:hover>.addusexbutton { margin-top: -4px; height: 19px; } .addusexbutton>a { vertical-align: top; cursor: pointer; font-size: 10px; } .addusexbutton>a+a { margin-left: 15px } .addusexbutton li a { display: block; cursor: pointer; } .addusexbutton li a.DSBinactive { color: #AAAAAA; cursor: default; } .addusexbutton ul { display: none; position: absolute; background-color: #FFFFFF; border: 1px solid #AAA; list-style: none; padding: 1px 10px; margin: -12px 0 0 5px; } .DSBRedButton, .DSBGreenButton { display: inline-block; padding: 0px; border-radius: 5px; border: #9D9D9D solid 1px; } .DSBRedButton { margin-right: 5px; margin-left: 3px; } .DSBRedButton div, .DSBGreenButton div { padding: 1px 5px; display: inline-block; font-size: 14px; color: white; font-weight: bold; border-radius: 5px; cursor: pointer; } .DSBRedButton div { border-left: 1px solid #CA0000; border-top: 1px solid #CA0000; background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #C70000),color-stop(1, #7A0000)); background: -moz-linear-gradient(top, #C70000, #7A0000); background: -o-linear-gradient(top, #C70000, #7A0000); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#C70000', endColorstr='#7A0000'); -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#C70000', endColorstr='#7A0000'); background-color: #C70000; } .DSBGreenButton div { border-left: 1px solid #3BB677; border-top: 1px solid #3BB677; background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #3BB475),color-stop(1, #246E48)); background: -moz-linear-gradient(top, #3BB475, #246E48); background: -o-linear-gradient(top, #3BB475, #246E48); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3BB475', endColorstr='#246E48'); -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3BB475', endColorstr='#246E48'); background-color: #3BB475; } mv6bxcbnp2yxxg7t6oodkz7m84s05xd MediaWiki:Gadget-DeveloperEditorTweaks.js 8 18008 89019 2019-01-18T00:08:34Z en>Erutuon 0 a bit odd to have "advanced" section with only one thing in it 89019 javascript text/javascript 'use strict'; /*jshint undef:true */ // {{documentation}} /*global mw, jQuery */ if ((mw.config.get('wgAction') === 'edit') || (mw.config.get('wgAction') === 'submit')) jQuery(document).ready(function () { var isCoding = { 'javascript': true, 'css': true, 'Scribunto': true }; var wgPageContentModel = mw.config.get('wgPageContentModel'); var wpTextbox1 = jQuery('#wpTextbox1'); if (!wpTextbox1.length) { console.error("det: failed to find WikiEditor entry point"); return; } if (!wpTextbox1.wikiEditor) { console.error("det: WikiEditor not loaded?"); return; } if (wgPageContentModel !== 'wikitext') { // remove irrelevant buttons // XXX: this should be reported to Bugzilla, really wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'main', 'group': 'insert' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'main', 'group': 'format' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'help' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'heading' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'format' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'size' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'insert' }); } // workaround [[gerrit:118993]] mw.util.addCSS( ".group-codeeditor-tools," + ".codeEditor-ui-toolbar .group-insert," + ".codeEditor-ui-toolbar .group-format," + ".codeEditor-ui-toolbar .tabs span.tab-advanced," + ".codeEditor-ui-toolbar .tabs span.tab-characters," + ".codeEditor-ui-toolbar .tabs span.tab-help," + ".codeEditor-ui-toolbar .sections {" + " display: block !important;" + "}"); if (isCoding[wgPageContentModel]) { wpTextbox1.wikiEditor('addToToolbar', { 'section': 'main', 'groups': { 'codefmt': { 'tools': { 'normws': { 'type': 'button', 'label': 'Normalise whitespace', 'icon': '//upload.wikimedia.org/wikipedia/commons/thumb/0/00/VisualEditor_-_Icon_-_Indent-list-ltr.svg/24px-VisualEditor_-_Icon_-_Indent-list-ltr.svg.png', // XXX 'action': { 'type': 'callback', 'execute': function (context) { function normws(text, lineStart, lineEnd) { text = text.replace(lineEnd ? /[ \t]+(\n|$)/g : /[ \t]+(\n)/g, '$1'); var step = 4; // XXX: guess it by inspecting the source? text = text.replace(lineStart ? /(^|\n)([\t ]+)/g : /(\n)([\t ]+)/g, function (_, nl, indent) { indent = indent.replace(/ /g, '\t').replace(/ +\t/g, '\t').replace(/\t/g, ' '); var steps = Math.floor(indent.length / step); indent = ''; for (var i = 0; i < steps; ++i) indent += '\t'; return nl + indent; }); return text; } if (!context.$textarea.textSelection('getSelection')) { if (context.codeEditor) context.codeEditor.selectAll(); else context.$textarea[0].select(); } context.$textarea.textSelection('encapsulateSelection', { replace: true, selectPeri: true, peri: normws(context.$textarea[0].value, true, true) }); } } } } } } }); } if ((wgPageContentModel === 'javascript') || (mw.config.get('wgPageName') === 'MediaWiki:Gadgets-definition')) { var moduleDescriptions = { 'mediawiki.Title': "<code>mw.Title</code> object", 'mediawiki.Uri' : "<code>mw.Uri</code> object", 'mediawiki.util' : "<code>mw.util</code>", 'mediawiki.user' : "<code>mw.user</code>", 'moment' : "Moment.js", 'site' : "Site-specific scripts: [[MediaWiki:Common.js]] and per-skin JS", 'es5-shim' : "ECMAScript 5 shim for older browsers", '':"" }; wpTextbox1.wikiEditor('addToToolbar', { 'sections': { 'js': { 'type': 'booklet', 'label': "JavaScript reference", 'pages': { 'modules': { 'layout': 'table', 'label': "ResourceLoader modules", 'headings': [ { 'text': "Identifier" }, { 'text': "Description" } ], 'rows': mw.loader.getModuleNames().sort().filter(function (modname) { // they are quite dull modules, but they are there if (/^ext\.geshi\.language\./.test(modname)) return false; if (/^ext\.math\.mathjax\.jax\.output\./.test(modname)) return false; return true; }).map(function (modname) { return { 'id': { 'html': '<code>' + modname + '</code>', }, 'desc': { 'html': moduleDescriptions[modname] || '<small style="color:gray;">(no description)</small>' } }; }) } } } } }); } if (wgPageContentModel === 'javascript') { var jshintDescriptions = { 'bitwise' : "Prohibit bitwise operators", 'camelcase' : "Mandate <code>javaCamelCase</code> (deprecated)", 'curly' : "Mandate curly brackets in control structures", 'eqeqeq' : "Prohibit <code>==</code> and <code>!=</code>", 'es3' : "Mandate ECMAScript 3 compatibility (deprecated; use <code>esversion:3</code>)", 'es5' : "Mandate ECMAScript 5 compatibility (deprecated; use <code>esversion:5</code>)", 'esversion:<var>n</var>' : 'Mandate compatibility with an ECMAScript version (3, 5<span class="serial-comma">,</span> or 6)', 'forin' : "Mandate <code>hasOwnProperty</code> in <code>for..in</code> loops", 'freeze' : "Prohibit changing prototypes of built-in objects", 'futurehostile' : "Warn about identifiers defined in future versions of JavaScript", 'globals' : "Disable warnings for these globals", 'immed' : "Mandate parentheses around immediately-executed function expressions (deprecated)", 'indent:<var>n</var>' : "Set tab width (deprecated)", 'latedef' : "Prohibit using variables before their declaration", 'newcap' : "Mandate capitalisation of constructors (deprecated)", 'noarg' : "Prohibit use of <code>arguments.caller</code> and <code>arguments.callee</code>", 'noempty' : "Warn about empty blocks (deprecated)", 'nonbsp' : "Warn about non-breaking space", 'nonew' : "Prohibit constructor usage for side effects", 'plusplus' : "Prohibit unary increment and decrement operators", 'quotmark:true' : "Mandate consistency of quotation marks (deprecated)", 'quotmark:single' : "Mandate single quotation marks only (deprecated)", 'quotmark:double' : "Mandata double quotation marks only (deprecated)", 'undef' : "Prohibit use of variables not explicitly declared", 'unused' : "Warn about unused variables", 'varstmt' : "Prohibit <code>var</code> (use <code>let</code> or <code>const</code>)", 'strict' : "Mandate strict mode compatibility", 'maxparams:<var>n</var>' : "Enforce maximum number of formal parameters", 'maxdepth:<var>n</var>' : "Enforce maximum depth of nested blocks", 'maxstatements' : "Enforce maximum number of statements per function", 'maxcomplexity:<var>n</var>': "Enforce maximum cyclomatic complexity", 'maxlen' : "Enforce maximum length of a line (deprecated)", 'asi' : "Allow semicolon insertion", 'boss' : "Allow assignment-expressions", 'debug' : "Allow <code>debugger</code> statements", 'eqnull' : "Allow <code>== null</code> comparisons", 'esnext' : "Allow ES.next syntax (deprecated; use <code>esversion:6</code>)", 'evil' : "Allow <code>eval</code>", 'expr' : "Allow expressions where statements are expected", 'funcscope' : "Allow using variables outside the block where they are declared", 'globalstrict' : "Allow global strict mode (deprecated)", 'iterator' : "Allow using <code>__iterator__</code>", 'lastsemic' : "Allow omitting semicolons last statement", 'laxbreak' : "Allow lax line breaks (deprecated)", 'laxcomma' : "Allow comma-first coding style (deprecated)", 'loopfunc' : "Allow making functions within a loop", 'maxerr:<var>n</var>' : "Set maximum number of warnings", 'moz' : "Allow Mozilla extensions", 'multistr' : "Allow multi-line string literals (deprecated)", 'notypeof' : "Allow lax usage of <code>typeof</code>", 'proto' : "Allow using <code>__proto__</code>", 'scripturl' : "Allow <code>javascript:</code> URLs", 'shadow' : "Allow variable shadowing", 'sub' : "Allow bracket notation for object member access (deprecated)", 'supernew' : "Allow atypical constructor usage", 'validthis' : "<code>this</code> is valid in this function", 'noyield' : "Allow generators without <code>yield</code>", 'browser' : "Assume a browser environment", 'devel' : "Assume <code>console</code> is available", 'jquery' : "Assume jQuery is available", 'nonstandard' : "Assume non-standard global functions are available", 'worker' : "Assume Web Worker globals are available", /* probably not useful: assume a framework is available 'couch' : "", 'dojo' : "", 'mootools' : "", 'node' : "", 'phantom' : "", 'prototypejs' : "", 'rhino' : "", 'wsh' : "", 'yui' : "", */ }; wpTextbox1.wikiEditor('addToToolbar', { 'section': 'js', 'pages': { 'jshint': { 'layout': 'table', 'label': "JSHint options", 'headings': [ { 'text': "Option" }, { 'text': "Description" } ], 'rows': Object.keys(jshintDescriptions).sort().map(function (option) { return { 'option': { 'html': '<code>' + option.replace( /^[^:]+/, '<a href="https://jshint.com/docs/options/#$&" target="_blank">$&</a>') + '</code>' }, 'description': { 'html': jshintDescriptions[option] } }; }) } } }); } if (wgPageContentModel === 'Scribunto') { // XXX: move console upwards } }); mtyoqowtbn14jj0l34ztugvpd9j8an9 89020 89019 2026-08-06T23:34:03Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-DeveloperEditorTweaks.js]] 89019 javascript text/javascript 'use strict'; /*jshint undef:true */ // {{documentation}} /*global mw, jQuery */ if ((mw.config.get('wgAction') === 'edit') || (mw.config.get('wgAction') === 'submit')) jQuery(document).ready(function () { var isCoding = { 'javascript': true, 'css': true, 'Scribunto': true }; var wgPageContentModel = mw.config.get('wgPageContentModel'); var wpTextbox1 = jQuery('#wpTextbox1'); if (!wpTextbox1.length) { console.error("det: failed to find WikiEditor entry point"); return; } if (!wpTextbox1.wikiEditor) { console.error("det: WikiEditor not loaded?"); return; } if (wgPageContentModel !== 'wikitext') { // remove irrelevant buttons // XXX: this should be reported to Bugzilla, really wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'main', 'group': 'insert' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'main', 'group': 'format' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'help' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'heading' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'format' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'size' }); wpTextbox1.wikiEditor('removeFromToolbar', { 'section': 'advanced', 'group': 'insert' }); } // workaround [[gerrit:118993]] mw.util.addCSS( ".group-codeeditor-tools," + ".codeEditor-ui-toolbar .group-insert," + ".codeEditor-ui-toolbar .group-format," + ".codeEditor-ui-toolbar .tabs span.tab-advanced," + ".codeEditor-ui-toolbar .tabs span.tab-characters," + ".codeEditor-ui-toolbar .tabs span.tab-help," + ".codeEditor-ui-toolbar .sections {" + " display: block !important;" + "}"); if (isCoding[wgPageContentModel]) { wpTextbox1.wikiEditor('addToToolbar', { 'section': 'main', 'groups': { 'codefmt': { 'tools': { 'normws': { 'type': 'button', 'label': 'Normalise whitespace', 'icon': '//upload.wikimedia.org/wikipedia/commons/thumb/0/00/VisualEditor_-_Icon_-_Indent-list-ltr.svg/24px-VisualEditor_-_Icon_-_Indent-list-ltr.svg.png', // XXX 'action': { 'type': 'callback', 'execute': function (context) { function normws(text, lineStart, lineEnd) { text = text.replace(lineEnd ? /[ \t]+(\n|$)/g : /[ \t]+(\n)/g, '$1'); var step = 4; // XXX: guess it by inspecting the source? text = text.replace(lineStart ? /(^|\n)([\t ]+)/g : /(\n)([\t ]+)/g, function (_, nl, indent) { indent = indent.replace(/ /g, '\t').replace(/ +\t/g, '\t').replace(/\t/g, ' '); var steps = Math.floor(indent.length / step); indent = ''; for (var i = 0; i < steps; ++i) indent += '\t'; return nl + indent; }); return text; } if (!context.$textarea.textSelection('getSelection')) { if (context.codeEditor) context.codeEditor.selectAll(); else context.$textarea[0].select(); } context.$textarea.textSelection('encapsulateSelection', { replace: true, selectPeri: true, peri: normws(context.$textarea[0].value, true, true) }); } } } } } } }); } if ((wgPageContentModel === 'javascript') || (mw.config.get('wgPageName') === 'MediaWiki:Gadgets-definition')) { var moduleDescriptions = { 'mediawiki.Title': "<code>mw.Title</code> object", 'mediawiki.Uri' : "<code>mw.Uri</code> object", 'mediawiki.util' : "<code>mw.util</code>", 'mediawiki.user' : "<code>mw.user</code>", 'moment' : "Moment.js", 'site' : "Site-specific scripts: [[MediaWiki:Common.js]] and per-skin JS", 'es5-shim' : "ECMAScript 5 shim for older browsers", '':"" }; wpTextbox1.wikiEditor('addToToolbar', { 'sections': { 'js': { 'type': 'booklet', 'label': "JavaScript reference", 'pages': { 'modules': { 'layout': 'table', 'label': "ResourceLoader modules", 'headings': [ { 'text': "Identifier" }, { 'text': "Description" } ], 'rows': mw.loader.getModuleNames().sort().filter(function (modname) { // they are quite dull modules, but they are there if (/^ext\.geshi\.language\./.test(modname)) return false; if (/^ext\.math\.mathjax\.jax\.output\./.test(modname)) return false; return true; }).map(function (modname) { return { 'id': { 'html': '<code>' + modname + '</code>', }, 'desc': { 'html': moduleDescriptions[modname] || '<small style="color:gray;">(no description)</small>' } }; }) } } } } }); } if (wgPageContentModel === 'javascript') { var jshintDescriptions = { 'bitwise' : "Prohibit bitwise operators", 'camelcase' : "Mandate <code>javaCamelCase</code> (deprecated)", 'curly' : "Mandate curly brackets in control structures", 'eqeqeq' : "Prohibit <code>==</code> and <code>!=</code>", 'es3' : "Mandate ECMAScript 3 compatibility (deprecated; use <code>esversion:3</code>)", 'es5' : "Mandate ECMAScript 5 compatibility (deprecated; use <code>esversion:5</code>)", 'esversion:<var>n</var>' : 'Mandate compatibility with an ECMAScript version (3, 5<span class="serial-comma">,</span> or 6)', 'forin' : "Mandate <code>hasOwnProperty</code> in <code>for..in</code> loops", 'freeze' : "Prohibit changing prototypes of built-in objects", 'futurehostile' : "Warn about identifiers defined in future versions of JavaScript", 'globals' : "Disable warnings for these globals", 'immed' : "Mandate parentheses around immediately-executed function expressions (deprecated)", 'indent:<var>n</var>' : "Set tab width (deprecated)", 'latedef' : "Prohibit using variables before their declaration", 'newcap' : "Mandate capitalisation of constructors (deprecated)", 'noarg' : "Prohibit use of <code>arguments.caller</code> and <code>arguments.callee</code>", 'noempty' : "Warn about empty blocks (deprecated)", 'nonbsp' : "Warn about non-breaking space", 'nonew' : "Prohibit constructor usage for side effects", 'plusplus' : "Prohibit unary increment and decrement operators", 'quotmark:true' : "Mandate consistency of quotation marks (deprecated)", 'quotmark:single' : "Mandate single quotation marks only (deprecated)", 'quotmark:double' : "Mandata double quotation marks only (deprecated)", 'undef' : "Prohibit use of variables not explicitly declared", 'unused' : "Warn about unused variables", 'varstmt' : "Prohibit <code>var</code> (use <code>let</code> or <code>const</code>)", 'strict' : "Mandate strict mode compatibility", 'maxparams:<var>n</var>' : "Enforce maximum number of formal parameters", 'maxdepth:<var>n</var>' : "Enforce maximum depth of nested blocks", 'maxstatements' : "Enforce maximum number of statements per function", 'maxcomplexity:<var>n</var>': "Enforce maximum cyclomatic complexity", 'maxlen' : "Enforce maximum length of a line (deprecated)", 'asi' : "Allow semicolon insertion", 'boss' : "Allow assignment-expressions", 'debug' : "Allow <code>debugger</code> statements", 'eqnull' : "Allow <code>== null</code> comparisons", 'esnext' : "Allow ES.next syntax (deprecated; use <code>esversion:6</code>)", 'evil' : "Allow <code>eval</code>", 'expr' : "Allow expressions where statements are expected", 'funcscope' : "Allow using variables outside the block where they are declared", 'globalstrict' : "Allow global strict mode (deprecated)", 'iterator' : "Allow using <code>__iterator__</code>", 'lastsemic' : "Allow omitting semicolons last statement", 'laxbreak' : "Allow lax line breaks (deprecated)", 'laxcomma' : "Allow comma-first coding style (deprecated)", 'loopfunc' : "Allow making functions within a loop", 'maxerr:<var>n</var>' : "Set maximum number of warnings", 'moz' : "Allow Mozilla extensions", 'multistr' : "Allow multi-line string literals (deprecated)", 'notypeof' : "Allow lax usage of <code>typeof</code>", 'proto' : "Allow using <code>__proto__</code>", 'scripturl' : "Allow <code>javascript:</code> URLs", 'shadow' : "Allow variable shadowing", 'sub' : "Allow bracket notation for object member access (deprecated)", 'supernew' : "Allow atypical constructor usage", 'validthis' : "<code>this</code> is valid in this function", 'noyield' : "Allow generators without <code>yield</code>", 'browser' : "Assume a browser environment", 'devel' : "Assume <code>console</code> is available", 'jquery' : "Assume jQuery is available", 'nonstandard' : "Assume non-standard global functions are available", 'worker' : "Assume Web Worker globals are available", /* probably not useful: assume a framework is available 'couch' : "", 'dojo' : "", 'mootools' : "", 'node' : "", 'phantom' : "", 'prototypejs' : "", 'rhino' : "", 'wsh' : "", 'yui' : "", */ }; wpTextbox1.wikiEditor('addToToolbar', { 'section': 'js', 'pages': { 'jshint': { 'layout': 'table', 'label': "JSHint options", 'headings': [ { 'text': "Option" }, { 'text': "Description" } ], 'rows': Object.keys(jshintDescriptions).sort().map(function (option) { return { 'option': { 'html': '<code>' + option.replace( /^[^:]+/, '<a href="https://jshint.com/docs/options/#$&" target="_blank">$&</a>') + '</code>' }, 'description': { 'html': jshintDescriptions[option] } }; }) } } }); } if (wgPageContentModel === 'Scribunto') { // XXX: move console upwards } }); mtyoqowtbn14jj0l34ztugvpd9j8an9 MediaWiki:Gadget-AjaxEdit.js 8 18009 89021 2026-07-23T22:16:54Z en>Surjection 0 do not insert a comma on Vector-2022 89021 javascript text/javascript // AjaxEdit // <nowiki> "use strict"; // Description : With a new button "Ædit" one can edit specific sections without reloading the whole page. // Supports TabbedLanguages gadget // Dependencies: mediawiki.util, mediawiki.Uri, mediawiki.user, mediawiki.api /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, sub:true, esversion:5, esnext:false */ /* global mw, $ */ (function ajaxEditIife() { window.AjaxEdit = {}; window.AjaxEdit.scriptLink = ""; if (mw.config.get("wgSiteName") !== "Wiktionary") window.AjaxEdit.scriptLink += "wikt:"; if (mw.config.get("wgContentLanguage") !== "en") window.AjaxEdit.scriptLink += "en:"; window.AjaxEdit.scriptLink += "MediaWiki:Gadget-AjaxEdit.js"; var $document = $(document); window.AjaxEdit.FireEvents = function () { // fire page load events like the [quotations ▼] thing // see https://github.com/wikimedia/mediawiki/blob/master/resources/src/mediawiki.action/mediawiki.action.edit.preview.js mw.hook("wikipage.content").fire($document); mw.hook("wikipage.categories").fire($document); }; var isVector2022 = mw.config.get("skin") === "vector-2022"; window.AjaxEdit.Click = function (ajaxEditAnchor) { if (ajaxEditAnchor.hasEditBox) { mw.notify("This AjaxEdit edit box is already open."); return; } else if (document.getElementById("ajaxedit-wrapper")) { mw.notify("An AjaxEdit edit box is already open on this page."); return; } else { ajaxEditAnchor.hasEditBox = true; } var elements = {}; var _query = new URL($(ajaxEditAnchor) .parent() .find("a[href*='action=edit']") .attr("href"), location.href).searchParams, title = _query.get("title"), section = _query.get("section"); section = section.replace("T-", ""); //transclusions... var hdr = $(ajaxEditAnchor).parent().parent(); var sectionName = hdr.children(":header").first().text(); if (window.tabbedLanguages && !hdr.is(":header")) { sectionName = window.tabbedLanguages[window.currentLanguageTab]; } var data = { action: 'raw', title: title, section: section }; $.get(mw.util.wikiScript('index'), data).then(function (wikitext) { var rowHeight = Math.min(15, 1 + wikitext.split("\n").length); elements.textarea = $("<textarea/>") .attr({ rows: rowHeight }) .addClass("mw-editfont-monospace") .text(wikitext); elements.textareaSummary = $("<input/>") .attr({ type: "text", maxlength: 500, spellcheck: true, name: "wpSummary", }) .keydown(event, function () { if (event.keyCode == 13) { // on enter elements.saveButton.click(); } }); function checkboxAndLabel(id, text) { var checkbox = $("<input/>") .attr({ "id": id, "type": "checkbox", }); var label = $("<label/>") .attr("for", id) .text(text); return [checkbox, label]; } var minorEdit = checkboxAndLabel("ajaxedit-minor-edit-checkbox", "Minor edit"); elements.minorEditCheckbox = minorEdit[0], elements.minorEditLabel = minorEdit[1]; elements.saveButton = $("<button/>") .text("Save") .click(function () { elements.textarea.attr('disabled', true); elements.textareaSummary.attr('disabled', true); window.AjaxEdit.Save(section, sectionName, elements.textarea.val(), title, elements.textareaSummary.val(), elements.minorEditCheckbox.prop("checked")) .then(function (apiSaveResponse) { if (apiSaveResponse.error) return; //if abusefilter was triggered new mw.Api().get({ page: mw.config.get("wgPageName"), action: "parse", prop: "text|categorieshtml" }) .then(function (newHtml) { $("#ajaxedit-wrapper").remove(); $("#mw-content-text").html(newHtml.parse.text["*"]); $("#catlinks").replaceWith(newHtml.parse.categorieshtml["*"]); window.AjaxEdit.FireEvents(); mw.loader.moduleRegistry["site"].state = "registered"; //mw.loader.moduleRegistry["site"].version="generate-unique-guid-here"; mw.loader.moduleRegistry["site"].script = undefined; mw.loader.using("site", function () { }); window.AjaxEdit.Submain(); }); }); }) .css("margin-left", "3px"); elements.cancelButton = $('<button/>') .text("Cancel") .click(function () { $("#ajaxedit-wrapper").remove(); ajaxEditAnchor.hasEditBox = false; }); elements.previewDiv = $("<div/>") .css({ "border-style": "solid", "border-width": "1px 1px 1px 4px", "border-radius": "0.33em", "border-color": "#a3d3ff", }) .hide(); function timestamp() { return new Date().toISOString(); } var previousText; var previousTextTimestamp = timestamp(); function loadPreview() { var newText = elements.textarea.val(); var textTimestamp = timestamp(); if (!previousText || previousText != newText) { new mw.Api() .parse( newText, { title: mw.config.get("wgPageName"), pst: "true", preview: "true", sectionpreview: "true", disableeditsection: "true" } ) .done(function (html) { if (textTimestamp > previousTextTimestamp) { elements.previewDiv.html(html); window.AjaxEdit.FireEvents(); previousTextTimestamp = textTimestamp; } }); } previousText = newText; } var livePreview = checkboxAndLabel("ajaxedit-live-preview-checkbox", "Live preview"); elements.livePreviewCheckbox = livePreview[0], elements.livePreviewLabel = livePreview[1]; elements.livePreviewCheckbox.on("change", function () { if ($(this).prop("checked")) { elements.previewDiv.show("slow"); loadPreview(); this.previewIntervalId = setInterval(loadPreview, 500); } else { clearInterval(this.previewIntervalId); elements.previewDiv.hide("fast"); elements.previewDiv.empty(); } }); var wrapper = $("<div/>") .attr("id", "ajaxedit-wrapper") .css({ width: "auto", "margin": 0, "overflow": "hidden" }) .append(elements.textarea) .append(elements.textareaSummary) .append(elements.saveButton) .append(elements.livePreviewCheckbox) .append(elements.livePreviewLabel) .append(elements.minorEditCheckbox) .append(elements.minorEditLabel) .append(elements.cancelButton) .append(elements.previewDiv); //tabbed languages support if ($(ajaxEditAnchor).is("#tabstable .editlangsection a")) { $(".languageContainer:not(:hidden)") .first() .prepend(wrapper); } else { hdr.after(wrapper); } }); }; /* * Define edit summary template with window.AjaxEditSummary. For instance: window.AjaxEditSummary = "Æ $sectionlink $summary"; */ window.AjaxEdit.Save = function (sectionID, sectionName, sectionText, title, summary, minorEdit) { var finalSummary; if (typeof window.AjaxEditSummary === "string") { var usedSummary = false; finalSummary = window.AjaxEditSummary.replace( /\$([a-zA-Z_][a-zA-Z0-9_]*)/g, function (fullMatch, name) { switch (name) { case "summary": { usedSummary = true; return summary; } case "scriptlink": return window.AjaxEdit.scriptLink; case "sectionname": return sectionText; case "sectionlink": return "/* " + sectionName + " */"; default: { mw.notify( "Your edit summary template (window.AjaxEditSummary) contains an unknown variable name. Variable name: " + name + ". Choose from summary, scriptlink, sectionname, sectionlink." ); return ""; } } }); if (!usedSummary) { mw.notify( "Your edit summary template (window.AjaxEditSummary) doesn't use the edit summary you supplied, so your edit summary will be appended to the template: " + window.AjaxEditSummary); finalSummary += " " + summary; } } else { finalSummary = "/* " + sectionName + " */ " + summary + " (using [[" + window.AjaxEdit.scriptLink + "|AjaxEdit]])"; } var data = { format: 'json', action: 'edit', title: title, section: sectionID, summary: finalSummary, text: sectionText, token: mw.user.tokens.get('csrfToken'), minor: minorEdit, }; return new mw.Api().post(data).then(function (response) { if (response && response.edit && response.edit.result == 'Success') { mw.notify("successful"); } else if (response && response.error) { mw.notify('Error: API returned error code "' + response.error.code + '": ' + response.error.info); } return response; }).fail(function (xhr) { mw.notify('Error: Request failed.'); $('#ajaxedit-wrapper *').attr('disabled', false); }); }; window.AjaxEdit.Submain = function () { $(".mw-body-content .mw-editsection > .mw-editsection-bracket:contains(']')").each(function () { var btn = $('<a/>').text("Ædit").on("click", function () { window.AjaxEdit.Click(this) }); $(this).before(!isVector2022 ? ", " : "").before(btn); }); }; window.AjaxEdit.Main = function () { $(".mw-editsection > .mw-editsection-bracket:contains(']')").each(function () { var btn = $('<a/>').text("Ædit").on("click", function () { window.AjaxEdit.Click(this) }); $(this).before(!isVector2022 ? ", " : "").before(btn); }); }; if (mw.config.get('wgAction') == "view") $(window.AjaxEdit.Main); })(); // </nowiki> eczkpa0tlqnt9ygeasfy4grqwh42u0e 89022 89021 2026-08-06T23:34:10Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-AjaxEdit.js]] 89021 javascript text/javascript // AjaxEdit // <nowiki> "use strict"; // Description : With a new button "Ædit" one can edit specific sections without reloading the whole page. // Supports TabbedLanguages gadget // Dependencies: mediawiki.util, mediawiki.Uri, mediawiki.user, mediawiki.api /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, sub:true, esversion:5, esnext:false */ /* global mw, $ */ (function ajaxEditIife() { window.AjaxEdit = {}; window.AjaxEdit.scriptLink = ""; if (mw.config.get("wgSiteName") !== "Wiktionary") window.AjaxEdit.scriptLink += "wikt:"; if (mw.config.get("wgContentLanguage") !== "en") window.AjaxEdit.scriptLink += "en:"; window.AjaxEdit.scriptLink += "MediaWiki:Gadget-AjaxEdit.js"; var $document = $(document); window.AjaxEdit.FireEvents = function () { // fire page load events like the [quotations ▼] thing // see https://github.com/wikimedia/mediawiki/blob/master/resources/src/mediawiki.action/mediawiki.action.edit.preview.js mw.hook("wikipage.content").fire($document); mw.hook("wikipage.categories").fire($document); }; var isVector2022 = mw.config.get("skin") === "vector-2022"; window.AjaxEdit.Click = function (ajaxEditAnchor) { if (ajaxEditAnchor.hasEditBox) { mw.notify("This AjaxEdit edit box is already open."); return; } else if (document.getElementById("ajaxedit-wrapper")) { mw.notify("An AjaxEdit edit box is already open on this page."); return; } else { ajaxEditAnchor.hasEditBox = true; } var elements = {}; var _query = new URL($(ajaxEditAnchor) .parent() .find("a[href*='action=edit']") .attr("href"), location.href).searchParams, title = _query.get("title"), section = _query.get("section"); section = section.replace("T-", ""); //transclusions... var hdr = $(ajaxEditAnchor).parent().parent(); var sectionName = hdr.children(":header").first().text(); if (window.tabbedLanguages && !hdr.is(":header")) { sectionName = window.tabbedLanguages[window.currentLanguageTab]; } var data = { action: 'raw', title: title, section: section }; $.get(mw.util.wikiScript('index'), data).then(function (wikitext) { var rowHeight = Math.min(15, 1 + wikitext.split("\n").length); elements.textarea = $("<textarea/>") .attr({ rows: rowHeight }) .addClass("mw-editfont-monospace") .text(wikitext); elements.textareaSummary = $("<input/>") .attr({ type: "text", maxlength: 500, spellcheck: true, name: "wpSummary", }) .keydown(event, function () { if (event.keyCode == 13) { // on enter elements.saveButton.click(); } }); function checkboxAndLabel(id, text) { var checkbox = $("<input/>") .attr({ "id": id, "type": "checkbox", }); var label = $("<label/>") .attr("for", id) .text(text); return [checkbox, label]; } var minorEdit = checkboxAndLabel("ajaxedit-minor-edit-checkbox", "Minor edit"); elements.minorEditCheckbox = minorEdit[0], elements.minorEditLabel = minorEdit[1]; elements.saveButton = $("<button/>") .text("Save") .click(function () { elements.textarea.attr('disabled', true); elements.textareaSummary.attr('disabled', true); window.AjaxEdit.Save(section, sectionName, elements.textarea.val(), title, elements.textareaSummary.val(), elements.minorEditCheckbox.prop("checked")) .then(function (apiSaveResponse) { if (apiSaveResponse.error) return; //if abusefilter was triggered new mw.Api().get({ page: mw.config.get("wgPageName"), action: "parse", prop: "text|categorieshtml" }) .then(function (newHtml) { $("#ajaxedit-wrapper").remove(); $("#mw-content-text").html(newHtml.parse.text["*"]); $("#catlinks").replaceWith(newHtml.parse.categorieshtml["*"]); window.AjaxEdit.FireEvents(); mw.loader.moduleRegistry["site"].state = "registered"; //mw.loader.moduleRegistry["site"].version="generate-unique-guid-here"; mw.loader.moduleRegistry["site"].script = undefined; mw.loader.using("site", function () { }); window.AjaxEdit.Submain(); }); }); }) .css("margin-left", "3px"); elements.cancelButton = $('<button/>') .text("Cancel") .click(function () { $("#ajaxedit-wrapper").remove(); ajaxEditAnchor.hasEditBox = false; }); elements.previewDiv = $("<div/>") .css({ "border-style": "solid", "border-width": "1px 1px 1px 4px", "border-radius": "0.33em", "border-color": "#a3d3ff", }) .hide(); function timestamp() { return new Date().toISOString(); } var previousText; var previousTextTimestamp = timestamp(); function loadPreview() { var newText = elements.textarea.val(); var textTimestamp = timestamp(); if (!previousText || previousText != newText) { new mw.Api() .parse( newText, { title: mw.config.get("wgPageName"), pst: "true", preview: "true", sectionpreview: "true", disableeditsection: "true" } ) .done(function (html) { if (textTimestamp > previousTextTimestamp) { elements.previewDiv.html(html); window.AjaxEdit.FireEvents(); previousTextTimestamp = textTimestamp; } }); } previousText = newText; } var livePreview = checkboxAndLabel("ajaxedit-live-preview-checkbox", "Live preview"); elements.livePreviewCheckbox = livePreview[0], elements.livePreviewLabel = livePreview[1]; elements.livePreviewCheckbox.on("change", function () { if ($(this).prop("checked")) { elements.previewDiv.show("slow"); loadPreview(); this.previewIntervalId = setInterval(loadPreview, 500); } else { clearInterval(this.previewIntervalId); elements.previewDiv.hide("fast"); elements.previewDiv.empty(); } }); var wrapper = $("<div/>") .attr("id", "ajaxedit-wrapper") .css({ width: "auto", "margin": 0, "overflow": "hidden" }) .append(elements.textarea) .append(elements.textareaSummary) .append(elements.saveButton) .append(elements.livePreviewCheckbox) .append(elements.livePreviewLabel) .append(elements.minorEditCheckbox) .append(elements.minorEditLabel) .append(elements.cancelButton) .append(elements.previewDiv); //tabbed languages support if ($(ajaxEditAnchor).is("#tabstable .editlangsection a")) { $(".languageContainer:not(:hidden)") .first() .prepend(wrapper); } else { hdr.after(wrapper); } }); }; /* * Define edit summary template with window.AjaxEditSummary. For instance: window.AjaxEditSummary = "Æ $sectionlink $summary"; */ window.AjaxEdit.Save = function (sectionID, sectionName, sectionText, title, summary, minorEdit) { var finalSummary; if (typeof window.AjaxEditSummary === "string") { var usedSummary = false; finalSummary = window.AjaxEditSummary.replace( /\$([a-zA-Z_][a-zA-Z0-9_]*)/g, function (fullMatch, name) { switch (name) { case "summary": { usedSummary = true; return summary; } case "scriptlink": return window.AjaxEdit.scriptLink; case "sectionname": return sectionText; case "sectionlink": return "/* " + sectionName + " */"; default: { mw.notify( "Your edit summary template (window.AjaxEditSummary) contains an unknown variable name. Variable name: " + name + ". Choose from summary, scriptlink, sectionname, sectionlink." ); return ""; } } }); if (!usedSummary) { mw.notify( "Your edit summary template (window.AjaxEditSummary) doesn't use the edit summary you supplied, so your edit summary will be appended to the template: " + window.AjaxEditSummary); finalSummary += " " + summary; } } else { finalSummary = "/* " + sectionName + " */ " + summary + " (using [[" + window.AjaxEdit.scriptLink + "|AjaxEdit]])"; } var data = { format: 'json', action: 'edit', title: title, section: sectionID, summary: finalSummary, text: sectionText, token: mw.user.tokens.get('csrfToken'), minor: minorEdit, }; return new mw.Api().post(data).then(function (response) { if (response && response.edit && response.edit.result == 'Success') { mw.notify("successful"); } else if (response && response.error) { mw.notify('Error: API returned error code "' + response.error.code + '": ' + response.error.info); } return response; }).fail(function (xhr) { mw.notify('Error: Request failed.'); $('#ajaxedit-wrapper *').attr('disabled', false); }); }; window.AjaxEdit.Submain = function () { $(".mw-body-content .mw-editsection > .mw-editsection-bracket:contains(']')").each(function () { var btn = $('<a/>').text("Ædit").on("click", function () { window.AjaxEdit.Click(this) }); $(this).before(!isVector2022 ? ", " : "").before(btn); }); }; window.AjaxEdit.Main = function () { $(".mw-editsection > .mw-editsection-bracket:contains(']')").each(function () { var btn = $('<a/>').text("Ædit").on("click", function () { window.AjaxEdit.Click(this) }); $(this).before(!isVector2022 ? ", " : "").before(btn); }); }; if (mw.config.get('wgAction') == "view") $(window.AjaxEdit.Main); })(); // </nowiki> eczkpa0tlqnt9ygeasfy4grqwh42u0e MediaWiki:Gadget-EditHere.js 8 18010 89023 2026-06-18T17:04:16Z en>Fenakhay 0 Undid revision [[Special:Diff/91219463|91219463]] by [[Special:Contributions/Fenakhay|Fenakhay]] ([[User talk:Fenakhay|talk]]) 89023 javascript text/javascript // <nowiki> /** Edit Here **/ // Edit sections of a page without leaving the article // Based on [[en:w:User:BrandonXLF/QuickEdit]] by [[en:w:User:BrandonXLF]] (function () { let mobile = mw.config.get('skin') === 'minerva'; let titleRegexp = new RegExp( mw.config.get('wgArticlePath').replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\$1/, '([^?]+)') + '|[?&]title=([^&#]*)' ); let apiSingleton; const LIVE_PREVIEW_KEY = 'edithere-live-preview'; function getLivePreviewPref() { try { return localStorage.getItem(LIVE_PREVIEW_KEY) === '1'; } catch (e) { return false; } } function setLivePreviewPref(value) { try { localStorage.setItem(LIVE_PREVIEW_KEY, value ? '1' : '0'); } catch (e) { /* empty */ } } function api(func, params) { if (!apiSingleton) { apiSingleton = new mw.Api(); } $.extend(params, { errorformat: 'html', errorlang: mw.config.get('wgUserLanguage'), errorsuselocal: true }); return apiSingleton[func](params).fail(function (_, data) { mw.notify(apiSingleton.getErrorMessage(data), { type: 'error', tag: 'edithere' }); }); } function getPageInfo(title, sectionID) { return api('get', { action: 'query', curtimestamp: 1, prop: 'revisions', indexpageids: 1, titles: title, rvprop: ['timestamp', 'content'], rvslots: 'main', rvsection: sectionID }).then(function (res) { let rev = res.query.pages[res.query.pageids[0]].revisions[0]; return { start: res.curtimestamp, base: rev.timestamp, full: rev.slots.main['*'] }; }); } function getPreviewCallback(editor) { editor.children('.preview').remove(); new OO.ui.ProgressBarWidget().$element.css({ maxWidth: '100%', borderRadius: '0', boxShadow: 'none', margin: '8px 0' }).addClass('preview').appendTo(editor); return function (html) { editor.children('.preview').remove(); const $preview = $('<div>') .html(html) .addClass('editHere-borderColorBase').css({ borderWidth: '1px', borderStyle: 'solid', padding: '8px', overflowX: 'hidden' }) .addClass('preview') .appendTo(editor); mw.hook('wikipage.content').fire($preview); }; } function showCompare(editor, title, from, to) { mw.loader.load('mediawiki.diff.styles'); api('post', { action: 'compare', fromslots: 'main', 'fromtext-main': from, fromtitle: title, frompst: 'true', toslots: 'main', 'totext-main': to, totitle: title, topst: 'true' }).then(function (r) { return r.compare['*'] ? $('<table>').addClass('diff').append( $('<colgroup>').append( $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content'), $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content') ) ).append(r.compare['*']) : 'No differences.'; }).then(getPreviewCallback(editor)); } // Parts taken from EditPage::extractSectionTitle and Parser::stripSectionName function getSectionSummary(text) { let match = text.match(/^(=+)(.+)\1\s*(\n|$)/); return !match ? '' : '/* ' + match[2].trim() // Strip internal link markup .replace(/\[\[:?([^[|]+)\|([^[]+)\]\]/g, '$2') .replace(/\[\[:?([^[]+)\|?\]\]/g, '$1') // Strip external link markup .replace(new RegExp('\\[(?:' + mw.config.get('wgUrlProtocols') + ')([^ ]+?) ([^\\[]+)\\]', 'ig'), '$2') // Remove wikitext quotes .replace(/(''|'''|''''')(?!')/g, '') // Strip HTML tags .replace(/<[^>]+?>/g, '') + ' */ '; } function showEditor($element) { let progress = new OO.ui.ProgressBarWidget(); // https://www.mediawiki.org/wiki/Heading_HTML_changes // Cannot use .closest() because DiscussionTools nests an h2 within a .mw-heading let heading = $element.parents(':header, .mw-heading').last(); let matcher = heading.nextUntil.bind(heading); let inserter = heading.after.bind(heading); let targetEl = $element.siblings('.edithere-target').last(); let titleMatch = targetEl.attr('href').match(titleRegexp); let title = decodeURIComponent(titleMatch[1] || titleMatch[2]); let sectionID = /[?&]v?e?section=T?-?(\d*)/.exec(targetEl.attr('href'))[1]; if (!heading.closest('.mw-parser-output').length) { let $articleContent = $('#mw-content-text .mw-parser-output'); matcher = function (selector) { let $child = $articleContent.children(selector).first(); if ($child.length) { return $child.prevAll(); } return $articleContent.children(); }; inserter = $articleContent.prepend.bind($articleContent); } inserter(progress.$element.css({ maxWidth: '100%', borderRadius: '0', boxShadow: 'none' })); $element.addClass('edithere-loading'); $('.edithere-hide').removeClass('edithere-hide'); $('.edithere-heading').removeClass('edithere-heading'); $('#edithere-editor').remove(); getPageInfo(title, sectionID).then(function (r) { var start = r.start, base = r.base, full = r.full, saving = false, expanded = false, remainderStart = full.match(/\n=+.+=+(?:\n|$)/), part = remainderStart ? full.substring(0, remainderStart.index) : full, remainder = remainderStart ? full.substring(remainderStart.index) : '', level = 0, editor; full.replace(/^(=+).+?(=+)(?:\n|$)/, function (m, a, b) { level = Math.min(a.length, b.length); return m; }); var levelMatch = 'h1'; for (var i = 2; i <= level; i++) levelMatch += ', h' + i + ':has(*), .mw-heading' + i; var partSection = matcher(':header:has(*), .mw-heading'), fullSection = matcher(levelMatch), textarea = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: part }), summary = new OO.ui.TextInputWidget({ value: getSectionSummary(part) }), minor = new OO.ui.CheckboxInputWidget({ accessKey: 'i', }), save = new OO.ui.ButtonInputWidget({ label: 'Save', title: 'Save your changes', flags: ['primary', 'progressive'], accessKey: 's' }), preview = new OO.ui.ButtonInputWidget({ label: 'Preview', title: 'Preview the new wikitext', accessKey: 'p' }), compare = new OO.ui.ButtonInputWidget({ label: 'Compare', title: 'View the difference between the current revision and your revision', accessKey: 'v' }), cancel = new OO.ui.ButtonInputWidget({ useInputTag: true, label: 'Cancel', title: 'Close the edit form and discard changes', flags: ['secondary', 'destructive'] }), more = new OO.ui.ButtonInputWidget({ label: '+', title: 'Edit the entire section (including subsections)' }), livePreview = new OO.ui.CheckboxInputWidget({ selected: getLivePreviewPref(), title: 'Automatically update the preview as you type' }), livePreviewField = new OO.ui.FieldLayout(livePreview, { label: 'Live preview', align: 'inline' }), buttons = new OO.ui.HorizontalLayout({ items: [save, preview, livePreviewField, compare, cancel] }); livePreviewField.$element.css({ display: 'flex', alignItems: 'center' }); if (part != full) { buttons.addItems([more], 4); } partSection.addClass('edithere-hide'); heading.addClass('edithere-heading'); $element.removeClass('edithere-loading'); progress.$element.remove(); textarea.$input.css({ borderRadius: '0' }); summary.on('enter', function () { save.emit('click'); }); save.on('click', function () { if (saving) return; var fullText = textarea.getValue() + (expanded ? '' : remainder); saving = true; save.setLabel('Saving...'); compare.setDisabled(true); preview.setDisabled(true); cancel.setDisabled(true); more.setDisabled(true); api('postWithEditToken', { action: 'edit', title: title, section: sectionID, summary: summary.getValue(), text: fullText, minor: minor.isSelected() ? true : undefined, notminor: minor.isSelected() ? undefined : true, starttimestamp: start, basetimestamp: base }).then(function () { api('get', { action: 'parse', page: mw.config.get('wgPageName'), prop: ['text', 'categorieshtml'] }).then(function (r) { var contentText = $('#mw-content-text'), catLinks = $('#catlinks'); contentText.find('.mw-parser-output').replaceWith(r.parse.text['*']); mw.hook('wikipage.content').fire(contentText); catLinks.replaceWith(r.parse.categorieshtml['*']); mw.hook('wikipage.categories').fire(catLinks); saving = false; }); }, function (code) { if (code == 'editconflict') { showEditConflict(editor, title, sectionID, fullText).then(function (r) { start = r.start; base = r.base; textarea = r.textarea; expanded = true; }); } compare.setDisabled(false); preview.setDisabled(false); cancel.setDisabled(false); more.setDisabled(expanded); saving = false; save.setLabel('Save'); }); }); var livePreviewTimer; function runPreview() { return api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: textarea.getValue() }).then(function (r) { return r.parse.text['*'] + '<div style="clear:both;"></div>'; }).then(getPreviewCallback(editor)); } preview.on('click', runPreview); textarea.on('change', function () { if (!livePreview.isSelected()) return; clearTimeout(livePreviewTimer); livePreviewTimer = setTimeout(runPreview, 300); }); livePreview.on('change', function (selected) { setLivePreviewPref(selected); clearTimeout(livePreviewTimer); if (selected) { runPreview(); } }); compare.on('click', function () { showCompare(editor, title, part + (expanded ? remainder : ''), textarea.getValue()); }); cancel.on('click', function () { editor.remove(); heading.removeClass('edithere-heading'); fullSection.removeClass('edithere-hide'); }); more.on('click', function () { expanded = true; textarea.setValue(textarea.getValue() + remainder); fullSection.addClass('edithere-hide'); more.setDisabled(true); }); editor = $('<div id="edithere-editor">').css({ overflowX: 'hidden' }).append( $('<div>').addClass('editHere-backgroundColorInteractive editHere-colorBase editHere-borderColorBase').css({ borderBottomWidth: '1px', borderBottomStyle: 'solid', marginBottom: '8px' }).append( textarea.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }).addClass('edithere-textarea'), $('<div>').addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px' }).append( $('<div>').css({ padding: '8px 4px 8px 8px', display: 'table-cell', verticalAlign: 'middle' }).html('Edit&nbsp;summary:'), summary.$element.css({ width: '100%', maxWidth: '100%', padding: '8px 0px', display: 'table-cell', verticalAlign: 'middle' }), new OO.ui.FieldLayout(minor, { label: new OO.ui.HtmlSnippet('Minor&nbsp;edit?'), align: 'inline' }).$element.css({ padding: '8px 8px 8px 4px', display: 'table-cell', verticalAlign: 'middle' }) ), buttons.$element.addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px', padding: '0 8px 8px' }), title !== mw.config.get('wgPageName') ? $('<div>').addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px', padding: '0 8px 8px' }).append( 'Editing page: ', $('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).css({ fontWeight: 'bold' }).text(title.replace(/_/g, ' ')) ) : undefined ) ); inserter(editor); // Fix cases when editing a section next to two floating images like at // https://en.wikipedia.org/w/index.php?title=Elevation&oldid=1235703526#Aviation textarea.updatePosition(); if (livePreview.isSelected()) { runPreview(); } }, function () { $element.removeClass('edithere-loading'); progress.$element.remove(); }); } function showEditConflict(editor, title, sectionID, text) { return getPageInfo(title, sectionID).then(function (r) { var textarea = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: r.full }), textarea2 = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: text, }); function syncSize() { textarea.styleHeight = -1; textarea.adjustSize(true); textarea2.styleHeight = -1; textarea2.adjustSize(true); var height = Math.max(textarea.$input.height(), textarea2.$input.height()); textarea.$input.height(height); textarea2.$input.height(height); } textarea.$input.css({ borderRadius: '0' }); editor.find('> :first-child > :first-child').remove(); $('<table>').addClass('editHere-borderColorBase').css({ width: '100%', borderWidth: '1px', borderStyle: 'solid', borderBottom: 'none', borderSpacing: '0', margin: '0 !important' }).append( $('<tr>').append( $('<th>').css({ width: '50%', paddingTop: '4px' }).text('Their version (to be saved)'), $('<th>').css({ width: '50%', paddingTop: '4px' }).text('Your version') ), $('<tr>').append( $('<td>').css({ width: '50%', padding: '4px 4px 0 8px' }).append( textarea.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ), $('<td>').css({ width: '50%', padding: '4px 8px 0 4px' }).append( textarea2.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ) ) ).prependTo(editor.find('> :first-child')); textarea.on('change', syncSize); textarea2.on('change', syncSize); syncSize(); showCompare(editor, title, text, r.full); r.textarea = textarea; return r; }); } function clickHandler(event) { const $element = $(event.target).closest('.edithere-editlink'); if (!$element.length || $element.hasClass('edithere-loading')) return; event.preventDefault(); showEditor($element); } function addLinksToChildren($element) { $element.find('#edithere-editor, .edithere-section').remove(); const $editHereLink = $('<a>') .addClass('edithere-section edithere-editlink') .attr('href', '#'); if (mobile) { $editHereLink .addClass('edithere-icon edithere-minerva-icon') .attr('role', 'button') .attr('tabindex', '0') .append( createSvg(20, 20) .html('<path d="M20 14.4286L16.4 14.4286L16.4 7L14.6 7L14.6 14.4286L11 14.4286L15.5 20L20 14.4286Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M16.4 7.63119V7H15.7688L16.4 7.63119ZM14.6 10.1498L15.7094 9.04044L14.6 7.93109V10.1498ZM13.7688 5L18.4 5V6.31934L18.7092 6.00057C18.8955 5.81322 19 5.55978 19 5.2956C19 5.03143 18.8955 4.77799 18.7092 4.59063L15.3694 1.29078C15.182 1.10454 14.9286 1 14.6644 1C14.4002 1 14.1468 1.10454 13.9594 1.29078L11.9995 3.23069L13.7688 5ZM9.27453 15.4753L5.74979 19H1V14.2502L10.9596 4.29065L12.6 5.93109V12.1498L12.3212 12.4286H6.81374L9.27453 15.4753Z" />') ); } else { $editHereLink.text('edit here'); } $element.find('.mw-editsection').each(function () { $('[href*="section="]', this) .last() .after($editHereLink.clone(true)) .addClass('edithere-target'); }); } function createSvg( width, height, viewBoxWidth = width, viewBoxHeight = height ) { return $(document.createElementNS('http://www.w3.org/2000/svg', 'svg')) .attr('width', width) .attr('height', height) .attr('viewBox', `0 0 ${viewBoxWidth} ${viewBoxHeight}`) .attr('aria-hidden', 'true') // https://en.wikipedia.org/wiki/Project:Dark_mode_(gadget) .addClass('mw-invert'); } $.when(mw.loader.using(['oojs-ui-core']), $.ready).done(function () { const $body = $(document.body); $body.on('click', clickHandler); addLinksToChildren($body); mw.hook('wikipage.content').add(addLinksToChildren); }); mw.loader.addStyleTag(` .editHere-backgroundColorInteractive { background-color: var(--background-color-interactive, #eaecf0); } .editHere-colorBase { color: var(--color-base, #202122); } .editHere-borderColorBase { border-color: var(--border-color-base, #a2a9b1); } .skin-minerva .mw-editsection { white-space: nowrap; } .skin-minerva .content .collapsible-heading .edithere-section { visibility: hidden; } .skin-minerva .content .collapsible-heading.open-block .edithere-section { visibility: visible; } .edithere-hide { display: none !important; } .edithere-loading, .edithere-heading { color: #777; } .edithere-icon { display: inline-flex; align-items: center; justify-content: center; background-image: none; svg { fill: currentcolor; } } .edithere-minerva-icon.edithere-minerva-icon { color: var(--color-subtle, #54595d); min-width: 44px; min-height: 44px; box-sizing: border-box; border: 1px solid transparent; border-radius: 2px; } .edithere-minerva-icon.edithere-minerva-icon:hover { background-color: var(--background-color-button-quiet--hover,rgba(0, 24, 73, .027)); } .edithere-minerva-icon.edithere-minerva-icon:active { background-color: var(--background-color-button-quiet--active,rgba(0, 24, 73, .082)); border-color: var(--border-color-interactive, #72777d); } .edithere-minerva-icon.edithere-minerva-icon:focus { outline: 1px solid transparent; } .edithere-minerva-icon.edithere-minerva-icon:focus:not(:active) { border-color: var(--border-color-progressive--focus, #36c); box-shadow: inset 0 0 0 1px var(--box-shadow-color-progressive--focus, #36c); }`); })(); // </nowiki> 919ikf58eonsxxpcy3ek8pkzunm1z6v 89024 89023 2026-08-06T23:34:20Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-EditHere.js]] 89023 javascript text/javascript // <nowiki> /** Edit Here **/ // Edit sections of a page without leaving the article // Based on [[en:w:User:BrandonXLF/QuickEdit]] by [[en:w:User:BrandonXLF]] (function () { let mobile = mw.config.get('skin') === 'minerva'; let titleRegexp = new RegExp( mw.config.get('wgArticlePath').replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\$1/, '([^?]+)') + '|[?&]title=([^&#]*)' ); let apiSingleton; const LIVE_PREVIEW_KEY = 'edithere-live-preview'; function getLivePreviewPref() { try { return localStorage.getItem(LIVE_PREVIEW_KEY) === '1'; } catch (e) { return false; } } function setLivePreviewPref(value) { try { localStorage.setItem(LIVE_PREVIEW_KEY, value ? '1' : '0'); } catch (e) { /* empty */ } } function api(func, params) { if (!apiSingleton) { apiSingleton = new mw.Api(); } $.extend(params, { errorformat: 'html', errorlang: mw.config.get('wgUserLanguage'), errorsuselocal: true }); return apiSingleton[func](params).fail(function (_, data) { mw.notify(apiSingleton.getErrorMessage(data), { type: 'error', tag: 'edithere' }); }); } function getPageInfo(title, sectionID) { return api('get', { action: 'query', curtimestamp: 1, prop: 'revisions', indexpageids: 1, titles: title, rvprop: ['timestamp', 'content'], rvslots: 'main', rvsection: sectionID }).then(function (res) { let rev = res.query.pages[res.query.pageids[0]].revisions[0]; return { start: res.curtimestamp, base: rev.timestamp, full: rev.slots.main['*'] }; }); } function getPreviewCallback(editor) { editor.children('.preview').remove(); new OO.ui.ProgressBarWidget().$element.css({ maxWidth: '100%', borderRadius: '0', boxShadow: 'none', margin: '8px 0' }).addClass('preview').appendTo(editor); return function (html) { editor.children('.preview').remove(); const $preview = $('<div>') .html(html) .addClass('editHere-borderColorBase').css({ borderWidth: '1px', borderStyle: 'solid', padding: '8px', overflowX: 'hidden' }) .addClass('preview') .appendTo(editor); mw.hook('wikipage.content').fire($preview); }; } function showCompare(editor, title, from, to) { mw.loader.load('mediawiki.diff.styles'); api('post', { action: 'compare', fromslots: 'main', 'fromtext-main': from, fromtitle: title, frompst: 'true', toslots: 'main', 'totext-main': to, totitle: title, topst: 'true' }).then(function (r) { return r.compare['*'] ? $('<table>').addClass('diff').append( $('<colgroup>').append( $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content'), $('<col>').addClass('diff-marker'), $('<col>').addClass('diff-content') ) ).append(r.compare['*']) : 'No differences.'; }).then(getPreviewCallback(editor)); } // Parts taken from EditPage::extractSectionTitle and Parser::stripSectionName function getSectionSummary(text) { let match = text.match(/^(=+)(.+)\1\s*(\n|$)/); return !match ? '' : '/* ' + match[2].trim() // Strip internal link markup .replace(/\[\[:?([^[|]+)\|([^[]+)\]\]/g, '$2') .replace(/\[\[:?([^[]+)\|?\]\]/g, '$1') // Strip external link markup .replace(new RegExp('\\[(?:' + mw.config.get('wgUrlProtocols') + ')([^ ]+?) ([^\\[]+)\\]', 'ig'), '$2') // Remove wikitext quotes .replace(/(''|'''|''''')(?!')/g, '') // Strip HTML tags .replace(/<[^>]+?>/g, '') + ' */ '; } function showEditor($element) { let progress = new OO.ui.ProgressBarWidget(); // https://www.mediawiki.org/wiki/Heading_HTML_changes // Cannot use .closest() because DiscussionTools nests an h2 within a .mw-heading let heading = $element.parents(':header, .mw-heading').last(); let matcher = heading.nextUntil.bind(heading); let inserter = heading.after.bind(heading); let targetEl = $element.siblings('.edithere-target').last(); let titleMatch = targetEl.attr('href').match(titleRegexp); let title = decodeURIComponent(titleMatch[1] || titleMatch[2]); let sectionID = /[?&]v?e?section=T?-?(\d*)/.exec(targetEl.attr('href'))[1]; if (!heading.closest('.mw-parser-output').length) { let $articleContent = $('#mw-content-text .mw-parser-output'); matcher = function (selector) { let $child = $articleContent.children(selector).first(); if ($child.length) { return $child.prevAll(); } return $articleContent.children(); }; inserter = $articleContent.prepend.bind($articleContent); } inserter(progress.$element.css({ maxWidth: '100%', borderRadius: '0', boxShadow: 'none' })); $element.addClass('edithere-loading'); $('.edithere-hide').removeClass('edithere-hide'); $('.edithere-heading').removeClass('edithere-heading'); $('#edithere-editor').remove(); getPageInfo(title, sectionID).then(function (r) { var start = r.start, base = r.base, full = r.full, saving = false, expanded = false, remainderStart = full.match(/\n=+.+=+(?:\n|$)/), part = remainderStart ? full.substring(0, remainderStart.index) : full, remainder = remainderStart ? full.substring(remainderStart.index) : '', level = 0, editor; full.replace(/^(=+).+?(=+)(?:\n|$)/, function (m, a, b) { level = Math.min(a.length, b.length); return m; }); var levelMatch = 'h1'; for (var i = 2; i <= level; i++) levelMatch += ', h' + i + ':has(*), .mw-heading' + i; var partSection = matcher(':header:has(*), .mw-heading'), fullSection = matcher(levelMatch), textarea = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: part }), summary = new OO.ui.TextInputWidget({ value: getSectionSummary(part) }), minor = new OO.ui.CheckboxInputWidget({ accessKey: 'i', }), save = new OO.ui.ButtonInputWidget({ label: 'Save', title: 'Save your changes', flags: ['primary', 'progressive'], accessKey: 's' }), preview = new OO.ui.ButtonInputWidget({ label: 'Preview', title: 'Preview the new wikitext', accessKey: 'p' }), compare = new OO.ui.ButtonInputWidget({ label: 'Compare', title: 'View the difference between the current revision and your revision', accessKey: 'v' }), cancel = new OO.ui.ButtonInputWidget({ useInputTag: true, label: 'Cancel', title: 'Close the edit form and discard changes', flags: ['secondary', 'destructive'] }), more = new OO.ui.ButtonInputWidget({ label: '+', title: 'Edit the entire section (including subsections)' }), livePreview = new OO.ui.CheckboxInputWidget({ selected: getLivePreviewPref(), title: 'Automatically update the preview as you type' }), livePreviewField = new OO.ui.FieldLayout(livePreview, { label: 'Live preview', align: 'inline' }), buttons = new OO.ui.HorizontalLayout({ items: [save, preview, livePreviewField, compare, cancel] }); livePreviewField.$element.css({ display: 'flex', alignItems: 'center' }); if (part != full) { buttons.addItems([more], 4); } partSection.addClass('edithere-hide'); heading.addClass('edithere-heading'); $element.removeClass('edithere-loading'); progress.$element.remove(); textarea.$input.css({ borderRadius: '0' }); summary.on('enter', function () { save.emit('click'); }); save.on('click', function () { if (saving) return; var fullText = textarea.getValue() + (expanded ? '' : remainder); saving = true; save.setLabel('Saving...'); compare.setDisabled(true); preview.setDisabled(true); cancel.setDisabled(true); more.setDisabled(true); api('postWithEditToken', { action: 'edit', title: title, section: sectionID, summary: summary.getValue(), text: fullText, minor: minor.isSelected() ? true : undefined, notminor: minor.isSelected() ? undefined : true, starttimestamp: start, basetimestamp: base }).then(function () { api('get', { action: 'parse', page: mw.config.get('wgPageName'), prop: ['text', 'categorieshtml'] }).then(function (r) { var contentText = $('#mw-content-text'), catLinks = $('#catlinks'); contentText.find('.mw-parser-output').replaceWith(r.parse.text['*']); mw.hook('wikipage.content').fire(contentText); catLinks.replaceWith(r.parse.categorieshtml['*']); mw.hook('wikipage.categories').fire(catLinks); saving = false; }); }, function (code) { if (code == 'editconflict') { showEditConflict(editor, title, sectionID, fullText).then(function (r) { start = r.start; base = r.base; textarea = r.textarea; expanded = true; }); } compare.setDisabled(false); preview.setDisabled(false); cancel.setDisabled(false); more.setDisabled(expanded); saving = false; save.setLabel('Save'); }); }); var livePreviewTimer; function runPreview() { return api('post', { action: 'parse', title: title, prop: 'text', pst: 'true', disablelimitreport: 'true', disableeditsection: 'true', sectionpreview: 'true', disabletoc: 'true', text: textarea.getValue() }).then(function (r) { return r.parse.text['*'] + '<div style="clear:both;"></div>'; }).then(getPreviewCallback(editor)); } preview.on('click', runPreview); textarea.on('change', function () { if (!livePreview.isSelected()) return; clearTimeout(livePreviewTimer); livePreviewTimer = setTimeout(runPreview, 300); }); livePreview.on('change', function (selected) { setLivePreviewPref(selected); clearTimeout(livePreviewTimer); if (selected) { runPreview(); } }); compare.on('click', function () { showCompare(editor, title, part + (expanded ? remainder : ''), textarea.getValue()); }); cancel.on('click', function () { editor.remove(); heading.removeClass('edithere-heading'); fullSection.removeClass('edithere-hide'); }); more.on('click', function () { expanded = true; textarea.setValue(textarea.getValue() + remainder); fullSection.addClass('edithere-hide'); more.setDisabled(true); }); editor = $('<div id="edithere-editor">').css({ overflowX: 'hidden' }).append( $('<div>').addClass('editHere-backgroundColorInteractive editHere-colorBase editHere-borderColorBase').css({ borderBottomWidth: '1px', borderBottomStyle: 'solid', marginBottom: '8px' }).append( textarea.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }).addClass('edithere-textarea'), $('<div>').addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px' }).append( $('<div>').css({ padding: '8px 4px 8px 8px', display: 'table-cell', verticalAlign: 'middle' }).html('Edit&nbsp;summary:'), summary.$element.css({ width: '100%', maxWidth: '100%', padding: '8px 0px', display: 'table-cell', verticalAlign: 'middle' }), new OO.ui.FieldLayout(minor, { label: new OO.ui.HtmlSnippet('Minor&nbsp;edit?'), align: 'inline' }).$element.css({ padding: '8px 8px 8px 4px', display: 'table-cell', verticalAlign: 'middle' }) ), buttons.$element.addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px', padding: '0 8px 8px' }), title !== mw.config.get('wgPageName') ? $('<div>').addClass('editHere-borderColorBase').css({ borderStyle: 'solid', borderWidth: '0 1px', padding: '0 8px 8px' }).append( 'Editing page: ', $('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).css({ fontWeight: 'bold' }).text(title.replace(/_/g, ' ')) ) : undefined ) ); inserter(editor); // Fix cases when editing a section next to two floating images like at // https://en.wikipedia.org/w/index.php?title=Elevation&oldid=1235703526#Aviation textarea.updatePosition(); if (livePreview.isSelected()) { runPreview(); } }, function () { $element.removeClass('edithere-loading'); progress.$element.remove(); }); } function showEditConflict(editor, title, sectionID, text) { return getPageInfo(title, sectionID).then(function (r) { var textarea = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: r.full }), textarea2 = new OO.ui.MultilineTextInputWidget({ rows: 1, maxRows: 20, autosize: true, value: text, }); function syncSize() { textarea.styleHeight = -1; textarea.adjustSize(true); textarea2.styleHeight = -1; textarea2.adjustSize(true); var height = Math.max(textarea.$input.height(), textarea2.$input.height()); textarea.$input.height(height); textarea2.$input.height(height); } textarea.$input.css({ borderRadius: '0' }); editor.find('> :first-child > :first-child').remove(); $('<table>').addClass('editHere-borderColorBase').css({ width: '100%', borderWidth: '1px', borderStyle: 'solid', borderBottom: 'none', borderSpacing: '0', margin: '0 !important' }).append( $('<tr>').append( $('<th>').css({ width: '50%', paddingTop: '4px' }).text('Their version (to be saved)'), $('<th>').css({ width: '50%', paddingTop: '4px' }).text('Your version') ), $('<tr>').append( $('<td>').css({ width: '50%', padding: '4px 4px 0 8px' }).append( textarea.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ), $('<td>').css({ width: '50%', padding: '4px 8px 0 4px' }).append( textarea2.$element.css({ width: '100%', maxWidth: '100%', fontFamily: 'monospace, monospace' }) ) ) ).prependTo(editor.find('> :first-child')); textarea.on('change', syncSize); textarea2.on('change', syncSize); syncSize(); showCompare(editor, title, text, r.full); r.textarea = textarea; return r; }); } function clickHandler(event) { const $element = $(event.target).closest('.edithere-editlink'); if (!$element.length || $element.hasClass('edithere-loading')) return; event.preventDefault(); showEditor($element); } function addLinksToChildren($element) { $element.find('#edithere-editor, .edithere-section').remove(); const $editHereLink = $('<a>') .addClass('edithere-section edithere-editlink') .attr('href', '#'); if (mobile) { $editHereLink .addClass('edithere-icon edithere-minerva-icon') .attr('role', 'button') .attr('tabindex', '0') .append( createSvg(20, 20) .html('<path d="M20 14.4286L16.4 14.4286L16.4 7L14.6 7L14.6 14.4286L11 14.4286L15.5 20L20 14.4286Z" /><path fill-rule="evenodd" clip-rule="evenodd" d="M16.4 7.63119V7H15.7688L16.4 7.63119ZM14.6 10.1498L15.7094 9.04044L14.6 7.93109V10.1498ZM13.7688 5L18.4 5V6.31934L18.7092 6.00057C18.8955 5.81322 19 5.55978 19 5.2956C19 5.03143 18.8955 4.77799 18.7092 4.59063L15.3694 1.29078C15.182 1.10454 14.9286 1 14.6644 1C14.4002 1 14.1468 1.10454 13.9594 1.29078L11.9995 3.23069L13.7688 5ZM9.27453 15.4753L5.74979 19H1V14.2502L10.9596 4.29065L12.6 5.93109V12.1498L12.3212 12.4286H6.81374L9.27453 15.4753Z" />') ); } else { $editHereLink.text('edit here'); } $element.find('.mw-editsection').each(function () { $('[href*="section="]', this) .last() .after($editHereLink.clone(true)) .addClass('edithere-target'); }); } function createSvg( width, height, viewBoxWidth = width, viewBoxHeight = height ) { return $(document.createElementNS('http://www.w3.org/2000/svg', 'svg')) .attr('width', width) .attr('height', height) .attr('viewBox', `0 0 ${viewBoxWidth} ${viewBoxHeight}`) .attr('aria-hidden', 'true') // https://en.wikipedia.org/wiki/Project:Dark_mode_(gadget) .addClass('mw-invert'); } $.when(mw.loader.using(['oojs-ui-core']), $.ready).done(function () { const $body = $(document.body); $body.on('click', clickHandler); addLinksToChildren($body); mw.hook('wikipage.content').add(addLinksToChildren); }); mw.loader.addStyleTag(` .editHere-backgroundColorInteractive { background-color: var(--background-color-interactive, #eaecf0); } .editHere-colorBase { color: var(--color-base, #202122); } .editHere-borderColorBase { border-color: var(--border-color-base, #a2a9b1); } .skin-minerva .mw-editsection { white-space: nowrap; } .skin-minerva .content .collapsible-heading .edithere-section { visibility: hidden; } .skin-minerva .content .collapsible-heading.open-block .edithere-section { visibility: visible; } .edithere-hide { display: none !important; } .edithere-loading, .edithere-heading { color: #777; } .edithere-icon { display: inline-flex; align-items: center; justify-content: center; background-image: none; svg { fill: currentcolor; } } .edithere-minerva-icon.edithere-minerva-icon { color: var(--color-subtle, #54595d); min-width: 44px; min-height: 44px; box-sizing: border-box; border: 1px solid transparent; border-radius: 2px; } .edithere-minerva-icon.edithere-minerva-icon:hover { background-color: var(--background-color-button-quiet--hover,rgba(0, 24, 73, .027)); } .edithere-minerva-icon.edithere-minerva-icon:active { background-color: var(--background-color-button-quiet--active,rgba(0, 24, 73, .082)); border-color: var(--border-color-interactive, #72777d); } .edithere-minerva-icon.edithere-minerva-icon:focus { outline: 1px solid transparent; } .edithere-minerva-icon.edithere-minerva-icon:focus:not(:active) { border-color: var(--border-color-progressive--focus, #36c); box-shadow: inset 0 0 0 1px var(--box-shadow-color-progressive--focus, #36c); }`); })(); // </nowiki> 919ikf58eonsxxpcy3ek8pkzunm1z6v MediaWiki:Gadget-FlagMovedPageForDeletion.js 8 18011 89025 2025-09-14T18:43:14Z en>Ioaxxere 0 Update and cleanup to async/await 89025 javascript text/javascript // <nowiki> // Idea: set a local storage item to remember which page got moved. // Then, on the "other side", make an automated edit which replaces the redirect with {{d}}. (async () => { // Setup. Don't add the button if the user already has permissions to delete the page immediately. if (document.querySelector(".movepage-wrapper") && !document.querySelector("#wpLeaveRedirect")) { let firstCheckbox = document.querySelector(".movepage-wrapper .oo-ui-fieldLayout-align-inline"); firstCheckbox.insertAdjacentHTML("afterEnd", `<div id="flag-delete-field" class="oo-ui-layout oo-ui-labelElement oo-ui-fieldLayout oo-ui-fieldLayout-align-inline"><div class="oo-ui-fieldLayout-body"><span class="oo-ui-fieldLayout-field"><span id="flag-delete" class="oo-ui-widget oo-ui-widget-enabled oo-ui-inputWidget oo-ui-checkboxInputWidget"><input type="checkbox" tabindex="0" id="flag-delete-checkbox" class="oo-ui-inputWidget-input"><span class="oo-ui-checkboxInputWidget-checkIcon oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-check oo-ui-iconElement oo-ui-labelElement-invisible oo-ui-iconWidget oo-ui-image-invert"></span></span></span><span class="oo-ui-fieldLayout-header"><label for="flag-delete-checkbox" class="oo-ui-labelElement-label">Flag the source page for deletion</label></span></div></div>`); let flagDeleteCheckbox = document.querySelector("#flag-delete-checkbox"); let submitButton = document.querySelector(".movepage-wrapper button"); submitButton.addEventListener("click", () => { if (flagDeleteCheckbox.checked) { let oldPageTitle = document.querySelector(`[name="wpOldTitle"]`).value; localStorage.setItem("flagDelete", oldPageTitle); } }); } // Make the edit after the move has completed. let sourcePageElem = document.querySelector("#movepage-oldlink"); let pageToFlagDelete = localStorage.getItem("flagDelete"); if (pageToFlagDelete && sourcePageElem && sourcePageElem.textContent === localStorage.getItem("flagDelete")) { localStorage.removeItem("flagDelete"); let actionAPI = new mw.Api({ajax: {headers: { "Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); let targetPage = document.querySelector("#movepage-newlink").textContent; let reason = "(no reason provided)"; let pageExists = false; let ns = (new mw.Title(pageToFlagDelete)).namespace; // 1. Make sure the moved page still exists (sometimes it gets deleted immediately) let pageExistsQuery = await actionAPI.get({action: "query", titles: pageToFlagDelete, format: "json"}); if (pageExistsQuery.query.pages[-1] === undefined) { pageExists = true; // 2. Find out the edit summary through the logevents API. let moveLogResponse = await actionAPI.get({ action: "query", letitle: pageToFlagDelete, list: "logevents", letype: "move", format: "json" }); if (moveLogResponse.query.logevents[0] && moveLogResponse.query.logevents[0].comment) reason = moveLogResponse.query.logevents[0].comment; try { // 3. Make the edit. await actionAPI.postWithToken("csrf", { action: "edit", title: pageToFlagDelete, summary: "Flagging for deletion after moving the page to [[:" + targetPage + "]]: " + reason + " ([[MediaWiki:Gadget-FlagMovedPageForDeletion.js|automated]])", text: "{{d|Page moved to [[:" + targetPage + "]]: " + reason + "}}" }); } catch (e) { // 4. If there's an error, try again on /documentation. if (ns === 8 || ns === 9 || ns === 10 || ns === 11 || ns === 828 || ns === 829) { await actionAPI.postWithToken("csrf", { action: "edit", title: pageToFlagDelete + "/documentation", summary: "Flagging for deletion after moving the page to [[:" + targetPage + "]]: " + reason + " ([[MediaWiki:Gadget-FlagMovedPageForDeletion.js|automated]])", text: "{{d|Page moved to [[:" + targetPage + "]]: " + reason + "}}" }); } } } // 5. Display a message on success. let a = document.createElement("a"); a.href = mw.util.getUrl(pageToFlagDelete); a.textContent = pageToFlagDelete; let message = document.createElement("span"); message.append(a, pageExists ? " has been successfully flagged for deletion." : " has been deleted."); mw.notify(message); } })(); // </nowiki> at6kg31pq5njx9y9yt3evgb0xu9goh0 89026 89025 2026-08-06T23:34:30Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:MediaWiki:Gadget-FlagMovedPageForDeletion.js]] 89025 javascript text/javascript // <nowiki> // Idea: set a local storage item to remember which page got moved. // Then, on the "other side", make an automated edit which replaces the redirect with {{d}}. (async () => { // Setup. Don't add the button if the user already has permissions to delete the page immediately. if (document.querySelector(".movepage-wrapper") && !document.querySelector("#wpLeaveRedirect")) { let firstCheckbox = document.querySelector(".movepage-wrapper .oo-ui-fieldLayout-align-inline"); firstCheckbox.insertAdjacentHTML("afterEnd", `<div id="flag-delete-field" class="oo-ui-layout oo-ui-labelElement oo-ui-fieldLayout oo-ui-fieldLayout-align-inline"><div class="oo-ui-fieldLayout-body"><span class="oo-ui-fieldLayout-field"><span id="flag-delete" class="oo-ui-widget oo-ui-widget-enabled oo-ui-inputWidget oo-ui-checkboxInputWidget"><input type="checkbox" tabindex="0" id="flag-delete-checkbox" class="oo-ui-inputWidget-input"><span class="oo-ui-checkboxInputWidget-checkIcon oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-check oo-ui-iconElement oo-ui-labelElement-invisible oo-ui-iconWidget oo-ui-image-invert"></span></span></span><span class="oo-ui-fieldLayout-header"><label for="flag-delete-checkbox" class="oo-ui-labelElement-label">Flag the source page for deletion</label></span></div></div>`); let flagDeleteCheckbox = document.querySelector("#flag-delete-checkbox"); let submitButton = document.querySelector(".movepage-wrapper button"); submitButton.addEventListener("click", () => { if (flagDeleteCheckbox.checked) { let oldPageTitle = document.querySelector(`[name="wpOldTitle"]`).value; localStorage.setItem("flagDelete", oldPageTitle); } }); } // Make the edit after the move has completed. let sourcePageElem = document.querySelector("#movepage-oldlink"); let pageToFlagDelete = localStorage.getItem("flagDelete"); if (pageToFlagDelete && sourcePageElem && sourcePageElem.textContent === localStorage.getItem("flagDelete")) { localStorage.removeItem("flagDelete"); let actionAPI = new mw.Api({ajax: {headers: { "Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]"}}}); let targetPage = document.querySelector("#movepage-newlink").textContent; let reason = "(no reason provided)"; let pageExists = false; let ns = (new mw.Title(pageToFlagDelete)).namespace; // 1. Make sure the moved page still exists (sometimes it gets deleted immediately) let pageExistsQuery = await actionAPI.get({action: "query", titles: pageToFlagDelete, format: "json"}); if (pageExistsQuery.query.pages[-1] === undefined) { pageExists = true; // 2. Find out the edit summary through the logevents API. let moveLogResponse = await actionAPI.get({ action: "query", letitle: pageToFlagDelete, list: "logevents", letype: "move", format: "json" }); if (moveLogResponse.query.logevents[0] && moveLogResponse.query.logevents[0].comment) reason = moveLogResponse.query.logevents[0].comment; try { // 3. Make the edit. await actionAPI.postWithToken("csrf", { action: "edit", title: pageToFlagDelete, summary: "Flagging for deletion after moving the page to [[:" + targetPage + "]]: " + reason + " ([[MediaWiki:Gadget-FlagMovedPageForDeletion.js|automated]])", text: "{{d|Page moved to [[:" + targetPage + "]]: " + reason + "}}" }); } catch (e) { // 4. If there's an error, try again on /documentation. if (ns === 8 || ns === 9 || ns === 10 || ns === 11 || ns === 828 || ns === 829) { await actionAPI.postWithToken("csrf", { action: "edit", title: pageToFlagDelete + "/documentation", summary: "Flagging for deletion after moving the page to [[:" + targetPage + "]]: " + reason + " ([[MediaWiki:Gadget-FlagMovedPageForDeletion.js|automated]])", text: "{{d|Page moved to [[:" + targetPage + "]]: " + reason + "}}" }); } } } // 5. Display a message on success. let a = document.createElement("a"); a.href = mw.util.getUrl(pageToFlagDelete); a.textContent = pageToFlagDelete; let message = document.createElement("span"); message.append(a, pageExists ? " has been successfully flagged for deletion." : " has been deleted."); mw.notify(message); } })(); // </nowiki> at6kg31pq5njx9y9yt3evgb0xu9goh0 Teamplaid:VectorTab 10 18012 89027 2025-09-09T16:26:26Z en>Surjection 0 89027 wikitext text/x-wiki <templatestyles src="Template:VectorTab/style.css" /><span class="mw-parser-output"><span class="vectortab">{{{1|entry}}}</span></span><noinclude>{{documentation}}</noinclude> fgq5vy1fsmsp8s911jec76ulnnfk4gq 89028 89027 2026-08-07T01:04:06Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:VectorTab]] 89027 wikitext text/x-wiki <templatestyles src="Template:VectorTab/style.css" /><span class="mw-parser-output"><span class="vectortab">{{{1|entry}}}</span></span><noinclude>{{documentation}}</noinclude> fgq5vy1fsmsp8s911jec76ulnnfk4gq Teamplaid:VectorTab/style.css 10 18013 89029 2025-09-09T16:28:46Z en>Surjection 0 89029 sanitized-css text/css .vectortab { padding-left: 0.4em; padding-right: 0.4em; background-color: var(--wikt-palette-lightblue, #d9ebff); border: var(--wikt-palette-deepblue, #2f445c) 1px solid; color: var(--wikt-palette-black, #202122); } body.skin-vector-legacy .vectortab { background-color: #EDF6FB; border-bottom: 1px solid #A7D7F9; border-right: 1px solid #A7D7F9; border-left: 1px solid #A7D7F9; border-top: none; color: #0645AD; } body.skin-vector-2022 .vectortab { padding-left: 0em; padding-right: 0em; margin-left: 0.2em; margin-right: 0.2em; border: unset; background-color: unset; border-color: unset; border-bottom: 2px solid; font-size: 14px; padding-bottom: 0.25em; } hv2a9rld85p7hif1xwco8tkq928wjvp 89030 89029 2026-08-07T01:04:20Z Altronic 4137 Chaidh 1 mhùthadh ion-phortachadh o [[:en:Template:VectorTab/style.css]] 89029 sanitized-css text/css .vectortab { padding-left: 0.4em; padding-right: 0.4em; background-color: var(--wikt-palette-lightblue, #d9ebff); border: var(--wikt-palette-deepblue, #2f445c) 1px solid; color: var(--wikt-palette-black, #202122); } body.skin-vector-legacy .vectortab { background-color: #EDF6FB; border-bottom: 1px solid #A7D7F9; border-right: 1px solid #A7D7F9; border-left: 1px solid #A7D7F9; border-top: none; color: #0645AD; } body.skin-vector-2022 .vectortab { padding-left: 0em; padding-right: 0em; margin-left: 0.2em; margin-right: 0.2em; border: unset; background-color: unset; border-color: unset; border-bottom: 2px solid; font-size: 14px; padding-bottom: 0.25em; } hv2a9rld85p7hif1xwco8tkq928wjvp