模組:Category tree/topic cat/data/Places/sandbox


簡介

编辑

這是Module:category tree/topic cat子系統及其子模組的主資料模組的文檔頁面。這些模組負責產生主題頁面的描述和分類,例如Category:英語 鳥Category:西班牙語 法國Category:漢語 德國州首府,以及相應的、非特定於語言的頁面,例如Category:鳥Category:法國Category:德國州首府。(透過 {{auto cat}} 系統處理的所有其他分類均由 Module:category tree/poscatboiler 子系統處理。)

Module:category tree/topic cat/data處的主資料模組本身不包含資料,而是從其子模組導入資料,並套用一些後處理。

  • 若要尋找哪個子模組實現特定類別,請使用右側的搜尋框。
  • 若要新增新的資料子模組,請複製現有subpages並修改其內容。 然後,將其名稱新增至 Module:category tree/topic cat/data 頂部的子頁面列表中。
透過這個模組使用的任何分類頁面的文字應該僅使用{{auto cat}}
在處理特定類別頁面時,應該通過{{auto cat}}來調用Module:category tree/topic cat。您通常不應該直接調用{{topic cat}}。如果您找到一個直接調用{{topic cat}}的類別頁面,該頁面可能是在{{auto cat}}創建之前建立的舊頁面,應該進行更改。

概念

编辑

各語言分類和傘分類

编辑

The topic cat system internally makes a distinction based on which languages a category applies to:

  1. Per-language categories. These are of the form langcode:label (e.g. Category:es:Birds and Category:de:States of the United States). Here, langcode is the language code of a recognized full Wiktionary language (see WT:LOL for the list of all such languages and their codes), and label is a topic, generally one that can apply to multiple languages. The intended category contents is terms in the language in question that are either related to, instances of or types of the topic in question (depending on the type of category; see below). Associated with each per-language category is an umbrella category; see below. The following restrictions apply to per-language categories:
    1. The language mentioned by langcode must currently be a full language, not an etymology-only language. (Etymology-only languages include lects such as Provençal, considered a variety of Occitan, and Biblical Hebrew, considered a variety of Hebrew. See here for the list of such lects.)
    2. The category label specified by label as found in the category name always begins with a capital letter, whether or not the underlying form of the label is capitalized (contrast Category:en:Birds with Category:en:France). Internally, this is different, and the internal form of a label begins with a lowercase or uppercase letter as appropriate (Template:Kbd but Template:Kbd).
  2. Umbrella categories. These are of the form label, i.e. a bare category label. As with per-language categories, this label is always capitalized in the category name, regardless of the underlying form of the label. Examples are Category:Birds, Category:France and Category:State capitals of Germany. Umbrella categories serve to group all the per-language categories for a particular topic. They also serve to group more specific subcategories, e.g. under Category:Birds can be found Category:Birds of prey, Category:Freshwater birds, Category:Columbids (which includes doves and pigeons), etc. as well as Category:Eggs and Category:Feathers. Umbrella categories should not normally directly contain any terms.
  3. Unlike for the poscatboiler system, language-specific categories do NOT currently exist. These would be topics that only make sense for a given language or small set of languages, and which are allowed allowed for that language or those languages. Currently, all topics are cross-language even if in practice they don't make sense except in conjunction with a subset of languages; but this may change in the future.

分類類型

编辑

In addition to the above distinction, the topic cat system divides categories according to the category type, which specifies the relationship between the category and the members of that category:

  1. Related-to categories (type = "related-to") contain terms that are semantically related to the category topic. For example, Category:en:Chess contains terms such as checkmate, rank (a row on a chessboard), endgame, en passant, Grandmaster, etc. "Related to" is a nebulous criterion, and as a result the terms in the category should be related to the category as directly as possible, to avoid the category becoming a grab bag of random terms.
  2. Name (type = "name") categories contain terms that are names of individual, specific instances of the category. For example, Category:Chess openings contains names of specific openings, such as Ruy Lopez and Sicilian Defense. Even more clearly, Category:Moons of Jupiter contains names of individual moons that orbit the planet Jupiter.
  3. Type (type = "type") categories contains terms for types of the entity described by the category name. For example, Category:Checkmate patterns contains types of checkmates, such as ladder mate and smothered mate. Even more clearly, Category:Hobbyists contains terms for types of hobbyists, such as oenophile (a wine enthusiast), numismatist (a stamp collector), etc. (If this were a name category, it would contain names of specific, presumably famous, hobbyists — something that would probably not be dictionary-worthy material.)
  4. Set (type = "set") categories are used when the distinction between names and types of a given topic may not always be clear, but the overall membership is still well-defined. For example, Category:Heraldic charges contains terms for components of coats of arms, e.g. bend sinister (a diagonal band from lower left to upper right), fleur-de-lis (a stylized image of a lily, as is commonly associated with New Orleans) and quatrefoil (a symmetrical shape made from the outline of four circles).
  5. Grouping (type = "grouping") categories are higher-level categories that are used only to group more specific categories and should not contain elements themselves (but nevertheless sometimes do). An example is Category:Industries, which contains subcategories devoted to particular industries (e.g. Category:Banking, Category:Mining, Category:Music industry, Category:Oil industry, etc.).
  6. Top-level (type = "toplevel") categories are special high-level categories that list all the categories of one of the above types, and which are always named List of type categories, e.g. Category:List of related-to categories (listing all the "related-to" umbrella categories) or Category:es:List of name categories (listing all the Spanish name-type categories). The number of top-level categories is fixed.

