This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected.
This module is used by {{wikt-lang}} and {{wt}}. It is inspired by the templates {{m}} and {{l}} and their associated modules on Wiktionary. It has a Wiktionary link function that links to the correct section of the Wiktionary entry, and applies correct language formatting and italics. The language-tagging function does most of what {{lang{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}{{---}}}} does, except that italics can't be customized and categories aren't added.
The module uses Module:Language/data to retrieve the language name for a language code, and to perform the necessary entry-name replacements (for instance, removing macrons from Latin entry names). These are unfortunately not automatically retrieved from Wiktionary's language data modules. For language codes that do not have a name value in this module, the language name is fetched with mw.language.fetchLanguage. When mw.language.fetchLanguage does not fetch the correct language name (or any language name at all), please add it to Module:language/data, and similarly when the correct entry name is not generated, please add the entry name replacements to the module.
require('strict')localm_data=mw.loadData("Module:Language/data")locallangData=m_data.languagesorm_datalocalp={}localfunctionifNotEmpty(value)ifvalue==""thenreturnnilelsereturnvalueendendlocalfunctionmakeLinkedName(languageCode)localdata=langData[languageCode]localarticle=data["article"]localname=data["Wikipedia_name"]ordata["name"]return"[["..article.."|"..name.."]]: "endlocalfunctionmakeEntryName(word,languageCode)localdata=langData[languageCode]localugsub=mw.ustring.gsubword=tostring(word)ifword==nilthenerror("The function makeEntryName requires a string argument")elseifword==""thenreturn""else-- Remove bold and italics, so that words that contain bolding or emphasis can be linked without piping.word=word:gsub("\'\'\'","")word=word:gsub("\'\'","")ifdata==nilthenreturnwordelselocalreplacements=dataanddata["replacements"]ifreplacements==nilthenreturnwordelse-- Decompose so that the diacritics of characters such-- as á can be removed in one go.-- No need to compose at the end, because the MediaWiki software-- will handle that.ifreplacements.decomposethenword=mw.ustring.toNFD(word)fori,frominipairs(replacements.from)doword=ugsub(word,from,replacements.toandreplacements.to[i]or"")endelseforregex,replacementinpairs(replacements)doword=ugsub(word,regex,replacement)endendreturnwordendendendendp.makeEntryName=makeEntryNamelocalfunctionfixScriptCode(firstLetter,threeLetters)returnstring.upper(firstLetter)..string.lower(threeLetters)endlocalfunctiongetCodes(codes,text)locallanguageCode,scriptCode,invalidCodelocalerrorTextifcodes==nilorcodes==""thenerrorText='no language or script code provided'elseifcodes:find("^%a%a%a?$")orcodes:find("^%a%a%a?%-%a%a%a%a$")then-- A three- or two-letter lowercase sequence at beginning of first parameterlanguageCode=codes:find("^%a%a%a?")and(codes:match("^(%l%l%l?)")orcodes:match("^(%a%a%a?)"):gsub("(%a%a%a?)",string.lower,1))-- One uppercase and three lowercase letters at the end of the first parameterscriptCode=codes:find("%a%a%a%a$")and(codes:match("(%u%l%l%l)$")orgsub(codes:match("(%a%a%a%a)$"),"(%a)(%a%a%a)",fixScriptCode,1))elseifcodes:find("^%a%a%a?%-%a%a%a?$")orcodes:find("^%a%a%a%-%a%a%a%-%a%a%a$")thenlanguageCode=codes-- Private-use subtag: x followed by one or more sequences of 1-8 lowercase-- letters separated by hyphens. This only allows for one sequence, as it is-- needed for proto-languages such as ine-x-proto (Proto-Indo-European).elseifcodes:find("^%a%a%a?%-x%-%a%a?%a?%a?%a?%a?%a?%a?$")thenlanguageCode,scriptCode=codes:match("^(%a%a%a%-x%-%a%a?%a?%a?%a?%a?%a?%a?)%-?(.*)$")ifnotlanguageCodethenerrorText='<code>'..codes..'</code> is not a valid language or script code.'elseifscriptCode~=""andnotscriptCode:find("%a%a%a%a")thenerrorText='<code>'..scriptCode..'</code> is not a valid script code.'elsescriptCode=scriptCode:gsub("(%a)(%a%a%a)",fixScriptCode,1)endelseifcodes:find("^%a%a%a?")thenlanguageCode,invalidCode=codes:match("^(%a%a%a?)%-?(.*)")languageCode=string.lower(languageCode)errorText='<code>'..invalidCode..'</code> is not a valid script code.'elseifcodes:find("%-?%a%a%a%a$")theninvalidCode,scriptCode=codes:match("(.*)%-?(%a%a%a%a)$")scriptCode=gsub(scriptCode,"(%a)(%a%a%a)",fixScriptCode)errorText='<code>'..invalidCode..'</code> is not a valid language code.'elseerrorText='<code>'..codes..'</code> is not a valid language or script code.'endifnotscriptCodeorscriptCode==""thenscriptCode=require("Module:Unicode data").is_Latin(text)and"Latn"or"unknown"endiferrorTextthenerrorText=' <span style="font-size: smaller">['..errorText..']</span>'elseerrorText=""endlanguageCode=m_data.redirects[languageCode]orlanguageCodereturnlanguageCode,scriptCode,errorTextendlocalfunctiontag(text,languageCode,script,italics)localdata=langData[languageCode]-- Use Wikipedia code if it has been given: for instance,-- Proto-Indo-European has the Wiktionary code "ine-pro" but the Wikipedia-- code "ine-x-proto".languageCode=dataanddata.Wikipedia_codeorlanguageCodelocalitalicize=script=="Latn"anditalicsifnottextthentext="[text?]"endlocaltextDirectionMarkers={"","",""}ifdataanddata["direction"]=="rtl"thentextDirectionMarkers={' dir="rtl"','‏','‎'}endlocalout={textDirectionMarkers[2]}ifitalicizethentable.insert(out,"<i lang=\""..languageCode.."\""..textDirectionMarkers[1]..">"..text.."</i>")elsetable.insert(out,"<span lang=\""..languageCode.."\""..textDirectionMarkers[1]..">"..text.."</span>")endtable.insert(out,textDirectionMarkers[3])returntable.concat(out)endfunctionp.lang(frame)localparent=frame:getParent()localargs=parent.args[1]andparent.argsorframe.argslocalcodes=args[1]andmw.text.trim(args[1])localtext=args[2]orerror("Provide text in the second parameter")locallanguageCode,scriptCode,errorText=getCodes(codes,text)localitalics=args.italicsorargs.iorargs.italicitalics=not(italics=="n"oritalics=="-"oritalics=="no")returntag(text,languageCode,scriptCode,italics)..errorTextendlocalfunctionlinkToWiktionary(entry,linkText,languageCode)localdata=langData[languageCode]localnameiflanguageCodethenifdataanddata.namethenname=data.nameelse-- On other languages' wikis, use mw.getContentLanguage():getCode(),-- or replace 'en' with that wiki's language code.name=mw.language.fetchLanguageName(languageCode,'en')ifname==""thenerror("Name for the language code "..("%q"):format(languageCodeornil).." could not be retrieved with mw.language.fetchLanguageName, ".."so it should be added to [[Module:Language/data]]")endendifentry:sub(1,1)=="*"thenifname~=""thenentry="Reconstruction:"..name.."/"..entry:sub(2)elseerror("Language name is empty")endelseifdataanddata.type=="reconstructed"thenmw.log("Reconstructed language without asterisk:",languageCode,name,entry)localframe=mw.getCurrentFrame()-- Track reconstructed entries with no asterisk by transcluding-- a nonexistent template. This technique is used in Wiktionary:-- see [[wikt:Module:debug]].-- [[Special:WhatLinksHere/tracking/wikt-lang/reconstructed with no asterisk]]pcall(frame.expandTemplate,frame,{title='tracking/wikt-lang/reconstructed with no asterisk'})ifname~=""thenentry="Reconstruction:"..name.."/"..entryelseerror("Language name is empty")endelseifdataanddata.type=="appendix"thenifname~=""thenentry="Appendix:"..name.."/"..entryelseerror("Language name is empty")endendifentryandlinkTextthenreturn"[[wikt:"..entry.."#"..name.."|"..linkText.."]]"elseerror("linkToWiktionary needs a Wiktionary entry or link text, or both")endelsereturn"[[wikt:"..entry.."|"..linkText.."]]"endendfunctionp.wiktlang(frame)localparent=frame:getParent()localargs=parent.args[1]andparent.argsorframe.argslocalcodes=args[1]andmw.text.trim(args[1])localword1=ifNotEmpty(args[2])localword2=ifNotEmpty(args[3])ifnotargs[2]thenerror("Parameter 2 is required")endlocallanguageCode,scriptCode,errorText=getCodes(codes,word2orword1)localitalics=args.italicsorargs.iorargs.italicitalics=not(italics=="n"oritalics=="-"oritalics=="no")localentry,linkTextifword2andword1thenentry=makeEntryName(word1,languageCode)linkText=word2elseifword1thenentry=makeEntryName(word1,languageCode)linkText=word1endlocaloutiflanguageCodeandentryandlinkTextthenout=tag(linkToWiktionary(entry,linkText,languageCode),languageCode,scriptCode,italics)elseifentryandlinkTextthenout=linkToWiktionary(entry,linkText)elseout='<span style="font-size: smaller;">[text?]</span>'endifoutanderrorTextthenreturnout..errorTextelsereturnerrorTextorerror("The function wiktlang generated nothing")endendfunctionp.wikt(frame)localparent=frame:getParent()localargs=parent.args[1]andparent.argsorframe.argslocalcodes=args[1]andmw.text.trim(args[1])localword1=ifNotEmpty(args[2])localword2=ifNotEmpty(args[3])ifnotword1thenerror("Provide a word in parameter 2.")endlocallanguageCode,scriptCode,errorText=getCodes(codes,word1)localentry,linkTextifword2andword1thenentry=makeEntryName(word1,languageCode)linkText=word2elseifword1thenentry=makeEntryName(word1,languageCode)linkText=word1endlocaloutiflanguageCodeandentryandlinkTextthenout=linkToWiktionary(entry,linkText,languageCode)elseifentryandlinkTextthenout=linkToWiktionary(entry,linkText)elseout='<span style="font-size: smaller;">[text?]</span>'endifoutanderrorTextthenreturnoutandout..errorTextelsereturnerrorTextorerror("The function wikt generated nothing")endendreturnp