跳转到内容

模組:Gender and number

維基詞典,自由的多語言詞典

此模組顯示性/數標記,例如 (陽性)、 (中性複數)或  有生 (陰性有生雙數)。「性」(Gender)在這裡有點名不副實,因為可用的標記類別還包括其他類似的詞彙特徵,如有生性和動詞體(儘管前者有時也被視為詞性的組成部分)。根據特定語言,這些標記會附於名詞、代名詞及其他具有此類詞彙類別的詞類。標記以參數形式出現,例如用於詞頭模板 {{head}}{{es-noun}}(西班牙語名詞)、{{fr-proper noun}}(法語專有名詞)和 {{ru-verb}}(俄語動詞);翻譯模板如 {{t}}{{t+}}{{t-check}};定義模板如 {{demonym-noun}};以及專門的性/數模板如 {{g}}

性/數規範

指定的標記使用「性/數規範」來描述。每個規範都是一個以連字號分隔的「性/數代碼」列表,其中每個代碼描述特定類別的單一值(例如:m 代表「陽性」,an 代表「有生」,p 代表「複數」)。由於某些術語屬於多個可能的性/數類別,模板通常接受一組性/數規範列表,而不僅僅是單個規範。根據所使用的模板,這些規範將透過不同的參數或單個以逗號分隔的參數提供。

顯示規範時,規範中的每個代碼都會轉換為相應的顯示形式。隨後將規範內的各個代碼相連,並以空格分隔。

範例:

列表 結果
{"m"}
{"m-p"}  
{"m-an-p"}  有生 
{"mfbysense-p"}     遵詞義
{"?-p"} ? 
{"?!-an-s"} 性別無記錄 有生 
{"f-d", "m-p"}    
{"m-p", "f-p"}    
{"m", "f", "p"}

目前所辨識之代碼的資料來源為 Module:gender and number/data

下表列出了:

  1. 目前可辨識的代碼;
  2. 它們所屬的類型類別(在給定的規範中,每個類型類別只能出現一個代碼);
  3. 代碼的顯示方式(將滑鼠懸停在顯示形式上可查看該代碼含義的說明);
  4. 如果術語的詞頭性/數規範中包含該代碼,該術語將被分配到的分類(如果有),其中 POS 會替換為術語複數形式的詞性。
代碼 類型 顯示文字 分類
g? gender 性別未指定
n gender 中性POS
m gender 陽性POS
gneut gender 中立 性別中立POS
f gender 陰性POS
c gender 通性POS
g! gender 性別無記錄
d number 唯雙POS
s number
num! number 數無記載
p number 唯複POS
an animacy 有生 有生POS
in animacy 無生 無生POS
an! animacy 有生性無記錄
pr animacy 個人 個人POS
an? animacy 有生性未指定
np animacy 非個人 非個人POS
anml animacy 動物 動物POS
vr virility 男性POS
nv virility 非男 非男性POS
asp! aspect 體貌無記錄
pf aspect 完整體POS
asp? aspect 體貌未指定
impf aspect 非完 非完整體POS
? other ?
?! other 性別無記錄

某些性/數代碼是「組合代碼」,這與在不同的性/數規範中分別指定兩個或多個同一類型的代碼大致等效。某些組合代碼會有額外的分類和顯示方式。下表列出了這些組合代碼:

組合 獨立代碼 額外顯示的文字 分類
biasp impf, pf
mf m, f
mfbysense m, f 遵詞義 性別遵照被指代者的POS
mfequiv m, f 同義

在某些類型類別中,如果給出了多個該類別的代碼(必須在不同的性/數規範中),則該術語會被加入到一個特殊的分類。下表列出了這些多代碼分類:

類型 存在多個相同類型代碼時的分類
gender 有多種性別的POS
animacy 有多種有生性的POS
aspect 雙體POS

名詞類別

以「c」開頭(但「c」本身除外)的規範會被特殊處理。它們被視為名詞類別(noun classes),「c」後面的部分被簡單地視為名詞類別的某種名稱;通常是一個數字。名詞類別沒有子部分,因此不包含連字號。當提供多個規範時,它們必須全部都是名詞類別,並改用斜線(/)分隔顯示,且前面冠以「類別」。

範例:

列表 結果
{"c1"} 類別1
{"c1", "c2"} 類別1/2
{"c1a", "c2a"} 類別1a/2a

用法

本模組可供其他模組調用,方法是導入模組並調用其導出的 format_list 函式。它需要一個參數,該參數必須是由零個或多個字串組成的表(table)。它隨後將返回包含結果的字串。例如:

