Mô đun:Author

Văn thư lưu trữ mở Wikisource
Buớc tưới chuyển hướng Bước tới tìm kiếm

Mô đun này xử lý logic trong các trang không gian tên Tác gia. Nó dùng Wikidata khi có thể, và cho phép ghi đè nếu cần.

Kiểm thử tại Mô đun:Author/kiểm thử và kết quả có thể xem tại Thảo luận Mô đun:Author/kiểm thử.

Hàm: dates[sửa]

Lấy chuỗi ngày tháng trang tác gia và ghi thể loại.

Cách dùng
Thường dùng: {{#gọi|Author|dates}}
Đầy đủ tham số: {{#gọi|Author|dates|birthyear=|deathyear=|dates=|wikidata_id=}}

{{#gọi|Author|dates|năm sinh=|năm mất=|năm=|mã wikidata=}}

Tham số
  • năm — nếu có thì dùng chính tham số để hiển thị năm (tuy nhiên, năm sinh và năm mất vẫn có thể dùng để tạo thể loại)
  • năm sinhnăm mất — năm sinh và mất, theo định dạng sau:
    • năm số
    • "?" hoặc để trống nếu không rõ (hoặc còn sống)
    • dùng TCN cho năm trước Năm 1
    • Năm xấp xỉ:
      • Thập niên hoặc thế kỷ: "1930s" or "20th century"
      • Circa: "c/1930" or "c. 1930" or "ca 1930" or "circa 1930"
      • Tenuous year: "1932/?"
      • Choice of two or more years: "1932/1933"
  • wikidata_id — the Wikidata identifier to use. Will default to the current page if not supplied.
  • pagetitle — a page title to use instead of the current page (only used for testing purposes).
Returns
This function returns the author's birth and death years, wrapped in parentheses and separated by an en dash. The return string is prefixed with a <br />, and suffixed with the list of appropriate categories (see below).

Thể loại[sửa]

Hàm này thêm trang vào các thể loại sau:

  1. Trong mọi trường hợp (khi có thể):
  2. Nếu năm sinh và/hoặc năm mất bị ghi đè:

Function: date[sửa]

Get a single formatted date, with no categories.

Usage
Common usage: {{#invoke|Author|date|type=}}
All parameters: {{#invoke|Author|date|type=|year=|wikidata_id=}}
Parameters
  • type — either birth or death.
  • year — the year to display, following the same format as birthyear in the dates function above.
  • wikidata_id — the Wikdiata Q-identifier of the author to use.
Returns
A simple string with no categories or leading or trailing line breaks.

-- Global variables.
dateModule = require( "Mô đun:Date" )
tableToolsModule = require( "Mô đun:TableTools" )
categories = {} -- List of categories to add page to.

-- Việt hóa tham số
local argByViArg = {
	["năm sinh"] = "birthyear",
	["năm mất"] = "deathyear",
	["trôi"] = "dates",
	["rộng"] = "wikidata_id"
}

local rawGetArgs = require('Mô đun:Arguments').getArgs
local getArgs = function (frame, options)
	local args = rawGetArgs(frame, options)
	
	for viArgName, argName in pairs(argByViArg) do
		if args[viArgName] then
			args[argName] = args[viArgName]
		end
	end
	
	return args
end

--------------------------------------------------------------------------------
-- Get a given or family name property. This concatenates (with spaces) all
-- statements of the given property in order of the series ordinal (P1545)
-- qualifier. @TODO fix this.
function getNameFromWikidata( item, property )
	local statements = item:getBestStatements( property )
	local out = {}
	if statements[1] ~= nil and statements[1].mainsnak.datavalue ~= nil then
		local itemId = statements[1].mainsnak.datavalue.value.id
		table.insert( out, mw.wikibase.label( itemId ) or '' )
	end
	return table.concat( out, ' ' )
end

--------------------------------------------------------------------------------
function getPropertyValue( item, property )
	local statements = item:getBestStatements( property )
	if statements[1] ~= nil and statements[1].mainsnak.datavalue ~= nil then
		return statements[1].mainsnak.datavalue.value
	end	
end

--------------------------------------------------------------------------------
-- Định dạng năm sinh và mất tại 'Wikisource' như sau:
--     "?" hoặc để trống nếu không rõ (hoặc còn sống)or empty for unknown (or still alive)
--     Dùng TCN cho năm trước Năm 1
--     Năm gần đúng:
--         Thập niên hoặc thế kỷ: "thập niên 1930" hoặc "thế kỷ 20"
--         Khoảng: "k/1930" hoặc "k. 1930" hoặc "kh 1930" hoặc "khoảng 1930"
--         Có năm nhưng không chắc: "1932/?"
--         Có thể là một trong nhiều năm: "1932/1933"
-- Hàm này hơi phức tạp hơn bình thường, nhưng sau này có thể xóa.
-- @param dạng chuỗi hoặc 'sinh' hoặc 'mất'
-- @return dãy năm để hiển thị
function formatWikisourceYear( year, type )
	if year == nil or year == '' then
		return ''
	end
	local yearParts = mw.text.split( year, '/', true )
	-- Ends in a question mark.
	if yearParts[2] == '?' then
		addCategory( 'Tác gia không rõ năm ' .. type)
		if tonumber( yearParts[1] ) == nil then
			addCategory( 'Tác gia có năm ' .. type .. ' không phải số' )
		else
			addCategory( 'Tác gia ' .. dateModule.era( yearParts[1] ) )
			addCategory( type .. ' ' .. yearParts[1] )
		end
		return yearParts[1] .. '?'
	end
	-- Bắt đầu bằng viết tắt 'khoảng'
	local circaNames = { 'k', 'k.', 'kh', 'kh.', 'khoảng' }
	for _, circaName in pairs( circaNames ) do
		if yearParts[1] == circaName then
			addCategory( 'Tác gia có năm ' .. type .. ' xấp xỉ' )
			local out = 'khoảng ' .. yearParts[2]
			if tonumber( yearParts[2] ) == nil then
				addCategory( 'Tác gia có năm ' .. type .. ' không phải số' )
			else
				addCategory( 'Tác gia ' .. dateModule.era( yearParts[2] ) )
				addCategory( type .. ' ' .. yearParts[2] )
			end
			return out
		end
	end
	-- Nếu có nhiều hơn một năm, và tất cả đều là số, thêm thể loại.
	local allPartsAreNumeric = true
	if #yearParts > 1 then
		for _, yearPart in pairs( yearParts ) do
			if tonumber( yearPart ) ~= nil then
				addCategory( type .. ' ' .. yearPart )
				addCategory( 'Tác gia ' .. dateModule.era( yearPart ) )
			else
				allPartsAreNumeric = false
			end
		end
		if allPartsAreNumeric then
			addCategory( 'Tác gia có năm sinh xấp xỉ' )
		end
	end
	-- Ngược lại, chỉ dùng cái được cung cấp
	if #yearParts == 1 and tonumber( year ) == nil then
		addCategory( 'Tác gia có năm ' .. type .. ' không phải số' )
	end
	if #yearParts == 1 or allPartsAreNumeric == false then
		addCategory( type .. ' ' .. year )
	end
	return year
end

--------------------------------------------------------------------------------
-- Lấy năm được định dạng từ thuộc tính có sẵn và thêm thể loại phù hợp.
--   P569   ngày sinh
--   P570   ngày mất
--   P1317  sống vào khoảng
function formatWikidataYear( item, property )
	-- Kiểm tra độ sạch sẽ.
	if item == nil or string.sub( property, 1, 1 ) ~= 'P' then
		return ''
	end
	local type = 'sinh'
	if property == 'P570' then
		type = 'mất'
	end
	-- Lấy thông tin thuộc tính.
	local statements = item:getBestStatements( property )
	if #statements == 0 then
		-- Nếu không có thông tin nào cả, thêm thể loại 'thiếu'.
		if type == 'sinh' or type == 'mất' then
			addCategory( 'Tác gia không rõ năm ' .. type )
		end
		local isHuman = item:formatPropertyValues( 'P31' ).value == 'người'
		if type == 'mất' and isHuman then
			-- Nếu không có thông tin ngày mất, cho là còn sống.
			addCategory( 'Tác gia còn sống' )
		end
	end

	-- Soạn danh sách năm, mỗi cái từ mỗi thông tin.
	local years = {}
	for _, statement in pairs( statements ) do
		local year = getYearStringFromSingleStatement( statement, type )
		table.insert( years, year )
	end
	years = tableToolsModule.removeDuplicates( tableToolsModule.compressSparseArray( years ) )

	-- Nếu không tìm thấy năm nào, thử tìm sống vào khoảng.
	if #years == 0 or table.concat( years, '/' ) == '?' then
		floruitStatements = item:getBestStatements( 'P1317' )
		for _, statement in pairs( floruitStatements ) do
			-- Nếu tất cả những gì có là 'không rõ', thay nó.
			if table.concat( years, '/' ) == '?' then
				years = {}
			end
			addCategory( 'Tác gia có khoảng thời gian sống' )
			year = getYearStringFromSingleStatement( statement, 'sống' )
			table.insert( years, year )
		end
	end
	years = tableToolsModule.removeDuplicates( tableToolsModule.compressSparseArray( years ) )

	-- sắp xếp theo năm( years );
	return table.concat( years, '/' )
end

--------------------------------------------------------------------------------
-- Lấy một thông tin về một thuộc tính cung cấp và tạo ra một dãy năm dễ đọc
-- thêm thể loại phù hợp khi làm.
-- @param table statement Phần thông tin.
-- @param string type Một trong 'sinh' hoặc 'mất'.
function getYearStringFromSingleStatement( statement, type )
	local snak = statement.mainsnak
	-- Chúng không dùng mw.wikibase.formatValue vì chỉ muốn lấy năm.

	-- Không có giá trị. Sai cho năm sinh (nên là 'giá trị nào đó')
	-- và ghi 'còn sống' cho năm mất.
	if snak.snaktype == 'novalue' and type == 'sinh' then
		addCategory( 'Tác gia thiếu năm sinh' )
		return ''
	end
	if snak.snaktype == 'novalue' and type == 'mất' then
		addCategory( 'Tác gia còn sống' )
		return ''
	end

	-- Giá trị không rõ
	if snak.snaktype == 'somevalue' then
		addCategory( 'Tác gia không rõ năm ' .. type )
		return '?'
	end

	-- Lấy năm từ giá trị thời gian.
	local _,_, extractedYear = string.find( snak.datavalue.value.time, '([%+%-]%d%d%d+)%-' )
	year = math.abs( tonumber( extractedYear ) )
	addCategory( 'Tác gia ' .. dateModule.era( extractedYear ) )
	 -- Độ chính xác thế kỷ và thiên niên kỷ.
	if snak.datavalue.value.precision == 6 or snak.datavalue.value.precision == 7 then
		local ceilfactor = 100
		local precisionName = 'thế kỷ'
		if snak.datavalue.value.precision == 6 then
			ceilfactor = 1000
			precisionName = 'thiên niên kỷ'
		end
		local cent = math.max( math.ceil( year / ceilfactor ), 1 )
		-- @TODO: extract this to use something like [[en:wikipedia:Module:Ordinal]]
		
		year = precisionName .. ' ' .. cent
		addCategory( 'Tác gia có năm ' .. type .. ' xấp xỉ' )
	end
	if snak.datavalue.value.precision == 8 then -- decade precision
		year = 'thập niên ' .. math.floor( tonumber( year ) / 10 ) * 10
		addCategory( 'Tác gia có năm ' .. type .. ' xấp xỉ' )
	end
	if tonumber( extractedYear ) < 0 then
		year = year .. ' TCN'
	end

	-- Bỏ ra khỏi 'Tác gia còn sống' khi điều đó là vô lý.
	if tonumber( extractedYear ) < tonumber( os.date( '%Y' ) - 110 ) then
		removeCategory( 'Tác gia còn sống' )
	end

	-- Thêm vào thể loại 'Sinh YYYY' (trước khi thêm tiền tố 'khoảng ' hay 'sống vào khoảng').
	if type == 'sinh' or type == 'mất' then
		addCategory( type .. ' ' .. year )
	end

	-- Lấy xấp xỉ (P1480 = mức độ chính xác, Q5727902 = khoảng)
	if statement.qualifiers ~= nil and statement.qualifiers.P1480 ~= nil then
		for _,qualifier in pairs(statement.qualifiers.P1480) do
			if qualifier.datavalue.value.id == 'Q5727902' then
				addCategory( 'Tác gia có năm ' .. type .. ' xấp xỉ' )
				year = 'khoảng ' .. year
			end
		end
	end

	-- Add floruit abbreviation.
	if type == 'sống' then
		year = 'sống ' .. year
	end

	return year
end

--------------------------------------------------------------------------------
-- Thêm thể loại vào danh sách thể loại hiện tại. Không ghi tiền tố Thể loại.
function addCategory( category )
	for _, cat in pairs( categories ) do
    	if cat == category then
    		-- Đã có rồi
			return
    	end
  	end
	table.insert( categories, category )
end

--------------------------------------------------------------------------------
-- Xóa thể loại. Không ghi tiền tố Thể loại.
function removeCategory( category )
	for catPos, cat in pairs( categories ) do
    	if cat == category then
    		table.remove( categories, catPos )
    	end
  	end
end

--------------------------------------------------------------------------------
-- Lấy mã wiki của các thể loại dùng addCategory.
function getCategories()
	table.sort( categories )
	local out = ''
	for _, cat in pairs( categories ) do
		out = out .. '[[Thể loại:' .. cat .. ']]'
	end
	return out
end

--------------------------------------------------------------------------------
-- Kiểm tra tựa trang hiện tại có năm đúng làm hậu tố định hướng.
function checkTitleDatesAgainstWikidata( title, wikidata_id )
	-- Tất cả trang tác gia định hướng đều có ngoặc đơn trong tên.
	local titleHasParentheses = string.find( tostring( title ), '%d%)' )
	if titleHasParentheses == nil then
		return
	end

	-- Tựa trang nên kết thúc bằng năm có cùng định dạng như trong tiêu đề
	-- trang nhưng với dấu gạch thông thường thay vì gạch dài.
	local birthYear = date( { type = 'sinh'; wikidata_id = wikidata_id } )
	local deathYear = date( { type = 'mất'; wikidata_id = wikidata_id } )
	local dates = '(' .. birthYear .. '-' .. deathYear .. ')'
	if string.sub( tostring( title ), -string.len( dates ) ) ~= dates then 
		addCategory( 'Tác gia có tiêu đề năm không khớp' )
	end
end

--------------------------------------------------------------------------------
-- Lấy chuỗi định dạng năm mà tác gia đã sống,
-- sau đó xếp vào thể loại phù hợp.
-- Chuỗi trả về bắt đầu bằng xuống hàng (<br />).
function dates( args )
	local item = mw.wikibase.getEntity()
	if args.wikidata_id ~= nil and args.wikidata_id ~= '' then
		-- Kiểm tra này là cần thiết vì getEntity không chép được chuỗi trống.
		item = mw.wikibase.getEntity( args.wikidata_id )
	end
	local outHtml = mw.html.create()
	
	-- Kiểm tra trang định hướng có tiêu đề đúng chưa.
	checkTitleDatesAgainstWikidata( args.pagetitle or mw.title.getCurrentTitle(), args.wikidata_id )

	-- Lấy năm (năm mất trước, để sau đó năm sinh có ghi đè thể loại khi cần):
	-- Mất.
	local wikidataDeathyear = formatWikidataYear( item, 'P570' ) -- P570 Ngày mất
	local wikisourceDeathyear = formatWikisourceYear( args.deathyear, 'mất' )
	if args.deathyear == nil or args.deathyear == '' then
		args.deathyear = wikidataDeathyear
	else
		-- Đối với năm mất do Wikisource tự ghi.
		args.deathyear = wikisourceDeathyear
		addCategory( 'Tác gia có năm mất bị ghi đè' )
		if item ~= nil and wikisourceDeathyear ~= wikidataDeathyear then
			addCategory( 'Tác gia có năm mất khác với Wikidata' )
		end
		if tonumber( args.deathyear ) ~= nil then
			addCategory( 'Tác gia ' .. dateModule.era( args.deathyear ))
		end
	end
	if args.deathyear == '' and item == nil then
		addCategory( 'Tác gia thiếu năm mất' )
	end
	-- Sinh.
	local wikidataBirthyear = formatWikidataYear( item, 'P569' ) -- P569 Ngày sinh
	local wikisourceBirthyear = formatWikisourceYear( args.birthyear, 'sinh' )
	if args.birthyear == nil or args.birthyear == '' then
		args.birthyear = wikidataBirthyear
	else
		-- Đối với năm sinh do Wikisource tự ghi.
		args.birthyear = wikisourceBirthyear
		addCategory( 'Tác gia có năm sinh bị ghi đè' )
		if item ~= nil and wikisourceBirthyear ~= wikidataBirthyear then
			addCategory( 'Tác gia có năm sinh khác với Wikidata' )
		end
		if tonumber( args.birthyear ) ~= nil then
			addCategory( 'Tác gia ' .. dateModule.era( args.birthyear ))
		end
	end
	if args.birthyear == '' then
		addCategory( 'Tác gia thiếu năm sinh' )
	end

	-- Ghép chúng lại, gồm cả ghi đè năm.
	local dates = ''
	if args.dates ~= nil and args.dates ~= '' then
		-- Ngoặc được lặp lại ở đây và trong getFormattedDates()
		addCategory( 'Tác gia có năm bị ghi đè' )
		dates = '<br />(' .. args.dates .. ')'
	else
		dates = getFormattedDates( args.birthyear, args.deathyear )
	end
	outHtml:wikitext( dates .. getCategories() )
	return tostring( outHtml )
end

--------------------------------------------------------------------------------
-- Lấy ngày định dạng đơn, không có thể loại.
-- args.year, args.type, args.wikidata_id
function date( args )
	if args.type == nil then
		args.type = 'sinh'
	end
	if args.year == nil or args.year == '' then
		if args.wikidata_id == '' then
			-- Nil nếu không ghi.
			args.wikidata_id = nil
		end
		local item = mw.wikibase.getEntity( args.wikidata_id )
		local property = 'P570' -- P570 Ngày mất
		if args.type == 'sinh' then
			property = 'P569' -- P569 Ngày sinh
		end
		return formatWikidataYear( item, property )
	else
		return formatWikisourceYear( args.year, args.type )
	end
end

--------------------------------------------------------------------------------
-- Lấy chuỗi HTML đóng trong ngoặc thật sự để hiển thị ngày.
function getFormattedDates( birthyear, deathyear )
	local dates = ''
	if birthyear ~= '' or deathyear ~= '' then
		dates = dates .. '<br />('
	end
	if birthyear ~= '' then
		dates = dates .. birthyear
	end
	if ( birthyear ~= '' or deathyear ~= '' ) and birthyear ~= deathyear then
		-- Thêm khoảng trống nếu có khoảng trống giữa các năm.
		local spaces = ''
		if string.match( birthyear .. deathyear, ' ' ) then
			spaces = ' '
		end
		dates = dates .. spaces .. '–' .. spaces
	end
	if deathyear ~= '' and birthyear ~= deathyear then
		dates = dates .. deathyear
	end
	if birthyear ~= '' or deathyear ~= '' then
		dates = dates .. ')'
	end
	return dates
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Export all public functions.
return {
	header = function( frame ) return header( frame.args ) end;
	dates = function( frame ) return dates( frame.args ) end;
	date = function( frame ) return date( frame.args ) end;
}