require('strict')  -- Module to create sister project link box local getArgs = require('Module:Arguments').getArgs local sideBox = require('মডিউল:পার্শ্ব বাক্স')._main local p = {}  local inSandbox = mw.getCurrentFrame():getTitle():find('খেলাঘর', 1, true)   -- Function to add "-sand" to classes when called from sandbox local function sandbox(s) 	return inSandbox and s.."-sand" or s end  -- Information about how to handle each sister lives in separate data file local cfg = mw.loadData(sandbox('মডিউল:সহপ্রকল্প সংযোগসমূহ/কনফিগ')) local logo = cfg.logo local prefixList = cfg.prefixList local sisterName = cfg.sisterName local sisterInfo = cfg.sisterInfo local defaultSisters = cfg.defaultSisters local sisterDb = cfg.sisterDb local trackingType = cfg.trackingType   -- Function to canonicalize string -- search for variants of "yes", and "no", and transform -- them into a standard form (like Template:YesNo) -- Argument: --   s --- input string -- Result: --  {x,y} list of length 2 --    x = nil if s is canonicalized, otherwise has trimmed s --    y = canonical form of s (true if "yes" or other, false if "no", nil if blank) local function canonicalize(s) 	if s == nil then 		return {nil, nil} 	end 	-- if s is table/list, then assume already canonicalized and return unchanged 	if tostring(type(s)) == "table" then 		return s 	end 	s = mw.text.trim(tostring(s)) 	if s == "" then 		return {nil, nil} 	end 	local lowerS = s:lower() 	-- Check for various forms of "yes" 	if lowerS == 'yes' or lowerS == 'y' or lowerS == 't'  	      or lowerS == '1' or lowerS == 'true' or lowerS == 'on' then 		return {nil, true} 	end     -- Check for various forms of "no" 	if lowerS == 'no' or lowerS == 'n' or lowerS == 'f'  	       or lowerS == '0' or lowerS == 'false' or lowerS == 'off'then 		return {nil, false} 	end     -- Neither yes nor no recognized, leave string trimmed 	return {s, true} end  -- Merge two or more canonicalized argument lists -- Arguments: --  argList = list of canonicalized arguments --  noAll = if true, return no when all argList is no. --          otherwise, return blank when all argList is blank local function mergeArgs(argList,noAll) 	local test = nil -- default, return blank if all blank 	if noAll then 		test = false -- return no if all no 	end 	local allSame = true 	-- Search through string for first non-no or non-blank 	for _, arg in ipairs(argList) do 		if arg[2] then 			return arg -- found non-no and non-blank, return it 		end 		-- test to see if argList is all blank / no 		allSame = allSame and (arg[2] == test) 	end 	-- if all blank / no, return blank / no 	if allSame then 		return {nil, test} -- all match no/blank, return it 	end 	-- otherwise, return no / blank 	if noAll then 		return {nil, nil} 	end 	return {nil, false} end 		 -- Function to get sitelink for a wiki -- Arguments: --   wiki = db name of wiki to lookup --   qid = QID of entity to search for, current page entity by default local function getSitelink(wiki,qid) 	-- return nil if some sort of lookup failure 	return qid and mw.wikibase.getSitelink(qid,wiki) end  -- Function to get sitelink for a wiki -- Arguments: --   prefix = prefix string for wiki to lookup --   qid = QID of entity to search for, current page entity by default local function fetchWikidata(prefix,qid) 	local sisterDbName = sisterDb[prefix] 	return sisterDbName and getSitelink(sisterDbName,qid) end  -- Function to generate the sister link itself -- Arguments: --  args = argument table for function --     args[1] = page to fetch --     args.default = link when blank --     args.auto = new auto mode (don't fall back to search) --     args.sitelink = wikidata sitelink (if available) --     args.qid = QID of entity --     args.search = fallback string to search for --     args.sisterPrefix = wikitext prefix for sister site --     args.information = type of info sister site contains --  tracking = tracking table local function genSisterLink(args, tracking) 	if args[1][2] == false or (not args.default and args[1][2] == nil) then 		return nil --- either editor specified "no", or "blank" (and default=no), then skip this sister 	end 	local sitelink = args.sitelink or fetchWikidata(args.sisterPrefix,args.qid) 	if args.auto and not sitelink and args[1][2] == nil then 		return nil --- in auto mode, if link is blank and no sitelink, then skip 	end 	-- fallback order of sister link: first specified page, then wikidata, then search 	local link = args[1][1] or sitelink or (args.search and "Special:"..args.search) 	if not link then 		return nil --- no link found, just skip 	end 	if tracking then 		-- update state for tracking categories 		if args[1][1] and sitelink then 			-- transform supplied page name to be in wiki-format 			local page = mw.ustring.gsub(args[1][1],"_"," ") 			page = mw.ustring.sub(page,1,1):upper()..mw.ustring.sub(page,2) 			local pageNS = mw.ustring.match(page,"^([^:]+):") 			local sitelinkNS = mw.ustring.match(sitelink,"^([^:]+):") 			if page == sitelink then 				tracking.wdHidden = args.sisterPrefix 			elseif pageNS ~= sitelinkNS then 				tracking.wdNamespace = args.sisterPrefix 			else 				tracking.wdMismatch = args.sisterPrefix 			end 		-- if no page link, nor a wikidata entry, and search is on, then warn 		elseif not (args[1][2] or sitelink) and args.search then 			tracking.defaultSearch = args.sisterPrefix 		end 	end 	return {prefix=args.sisterPrefix, link=link, logo=args.logo, name=args.name, 		    information=args.information, prep=args.prep} end  -- Function to handle special case of commons link local function commonsLinks(args, commonsPage) 	-- use Module:Commons link to determine best commons link 	local commonsLink = require('মডিউল:কমন্স সংযোগ') 	local cLink = (not args.commonscat) and commonsLink._hasGallery(args.qid) 	                 or commonsLink._hasCategory(args.qid) 	if commonsPage[1] and not mw.ustring.match(commonsPage[1]:lower(),"^category:") then 		commonsPage[1] = (args.commonscat and "Category:" or "")..commonsPage[1] 	end 	local commonsSearch = "Search/"..(args.commonscat and "Category:" or "")..args[1] 	return {link=cLink, search=commonsSearch} end  -- Function to handle special case for "author" and "cookbook" local function handleSubtype(args) 	local ns = args.ns 	local ns_len = mw.ustring.len(ns) 	local result = {} 	result.sitelink = fetchWikidata(args.prefix, args.qid) 	local subtype = false 	if args.page then 		if mw.ustring.sub(args.page,1,ns_len) == ns then     		subtype = true     	elseif args.subtype then     		result.page = ns..args.page     		subtype = true     	end 	elseif result.sitelink then 		subtype = mw.ustring.sub(result.sitelink,1,ns_len) == ns 	elseif args.subtype then 		result.search = "Search/"..ns..args.default 		subtype = true 	end 	if subtype then 		result.info = args.info 	end 	return result end  -- Function to create a sister link, by prefix -- Arguments: --   prefix = sister prefix (e.g., "c" for commons) --   args = arguments for this sister (see p._sisterLink above) --   tracking = tracking table local function sisterLink(prefix, args, tracking) 	-- determine arguments to genSisterLink according to prefix 	if prefix == 'species_author' and not args.species[1] and args.species[2] and not args.species_author[1] and args.species_author[2] then 		return nil 	end 	local default = defaultSisters[prefix] 	if default == 'auto' then 		default = args.auto 	end 	-- Handle exceptions by prefix 	local search = ((prefix == 'd' and "ItemByTitle/bnwiki/") or "Search/")..args[1] 	local sitelink = prefix == 'd' and args.qid     local page = args[prefix]     local info = sisterInfo[prefix]     -- special case handling of author and cookbook     local subtype = nil     if prefix == 's' then     	subtype = handleSubtype({prefix='s',qid=args.qid,subtype=args.author,page=page[1],     		                    ns='লেখক:',info=nil,default=args[1]})     elseif prefix == 'b' then     	subtype = handleSubtype({prefix='b',qid=args.qid,subtype=args.cookbook,page=page[1],     		                    ns='রন্ধনপ্রণালী:',info='রন্ধনপ্রণালী',default=args[1]})     end     if subtype then         page[1] = subtype.page or page[1] 		search = subtype.search or search 		sitelink = subtype.sitelink or sitelink 		info = subtype.info or info 	end     if prefix == 'voy' then     	if not args.bar then     		info = "ভ্রমণ তথ্য"     	end     	if page[1] then     		if mw.ustring.match(page[1],"বাক্যাংশ বই") then     			info = "বাক্যাংশ বই"     		end     	elseif page[2] or args.auto then     		sitelink = sitelink or fetchWikidata('voy',args.qid)     		if sitelink and mw.ustring.match(sitelink,"বাক্যাংশ বই") then     			info = "বাক্যাংশ বই"     		end 		end     end     info = args.information or info     if prefix == 'c' then     	local commons = commonsLinks(args, page)     	search = commons.search     	sitelink = commons.link     end     prefix = (prefix == 'species_author' and 'species') or prefix     local logo = logo[prefix]     local name = sisterName[prefix]     local prep = "হতে"     if mw.ustring.sub(prefix,1,2) == 'iw' then     	local lang = nil     	local iw_arg = args[prefix]     	if iw_arg[1] then     		lang = iw_arg[1]     	elseif iw_arg[2] then     		local P424 = mw.wikibase.getBestStatements(args.qid, "P424")[1] 	        if P424 and P424.mainsnak.datavalue then 	        	lang = P424.mainsnak.datavalue.value 	        end 	    end 		if lang == nil then 			return nil 		end 	    prefix = ':'..lang 	    page[1] = "" 	    page[2] = true 	    local langname = mw.language.fetchLanguageName( lang, 'bn') 	    if not langname or #langname == 0 then 	    	return nil 	    end 	    info = langname..' '..info 	    prep = ""     end     return genSisterLink({     	page,     	auto=args.auto,     	qid=args.qid,     	logo=logo,     	name=name,     	prep=prep,     	sitelink=sitelink,     	default=default,     	sisterPrefix = prefix,     	search=search,     	information=info}, tracking) end  local function templatestyles_page(is_bar) 	local sandbox = inSandbox and 'খেলাঘর/' or '' 	if is_bar then 		return mw.ustring.format( 			'মডিউল:সহপ্রকল্প সংযোগসমূহ/দণ্ড/%sশৈলী.css', 			sandbox 		) 	end 	return mw.ustring.format( 		'মডিউল:সহপ্রকল্প সংযোগসমূহ/%sশৈলী.css', 		sandbox 	) end  -- Function to create html containers for sister project link list -- Arguments: --   args = table of arguments --      args.position: if 'left', position links to left --      args.collapsible: if non-empty, make box collapsible. If 'collapse', start box hidden --      args.style: CSS style string appended to end of default CSS --      args.display: boldface name to display local function createSisterBox(sisterList, args)  	local list = mw.html.create('ul')     for i, link in ipairs(sisterList) do 	  local li = list:tag('li') 	  -- html element for 27px-high logo 	  local logoSpan = li:tag('span') 	  logoSpan:addClass(sandbox("sister-logo")) 	  logoSpan:wikitext("27x27px|middle|link=|alt=") 	  -- html element for link 	  local linkspan = li:tag('span') 	  linkspan:addClass(sandbox("sister-link")) 	  local linkText = link.name.. " "..link.prep.." "..link.information .."" 	  linkspan:wikitext(linkText)     end     list:allDone()          return sideBox({ 		role = 'navigation', 		labelledby = 'sister-projects', 		class = sandbox("sister-box") .. ' sistersitebox plainlinks', 		position = args.position, 		style = args.style, 		abovestyle = args.collapsible and 'clear: both' or nil, 		above = mw.ustring.format( 			"উইকিপিডিয়ার সহপ্রকল্পে %s", 			args.display or args[1] 		), 		text = tostring(list), 		collapsible = args.collapsible, 		templatestyles = templatestyles_page() 	}) end  local function createSisterBar(sisterList,args) 	local nav = mw.html.create( 'div' ) 	nav:addClass( 'noprint') 	nav:addClass( 'metadata') 	nav:addClass( sandbox('sister-bar')) 	nav:attr( 'role', 'navigation' ) 	nav:attr( 'aria-label' , 'sister-projects' ) 	local header = nav:tag('div') 	header:addClass(sandbox('sister-bar-header')) 	local headerText = "উইকিপিডিয়ার " 	headerText = headerText..'সহপ্রকল্পে ' 	header:wikitext(headerText) 	local pagename = header:tag('b') 	pagename:wikitext(args.display or args[1]) 	header:wikitext(":") 	local container = nav:tag('ul') 	container:addClass(sandbox('sister-bar-content')) 	for _, link in ipairs(sisterList) do 		local item = container:tag('li') 		item:addClass(sandbox('sister-bar-item')) 		local logoSpan = item:tag('span') 		logoSpan:addClass(sandbox('sister-bar-logo')) 		logoSpan:wikitext("21x19px|link=|alt=") 		local linkSpan = item:tag('span') 		linkSpan:addClass(sandbox('sister-bar-link')) 		linkSpan:wikitext(link.name.." "..link.prep.." "..link.information .."") 	end 	return nav end  function p._main(args) 	local titleObject = mw.title.getCurrentTitle() 	local ns = titleObject.namespace 	-- find qid, either supplied with args, from search string, or from current page 	args.qid = args.qid or mw.wikibase.getEntityIdForTitle(args[1] or "") or mw.wikibase.getEntityIdForCurrentPage() 	args.qid = args.qid and args.qid:upper() 	-- search string defaults to PAGENAME     args[1] = args[1] or mw.wikibase.getSitelink(args.qid or "") or titleObject.text     -- handle redundant "commons"/"c" prefix     args.c = args.c or args.commons 	-- Canonicalize all sister links (handle yes/no/empty) 	for _, k in ipairs(prefixList) do 		args[k] = canonicalize(args[k]) 	end 	-- Canonicalize cookbook 	args.cookbook = canonicalize(args.cookbook) 	args.b = mergeArgs({args.b,args.cookbook}) 	args.cookbook = args.cookbook[2] 	-- handle trackSingle parameter 	if args.trackSingle == nil then     	args.trackSingle = true 	end     if ns ~= 0 and ns ~= 14 then     	args.trackSingle = false     end     -- Canonicalize general parameters     for _,k in pairs({"auto","commonscat","author","bar","tracking","sandbox","trackSingle"}) do     	args[k] = canonicalize(args[k])[2]     end 	-- Initialize tracking categories if main namespace 	local tracking = (args.tracking or ns == 0) and {}     local sisterList = {}     local prefix     -- Loop through all sister projects, generate possible links     for _, prefix in ipairs(prefixList) do     	local link = sisterLink(prefix, args, tracking)     	if link then 			table.insert(sisterList, link) 		end 	end     local box = mw.html.create()     if args.bar and #sisterList > 0 then     	box:wikitext(mw.getCurrentFrame():extensionTag{ 			name = 'templatestyles', args = { src = templatestyles_page(true) }     	})     	box:node(createSisterBar(sisterList,args))     elseif #sisterList == 1 then     	-- Use  single sister box instead of multi-sister box     	local sister = sisterList[1]     	local link =  ""..(args.display or args[1])..""     	if sister.name == 'Commons' then     		sister.name = 'উইকিমিডিয়া কমন্স' -- make single sister commons box look like      	end     	local text = sister.name.."ে "..link.." সম্পর্কিত "..mw.ustring.lower(sister.information).." রয়েছে।"     	if sister.name == 'Wikipedia' then  -- make single sister interwiki box look like      		text = ""..sister.information.." "..sister.prep.." উইকিপিডিয়া, মুক্ত বিশ্বকোষ"     	end     	box:wikitext(sideBox({     		role = 'navigation',     		position=args.position,     		image="40x40px|class=noviewer|alt=|link=",     		metadata='no',     		class='plainlinks sistersitebox',     	    text=text, 			templatestyles = templatestyles_page()     	}))     elseif #sisterList > 0 then     	-- else use sister box if non-empty     	box:wikitext(createSisterBox(sisterList,args))     end     if #sisterList == 0 and args.auto then     	local generateWarning = require('Module:If preview')._warning     	box:wikitext(generateWarning({"উইকিউপাত্তে কোনও সহপ্রকল্পের লিঙ্ক পাওয়া যায়নি। auto=0 ব্যবহার করে চেষ্টা করুন।"}))     end 	-- Append tracking categories to container div 	-- Alpha ordering is by sister prefix 	if tracking then 		for k, v in pairs(tracking) do 			box:wikitext("") 		end     	if #sisterList == 0 then     		box:wikitext("বিষয়শ্রেণী:খালি সহপ্রকল্প সংযোগসমূহযুক্ত পাতা")     	end 	end 	return tostring(box) end  -- Main entry point for generating sister project links box function p.main(frame) 	local args = getArgs(frame,{frameOnly=false,parentOnly=false,parentFirst=false}) 	return p._main(args) end  -- Lua entry point for generate one sister link function p._sisterlink(args)     local prefix = args.prefix 	-- Canonicalize all sister links (handle yes/no/empty) 	for _, k in ipairs(prefixList) do 		args[k] = canonicalize(args[k]) 	end 	-- Canonicalize cookbook 	args.cookbook = canonicalize(args.cookbook) 	args.b = mergeArgs({args.b,args.cookbook}) 	args.cookbook = args.cookbook[2]     -- Canonicalize general parameters     for _,k in pairs({"auto","commonscat","author"}) do     	args[k] = canonicalize(args[k])[2]     end     args[1] = args[1] or mw.title.getCurrentTitle().text 	args.qid = args.qid or mw.wikibase.getEntityIdForCurrentPage() 	args.qid = args.qid and args.qid:upper() 	local link = sisterLink(prefix, args,nil) 	if not link then 		return "" 	end 	return ""..link.information .." "..link.prep.." "..link.name end  -- Template entry point for generating one sister link function p.link(frame) 	local args = getArgs(frame) 	return p._sisterlink(args) end  return p