Note that name, type and set categories are conceptually similar to each other, in that each contains terms that have an is-a relationship with the topic in question, whereas related-to categories express a weaker sort of relation between term and topic, merely asserting that the term is in some way "related" or "pertinent" to the topic in question. For this reason, when creating new topics, you should always strive to create name, type or set topics whenever possible, and avoid related-to topics unless there is no alternative and you're convinced this topic is really necessary. Before creating such a category:

  1. Consider whether there is another category already in existence that will cover this semantic space.
  2. Consider whether you can convert the category to a name, type or set category.
  3. Investigate whether there needs to be a category for the semantic concept at all (in particular, abstract concepts often do not merit related-to categories).
  4. Make sure there are enough terms to fill up this category in at least two languages (one of which should be English). What qualifies as "enough" varies a bit from topic to topic but generally should be at least 10.
  5. Make sure the terms you add or consider adding to this category are directly related to the topic at hand. Do not add terms merely because the term contains the name of the topic in it (e.g. if you create a category named brick, do not add terms like brick house, thick as a brick or yellow brick road merely becaues they have the word "brick" in them; instead, use the ===Related terms=== section of the brick lemma to include these terms).

It should also be noted that name, type and set categories typically use the plural in their topic name, which related-to categories often use the singular. This is not a hard and fast rule, however, and there are exceptions in both directions. If it's not obvious what type of category a given topic refers to, consider making this explicit in the topic name, e.g. names of stars or types of stars rather than just stars. (In the future, all, or at least most, topic categories may be named in such a fashion.)

新增、刪除或修改分類

编辑

A sample entry is as follows (in this case, found in Module:category tree/topic cat/data/History):

labels["ancient history"] = {
	type = "related-to",
	description = "default",
	parents = {"history"},
}

This generates the description and categorization for all per-language categories of the form langcode:Ancient history (e.g. Category:en:Ancient history) as well as for the umbrella category Category:Ancient history (see above for the definition of per-language and umbrella categories).

The meaning of this snippet is as follows:

  • The label itself needs to use proper capitalization or lower case in the first letter of the label, even though the label as it appears in the category name is always capitalized, consistent with the principle that category names begin with a capital letter. In this case, the label is lowercase, and other labels that reference it need to use the same casing (as in the example below). By contrast, a label like Ancient Near East (as in the example below) is capitalized because the label refers to a specific region, and toponyms are capitalized in English.
  • the type field specifies the category type, as described above. This label is a "related-to" category.
  • The description field gives the description text that will appear when a user visits the category page. Certain special values are recognized, including "default", which generates a default label. The value of the default label depends on the label's name, the language of the category, and the label's type. In this case, it is equivalent to "{{{langname}}} terms related to [[ancient]] [[history]]" (where {{{langname}}} is replaced with the name of the language in question) and "terms related to [[ancient]] [[history]]"" for the umbrella category. See #Descriptions below for more information on specifying descriptions.
  • The parents field gives the labels of the parent categories. Here, the category specifies a single parent "history". This means that a category such as Category:en:Ancient history will have Category:en:History as its parent. An additional top-level list parent will automatically be added (in this case Category:en:List of related-to categories) as well as the umbrella parent Category:Ancient history.

Another example follows:

labels["places in Romance of the Three Kingdoms"] = {
	type = "name",
	displaytitle = "places in ''Romance of the Three Kingdoms''",
	description = "=places in ''{{w|Romance of the Three Kingdoms}}''",
	parents = {"Romance of the Three Kingdoms", "China"},
}

This is a subcategory of "Romance of the Three Kingdoms" (a 14th century Chinese historical novel) and accordingly specifies "Romance of the Three Kingdoms" as the parent, along with "China" (note the capitalization, in accordance with the principles laid out above). A description is given explicitly, preceded by = (which in this case prepends "names for specific" to the description). The displaytitle field is also set so that the name of the work is italicized.

分類標籤字段

编辑

The following fields are recognized for the object describing a label:

type
The type of the label (Template:Kbd, Template:Kbd, Template:Kbd, Template:Kbd, Template:Kbd or Template:Kbd, as described above. Mandatory. It is possible to specify multiple comma-separated types, for "mixed" categories that can contain more than one type of term. For example, the label flags currently has type = "related-to,name,type" because it contains a mixture of terms related to flags (e.g. flagpole and grommet), terms for individual flags (e.g. Star-Spangled Banner) and terms for types of flags (e.g. prayer flag, flag of convenience). Mixed categories are strongly dispreferred and should be split into separate per-type categories.
description
A plain English description for the label. This should generally be no longer than one sentence. Place additional, longer explanatory text in the additional field described below, and put {{wikipedia}} boxes in the topright field described below so that they are correctly right-aligned with the description. Template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} will be expanded appropriately;參見下文的#字段值中的模板替換。Certain values are handled specially, including "default" (and variants such as "default with the", "default wikify" and "default no singularize") and phrases preceded by an = sign, as explained in more detail below.
parents
A table listing one or more parent labels of this label. This controls the parent categories that the category is contained within, as well as the chain of breadcrumbs appearing across the top of the page (see below).
  • An item in the table can be either a single string (the parent label), or a table containing (at least) the two elements name and sort. In the latter case, name specifies the parent label name, while the sort value specifies the sort key to use to sort it in that category. The default sort key is the category's label.
  • If a parent label begins with Category: it is interpreted as a raw category name, rather than as a label name. It can still have its own sort key as usual.
  • The first listed parent controls the category's parent breadcrumb in the chain of breadcrumbs at the top of the page. (The breadcrumb of the category itself is determined by the breadcrumb setting, as described below.)
breadcrumb
The text of the last breadcrumb that appears at the top of the category page.
  • By default, it is the same as the category label, with the first letter capitalized.
  • The value can be either a string, or a table containing two elements called name and nocap. In the latter case, name specifies the breadcrumb text, while nocap can be used to disable the automatic capitalization of the breadcrumb text that normally happens.
  • Note that the breadcrumbs collectively are the chain of links that serve as a navigation aid for the hierarchical organization of categories. For example, a category like Category:en:Ancient Near East will have a breadcrumb chain similar to "Fundamental » All languages » English » All topics » History » Ancient history » Ancient Near East", where each breadcrumb is a link to a category at the appropriate level. The last breadcrumb here is "Ancient Near East", and its text is controlled by this field.
