Module:Cite Print

local p = {} local h = {} local data = mw.loadData("Module:Cite Print/Data")

local Franchise = require("Module:Franchise") local utilsArg = require("Module:UtilsArg") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local CAT_BOOK_QUOTES = "" local CAT_INVALID_ARGS = ""

-- We encapsulate Module:Error so that it is only transcluded on pages that actually have errors local function errFn(msg, warn) local utilsError = require("Module:UtilsError") return utilsError.error(msg, warn) end local function warn(msg) local utilsError = require("Module:UtilsError") utilsError.warn(msg) end

function p.Book(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Cite Book"]) local categories = err and err.categoryText or "" if args.quote then categories = categories..CAT_BOOK_QUOTES end local bookTitle = args.book if args.book and not h.hasItalics(args.book) then local bookLink = Franchise.link(args.book) if not bookLink then warn(string.format(" must be a code from Data:Franchise or else be written with italics.", bookTitle)) categories = categories..CAT_INVALID_ARGS else bookTitle = bookLink end end local phraseLink = args.book and Franchise.phraseLink(args.book) -- for manga and comics and such if phraseLink and phraseLink ~= "" then local byAuthor = string.find(phraseLink, " by ") if byAuthor then phraseLink = phraseLink.sub(phraseLink, 1, byAuthor - 1) -- strip the "by " part end bookTitle = phraseLink end if not bookTitle then bookTitle = errFn("book title required", true) categories = categories..CAT_INVALID_ARGS end local publisher if args.book and args.lang then local bookData = data.books[args.book] and data.books[args.book][args.lang] if not bookData then warn(string.format("No data exists for book  in language  . See Module:Cite Print/Data.", args.book, args.lang)) categories = categories..CAT_INVALID_ARGS end bookTitle = string.format("%s", Franchise.article(args.book) or bookData.display, bookData.display) publisher = bookData.publisher end if not publisher then publisher = args.publisher and p.getPublisherFromShortcut(args.publisher) or (args.book and Franchise.publisher(args.book)) end if not publisher then -- if after all that we still didn't manage to get a publisher... publisher = errFn("publisher required", true) categories = categories..CAT_INVALID_ARGS end local source = args source.title = bookTitle source.publisher = publisher local citation = h.printCitation(source, args.quote, args.character)

return citation, categories end -- Backwards compatibility for deprecated feature function p.getPublisherFromShortcut(publisher) local publishers = { ["enix"] = "Enix Corporation", ["nintendo"] = "Nintendo Co., Ltd.", ["piggyback"] = "Piggyback Interactive Limited", ["prima"] = "Prima Games", ["soleil"] = "Les Éditions Soleil", ["tokuma shoten"] = "Tokuma Shoten Publishing Co., Ltd.", }	local fullName = publishers[string.lower(publisher)] if fullName then warn(string.format("Publisher shortcuts are a deprecated feature. Please enter the full publisher name  instead of  ", fullName, publisher)) return fullName..CAT_INVALID_ARGS else return publisher end end

function p.Guide(frame) local Guide = require("Module:Guide")

local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Cite Guide"]) local categories = err and err.categoryText or "" if args.quote then categories = categories..CAT_BOOK_QUOTES end local guideArgs = {args.game, args.guide, "-"} local guideTitle, guideCategories, guidePublisher = Guide.guide(guideArgs, "Guide", true) categories = categories..guideCategories if args.year or args.edition then local editionYear = h.concat(", ", {args.edition, args.year}) guideTitle = guideTitle.." ("..editionYear..")" end local source = { title = guideTitle, publisher = guidePublisher, page = args.page, }	return h.printCitation(source, args.quote)..categories end

function p.Magazine(frame) local Magazine = require("Module:Magazine")

local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Cite Magazine"]) local categories = err and err.categoryText or "" if not args.magazine then return errFn("Magazine name required")..categories end -- We use italics as the cue for a custom magazine name - otherwise the magazine must be one supported by Template:Magazine if h.hasItalics(args.magazine) then args.title = args.magazine else local err = utilsArg.enum(Magazine.enum, args.magazine, "magazine") if err then categories = categories..""..err.category.."" end args.title = ""..args.magazine.."" if args.date then args.date = string.format("%s", args.magazine, args.date, args.date) end end return h.printCitation(args, args.quote, args.interviewee, args.url)..categories end

function p.Manual(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Cite Manual"]) local categories = err and err.categoryText or "" if not args.game and not args.product then categories = categories..CAT_INVALID_ARGS return errFn("game required"), categories end

if args.game then local gameLink = Franchise.link(args.game) if not gameLink then warn(string.format("Invalid game . See Data:Franchise for supported games.", args.game)) categories = categories..CAT_INVALID_ARGS else args.title = gameLink end end args.title = (args.title or args.game or args.product).." manual" if args.version then args.title = h.concat(", ", {args.title, args.version.." version"}) end return h.printCitation(args, args.quote), categories end

function h.printCitation(source, quote, speaker, archive) if type(source) == "table" then source = h.formatCitationSource(source) end local citation if not utilsString.isBlank(quote) and not utilsString.isBlank(speaker) then citation = string.format("%s" — %s (%s), quote, speaker, source) elseif not utilsString.isBlank(quote) then citation = string.format("%s" (%s), quote, source) elseif not utilsString.isBlank(speaker) then citation = string.format('%s (%s)', speaker, source) else citation = source end if archive then citation = string.format("%s ([%s archive])", citation, archive) end return citation end function h.formatCitationSource(source) local volume, issue, page = source.volume, source.issue, source.page if volume then volume = "vol. "..volume end if issue then issue = "no. "..issue end if page then page = "pg. "..page else page = "&#91;which page?&#93;" end local title = mw.getCurrentFrame:preprocess(source.title) local titleVolumeIssue = h.concat(" ", {title, volume, issue}) local sourceText = h.concat(", ", {titleVolumeIssue, source.publisher, source.edition, source.date, page}) return sourceText end function h.concat(separator, items) items = utilsTable.compact(items) items = utilsTable.filter(items, utilsString.notBlank) return table.concat(items, separator) end

function h.hasItalics(str) return string.find(str, ".*") end

function p.Data -- Performance optimization; importing this at the top with the others adds processing time to Template:Cite -- these dependencies are only needed on Module:Cite Print/Data/Documentation local Language = require("Module:Language") local utilsLayout = require("Module:UtilsLayout") local utilsMarkup = require("Module:UtilsMarkup") local utilsTable = require("Module:UtilsTable") local tableRows = {} for i, bookCode in ipairs(Franchise.enum({ includeNonfiction = true })) do		local bookData = data.books[bookCode] if bookData then table.insert(tableRows, {				{					content = string.format(" ", Franchise.article(bookCode) or bookCode, bookCode),					rowspan = utilsTable.size(bookData) + 1,					styles = {						["text-align"] = "center",					},				},			}) for i, langCode in ipairs(Language.enum) do				local bookLangData = bookData[langCode] if bookLangData then local lect = Language.getLect(langCode) table.insert(tableRows, {						{							content = lect.flags[1] .. " " .. lect.abbr,							sortValue = lect.lang,						},						string.format("%s", Franchise.article(bookCode) or bookLangData.display, bookLangData.display),						bookLangData.publisher					}) end end end end local booksTable = utilsLayout.table({		headers = {"Book", "Language", "Displayed Title", "Publisher"},		rows = tableRows,		sortable = true,	}) booksTable = utilsMarkup.heading(3, utilsMarkup.anchor("books", "Books in Other Languages"))..booksTable

return booksTable end

function p.Schemas local Language = require("Module:Language") return { Data = { type = "record", required = true, properties = { {					name = "books", required = true, desc = "Associates a book code from Data:Franchise to information about the publication of the book in other languages. Used by Template:Cite Book.", type = "map", keyPlaceholder = "bookCode", keys = { type = "string" }, values = { type = "map", keyPlaceholder = "langCode", keys = { type = "string", enum = Language.enum, desc = "A language code from Module:Language/Data.", },						values = { type = "record", properties = { {									name = "display", required = true, type = "string", desc = "The text to display when referring to the book - typically its subtitle.", },								{									name = "publisher", required = true, type = "string", desc = "The book's publisher." },							},						},					},				},			},		},	} end

p.Templates = { ["Cite Book"] = { format = "inline", paramOrder = {"quote", "character", "book", "publisher", "lang", "edition", "volume", "issue", "page"}, boilerplate = { tabs = { {					label = "Fiction", desc = "For citing manga, comics, novels, and other works of fiction.", params = {"quote", "book", "character", "publisher", "page"}, },				{					label = "Nonfiction", desc = "For citing books such as .", params = {"quote", "book", "publisher", "page"}, },				{					label = "Nonfiction (Alternative Language)", desc = "For citing books such as in other languages.", params = {"quote", "book", "lang", "page"}, },				{					label = "All Parameters", params = {"quote", "character", "book", "publisher", "lang", "edition", "volume", "issue", "page"}, },			},		},		params = { quote = { desc = "The quote to cite.", type = "content", trim = true, nilIfEmpty = true, },			character = { desc = "The name of the character speaking the quote. Use this for works of fiction such as manga, comics, and gamebooks.", type = "string", trim = true, nilIfEmpty = true, },			book = { desc = " The code for a book entry at Data:Franchise. To cite a book that is not licensed by Nintendo and therefore not defined in Data:Franchise, write the name of the book with italics. A book name without italics is considered invalid if it is not in Data:Franchise. ", type = "content", required = true, trim = true, nilIfEmpty = true, },			lang = { type = "string", desc = "A language code - used when citing books such as in other languages. See Module:Cite Print/Data for supported languages.", trim = true, nilIfEmpty = true, },			publisher = { desc = " The publisher of the book. Leave this empty when citing a book from Data:Franchise - the publisher will be automatically generated. ", type = "content", trim = true, nilIfEmpty = true, },			edition = { desc = "The book's edition.", type = "string", trim = true, nilIfEmpty = true, },			volume = { desc = "The volume number for the book quote, if applicable.", type = "string", trim = true, nilIfEmpty = true, },			issue = { desc = "A comic issue number.", type = "string", trim = true, nilIfEmpty = true, },			page = { desc = "The cited page(s).", type = "string", required = CATEGORY_MISSING_PAGE, trim = true, nilIfEmpty = true, },		},	},	["Cite Guide"] = { format = "inline", paramOrder = {"quote", "game", "guide", "page", "edition", "year"}, boilerplate = { tabs = { {					label = "Guide", params = {"quote", "game", "guide", "page"}, },				{					label = "Guide Edition", params = {"quote", "game", "guide", "page", "edition", "year"}, },			},		},		params = { quote = { desc = "The quote to cite.", type = "content", trim = true, nilIfEmpty = true, },			game = { desc = "The game abbreviation associated with the guide. See Template:Guide.", type = "string", required = true, trim = true, nilIfEmpty = true, },			guide = { aliases = {"publisher"}, desc = "The guide abbreviation. See Template:Guide. This parameter was formerly named .", type = "string", required = true, trim = true, nilIfEmpty = true, },			page = { desc = "The cited page(s).", type = "string", required = CATEGORY_MISSING_PAGE, trim = true, nilIfEmpty = true, },			edition = { desc = "The edition of the guide.", type = "string", trim = true, nilIfEmpty = true, },			year = { desc = "The year of release of the magazine edition.", type = "string", trim = true, nilIfEmpty = true, },		},		examples = { {				quote = "", game = "TLoZ", guide = "Nintendo", page = "5", },			{				quote = "", game = "TLoZ", guide = "NES Game Atlas", page = "5", },			{				quote = "This is a quote.", game = "TWWHD", guide = "Prima", page = "5", edition = "Premiere Edition", year = "2011", },			{				desc = "The  parameter was renamed to   but the former is still supported.", args = { quote = "", game = "ALttP", publisher = "Nintendo", page = "5", },			},			{				desc = "Error handling", args = { quote = "", game = "OoT3D", guide = "invalid guide", page = "", },			},			{				quote = "", game = "OoT", guide = "", page = "5", },			{				quote = "", game = "", guide = "", page = "5", }		},	},	["Cite Magazine"] = { purpose = "Citing magazines according to Guidelines:References.", format = "inline", paramOrder = {"quote", "interviewee", "magazine", "publisher", "volume", "issue", "date", "page", "url"}, boilerplate = { tabs = { {					label = "Magazine", params = {"quote", "magazine", "publisher", "volume", "issue", "date", "page", "url"}, },				{					label = "Magazine Interview", params = {"quote", "magazine", "interviewee", "publisher", "volume", "issue", "date", "page", "url"}, }			},			},		params = { quote = { desc = "The quote to cite.", type = "content", trim = true, nilIfEmpty = true, },			interviewee = { desc = "If  is an answer from an inteview, enter the interviewee's name.", type = "string", trim = true, nilIfEmpty= true, },			magazine = { desc = " The name of the magazine. Use a magazine name supported by Template:Magazine. To cite a magazine that is not licensed by Nintendo and therefore not supported by Template:Magazine, write the name of the magazine with italics. A magazine name without formatting is considered invalid if it is not supported by Template:Magazine. ", type = "content", required = true, trim = true, nilIfEmpty = true, },			publisher = { desc = " The publisher of the magazine. Leave this empty if citing a magazine supported by Template:Magazine. ", type = "content", trim = true, nilIfEmpty = true, },			date = { desc = "The of the cited magazine issue.", type = "string", required = true, trim = true, nilIfEmpty = true, },			volume = { desc = "The volume number of the cited magazine issue.", type = "string", trim = true, nilIfEmpty = true, },			issue = { desc = "The issue number of the cited magazine issue.", type = "string", trim = true, nilIfEmpty = true, },			url = { desc = "An archive.org URL where the magazine can be read. Use the URL specifically for the cited page.", type = "string", trim = true, nilIfEmpty = true, },			page = { desc = "The cited page(s).", type = "string", required = CATEGORY_MISSING_PAGE, trim = true, nilIfEmpty = true, },		},		examples = { {				quote = "If you distract its attention and sneak up, you might be able to ride it.", magazine = "Nintendo Magazine", publisher = "", date = "Winter 2021", volume = "", issue = "", url = "https://archive.org/details/nintendomagazine-2021winter-english/16.jpg", page = "16", },			{				quote = "", magazine = "Nintendo Power", publisher = "", date = "July/August 1988", volume = "", issue = "1", url = "https://archive.org/details/nintendo_power_issue1/page/n25", page = "26", },			{				quote = "", magazine = "Nintendo Fun Club News", publisher = "", date = "Fall 1987", volume = "1", issue = "3", url = "https://archive.org/details/NintendoFunClubMagazines/Nintendo%20Fun%20Club%20News%20Issue%203%20%28Fall%201987%29/page/n7", page = "8", },			{				quote = "I have already talked to Mr. Miyamoto about this so I am comfortable releasing this information--this title [Skyward Sword] takes place before Ocarina of Time.", magazine = "Official Nintendo Magazine", date = "December 2010", issue = "62", page = "51", interviewee = "Eiji Aonuma", },			{				desc = "To cite a magazine not licensed by Nintendo, write the magazine name with italics.", args = { quote = "Out: 10/05", magazine = "CD-i Magazine", publisher = "Haymarket Publishing", date = "April 1996", volume = " ", issue = "17", url = "https://archive.org/details/cdi-uk-17", page = "12", },			},			{				magazine = "invalid magazine", date = "October 2022", page = "", },			{				magazine = "", },		}	},	["Cite Manual"] = { format = "inline", paramOrder = {"quote", "game", "product", "version", "page"}, boilerplate = { tabs = { {					label = "Game Manual", params = {"quote", "game", "page"}, },				{					label = "Game Version", params = {"quote", "game", "version", "page"}, },				{					label = "Product Manual", params = {"quote", "product", "page"}, },			},		},		params = { quote = { desc = "The quote to cite.", type = "content", trim = true, nilIfEmpty = true, },			game = { desc = "The game abbreviation associated with the manual. See Data:Franchise for supported games.", type = "string", trim = true, nilIfEmpty = true, },			product = { desc = "Used instead of  to cite the manual of a product not defined at Data:Franchise - a console manual, for example.", type = "string", trim = true, nilIfEmpty = true, },			version = { desc = "Used to specify a specific port, game mode, or localization of the game if applicable.", type = "string", trim = true, nilIfEmpty = true, },			page = { desc = "The cited page or pages (format: 54 or 34-36).", type = "string", required = CATEGORY_MISSING_PAGE, trim = true, nilIfEmpty = true, },		},	}, }

return p