Module:Wiktionary

From Wikipedia, the free encyclopedia
--[[

Implements {{Wiktionary}}.

]]

require ('strict');
local local_wiki_tag = mw.language.getContentLanguage().code;					-- 'en' at enwiki

--[[--------------------------< E R R O R _ S I D E _ B O X >--------------------------------------------------

Return rendered error message text for {{sister project}} template which will then render the {{wiktionary}} side
box.  This function does not call {{Sister project}}.

{{Sister project
|position={{{position|}}}
|project=wiktionary
|text={{#invoke:Wiktionary|main}} <!-- creates side box content -->
}}

]]

local function error_side_box (args_t, message, categories_t, frame)
	return string.format ('<span style="color:#d33">%s: %s</span>%s',			-- render the error message with categories
			'<kbd>{{[[Template:Wiktionary|Wiktionary]]}}</kbd> error: ',
			message,
			table.concat (categories_t)
			);
	end


--[[--------------------------< S I D E _ B O X >--------------------------------------------------------------

Return rendered text for {{sister project}} template which will then render the {{wiktionary}} side box.  This
function does not call {{Sister project}}.

{{Sister project
|position={{{position|}}}
|project=wiktionary
|text={{#invoke:Wiktionary|main}} <!-- creates side box content -->
}}

]]

local function side_box (args_t, items_t, categories_t, frame)
	local links_t = {};															-- holds a list of interwiki-linked terms
	for i, item_t in ipairs (items_t) do										-- build an interwiki link to wiktionary
		local title = item_t.term;												-- wiktionary article title
		if item_t.anchor then
			title = title .. item_t.anchor;										-- add a language-specific anchor if language tag or #anchor supplied in template call
		end
		links_t[i] = string.format ('[[wiktionary:%s%s|%s]]',					-- create interwiki link for each individual term
			(item_t.isSearch and "Special:Search/" or ""),
			title,																-- wiktionary article title + anchor
			item_t.lang_text													-- term wrapped in {{lang}}-provided markup	for display
			);
	end
	local join1 = ', ';															-- create appropriate separators for the list of terms
	local join2 = #items_t > 2 and ',&nbsp;or ' or '&nbsp;or ';

	return string.format ('Look up %s in Wiktionary, the free dictionary.%s',	-- construct the text the goes inside the box
			mw.text.listToText (links_t, join1, join2),							-- concatenate the list of terms
			table.concat (categories_t)											-- add categories
			);
end


--[[--------------------------< C A T E G O R Y _ A D D >------------------------------------------------------

returns nothing.  Adds category wikilink to <categories_t> if the template is used in mainspace

TODO: categorize templates that have <term> without <tag>?  On initial implementation of this module, that would
	be every instance of the template so impractical at that time

]]

local added_cats_t = {};

local function category_add (category, categories_t)
	if not mw.title.getCurrentTitle():inNamespace (0) then						-- when not in mainspace
		return;																	-- abandon
	end
	
	if added_cats_t[category] then												-- when we've already added this category
		return;																	-- abandon
	end
	
	local category_names_t = {													-- a list of category names used by this module
		['error'] = 'Wiktionary template errors',
		['article title'] = 'Wiktionary template uses article title',
		['anchor'] = 'Wiktionary template uses manual anchor',
	--	['no tag'] = 'Wiktionary template without language tag',				-- see TODO above
		}

	table.insert (categories_t, table.concat ({									-- construct category wikilink
		'[[Category:',
		category_names_t[category],
		']]'
	}));

	added_cats_t[category] = true;												-- remember that we've added this category to <categories_t>
end


--[[--------------------------< S E T _ A N C H O R >----------------------------------------------------------

create a language-specific anchor (URI fragment) where the fragment is the wiktionary language name associated
with the language tag prefixed to the 'term'.  

]]

local function set_anchor (item_t)
	local wikt_lang_data = mw.loadData ('Module:Language/data');				-- load wikitionary supported languages list

	if not item_t.anchor then
		if wikt_lang_data.redirects[item_t.tag] then
			item_t.tag = wikt_lang_data.redirects[item_t.tag];
		end
		local data_t = wikt_lang_data.languages[item_t.tag];					-- primary wiktionary data source

		local mw_lang_name;														-- holds MediaWiki name for language tag
		if not ({['mis'] = true, ['mul'] = true, ['zxx'] = true})[item_t.tag] then		-- these are supported by MediaWiki but have no value here
			mw_lang_name = mw.language.fetchLanguageName (item_t.tag, local_wiki_tag);	-- get MediaWiki's language name as fallback
		end
		
		if data_t and data_t.name then											-- if wiktionary has name for language tag <item.tag>; not present for default tag 'und'
			item_t.anchor = mw.uri.anchorEncode ('#' .. data_t.name);			-- make an encoded anchor from the wiktionary language name so that it matches the language tag from the template call
		elseif mw_lang_name and (mw_lang_name ~= item_t.tag) and ('und' ~= item_t.tag) then	-- fetchLanguageName() returns tag if tag not supported
			item_t.anchor = mw.uri.anchorEncode ('#' .. mw_lang_name);			-- make an encoded anchor from the MediaWiki language name so that it matches the language tag from the template call
		elseif 'und' ~= item_t.tag then											-- when neither wikitionary nor MediaWiki have a definition for <item_t.tag> ('und' excepted)
			item_t.error = 'language tag "' .. item_t.tag .. '" is not known to wiktionary';
			return;																-- abandon
		end
	end

	if '' == item_t.anchor then													-- if anchor is set to empty string
		item_t.anchor = nil;													-- unset so we don't create a link with trailing '#' fragment marker
	end
end


--[[--------------------------< M A I N >----------------------------------------------------------------------

Return wikitext to display {{wiktionary}} box.

]]

local function main (frame)
	local args_t = require ('Module:Arguments').getArgs (frame);

	local items_t = {};
	local categories_t = {};
	local lang_mod = require ('Module:lang');									-- for direct access to the functions in Module:Lang
	local lang_text;															-- term and markup returned from Module:Lang.lang
	
	for _, arg in ipairs (args_t) do
		arg = mw.text.trim (arg);
		if arg ~= '' then
			local tag, term, anchor;
			if arg:match ('^%a%a%a?:.+') then									-- does this arg have language tag prefix and a term?
				tag, term = arg:match ('^(%a%a%a?):(.*)');						-- yep, then extract them
			else
				term = arg;														-- nope, just a term
			end

			if term:match ('.+#.+') then										-- does <term> hav an anchor (URL fragment)?
				term, anchor = term:match ('(.+)(#.+)');						-- split the 'term#ancor' into <term> and <anchor>
				category_add ('anchor', categories_t);							-- add a category
			end
			table.insert (items_t, {tag = tag or 'und', term = term, anchor = anchor});
		end
	end

	if items_t[1] then
		for _, item_t in ipairs (items_t) do
			local italic = (item_t.tag == local_wiki_tag) and 'yes' or nil;		-- local language same as language tag, italicize per words-as-words
			lang_text = lang_mod._lang ({item_t.tag, item_t.term, cat = 'no', italic = italic});		-- let {{lang}} control italics
			if lang_text:match ('color: *#d33') or lang_text:match ('color: *#33aa33') then
				category_add ('error', categories_t);							-- add a category
				return table.concat ({
					error_side_box (args_t, 'language tag "' .. item_t.tag .. '" is not known to wikipedia', categories_t, frame),
					(mw.title.getCurrentTitle():inNamespace (0) and '[[Category:Wiktionary template errors]]') or ''
				});																-- abandon with error message
			end
			item_t.lang_text = lang_text;
			set_anchor (item_t);
			if item_t.error then
				category_add ('error', categories_t);							-- add a category
				return table.concat ({											-- abandon with error message
					error_side_box (args_t, item_t.error, categories_t, frame),	-- tag not known to wikitionary
					(mw.title.getCurrentTitle():inNamespace (0) and '[[Category:Wiktionary template errors]]') or ''
				});																-- abandon with error message
			end
		end
	else																		-- no terms supplied in template call so use article title
		local title = mw.ustring.lower(mw.title.getCurrentTitle().subpageText);	-- get the title; TODO: should we be setting page title to lowercase?
		lang_text = lang_mod._lang ({local_wiki_tag, title, cat = 'no', italic = 'yes'});	-- for consistency use {{lang}} for article title; italic per words-as-words
		items_t[1] = {term = title, lang_text = lang_text, isSearch = true };	-- don't break side box
		category_add ('article title', categories_t);							-- add a category
	end
	return side_box (args_t, items_t, categories_t, frame);
end


--[[--------------------------< E X P O R T E D   F U N C T I O N S >------------------------------------------
]]

return {
	main = main
	}