displaytitle
Apply special formatting such as italics to the category page title, as with the {{DISPLAYTITLE:...}} magic word (see mw:Help:Magic words). The same formatting is also applied to breadcrumbs, descriptions and other mentions of the label in formatted text. The value of this is either a string (which should be the formatted label, e.g. "The Matrix", "people in Romance of the Three Kingdoms" or "Glee (TV series)") or a Lua function to generate the formatted category title. The Lua function is passed two parameters: the raw label (without any preceding language code) and the language object of the category's language (or nil for umbrella categories). It should return the appropriately formatted label. If the value of this field is a string, template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} will be expanded appropriately; see below. See Module:category tree/topic cat/data/Culture for examples of using displaytitle.
topright
Introductory text to display right-aligned, before the edit and recent-entries boxes on the right side. This field should be used for {{wikipedia}} and other similar boxes. Template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} are expanded appropriately, just as with description;參見下文的#字段值中的模板替換。 Compare the preceding field, which is similar to topright but used for left-aligned text placed above the description.
preceding
Introductory text to display directly before the text in the description field. The difference between the two is that description text will also be shown in the list of children categories shown on the parent category's page, while the preceding text will not. For this reason, use preceding instead of description for {{also}} hatnotes and similar text, and keep description relatively short. Template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} are expanded appropriately, just as with description;參見下文的#字段值中的模板替換。 Compare the topright field, which is similar to preceding but is right-aligned, placed above the edit and recent-entries boxes.
additional
Additional text to display directly after the text in the the description field. The difference between the two is that description text will also be shown in the list of children categories shown on the parent category's page, while the additional text will not. For this reason, use additional instead of description for long explanatory notes, See also references and the like, and keep description relatively short. Template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} are expanded appropriately, just as with description;參見下文的#字段值中的模板替換
wp
Display a box linking to a Wikipedia entry in the upper right corner. The value can either be true to link to an entry that is the same as the label; a string, to link to that entry; or a list of strings or true, to generate multiple boxes, one per list item. For example, if the label pesäpallo has wp = true, a box will be generated that links to Pesäpallo on Wikipedia, and if the label football (American) has wp = "American football", a box will be generated that links to American football on Wikipedia.
wpcat
Display a box linking to a Wikipedia category in the upper right corner. This is similar to wp except that the link is to a category (the generated entry or entries is/are prepended with Category:). For example, if the label animals has wpcat = true set, a box will be generated that links to Category:Animals on Wikipedia.
commonscat
Display a box linking to a Wikimedia Commons category in the upper right corner. This is similar to wpcat except that the link is to Wikimedia Commons instead of Wikipedia. For example, if the label racquet sports has commonscat = true set, a box will be generated that links to Category:Racquet sports on Wikimedia Commons.
topic
Text indicating the topic being handled by this category. This appears in the auto-generated "additional" message following the description, which indicates what type this category is (based on the type field) and what sorts of terms should go into it. This does not normally need to be specified, as it's derived directly from the label. But it is useful e.g. for the label Template:Kbd, which sets topic = "planets", because the auto-generated "additional" message contains the text " ... It should contain terms for types of {{{topic}}}, ...", and using the label directly will result in redundant text. Template invocations and special template-like references such as {{{langname}}} and {{{langcode}}} are expanded appropriately, just as with description;參見下文的#字段值中的模板替換。The value of this field can be "default" or "default with the", which will be expanded appropriately based on the label.
umbrella
A table describing the umbrella category that collects all language-specific categories associated with this label. The umbrella category is named using the label, without any language prefix. For example, for the label Template:Kbd, the umbrella category is named Category:Ancient history, and is a parent category (in addition to any categories specified using parents) of Category:en:Ancient history, Category:fr:Ancient history and all other language-specific categories holding adjectives. This table contains the following fields:
description
A plain English description for the umbrella category. By default, it is derived from the description field of the label itself by removing language references (specifically, {{{langname}}} , {{{langcode}}}:, {{{langcode}}} and {{{langcat}}} ) and adding Template:Kbd before the result. Text is automatically added to the end indicating that this category is an umbrella category that only contains other categories, and does not contain pages describing terms.
breadcrumb
The last breadcrumb in the chain of breadcrumbs at the top of the category page; see above. By default, this is the category label.
topright
Like the topright field on regular category pages; see above.
preceding
Like the preceding field on regular category pages; see above.
additional
Like the additional field on regular category pages; see above.
topic
Like the topic field on regular category pages; see above.
umbrella_description
The same as the description subfield of the umbrella field.

字段值中的模板替換

编辑

Template invocations can be inserted in the text of description, parents (both name and sort key), breadcrumb, toc_template and toc_template_full values, and will be expanded appropriately. In addition, the following special template-like invocations are recognized and replaced by the equivalent text:

{{PAGENAME}}
The name of the current page. (Note that two braces are used here instead of three, as with the other parameters described below.)
{{{langname}}}
The name of the language that the category belongs to. Not recognized in umbrella fields.
{{{langcode}}}
The code of the language that the category belongs to (e.g. en for English, de for German). Not recognized in umbrella fields.
{{{langcat}}}
The name of the language's main category, which adds "language" to the regular name. Not recognized in umbrella fields.
{{{langlink}}}
A link to the language's main category. Not recognized in umbrella fields.
{{{umbrella_msg}}}
The message normally at the end of the description for umbrella categories, indicating that the category contains no terms but only subcategories.
{{{topic}}}
The value of the topic field (or the umbrella.topic field for umbrella categories), if specified; else, the value of displaytitle (if specified) or the label, with "the" added if the description is "default with the" or a variant containing "with the" (such as "default with the wikify").

