Module:CitationLite
CitationLite is a lightweight Lua citation engine for Chalo Chatu. It powers minimal, stable versions of the following templates:
- {{Cite web}}
- {{Cite news}}
- {{Cite book}}
- {{Cite journal}}
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.
– used by {{Cite web}}
– used by {{Cite news}}
– used by {{Cite book}}
– used by {{Cite journal}}
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
- {{Cite web}} • {{Cite news}} • {{Cite book}} • {{Cite journal}}
- Help:Citation (Chalo Chatu guidance)
- Module:CitationLite (source)
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