local gen = require("Module:gender and number")
local example1 = gen.format_list({"m"})
local example2 = gen.format_list({"m", "f"})
local example3 = gen.format_list({"m-p"})

警告:傳入的列表(table)內容將被覆蓋。

它也可以從模板中調用,此時應使用 show_list 函式。其工作方式與 format_list 函式相同,但規範是作為模組調用的參數傳遞的,如下所示:

*{{#invoke:gender and number|show_list|m}}
*{{#invoke:gender and number|show_list|m|f}}
*{{#invoke:gender and number|show_list|m-p}}
  •  

以這種方式提供的參數數量沒有限制。模組將處理其所有參數,直到遇到空參數為止。這意味著以下範例僅會顯示「」而不會顯示「 」:

{{#invoke:gender and number|show_list|m||n}}

導出函式

Template:Module documentation

Module:Module_categorization第227行Lua错误:Did not recognize inferred module-type keyword 'and number' from root pagename 'Gender and number'


local export = {}

local debug_track_module = "Module:debug/track"
local load_module = "Module:load"
local pron_qualifier_module = "Module:pron qualifier"
local parameters_module = "Module:parameters"
local string_utilities_module = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"

local concat = table.concat
local insert = table.insert

local function debug_track(...)
	debug_track = require(debug_track_module)
	return debug_track(...)
end

local function deep_copy(...)
	deep_copy = require(table_module).deepCopy
	return deep_copy(...)
end

local function format_categories(...)
	format_categories = require(utilities_module).format_categories
	return format_categories(...)
end

local function format_pron_qualifiers(...)
	format_pron_qualifiers = require(pron_qualifier_module).format_qualifiers
	return format_pron_qualifiers(...)
end

local function load_data(...)
	load_data = require(load_module).load_data
	return load_data(...)
end

local function process_params(...)
	process_params = require(parameters_module).process
	return process_params(...)
end

local function split(...)
	split = require(string_utilities_module).split
	return split(...)
end

local gender_and_number_data
local function get_gender_and_number_data()
	gender_and_number_data, get_gender_and_number_data = load_data("Module:gender and number/data"), nil
	return gender_and_number_data
end


--[==[ intro:
This module creates standardised displays for gender and number. It converts a gender specification into Wiki/HTML format.

A gender/number specification consists of one or more gender/number elements, separated by hyphens. Examples are:
{"n"} (neuter gender), {"f-p"} (feminine plural), {"m-an-p"} (masculine animate plural),
{"pf"} (perfective aspect). Each gender/number element has the following properties:
# A code, as used in the spec, e.g. {"f"} for feminine, {"p"} for plural.
# A type, e.g. `gender`, `number` or `animacy`. Each element in a given spec must be of a different type.
# A display form, which in turn consists of a display code and a tooltip gloss. The display code
  may not be the same as the spec code, e.g. the spec code {"an"} has display code {"anim"} and tooltip
  gloss ''animate''.
# A category into which lemmas of the right part of speech are placed if they have a gender/number
  spec containing the given element. For example, a noun with gender/number spec {"m-an-p"} is placed
  into the categories `<var>lang</var> masculine nouns`, `<var>lang</var> animate nouns` and `<var>lang</var> pluralia tantum`.
]==]

--[==[
Version of format_list that can be invoked from a template.
]==]
function export.show_list(frame)
	local params = {
		[1] = {list = true},
		["lang"] = {type = "language"},
	}
	local iargs = process_params(frame.args, params)
	return export.format_list(iargs[1], iargs.lang)
end


--[==[
Older entry point; equivalent to format_genders() except that it formats the
categories and returns them appended to the formatted gender text rather than
returning the formatted text and categories separately.
]==]
function export.format_list(specs, lang, pos_for_cat, sort_key)
	debug_track("gender and number/old-format-list")
	local text, cats = export.format_genders(specs, lang, pos_for_cat)
	if not cats then
		return text
	end
	return text .. format_categories(cats, lang, sort_key)
end


local function autoadd_abbr(display)
	if not display then
		error("Internal error: '.display' for gender/number code is missing")
	end
	if display:find("<abbr", nil, true) then
		return display
	end
	return ('%s'):format(display, display)
end


-- Add qualifiers, labels and references to a formatted gender/number spec. `spec` is the object describing the
-- gender/number spec, which should optionally contain:
-- * left qualifiers in `q` or (for compatibility) `qualifiers`, an array of strings;
-- * right qualifiers in `qq`, an array of strings;
-- * left labels in `l`, an array of strings;
-- * right labels in `ll`, an array of strings;
-- * references in `refs`, an array either of strings (formatted reference text) or objects containing fields `text`
--   (formatted reference text) and optionally `name` and/or `group`;
-- `formatted` is the formatted version of the term itself, and `lang` is the optional language object passed into
-- format_genders().
local function add_qualifiers_and_refs(formatted, spec, lang)
	local function field_non_empty(field)
		local list = spec[field]
		if not list then
			return nil
		end
		if type(list) ~= "table" then
			error(("Internal error: Wrong type for `spec.%s`=%s, should be \"table\""):format(
				field, mw.dumpObject(list)))
		end
		return list[1]
	end

	if field_non_empty("q") or field_non_empty("qq") or field_non_empty("l") or field_non_empty("ll") or
		field_non_empty("qualifiers") or field_non_empty("refs") then
		formatted = format_pron_qualifiers{
			lang = lang,
			text = formatted,
			q = spec.q,
			qq = spec.qq,
			qualifiers = spec.qualifiers,
			l = spec.l,
			ll = spec.ll,
			refs = spec.refs,
		}
	end

	return formatted
end


--[==[
Format one or more gender/number specifications. Each spec is either a string, e.g. {"f-p"}, or a table of the form
{ {spec = "SPEC", qualifiers = {"QUALIFIER", "QUALIFIER", ...}}} where `.spec` is a gender/number spec such as {"f-p"}
and `.qualifiers` is a list of qualifiers to display before the formatted gender/number spec. `.spec` must be present
but `.qualifiers` may be omitted.

The function returns two values:
# the formatted text;
# a list of the categories to add.

If `lang` (which should be a language object) and `pos_for_cat` (which should be a plural part of speech) are given,
gender categories such as `German masculine nouns` or `Russian imperfective verbs` are added to the categories, and
request categories such as `Requests for gender in <var>lang</var> entries` or
`Requests for animacy in <var>lang</var> entries` may also be added. Otherwise, if only `lang` is given, only request
categories may be returned. If both are omitted, the returned list is empty.
]==]
function export.format_genders(specs, lang, pos_for_cat)
	local formatted_specs, categories, seen_types = {}
	local all_is_nounclass = nil
	local full_langname = lang and lang:getFullName() or nil

	local function do_gender_spec(spec, parts)
		local types = {}
		local codes = (gender_and_number_data or get_gender_and_number_data()).codes

		for key, code in ipairs(parts) do
			-- Is this code valid?
			if not codes[code] then
				error('The tag "' .. code .. '" in the gender specification "' .. spec.spec .. '" is not valid. See [[Module:gender and number]] for a list of valid tags.')
			end
			
			-- Check for multiple genders/numbers/animacies in a single spec.
			local typ = codes[code].type
			if typ ~= "other" and types[typ] then
				error('The gender specification "' .. spec.spec .. '" contains multiple tags of type "' .. typ .. '".')
			end
			types[typ] = true
				
			parts[key] = autoadd_abbr(codes[code].display)
		
			-- Generate categories if called for.
			if lang and pos_for_cat then
				local cat = codes[code].cat
				if cat then
					if not categories then
						categories = {}
					end
					insert(categories, mw.ustring.find(cat, "的") and mw.ustring.gsub(cat, "的", "的" .. full_langname) or full_langname .. cat)
				end
				if not seen_types then
					seen_types = {}
				elseif seen_types[typ] and seen_types[typ] ~= code then
					cat = (gender_and_number_data or get_gender_and_number_data()).multicode_cats[typ]
					if cat then
						if not categories then
							categories = {}
						end
						insert(categories, mw.ustring.find(cat, "的") and mw.ustring.gsub(cat, "的", "的" .. full_langname) or full_langname .. cat)
					end
				end
				seen_types[typ] = code
			end
			if lang and codes[code].req then
				local type_for_req = typ
				if code == "?" then
					-- Keep in mind `pos_for_cat` may be nil here.
					type_for_req = pos_for_cat == "動詞" and "體" or "性別"
				end
				if not categories then
					categories = {}
				end
				insert(categories, full_langname .. "詞條" .. type_for_req .. "請求")
			end
		end

		-- Add the processed codes together with non-breaking spaces
		if not parts[2] and parts[1] then
			return parts[1]
		else
			return concat(parts, "&nbsp;")
		end
	end

	for _, spec in ipairs(specs) do
		if type(spec) ~= "table" then
			spec = {spec = spec}
		end
		local spec_spec, is_nounclass = spec.spec
		-- If the specification starts with cX, then it is a noun class specification.
		if spec_spec:match("^%d") or spec_spec:match("^c[^-]") then
			is_nounclass = true
			local code = spec_spec:gsub("^c", "")
			
			local text
			if code == "?" then
				text = '<abbr class="noun-class" title="名詞類別缺失">?</abbr>'
				if lang then
					if not categories then
						categories = {}
					end
					insert(categories, "Requests for noun class in " .. full_langname .. " entries")
				end
			else
				text = '<abbr class="noun-class" title="名詞類別' .. code .. '">' .. code .. "</abbr>"
				if lang and pos_for_cat then
					if not categories then
						categories = {}
					end
					insert(categories, full_langname .. "第" .. code .. "類POS")
				end
			end
			local text_with_qual = add_qualifiers_and_refs(text, spec, lang)
			insert(formatted_specs, text_with_qual)
		else
			-- Split the parts and iterate over each part, converting it into its display form
			local parts = split(spec.spec, "-", true, true)
			local combined_codes = (gender_and_number_data or get_gender_and_number_data()).combinations

			if lang then
				-- Check if the specification is valid
				--elseif langinfo.genders then
				--	local valid_genders = {}
				--	for _, g in ipairs(langinfo.genders) do valid_genders[g] = true end
				--	
				--	if not valid_genders[spec.spec] then
				--		local valid_string = {}
				--		for i, g in ipairs(langinfo.genders) do valid_string[i] = g end
				--		error('The gender specification "' .. spec.spec .. '" is not valid for ' .. langinfo.names[1] .. ". Valid are: " .. concat(valid_string, ", "))
				--	end
				--end
			end

			local has_combined = false
			for _, code in ipairs(parts) do
				if combined_codes[code] then
					has_combined = true
					break
				end
			end

			if not has_combined then
				if formatted_specs[1] then
					insert(formatted_specs, " <small>或</small> ")
				end
				insert(formatted_specs, add_qualifiers_and_refs(do_gender_spec(spec, parts), spec, lang))
			else
				-- This logic is to handle combined gender specs like 'mf' and 'mfbysense'.
				local all_parts = {{}}
				local extra_displays
				local this_formatted_specs = {}

				for _, code in ipairs(parts) do
					if combined_codes[code] then
						local new_all_parts = {}
						for _, one_parts in ipairs(all_parts) do
							for _, one_code in ipairs(combined_codes[code].codes) do
								local new_combined_parts = deep_copy(one_parts)
								insert(new_combined_parts, one_code)
								insert(new_all_parts, new_combined_parts)
							end
						end
						all_parts = new_all_parts
						if lang and pos_for_cat then
							local extra_cat = combined_codes[code].cat
							if extra_cat then
								if not categories then
									categories = {}
								end
								rindex_de = mw.ustring.find(extra_cat, '的[^的]*$') -- L10N
								if rindex_de then
									extra_cat = mw.ustring.sub(extra_cat, 1, rindex_de) .. lang:getCanonicalName() .. mw.ustring.sub(extra_cat, rindex_de + 1)
								else
									extra_cat = lang:getCanonicalName() .. extra_cat
								end
								table.insert(categories, extra_cat)
							end
						end
						local extra_display = combined_codes[code].display
						if extra_display then
							if not extra_displays then
								extra_displays = {}
							end
							insert(extra_displays, autoadd_abbr(extra_display))
						end
					else
						for _, one_parts in ipairs(all_parts) do
							insert(one_parts, code)
						end
					end
				end

				for _, parts in ipairs(all_parts) do
					if this_formatted_specs[1] then
						insert(this_formatted_specs, " <small>或</small> ")
					end
					insert(this_formatted_specs, do_gender_spec(spec, parts))
				end

				if extra_displays then
					for _, display in ipairs(extra_displays) do
						insert(this_formatted_specs, display)
					end
				end

				insert(formatted_specs, add_qualifiers_and_refs(
					concat(this_formatted_specs, " "), spec, lang))
			end

			is_nounclass = false
		end

		-- Ensure that the specifications are either all noun classes, or none are.
		if all_is_nounclass == nil then
			all_is_nounclass = is_nounclass
		elseif all_is_nounclass ~= is_nounclass then
			error("Noun classes and genders cannot be mixed. Please use either one or the other.")
		end
	end

	if categories and lang and pos_for_cat then
		for i, cat in ipairs(categories) do
			categories[i] = cat:gsub("POS", pos_for_cat)
		end
	end

	if all_is_nounclass then
		-- Add the processed codes together with slashes
		return '<span class="gender">類別' .. concat(formatted_specs, "/") .. "</span>", categories
	else
		-- Add the processed codes together with spaces
		return '<span class="gender">' .. concat(formatted_specs, " ") .. "</span>", categories
	end
end

return export