描述

编辑

The description field is of one of three types:

  1. An English sentence, ending in a period.
  2. A phrase preceded by = and not ending in a period.
  3. The value "default" or one of its variants, such as "default with the" or "default wikify".

If preceded by =, the description is generated from the specified phrase by prepending {{{LANGNAME}}} (which is replaced with the language name) followed by standard type-dependent text, and appending a period. The text prepended is currently as follows:

Type Text
related-to terms related to
set terms for types or instances of
name names of specific
type terms for types of
grouping categories concerning more specific variants of
toplevel N/A

For example, for the label biblical characters, the description is currently "=characters in the [[Bible]]", which expands to {{{LANGNAME}}} names of specific characters in the [[Bible]]., and in turn is expanded to e.g. French names of specific characters in the [[Bible]]. (if the category is Category:fr:Biblical characters).

Note that no standard text is provided for top-level categories, all of which include a custom description.

If "default" or one of its variants is used as the description, a default description is generated as if the description consisted of = prepended to the label, except that the word the might be added to the beginning of the label, and the words in the label might be wikilinked. Specifically:

  1. If the description is of the form "default with the" (or a form such as "default with the wikify", "default with the no singularize", etc.), the word the is prefixed to the label.
  2. If the label is of the form "default wikify" (or a related form), the label is linked to Wikipedia. If the label ends in an -s, the label is linked to a Wikipedia entry based on the singular form of the label (which converts -ies to -y; converts -xes, -ches or -shes, respectively, to -x, -ch or -sh; and otherwise just removes -s), unless the label is "default wikify no singularize" or a related form, in which case the label is linked unchanged.
  3. Otherwise, the code attempts to link the entire label or the individual words of the label to Wiktionay terms, as follows:
    1. If the label ends in -s and no singularize is not specified in the description, and the singular form of the label (generated according to the algorithm described just above) is a Wiktionary term, the label is linked to that term. Note that "is a Wiktionary term" simply means that a page of this name exists; the code does not currently check to see whether there is an English entry or whether the term is a lemma.
    2. Otherwise, if the label itself is a Wiktionary term, the label is linked to that term.
    3. Otherwise, the label is split into individual words, and each word is checked to see if a page named according to that word exists. If so, the individual words are linked to their corresponding Wiktionary entries; otherwise, the label is left unlinked. Note that the last word is handled specially if it ends in -s and no singularize is not found in the description, in that the code first attempts to link the word to its singular equivalent, falling back to the word itself if the singular equivalent doesn't name a Wiktionary term.

For example, a label video games will be linked as [[video game]]s because the page video game exists, but Arabic deities will be linked as [[Arabian]] [[deity|deities]] because neither Arabian deity nor Arabian deities exists as a page. The use of no singularize is needed with labels such as linguistics, comics and humanities, because their respective singular forms linguistic, comic and humanity exist as Wiktionary pages.

Finally, note that the components of a default-type description (wikify, with the and no singularize) can be given in any order if more than one of them needs to be specified.

處理程式

编辑

It is also possible to have handlers that can handle arbitrarily-formed labels, e.g. political subdivisions of country for any country (categories such as Category:tg:Political subdivisions of the United Arab Emirates) or divisions of polity for any division and polity (e.g. Category:fr:Counties of South Korea or Category:pt:Municipalities of Tocantins, Brazil). Currently, handlers exist only in the toponym-handling code in Module:category tree/topic cat/data/Places and in Module:category tree/topic cat/data/Names. As example, the following is the 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)

The handler checks is passed a single argument (the label), checks if the passed-in label has a recognized form, and if so, returns an object that follows the same format as described above for directly-specified labels. In this case, the handler makes sure the given script name specifies an actual script, and constructs an appropriate link for the script, depending on whether an appendix page for the script exists (falling back to Wikipedia).

