Module:CitationLite

From Chalo Chatu, Zambia online encyclopedia
Jump to navigationJump to search

CitationLite is a lightweight Lua citation engine for Chalo Chatu. It powers minimal, stable versions of the following templates:

This module avoids the complexity of CS1/CS2 while covering the most common citation needs on Chalo Chatu. It has no external module dependencies and aims for predictable output and low error rates.

Entry points

Use {{#invoke}} only from templates. Do not call the module directly from articles.

Supported parameters

All four entry points accept a small, consistent set of parameters. Some are ignored when not applicable.

Core
author, authors, last, first, title, date, language/lang, access-date
Source and publication
website/work, publisher, newspaper (news only), journal (journal only)
Identifiers and detail
isbn (book), doi (journal), edition (book), volume, issue/number, pages/page, year, place/location
Links
url, archive-url, archive-date, url-status (use live or dead)
Extras
quote (short inline quotation)

Notes on parameters

  • Authors may be provided as
|author= or |last= with |first=, or |authors= with names separated by semicolons or commas.
  • |language= displays as a short marker in parentheses, for example (bemba), (ny), (en). Do not use long prose.
  • |access-date= is free-form; the module does not parse or validate dates.
  • Archive handling shows links as “URL • Archived 2025-07-20 (live/dead)”. If only |archive-url= is present, it will still display the archived link.

Output style

The module emits simple inline citations wrapped in a span with a type class:

  • <span class="citation web">...</span>
  • <span class="citation news">...</span>
  • <span class="citation book">...</span>
  • <span class="citation journal">...</span>

Formatting rules

  • Author list joins with commas and an ampersand before the last author.
  • Article and chapter titles use quotation marks.
  • Work, website, book, and journal names are italicised.
  • Blocks end with a final period if missing.

Examples

Web

{{Cite web
 | author       = Ministry of Information
 | title        = Government launches new portal
 | website      = Cabinet Office
 | publisher    = Government of the Republic of Zambia
 | date         = 2025-07-12
 | url          = https://www.example.gov.zm/portal
 | access-date  = 2025-09-08
 | archive-url  = https://web.archive.org/web/20250720/https://www.example.gov.zm/portal
 | archive-date = 2025-07-20
 | url-status   = live
 | language     = en
}}

News

{{Cite news
 | author      = Reporter Name
 | title       = Power outage hits parts of Lusaka
 | newspaper   = Times of Zambia
 | date        = 2025-08-29
 | url         = https://www.times.co.zm/article/power-outage
 | access-date = 2025-09-08
}}

Book

{{Cite book
 | author    = Mulenga, John
 | title     = History of Lusaka
 | edition   = 2nd
 | publisher = ZedPress
 | year      = 2019
 | place     = Lusaka
 | isbn      = 978-1-23456-789-7
 | pages     = 45–48
}}

Journal

{{Cite journal
 | authors  = Phiri, M.; Banda, T.
 | title    = Urban growth in Lusaka
 | journal  = Zambian Journal of Planning
 | volume   = 12
 | issue    = 2
 | pages    = 101–120
 | year     = 2024
 | doi      = 10.1234/zjp.2024.012
 | url      = https://journal.example.org/urban-growth
 | access-date = 2025-09-08
}}

Error handling and maintenance

The module is defensive about missing parameters. It will not throw Lua errors for empty fields. Where both |title= and |url= are missing, maintainers may enable an optional tracking category by adding the small helper in the module source and creating

  • Category:Citation Lite maintenance (hidden)

This is off by default to keep article output clean.

Migration guidance

  • Prefer these templates for straightforward sources on Chalo Chatu.
  • Legacy CS1-based templates may remain where advanced fields are required; otherwise consider converting to the lightweight forms for performance and consistency.
  • When converting, preserve dates and archive fields exactly as written by the editor.

Limitations

  • No automatic date parsing or reformatting.
  • No complex name parsing beyond simple lists.
  • No S2CID, JSTOR, OCLC, or similar identifiers.
  • No automatic punctuation trimming inside parameters; provide clean input.

See also

Testcases

Use the sandbox and testcases pages to validate changes:

Maintainers: keep the public interface stable. Any breaking change should be announced on the Village Pump before deployment.


-- Module:CitationLite
-- Lightweight citation renderer for Chalo Chatu
-- Supports: cite_web, cite_news, cite_book, cite_journal
-- Design goals: simple, robust, no complex date parsing, no heavy dependencies.

local p = {}

-- ========== Utilities ==========
local function trim(s)
	if type(s) ~= "string" then return s end
	return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

local function isempty(v)
	if v == nil then return true end
	if type(v) == "string" then return trim(v) == "" end
	return false
end

local function list_from(s)
	-- Accept lists split by ";", "," or ","
	if isempty(s) then return nil end
	local items = {}
	for part in tostring(s):gmatch("[^;]+") do
		table.insert(items, trim(part))
	end
	if #items == 1 and items[1]:find(",") then
		items = {}
		for part in tostring(s):gmatch("[^,]+") do
			table.insert(items, trim(part))
		end
	end
	return (#items > 0) and items or nil
end

local function join(parts, sep)
	local out = {}
	for _, v in ipairs(parts) do
		if not isempty(v) then table.insert(out, v) end
	end
	return table.concat(out, sep or " ")
end

local function wrap(spanClass, text)
	if isempty(text) then return nil end
	return string.format('<span class="%s">%s</span>', spanClass, text)
end

local function italic(s)  -- ''italics'' in wiki output
	if isempty(s) then return nil end
	return string.format("''%s''", s)
end

local function quoted(s)
	if isempty(s) then return nil end
	return string.format('"%s"', s)
end

local function extlink(url, label)
	if isempty(url) then return nil end
	label = isempty(label) and url or label
	return string.format('[%s %s]', url, label)
end

local function render_archive(url, date)
	if isempty(url) then return nil end
	local label = isempty(date) and "Archived" or ("Archived " .. tostring(date))
	return extlink(url, label)
end

local function render_url_block(url, archive_url, archive_date, url_status)
	if isempty(url) and isempty(archive_url) then return nil end
	local bits = {}
	if not isempty(url) then table.insert(bits, extlink(url, "URL")) end
	if not isempty(archive_url) then table.insert(bits, render_archive(archive_url, archive_date)) end
	if not isempty(url_status) then table.insert(bits, "(" .. tostring(url_status) .. ")") end
	return join(bits, " • ")
end

local function render_authors(args)
	-- Accept: |author=, |authors= (list), or |last= + |first=
	local authors = {}
	if not isempty(args.author) then
		table.insert(authors, args.author)
	end
	if not isempty(args.last) or not isempty(args.first) then
		local name = join({args.first, args.last}, " ")
		if not isempty(name) then table.insert(authors, name) end
	end
	if not isempty(args.authors) then
		local more = list_from(args.authors)
		if more then
			for _, a in ipairs(more) do table.insert(authors, a) end
		end
	end
	if #authors == 0 then return nil end
	if #authors == 1 then
		return authors[1]
	elseif #authors == 2 then
		return authors[1] .. " & " .. authors[2]
	else
		local last = table.remove(authors)
		return table.concat(authors, ", ") .. " & " .. last
	end
end

local function render_lang(lang)
	if isempty(lang) then return nil end
	return "(" .. tostring(lang) .. ")"
end

local function punct_concat(parts)
	-- Join with ". " and ensure final period.
	local text = join(parts, ". ")
	if isempty(text) then return "" end
	if not text:match("%.%s*$") then text = text .. "." end
	return text
end

-- Safe prefix helper to avoid nil concatenation
local function prefixed(prefix, v)
	if isempty(v) then return nil end
	return prefix .. tostring(v)
end

-- ========== Core builders ==========
local function cite_web_like(kind, args)
	-- author. "Title". ''Website/Work''. Publisher. Date. URL-Block. Accessed access-date. Quote
	local author    = render_authors(args)
	local title     = quoted(args.title or args.chapter or args.article)
	local work      = italic(args.website or args.work or (kind == "news" and args.newspaper) or nil)
	local publisher = args.publisher
	local date      = args.date or args["publication-date"]
	local urlblk    = render_url_block(args.url, args["archive-url"], args["archive-date"], args["url-status"])
	local access    = prefixed("Accessed ", args["access-date"])
	local lang      = render_lang(args.language or args.lang)
	local quote     = isempty(args.quote) and nil or ("“" .. tostring(args.quote) .. "”")

	local body = punct_concat({
		join({author, title}, ". "),
		join({work, publisher}, ". "),
		date,
		urlblk,
		access,
		lang,
		quote
	})

	return string.format('<span class="citation %s">%s</span>', kind, body)
end

local function cite_book(args)
	-- author. ''Title''. Edition. Publisher, Year. Place. ISBN. Pages. URL-Block. Accessed access-date.
	local author    = render_authors(args)
	local title     = italic(args.title)
	local edition   = args.edition
	local year      = args.year or args.date
	local place     = args.place or args.location
	local publisher = args.publisher
	local isbn      = args.isbn
	local pages     = args.pages or args.page
	local urlblk    = render_url_block(args.url, args["archive-url"], args["archive-date"], args["url-status"])
	local access    = prefixed("Accessed ", args["access-date"])
	local lang      = render_lang(args.language or args.lang)

	local publine
	if not isempty(publisher) and not isempty(year) then
		publine = publisher .. ", " .. tostring(year)
	else
		publine = publisher or year
	end

	local body = punct_concat({
		join({author, title}, ". "),
		edition,
		publine,
		place,
		prefixed("ISBN ", isbn),
		pages and ("pp. " .. tostring(pages)) or nil,
		urlblk,
		access,
		lang
	})

	return string.format('<span class="citation book">%s</span>', body)
end

local function cite_journal(args)
	-- author. "Article title". ''Journal''. volume (issue): pages, year. DOI/URL-Block. Accessed access-date. Lang.
	local author   = render_authors(args)
	local atitle   = quoted(args.title or args.article)
	local journal  = italic(args.journal or args.work)
	local volume   = args.volume
	local issue    = args.issue or args.number
	local pages    = args.pages or args.page
	local year     = args.year or args.date
	local doi      = prefixed("doi:", args.doi)
	local urlblk   = render_url_block(args.url, args["archive-url"], args["archive-date"], args["url-status"])
	local access   = prefixed("Accessed ", args["access-date"])
	local lang     = render_lang(args.language or args.lang)

	local voliss
	if not isempty(volume) and not isempty(issue) then
		voliss = tostring(volume) .. " (" .. tostring(issue) .. ")"
	else
		voliss = volume or issue
	end

	local pagestr = not isempty(pages) and tostring(pages) or nil  -- e.g., 12–34

	local after = join({
		voliss and (voliss .. (pagestr and (": " .. pagestr) or "")) or pagestr,
		year
	}, ", ")

	local tail = join({
		doi,
		urlblk
	}, ". ")

	local body = punct_concat({
		join({author, atitle}, ". "),
		journal,
		after,
		tail,
		access,
		lang
	})

	return string.format('<span class="citation journal">%s</span>', body)
end

-- ========== Entry points ==========
function p.cite_web(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args or {}
	return cite_web_like("web", args)
end

function p.cite_news(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args or {}
	return cite_web_like("news", args)
end

function p.cite_book(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args or {}
	return cite_book(args)
end

function p.cite_journal(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args or {}
	return cite_journal(args)
end

return p