The language submodules should return a table with two values. One, bib_ref
, should be the title of the page that houses the bibliography which {{R}}
will link to. The other, sources
, should contain the bibliographic information of all the sources cited. Each source should be formatted as such.
= {
= values,
...
},
{{R}}
. Note the following formatting guidelines:
Author:YEAR
, e.g. Nakassis:2013
which will be displayed as ⟨Nakassis (2013)⟩. Note the year may be followed by a letter (a
, b
, etc.) if there are multiple works by the same author from the same year in the bibliography. Multiple authors should be separated by ampersands &
and commas ,
, e.g. Author, Author & Author:YEAR
, although for works which multiple editors abbreviation are more common.OED
for the Oxford English Dictionary. This will be italicised and displayed on the bibliography page. You can also add a preceding author, e.g. Lejeune:Mémoires
is displayed as ⟨Lejeune Mémoires⟩. The alias without the colon is generated automatically, hence it can be called by {{R}}
simply as Lejeune Mémoires
.^
indicates that the following script should be in superscript. This is usually done for edition numbers, e.g. Documents^2
is displayed as ⟨Documents2⟩. The alias without the caret is generated automatically, hence it can be called simply as Documents2
.id
to override the data table key if needed.alias
may be a single string or lists of strings. All the possible aliases that {{R}}
may identify the source as.title
, formattable text.author
, formattable text, may be a list of authors.
type
for the author's role in the work, e.g. translator
, editor
, compiler
, etc.year
, non-formattable text.published_year
the year in which it was published, if for whatever reason differs from year
.first_edition
the year in which the first edition of the work was published in.location
, formattable text, may be a list.publisher
, formattable text, may be a list.
UP
.edition
, the cited edition number, e.g. 2nd
.volume
, indicates the cited volume of a work.
volumes
, which is a list of the volumes of the cited work.volume.number
, non-formattable text.volume.title
, formattable text.series
, indicates the series the work belongs to.
series.name
, the title of the series, mandatory, formattable text.series.number
, the number of the cited work within the series, non-formattable text.chapter_of
, indicates whether the cited work is just a chapter of a larger book.
transl_of
and volumes
do.chapter_of.pages
, the page range of the cited chapter, non-formattable text.journal
, indicates the journal the cited article belongs to.
journal.name
, the title of the journal, mandatory, formattable text.journal.number
, the cited issue. May be either a single number or a list of two numbers (usually described as the volume and the number).journal.pages
, the page range of the article, non-formattable text.transl_of
, if the work is a translation, specify information of the original work under this one.link
, various links.
link.isbn
link.doi
link.jstor
, JSTOR stable link ID.link.ia
, Internet Archive ID.link.gb
, Google Books ID.link.url
, the full URL.volumes
list of sources, indicates the volumes of the cited work.
volume
which indicates what the cited volume of a work.number
, which will be treated as if it was volume.number
.page_url
, entry_url
, section_url
, etc. Various examples, because it is tiring to explain in detail:
page_url = { ia = true }
, retrieves the Internet Archive ID from the link
parameter and uses that as the page URL.
true
.page_url = { gb = true, set_page = -3 }
, if the cited page and the URL page differ by three.page_url = {
ia = function(data)
if data.page < 500 then
return "first_id"
else
return "second_id"
end
end,
set_page = function(data)
if data.page < 500 then
return data.page
else
return data.page - 500
end
end
}
set_entry
or set_section
etc.data
are page
, volume
, entry
, section
and id
(which is the entry ID specified by {{R}}
, not to be confused with source ID).if
statemets where used for better understandability, though for faster typing I suggest mastering the logic behind ternary operators.entry_url = "http://www.nayiri.com/imagedDictionaryBrowser.jsp?dictionaryId=26&query=$ENTRY$"
. The parameters that can be specified in dollars are the same that are supported by the data
parameter of the set_...
functions (see above).entry_lang
, the language code that will be used to properly format the text of the entry cited.import_from
, the language code of the submodule to import the source from. If this parameter is given, no other parameter should be given.|
indicates a link to Wikipedia, various examples:
Pedia|Display
→ ]
|Display
→ ]
es:|Display
→ ]
family name, given name
and the pipe will automatically reorder them for the pedia link:
|Godart, Louis
→ ]
es:|Melena Jiménez, José Luis
→ ]
|Bennett, Emmett L., Jr.
→ ]
.
syntax as follows:
|Palmer, L.eonard R.obert
→ ]
hy:Նոր բառգիրք հայկազեան լեզուի
→ {{lang|hy|Նոր բառգիրք հայկազեան լեզուի}}
el:|el:Παπαδόπουλος, Άνθιμος
→ {{lang|el|]}}
.text
(mandatory), the original text to format. It supports all the syntax shown above.lang
the language code. Equivalent to specifying it at the beginning of text
followed by a colon.pedia
the Wikipedia page to link to. Equivalent to the pipe syntax.translit
the transliteration. May be either true
, which generated the transliteration automatically if a language is specified, or a string with the hardcoded transliteration, for languages without transliteration. It will appear after the text in the original script unless translit_only
(see below) is also specified.translit_only
if true
suppresses the text in the original script and only shows the transliteration.translation
adds a translation alongside the original text, e.g. title = { text = "ota:قاموس تركی", translit = "kamus-ı türki", translation = "Dictionary of Turkish" }
.{ "hy:Գաբրիել Ավետիքյան|hy:Աւետիքեան, Գ.աբրիէլ", "hy:Խաչատուր Սյուրմելյան|hy:Սիւրմէլեան, Խ.աչատուր", translit_only = true }
applies the translit_only = true
to all the texts in the list.-- See also ]
local export = {}
local tag_text = require("Module:script utilities").tag_text
local get_lang = require("Module:languages").getByCode
local assume_script = require("Module:scripts").findBestScriptWithoutLang
local utils = require("Module:bibliography/utils")
local function is_list(value)
return type(value) == "table" and #value > 0
end
local preprocess_frame -- defined in export.format_full_bibliography, used by format_text
local function format_text(text_data, is_person)
-- pipe stands for link, what is before it is the link destination, what is after is displayed
local text, lang, pedia, translation, translit, translit_only
if type(text_data) == "table" then
text = text_data.text
lang = text_data.lang
pedia = text_data.pedia
translation = text_data.translation
translit = text_data.translit
translit_only = text_data.translit_only
else
text = text_data
end
local link_prefix
if not pedia and text:match("^*%f") then
pedia = text:match("^.*%f")
text = text:gsub("^.*|", "")
-- check if there is a wiki prefix in the link destination, temporarily strip it if so
link_prefix = pedia:match("^+:")
if link_prefix then pedia = pedia:gsub("^"..link_prefix, "") end
end
-- check if there is a langcode before text for proper display
if not lang then
lang = text:match("^*%f")
if lang then
text = text:gsub("^"..lang..":", "")
end
end
if lang then lang = get_lang(lang) end
-- if the destination is empty, we can deduce it from the displayed form
if pedia == "" then
if is_person then
-- for Western naming tradition
local i = 1
for v in text:gmatch("+") do
-- family name
if i == 1 then
pedia = v
-- given name
elseif i == 2 then
pedia = mw.ustring.gsub(v, "%.(%a)", "%1").." "..pedia
-- suffix, esp. Americans
elseif i == 3 then pedia = pedia.." "..v
else error("Too many commas in author name") end
i = i + 1
end
-- if not a person, use the plain displayed form
else
pedia = text
end
end
-- reinsert the prefix in the link destination
if link_prefix then pedia = link_prefix..pedia end
-- shorten dotted given names, e.g. <J.ohn> displays as <J.>
if is_person then text = mw.ustring.gsub(text, "%.%a+", "."):gsub("^(.+,.+),", "%1") end
-- transliterate
if translit == true or (translit_only and not translit) then
if not lang then
error("Cannot translit from unspecified language")
end
translit = lang:transliterate(text)
end
-- format wikitext link
local display = text
if translit_only then display, translit = translit, nil end
-- preprocess if there are templates present
if display:match("{{.+}}") then
display = preprocess_frame:preprocess(display)
end
if pedia then display = "]" end
-- format according to text language
if not translit_only then
if lang then
display = tag_text(display, lang)
else
local script = assume_script(text)
if script:getCode() ~= "Latn" then
display = tag_text(display, get_lang("und"), script)
end
end
end
if translit or translation then
display = display.." ["
if translit then
display = display..translit
if translation then
display = display..", "
end
end
if translation then
display = display..translation
end
display = display.."]"
end
return display
end
local function render_list_or_value(value, sep, formatter)
-- support strings instead of functions for func
if type(formatter) == "string" then
local replacement_string = formatter
formatter = function(s) return replacement_string:format(s) end
end
-- if the value is a list, go through all values and format them
if is_list(value) then
-- inheritance of named parameters in lists
-- TODO: I cannot believe there is not a faster way to do this
for father_index, father_value in pairs(value) do
if type(father_index) ~= "number" then
for set_index, set_value in ipairs(value) do
if type(set_value) == "string" then
value = { text = set_value }
end
value = father_value
end
end
end
-- if the function is formatted, go through iterate through all the things
if formatter then
local ret = ""
for _, v in ipairs(value) do
ret = ret..formatter(v)..sep
end
return (ret:gsub(sep.."$", ""))
-- if no formatting function is specified, use the faster built-in function
else
return table.concat(value, sep)
end
-- if the value is a single string or table, simply return it, potentially formatted
elseif value then
return formatter and formatter(value) or value
-- handle possibility of nil value
elseif value == nil then
return nil
end
end
local format_listitem -- forward declaration
local function format_citation(source, tracking_lang, father)
local citation_text = ""
-- reorder volume values for children
if father and source.title or source.number then
source.volume = { title = source.title, number = source.number }
source.title, source.number = nil, nil
end
-- this function appends text to the citation string
local function add(a, b)
-- if one argument is given, it is simply appended
-- if two arguments are given, the first one is a separator, and is only appended if the string is not empty
if not b or citation_text:len() > 0 then citation_text = citation_text..a end
if b then citation_text = citation_text..b end
end
-- AUTHOR --
if source.author then
add((render_list_or_value(source.author, "; ", function (author)
if author == "et al." then return author end
local ret = format_text(author, true)
if type(author) == "table" and author.type then
ret = ret.." ["..(({
= "ed.",
= "transl.", = "transl.",
= "comp.",
}) or author.type).."]"
end
return ret
end):gsub("; et al%.$", " ''et al.''")))
end
-- YEAR --
local function format_year()
if source.year then
add(" ", "("..render_list_or_value(source.year, ", "):gsub("%-", "–")..")")
end
end
if source.author then format_year() end
-- TITLE --
if source.title then
add(". ", ((source.journal or source.chapter_of) and "“%s”" or "<cite>%s</cite>"):format(format_text(source.title)))
-- EDITION --
if source.edition then
add(" ("..source.edition.." ed.")
if source.first_edition then
add(", first publ. in "..source.first_edition)
end
add(")")
end
end
-- if no author is given, the year goes after the title
if not source.author then format_year() end
-- VOLUME --
if source.volume then
if type(source.volume) ~= "table" then
source.volume = { number = source.volume }
end
if source.volume.number then
add(", ", (father and "volume " or "vol. ")..source.volume.number)
end
if source.volume.title then
add(source.volume.number and ": " or ". ", "<cite>"..format_text(source.volume.title).."</cite>")
end
end
-- SERIES --
if source.series then
if not source.series.name then error("The parameter series.name is mandatory") end
add(" ", "("..format_text(source.series.name))
if source.series.number then
add(": "..source.series.number)
end
add(")")
end
-- CHAPTER_OF --
if source.chapter_of then
local chapter_pages = source.chapter_of.pages
source.chapter_of.pages = nil
add(". ", "In "..format_citation(source.chapter_of))
if chapter_pages then
add(", pp. "..chapter_pages:gsub("%-", "–"))
end
end
-- JOURNAL --
if source.journal then
-- .name
if source.journal.name == nil then error("The parameter journal.name is mandatory") end
add(". ", "<cite>"..format_text(source.journal.name))
-- .number
local number = source.journal.number
if number then
if type(number) == "table" then
if #number == 1 then
number = number
elseif #number == 2 then
-- TODO: reach an agreement on whether to have the space or not
add(", "..number.."</cite> ("..number..")")
else
error("Unusual amount of values in journal.number")
end
else
add(", "..number.."</cite>")
end
else
add("</cite>")
end
-- .pages
if source.journal.pages then
add(", pp. "..source.journal.pages:gsub("%-", "–"))
end
end
-- data about publication --
if source.location or source.publisher then
local location, publisher = source.location, source.publisher
if not location and type(publisher) == "string" and publisher:match(" UP$") then
location = publisher:gsub(" UP$", "")
end
if location then
add(". ", render_list_or_value(location, "/", format_text))
end
if publisher then
add(location and "; " or ". ", render_list_or_value(publisher, "/", format_text))
end
end
if source.published_year then
add(", ", "publ. in "..source.published_year)
end
-- TRANSLATION_OF --
if source.transl_of then
add(", ", "transl. of "..format_citation(source.transl_of))
end
-- LINK --
if source.link then
if type(source.link) == "string" then
source.link = { url = source.link }
end
local is_first = true
for _, link in ipairs {
{ key = "isbn", formatter = function (isbn)
return "]"
.. require("Module:check isxn").check_isbn(isbn,
' <span class="error" style="font-size:88%">Invalid ISBN</span>]'
)
end
},
{ key = "doi", formatter = "" },
{ key = "jstor", formatter = "" },
{ key = "ia", formatter = "" },
{ key = "gb", formatter = "" },
{ key = "academia", formatter = "" },
{ key = "url", formatter = "" },
} do
if source.link then
add(is_first and ": " or ", ", render_list_or_value(source.link, ", ", link.formatter))
is_first = false
end
end
end
-- VOLUMES --
if source.volumes and type(source.volumes) == "table" then
add(":", "<ul>")
local volumes_reordered = {}
local show_numbers = not source.volumes.hide_numbers
source.volumes.hide_numbers = nil
for index, volume in pairs(source.volumes) do
if show_numbers then
volume.number = volume.number or index
end
table.insert(volumes_reordered, {
number = type(index) == "number" and index or tonumber(index:match("^%d+")) or -1,
name = tostring(index),
data = volume,
})
end
table.sort(volumes_reordered, function(a, b)
return a.number == b.number and a.name < b.name or a.number < b.number
end)
for _, volume in ipairs(volumes_reordered) do
add(format_listitem(volume.data, tracking_lang, nil, source))
end
add("</ul>")
end
-- END
return citation_text:gsub("”()", "%1”"):gsub("(%]*'*)%.", "%1")
end
format_listitem = function (source, tracking_lang, sid, father)
local ret
-- SOURCE ID --
sid = sid or source.id
if sid then
-- hidden editor utilities
local raw_sid = utils.strip_markup(sid)
ret = '<li class="senseid" id="bib-'..raw_sid..'"><span class="vsHide">]] </span>"
-- format abbreviation
if utils.is_abbrev(sid) then
ret = ret..utils.format(sid).." = "
end
else
ret = "<li>"
end
-- format source citation
return ret..format_citation(source, tracking_lang, father).."</li>"
end
-- function invoked on bibliography pages to print the full bibliography
function export.format_full_bibliography(frame)
preprocess_frame = frame
-- loads sources from the module and makes a list of the IDs in alphabetical order
local submodule = require("Module:bibliography/data/"..frame.args.lang)
local sources, headers = submodule.sources, submodule.headers
submodule = nil
local ordered_sids = {}
for sid in pairs(sources) do table.insert(ordered_sids, sid) end
table.sort(ordered_sids) -- TODO: the sorting needs to take into consideration difficult Unicode characters
-- starts writing out the sources
local formatted = headers and {} or ""
for _, sid in pairs(ordered_sids) do
local source = sources
local tracking_lang = source.import_from or frame.args.lang
if source.import_from then
local source_header = source.header
source = require("Module:bibliography/data/"..source.import_from).sources
source.header = source_header
if not source then
error("Could not find source ID "..sid.." from ] to import from")
end
end
local formatted_item = format_listitem(source, tracking_lang, sid)
if headers then
local header = source.header or "DEFAULT"
formatted = (formatted or "")..formatted_item
else
formatted = formatted..formatted_item
end
end
if headers then
formatted = mw.ustring.gsub(headers, "%$(%a+)%$", function(header)
return "<ul>"..(
formatted or error("No elements in the header <code>"..header.."</code>.")
).."</ul>"
end)
else
formatted = "<ul>"..formatted.."</ul>"
end
return '<div class="vsSwitcher" data-toggle-category="editor utilities" style="max-width:100%;">'..formatted.."</div>"
end
return export