NOTE: The handler needs to be prepared to handle both umbrella categories and per-language categories. The label is passed in as it appears in the category; this means the handler may need to handle both uppercase-initial and lowercase-initial variants of the label. (For this handler, this isn't an issue because the script always appears uppercased.) One way to do that is to convert the label to lowercase-initial before further processing, using mw.getContentLanguage():lcfirst().

另請注意,如果指定了處理程序,則模組應傳回一個包含標籤和處理程式資料的表;請參閱上述模組。

子頁面

编辑



local labels = {}
local handlers = {}

local m_shared = require("Module:place/shared-data/sandbox")
local m_strutils = require("Module:string utilities")

--[=[

This module contains specifications that are used to create labels that allow {{auto cat}} and
{{topic cat}} to create the appropriate definitions for topic categories for places (e.g.re
'en:Waterfalls', 'de:Hokkaido', 'es:Cities in France', 'pt:Municipalities of Tocantins, Brazil',
etc.). Note that this module doesn't actually create the categories; that must be done manually,
with the text "{{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 such labels are created: (1) by manually adding an entry to the 'labels'
table, keyed by the label (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.
]=]

local function lcfirst(label)
	return mw.getContentLanguage():lcfirst(label)
end

labels["地點"] = {
	description = "{{{langname}}}中表示地方名稱的詞彙。",
	parents = {"名稱", "集合列表"},
}

-- Generate bare labels in 'label' for all political subdivisions.
-- Do this before handling 'general_labels' so the latter can override if necessary.
for subdiv, desc in pairs(m_shared.political_subdivisions) do
	labels[subdiv] = {
		description = "{{{langname}}} names of " .. desc .. ".",
		parents = {"political subdivisions", "集合列表"},
	}
end

-- General labels. These are intended for places of all sorts that are not qualified
-- by a holonym (e.g. it does not include 'regions in Africa'). These also do not need
-- to include any political subdivisions listed in 'political_subdivisions' in
-- [[Module:place-data/shared]]. Each entry is {LABEL, DESCRIPTION, PARENTS}.
-- PARENTS should not include "集合列表", which is added automatically.
local general_labels = {
	{"機場", "[[機場]]", {"地點"}},
	{"ancient settlements", "former [[city|cities]], [[town]]s and [[village]]s that existed in [[antiquity]]", {"historical settlements"}},
	{"環礁", "[[環礁]]", {"島嶼"}},
	{"bays", "[[bay]]s", {"地點", "水"}},
	{"beaches", "[[beach]]es", {"地點", "水"}},
	{"自治鎮", "[[自治鎮]]", {"政體"}},
	{"首都", "[[首都]]", {"城市"}},
	{"census-designated places", "[[census-designated place]]s", {"地點"}},
	{"城市", "[[城市]]", {"政體"}},
	{"city-states", "[[sovereign]] [[microstate]]s consisting of a single [[city]] and dependent [[territory|territories]]", {"政體"}},
	{"社區", "[[社區]]", {"政體"}},
	{"大洲", "[[大洲]]", {"地點"}},
	{"國家", "[[國家]]", {"政體"}},
	{"屬地", "[[屬地]]", {"政體"}},
	{"沙漠", "[[沙漠]]", {"地點"}},
	{"森林", "[[森林]]", {"地點"}},
	{"ghost towns", "[[ghost town]]s", {"historical settlements"}},
	{"海灣", "[[海灣]]", {"地點", "水"}},
	{"岬角", "[[岬角]]", {"地點"}},
	{"歷史和傳統地區", "regions that have no administrative significance", {"地點"}},
	{"historical capitals", "former [[capital]] [[city|cities]] and [[town]]s", {"historical settlements"}},
	{"historical political subdivisions", "[[political]] [[subdivision]]s (states, provinces, counties, etc.) that no longer exist", {"政體"}},
	{"歷史政體", "[[polity|polities]] (countries, kingdoms, empires, etc.) that no longer exist", {"政體"}},
	{"historical settlements", "[[city|cities]], [[town]]s and [[village]]s that no longer exist or have been merged or reclassified", {"historical polities"}},
	{"山丘", "[[山丘]]", {"地點"}},
	{"島嶼", "[[島嶼]]", {"地點"}},
	{"基布茲", "[[基布茲]]", {"地點"}},
	{"湖", "[[湖]]", {"地點", "水"}},
	{"地形", "[[地形]]", {"地球"}},
	{"山口", "[[山口]]", {"地點"}},
	{"山", "[[山]]", {"地點"}},
	{"moors", "[[moor]]s", {"地點"}},
	{"neighborhoods", "[[neighborhood]]s, [[district]]s and other subportions of a [[city]]", {"地點"}},
	-- FIXME, is the following parent correct?
	{"海洋", "[[海洋]]", {"海"}},
	{"公園", "[[公園]]", {"地點"}},
	{"半島", "[[半島]]", {"地點"}},
	{"高原", "[[高原]]", {"地點"}},
	{"政治選區", "[[political]] [[subdivision]]s, such as [[province]]s, [[state]]s or [[region]]s", {"政體"}},
	{"政體", "[[政體]]或[[政區]]", {"地點"}},
	{"河", "[[河]]", {"地點", "水"}},
	{"海", "[[海]]", {"地點", "水"}},
	{"海峽", "[[海峽]]", {"地點", "水"}},
	{"街道", "[[街道]]", {"政體"}},
	{"suburbs", "[[suburb]]s of a [[city]]", {"地點"}},
	{"鎮", "[[鎮]]", {"政體"}},
	{"小鎮", "[[小鎮]]", {"政體"}},
	{"unincorporated communities", "[[unincorporated]] [[community|communities]]", {"地點"}},
	{"谷", "[[谷]]", {"地點", "水"}},
	{"村", "[[村]]", {"政體"}},
	{"火山", "[[火山]]", {"地形"}},
	{"瀑布", "[[瀑布]]", {"地形", "水"}},
}

-- Generate bare labels in 'label' for all "general labels" (see above).
for _, label_spec in ipairs(general_labels) do
	local label, desc, parents = unpack(label_spec)
	table.insert(parents, "集合列表")
	labels[label] = {
		description = "{{{langname}}} names of " .. desc .. ".",
		parents = parents,
	}
end

labels["城市綽號"] = {
	-- special-cased description
	description = "{{{langname}}}中有關城市綽號的名稱(例如:[[Big Apple]]就是[[New York City]])",
	parents = {"城市", "集合列表"},
}

labels["外名"] = {
	-- special-cased description
	description = "{{{langname}}}中有關的[[外名]]。",
	parents = {"地點", "集合列表"},
}

-- Generate bare labels in 'label' for all polities (countries, states, etc.).
for _, group in ipairs(m_shared.polities) do
	for key, value in pairs(group.data) do
		group.bare_label_setter(labels, group, key, value)
	end
end

local function city_description(group, key, value)
	-- The purpose of all the following code is to construct the description. It's written in
	-- a general way to allow any number of containing polities, each larger than the previous one,
	-- so that e.g. for Birmingham, the description will read "{{{langname}}} terms related to the city of
	-- [[Birmingham]], in the county of the [[West Midlands]], in the [[constituent country]] of [[England]],
	-- in the [[United Kingdom]]."
	local bare_key, linked_key = m_shared.construct_bare_and_linked_version(key)
	local descparts = {}
	table.insert(descparts, "the city of " .. linked_key)
	local city_containing_polities = m_shared.get_city_containing_polities(group, key, value)
	local label_parent -- parent of the label, from the immediate containing polity
	for n, polity in ipairs(city_containing_polities) do
		local bare_polity, linked_polity = m_shared.construct_bare_and_linked_version(polity[1])
		if n == 1 then
			label_parent = bare_polity
		end
		table.insert(descparts, ", in ")
		if n < #city_containing_polities then
			local divtype = polity.divtype or group.default_divtype
			local pl_divtype = m_strutils.pluralize(divtype)
			local pl_linked_divtype = m_shared.political_subdivisions[pl_divtype]
			if not pl_linked_divtype then
				error("When creating city description for " .. key .. ", encountered divtype '" .. divtype .. "' not in m_shared.political_subdivisions")
			end
			local linked_divtype = m_strutils.singularize(pl_linked_divtype)
			table.insert(descparts, "the " .. linked_divtype .. " of ")
		end
		table.insert(descparts, linked_polity)
	end
	return table.concat(descparts), label_parent
end

-- Generate bare labels in 'label' for all cities.
for _, group in ipairs(m_shared.cities) do
	for key, value in pairs(group.data) do
		if not value.alias_of then
			local desc, label_parent = city_description(group, key, value)
			desc = "{{{langname}}} terms related to " .. desc .. "."
			local parents = value.parents or label_parent
			if not parents then
				error("When creating city bare label for " .. key .. ", at least one containing polity must be specified or an explicit parent must be given")
			end
			if type(parents) ~= "table" then
				parents = {parents}
			end
			local key_parents = {}
			for _, parent in ipairs(parents) do
				local polity_group, key_parent = m_shared.city_containing_polity_to_group_and_key(parent)
				if key_parent then
					local bare_key_parent, linked_key_parent =
						m_shared.construct_bare_and_linked_version(key_parent)
					table.insert(key_parents, bare_key_parent)
				else
					error("Couldn't find entry for city '" .. key .."' parent '" .. parent .. "'")
				end
			end

			labels[key] = {
				description = desc,
				parents = key_parents,
			}
		end
	end
end

-- Handler for "cities in the Bahamas", "rivers in Western Australia", etc.
-- Places that begin with "the" are recognized and handled specially.
table.insert(handlers, function(label)
	label = lcfirst(label)
	local place_type, place = label:match("^([a-z%- ]-) in (.*)$")
	if place_type and m_shared.generic_place_types[place_type] then
		for _, group in ipairs(m_shared.polities) do
			local placedata = group.data[place]
			if placedata then
				placedata = group.value_transformer(group, place, placedata)
				local allow_cat = true
				if place_type == "neighborhoods" and placedata.british_spelling or
					place_type == "neighbourhoods" and not placedata.british_spelling then
					allow_cat = false
				end
				if placedata.is_former_place and place_type ~= "地點" then
					allow_cat = false
				end
				if placedata.is_city and not m_shared.generic_place_types_for_cities[place_type] then
					allow_cat = false
				end
				if allow_cat then
					local parent
					if placedata.containing_polity then
						parent = place_type .. " in " .. placedata.containing_polity
					elseif place_type == "neighbourhoods" then
						parent = "neighborhoods"
					else
						parent = place_type
					end
					local bare_place, linked_place = m_shared.construct_bare_and_linked_version(place)
					local keydesc = placedata.keydesc or linked_place
					local parents
					if place_type == "地點" then
						parents = {{name = parent, sort = bare_place}, bare_place, "集合列表"}
					else
						parents = {{name = parent, sort = bare_place}, bare_place, "集合列表", "places in " .. place}
					end
					return {
						description = "{{{langname}}} names of " .. m_shared.generic_place_types[place_type] .. " in " .. keydesc .. ".",
						parents = parents
					}
				end
			end
		end
	end
end)

-- Handler for "places in Paris", "neighbourhoods of Paris", etc.
table.insert(handlers, function(label)
	label = lcfirst(label)
	local place_type, in_of, city = label:match("^(places) (in) (.*)$")
	if not place_type then
		place_type, in_of, city = label:match("^([a-z%- ]-) (of) (.*)$")
	end
	if place_type and m_shared.generic_place_types_for_cities[place_type] then
		for _, group in ipairs(m_shared.cities) do
			local city_data = group.data[city]
			if city_data then
				local spelling_matches = true
				if place_type == "neighborhoods" or place_type == "neighbourhoods" then
					local containing_polities = m_shared.get_city_containing_polities(group, city, city_data)
					local polity_group, polity_key = m_shared.city_containing_polity_to_group_and_key(
						containing_polities[1])
					if not polity_key then
						error("Can't find polity data for city '" .. place ..
							"' containing polity '" .. containing_polities[1] .. "'")
					end
					local polity_value = polity_group.value_transformer(polity_group, polity_key, polity_group[polity_key])

					if place_type == "neighborhoods" and polity_value.british_spelling or
						place_type == "neighbourhoods" and not polity_value.british_spelling then
						spelling_matches = false
					end
				end
				if spelling_matches then
					local parents
					if place_type == "地點" then
						parents = {city, "集合列表"}
					else
						parents = {city, "集合列表", "places in " .. city}
					end
					local desc = city_description(group, city, city_data)
					return {
						description = "{{{langname}}} names of " .. m_shared.generic_place_types_for_cities[place_type] .. " " .. in_of .. " " .. desc .. ".",
						parents = parents
					}
				end
			end
		end
	end
end)

-- Handler for "political subdivisions of the Philippines" and other "political subdivisions of X" categories.
table.insert(handlers, function(label)
	label = lcfirst(label)
	local place = label:match("^political subdivisions of (.*)$")
	if place then
		for _, group in ipairs(m_shared.polities) do
			local placedata = group.data[place]
			if placedata then
				placedata = group.value_transformer(group, place, placedata)
				local bare_place, linked_place = m_shared.construct_bare_and_linked_version(place)
				local keydesc = placedata.keydesc or linked_place
				local desc = "{{{langname}}} names of [[political]] [[subdivision]]s of " .. keydesc .. "."
				return {
					description = desc,
					parents = {bare_place, {name = "political subdivisions", sort = bare_place}, "集合列表"},
				}
			end
		end
	end
end)

-- Handler for "provinces of the Philippines", "counties of Wales", "municipalities of Tocantins, Brazil", etc.
-- Places that begin with "the" are recognized and handled specially.
table.insert(handlers, function(label)
	label = lcfirst(label)
	local place_type, place = label:match("^([a-z%- ]-) of (.*)$")
	if place then
		for _, group in ipairs(m_shared.polities) do
			local placedata = group.data[place]
			if placedata then
				placedata = group.value_transformer(group, place, placedata)
				local divcat = nil
				local poldiv_parent = nil
				if placedata.poldiv then
					for _, div in ipairs(placedata.poldiv) do
						if type(div) == "string" then
							div = {div}
						end
						if place_type == div[1] then
							divcat = "poldiv"
							poldiv_parent = div.parent
							break
						end
					end
				end
				if not divcat and placedata.miscdiv then
					for _, div in ipairs(placedata.miscdiv) do
						if type(div) == "string" then
							div = {div}
						end
						if place_type == div[1] then
							divcat = "miscdiv"
							break
						end
					end
				end
				if divcat then
					local linkdiv = m_shared.political_subdivisions[place_type]
					if not linkdiv then
						error("Saw unknown place type '" .. place_type .. "' in label '" .. label .. "'")
					end
					local bare_place, linked_place = m_shared.construct_bare_and_linked_version(place)
					local keydesc = placedata.keydesc or linked_place
					local desc = "{{{langname}}} names of " .. linkdiv .. " of " .. keydesc .. "."
					if divcat == "poldiv" then
						return {
							description = desc,
							parents = poldiv_parent and
								{{name = poldiv_parent, sort = bare_place}, bare_place, "集合列表"} or
								{"political subdivisions of " .. place, {name = place_type, sort = bare_place}, "集合列表"},
						}
					else
						return {
							description = desc,
							parents = {bare_place, "集合列表"},
						}
					end
				end
			end
		end
	end
end)

-- Generate bare labels in 'label' for all types of capitals.
for capital_cat, placetype in pairs(m_shared.capital_cat_to_placetype) do
	local pl_placetype = m_strutils.pluralize(placetype)
	local linkdiv = m_shared.political_subdivisions[pl_placetype]
	if not linkdiv then
		error("Saw unknown place type '" .. pl_placetype .. "' in label '" .. label .. "'")
	end
	labels[capital_cat] = {
		description = "{{{langname}}} names of [[capital]]s of " .. linkdiv .. ".",
		parents = {"首都", "集合列表"},
	}
end

-- Handler for "state capitals of the United States", "provincial capitals of Canada", etc.
-- Places that begin with "the" are recognized and handled specially.
table.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 m_shared.capital_cat_to_placetype[capital_cat] then
		local placetype = m_shared.capital_cat_to_placetype[capital_cat]
		local pl_placetype = m_strutils.pluralize(placetype)
		-- Locate the containing polity, fetch its known political subdivisions, and make sure
		-- the placetype corresponding to the type of capital is among the list.
		for _, group in ipairs(m_shared.polities) do
			local placedata = group.data[place]
			if placedata then
				placedata = group.value_transformer(group, place, placedata)
				if placedata.poldiv then
					local saw_match = false
					local variant_matches = {}
					for _, div in ipairs(placedata.poldiv) do
						if type(div) == "string" then
							div = {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 subdivision 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[1] or pl_placetype == div[1]:gsub("^.* ", "") then
							saw_match = true
							if pl_placetype ~= div[1] then
								table.insert(variant_matches, div[1])
							end
						end
					end
					if saw_match then
						-- Everything checks out, construct the category description.
						local linkdiv = m_shared.political_subdivisions[pl_placetype]
						if not linkdiv then
							error("Saw unknown place type '" .. pl_placetype .. "' in label '" .. label .. "'")
						end
						local bare_place, linked_place = m_shared.construct_bare_and_linked_version(place)
						local keydesc = placedata.keydesc or linked_place
						local variant_match_text = ""
						if #variant_matches > 0 then
							for i, variant_match in ipairs(variant_matches) do
								variant_matches[i] = m_shared.political_subdivisions[variant_match]
								if not variant_matches[i] then
									error("Saw unknown place type '" .. variant_match .. "' in label '" .. label .. "'")
								end
							end
							variant_match_text = " (including " .. require("Module:table").serialCommaJoin(variant_matches) .. ")"
						end
						local desc = "{{{langname}}} names of [[capital]]s of " .. linkdiv .. variant_match_text .. " of " .. keydesc .. "."
						return {
							description = desc,
							parents = {{name = capital_cat, sort = bare_place}, bare_place, "集合列表"},
						}
					end
				end
			end
		end
	end
end)

-- "regions in (continent)", esp. for regions that span multiple countries

labels["世界各地區"] = { -- for multinational regions which do not fit neatly within one continent
	"世界各[[地區]]的{{langname}}}名稱。",
	parents = {"地點", "集合列表"},
}

labels["非洲地區"] = {
	description = "{非洲各[[地區]]的{{langname}}}名稱。",
	parents = {"非洲", "集合列表"},
}

labels["美洲地區"] = {
	description = "{美洲各[[地區]]的{{langname}}}名稱。",
	parents = {"美洲", "集合列表"},
}

labels["亞洲地區"] = {
	description = "{亞洲各[[地區]]的{{langname}}}名稱。",
	parents = {"亞洲", "集合列表"},
}

labels["歐洲地區"] = { 
	description = "{歐洲各[[地區]]的{{langname}}}名稱。",
	parents = {"歐洲", "集合列表"},
}

-- "countries in (continent)", "rivers in (continent)"

for _, continent in ipairs({"非洲", "亞洲", "中美洲", "歐洲", "北美洲", "大洋洲", "南美洲"}) do
	labels[continent .. "國家"] = {
		description = "{{{langname}}}中[[" .. continent .. "]][[國家]]的名稱。",
		parents = {{name = "國家", sort = " "}, continent, "集合列表"},
	}
	labels[continent .. "河流"] = {
		description = "{{{langname}}}中[[" .. continent .. "]][[河流]]的名稱。",
		parents = {{name = "河", sort = " "}, continent, "集合列表"},
	}
end

-- autonomous communities, oblasts, etc

labels["autonomous communities of Spain"] = {
	-- special-cased description
	description = "{{{langname}}} names of the [[w:Autonomous communities of Spain|autonomous communities of Spain]].",
	parents = {{name = "political subdivisions", sort = "Spain"}, "Spain", "集合列表"},
}

labels["autonomous cities of Spain"] = {
	-- special-cased description
	description = "{{{langname}}} names of the [[w:Autonomous communities of Spain#Autonomous_cities|autonomous cities of Spain]].",
	parents = {{name = "political subdivisions", sort = "Spain"}, "Spain", "集合列表"},
}

-- boroughs

labels["boroughs in England"] = {
	description = "{{{langname}}} names of boroughs, local government districts and unitary authorities in [[England]].", 
	parents = {{name = "自治鎮", sort = "England"}, "England", "集合列表"},
}

labels["boroughs in Pennsylvania, USA"] = {
	description = "{{{langname}}} names of boroughs in [[Pennsylvania]], USA.",
	parents = {{name = "boroughs in the United States", sort = "Pennsylvania"}, "Pennsylvania, USA", "集合列表"},
}

labels["boroughs in New Jersey, USA"] = {
	description = "{{{langname}}} names of boroughs in [[New Jersey]], USA.",
	parents = {{name = "boroughs in the United States", sort = "New Jersey"}, "New Jersey, USA", "集合列表"},
}

labels["boroughs in New York City"] = {
	description = "{{{langname}}} names of boroughs in [[New York City]].",
	parents = {{name = "boroughs in the United States", sort = "New York City"}, "New York City", "集合列表"},
}

labels["boroughs in the United States"] = {
	description = "{{{langname}}} names of [[borough]]s in the [[United States]].",
	-- parent is "自治鎮" not "political subdivisions" and category says "in"
	-- not "of", because boroughs aren't really political subdivisions in the US
	-- (more like cities)
	parents = {{name = "自治鎮", sort = "United States"}, "United States", "集合列表"},
}

-- census-designated places

labels["census-designated places in the United States"] = {
	description = "{{{langname}}} names of [[census-designated place]]s in the [[United States]].",
	-- parent is just United States; census-designated places have no political
	-- status and exist only in the US, so no need for a top-level
	-- "census-designated places" category
	parents = {"United States", "集合列表"},
}

-- counties

labels["counties of Northern Ireland"] = {
	description = "{{{langname}}} names of the counties of [[Northern Ireland]].",
	-- has two parents: "political subdivisions" and "counties of Ireland"
	parents = {{name = "political subdivisions", sort = "Northern Ireland"}, {name = "counties of Ireland", sort = "Northern Ireland"}, "Northern Ireland", "集合列表"},
}

-- nomes

labels["nomes of Ancient Egypt"] = {
	-- special-cased description
	description = "{{{langname}}} names of the nomes of [[Ancient Egypt]].",
	parents = {{name = "political subdivisions", sort = "Egypt"}, "Ancient Egypt", "集合列表"},
}

-- regions and "regional units"

labels["regions of Albania"] = {
	-- special-cased description
	description = "{{{langname}}} names of the regions (peripheries) of [[Albania]].",
	parents = {{name = "political subdivisions", sort = "Albania"}, "Albania", "集合列表"},
}

labels["regions of Greece"] = {
	-- special-cased description
	description = "{{{langname}}} names of the regions (peripheries) of [[Greece]].",
	parents = {{name = "political subdivisions", sort = "Greece"}, "Greece", "集合列表"},
}

labels["regions of North Macedonia"] = {
	-- special-cased description
	description = "{{{langname}}} names of the regions (peripheries) of [[North Macedonia]].",
	parents = {{name = "political subdivisions", sort = "North Macedonia"}, "North Macedonia", "集合列表"},
}

-- subdistricts and subprefectures

labels["subdistricts of Jakarta"] = {
	description = "default-set",
	-- not listed in the normal place because no categories like "cities in Jakarta"
	parents = {{name = "political subdivisions", sort = "Jakarta"}, "Indonesia", "集合列表"},
}

labels["subprefectures of Japan"] = {
	-- special-cased description
	description = "{{{langname}}} names of subprefectures of Japanese prefectures.",
	parents = {{name = "political subdivisions", sort = "Japan"}, "Japan", "集合列表"},
}

-- towns and townships

labels["townships in Canada"] = {
	description = "{{{langname}}} names of townships in [[Canada]].",
	parents = {{name = "townships", sort = "Canada"}, "Canada", "集合列表"},
}

labels["townships in Ontario"] = {
	description = "{{{langname}}} names of townships in [[Ontario]]. Municipalities in Ontario can be called as a city, a town, a township, or a village.",
	parents = {{name = "townships in Canada", sort = "Ontario"}, "Ontario", "集合列表"},
}

labels["townships in Quebec"] = {
	description = "{{{langname}}} names of townships in [[Quebec]].",
	parents = {{name = "townships in Canada", sort = "Quebec"}, "Quebec", "集合列表"},
}

-- temporary while users adjust to recent changes, also kept in case of desire to use for its topical purpose, see description; can be removed later if unused

labels["place names"] = {
	description = "{{{langname}}} terms like ''hydronym'', for names for geographical [[place]]s.",
	parents = {"names", "集合列表"},
}

return {LABELS = labels, HANDLERS = handlers}