Module:External links#L-931

require('strict')

-- local genitive = require('Module:Genitive')._genitive

local contLang = mw.language.getContentLanguage()

local cmodule = {}

local conf = require 'Module:External links/conf'(contLang:getCode())

local hasdatafromwikidata = false

local hasdatafromlocal = false

local haswikidatalink = true -- we assume it's connected

local p = {}

local function getLabel(entity, use_genitive, pagetitle)

local label = (pagetitle and pagetitle ~= '') and pagetitle or nil

if not label and not entity then

label = mw.title.getCurrentTitle().text

elseif not label then

label = mw.wikibase.label(entity.id) or mw.title.getCurrentTitle().text

end

-- return use_genitive and genitive(label, 'sitt') or label

return use_genitive and label .. "'s" or label

end

-- @todo cleanup, this is in production, use the console

local function dump(obj)

return "

" .. mw.dumpObject(obj) .. "
"

end

local function stringFormatter( datavalue )

if datavalue == nil or datavalue['type'] ~= 'string' then

return nil

end

return datavalue.value

end

local pval = {}

pval.P1793 = { -- format as a regular expression

types = {

snaktype = 'value',

datatype = 'string',

},

}

pval.P407 = { -- language of work or name

types = {

snaktype = 'value',

datatype = 'wikibase-item',

datavalue = {

type = 'wikibase-entityid',

}

},

}

pval.P364 = { -- original language of work

types = {

snaktype = 'value',

datatype = 'wikibase-item',

datavalue = {

type = 'wikibase-entityid',

}

},

}

pval.P218 = { -- ISO 639-1 language

types = {

snaktype = 'value',

datatype = 'external-id',

datavalue = {

type = 'string',

}

},

}

pval.P305 = { -- IETF language tag

types = {

snaktype = 'value',

datatype = 'external-id',

datavalue = {

type = 'string',

}

},

}

pval.P582 = { -- end time

types = {

snaktype = 'value',

datatype = 'time',

datavalue = {

type = 'string',

}

},

}

-- This is a really makeshift crappy converter, but it'll do some basic

-- conversion from PCRE to Lua-style patterns (note that this only work

-- in very few cases)

local function regexConverter( regex )

local output = regex

output = string.gsub(output, "\\d{2}", "%%d%%d")

output = string.gsub(output, "\\d{3}", "%%d%%d%%d")

output = string.gsub(output, "\\d{4}", "%%d%%d%%d%%d")

output = string.gsub(output, "\\d{5}", "%%d%%d%%d%%d%%d")

output = string.gsub(output, "\\d{6}", "%%d%%d%%d%%d%%d%%d")

output = string.gsub(output, "\\d{7}", "%%d%%d%%d%%d%%d%%d%%d")

output = string.gsub(output, "\\d{8}", "%%d%%d%%d%%d%%d%%d%%d%%d")

output = string.gsub(output, "\\d", "%%d")

return output

end

local function getFormatterUrl( prop, value )

local head = ""

local tail = ""

local entity = mw.wikibase.getEntity(prop)

-- to avoid deep tests

if not entity or not entity.claims then

return head

end

-- get the claims for this entity

local statements = entity.claims['P1630'] -- formatter URL

-- to avoid deep tests

if not statements then

return head

end

local formatters = {}

-- let's go through the claims

for _, claim in ipairs( statements ) do

-- to avoid deep tests

if not claim then

claim = {}

end

local valid = claim['type'] == 'statement'

and claim['rank'] ~= 'deprecated'

if valid then

local mainsnak = claim.mainsnak or {}

local preferred = claim['rank'] == 'preferred'

-- get any qualifiers for this claim (we are interested in P1793 for

-- indication of which claim is correct)

local qualifiers = claim.qualifiers or {}

-- now let's check the qualifier we are interested in

local qualid = 'P1793' -- format as a regular expression

-- if the claim has this qualifier

if qualifiers[qualid] then

-- it's here, let's check it out!

local items = {}

-- traverse all snaks in this qualifier

for _, qualsnak in ipairs( qualifiers[qualid] ) do

if qualsnak and pval[qualid] then

--mw.log("qualsnak = " .. dump(qualsnak))

-- check if the snak is of the correct snaktype and datatype

local valid = qualsnak.snaktype == pval[qualid].types.snaktype

and qualsnak.datatype == pval[qualid].types.datatype

if valid then

-- we'll have to convert the regex to Lua-style

local regex = regexConverter(qualsnak.datavalue.value)

local test = string.match( value, '^'..regex..'$' )

if test then

-- it matched, this is correct and overrides any other.

if preferred then

head = mainsnak.datavalue.value

else

tail = mainsnak.datavalue.value

end

end

end

end

end

else

-- we don't have any qualifier, is it preferred?

if (head == and preferred) or (tail == and not preferred) then

-- if we don't have any other, use this one

if preferred and head == '' then

head = mainsnak.datavalue.value

elseif not preferred and tail == '' then

tail = mainsnak.datavalue.value

end

end

end

end

end

return head ~= '' and head or tail

end

local function getLanguageData(prop, qid)

local head = {}

local tail = {}

-- mw.log("getLanguageData, prop="..dump(prop).." qid="..dump(qid))

-- get the entity we are checking

local entity = mw.wikibase.getEntityObject(qid)

-- to avoid deep tests

if not entity then

return nil

end

if not entity.claims then

return {}

end

-- get the claims for this entity

local statements = entity.claims[prop]

-- to avoid deep tests

if not statements then

return {}

end

-- mw.log("getLanguageData going through claims="..dump(statements))

-- let's go through the claims

for _, claim in ipairs( statements ) do

-- to avoid deep tests

if not claim then

claim = {}

end

local valid = claim['type'] == 'statement'

and claim['rank'] ~= 'deprecated'

if valid then

local mainsnak = claim.mainsnak or {}

local preferred = claim['rank'] == 'preferred'

-- verify the item is what we expect

local valid = mainsnak.snaktype == pval[prop].types.snaktype

and mainsnak.datatype == pval[prop].types.datatype

and mainsnak.datavalue.type == pval[prop].types.datavalue.type

if valid then

-- mw.log("getLanguageData claim is valid="..dump(claim))

-- if this is the correct P-value, dive into it and get P218 (ISO 639-1)

if mainsnak.property == 'P364' then -- original language of work

if preferred then

head[#head+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))

else

tail[#tail+1] = table.concat(getLanguageData('P218', 'Q'..mainsnak.datavalue.value['numeric-id']), conf:a('mod-filter-separator'))

end

elseif mainsnak.property == 'P218' or mainsnak.property == 'P305' then -- ISO 639-1 code or IETF language tag

if preferred then

head[#head+1] = stringFormatter(mainsnak.datavalue)

else

tail[#tail+1] = stringFormatter(mainsnak.datavalue)

end

end

end

end

end

-- mw.log("getLanguageData returning head="..dump(head).." tail="..dump(tail))

return #head>0 and head or tail

end

local langqvalorder = {'P407','P364'}

local otherqvalorder = {'P582'}

local function getValuesFromWikidata(props)

local head = {}

local tail = {}

-- mw.log("getValuesFromWikidata, props="..dump(props))

-- get the entity we are checking

local entity = mw.wikibase.getEntityObject()

-- to avoid deep tests

if not entity then

--mw.log("getValuesFromWikidata no entity")

return nil

end

if not entity.claims or not props or not props.prop or props.prop == '' then

--mw.log("getValuesFromWikidata no claims or no props")

return {}

end

-- get the claims for this entity

local statements = entity.claims[props.prop]

-- to avoid deep tests

if not statements then

return {}

end

-- let's go through the claims

for _, claim in ipairs( statements ) do

-- to avoid deep tests

if not claim then

claim = {}

end

local valid = claim['type'] == 'statement'

and claim['rank'] ~= 'deprecated'

if valid then

-- mw.log("getValuesFromWikidata valid claim="..dump(claim))

local mainsnak = claim.mainsnak or {}

local preferred = claim['rank'] == 'preferred'

-- get the content of the claim (the identifier)

local langcode = props.langcode

local checklangcode = nil

if props.langcode and props.langcode ~= '' then

checklangcode = string.find(langcode, "([pP]%d+)")

end

if checklangcode and checklangcode ~= "" then

-- this is a P-value for language-code, so we'll check qualifiers for languagedata

-- first get any qualifiers

local qualifiers = claim.qualifiers or {}

for _, qualid in ipairs( langqvalorder ) do

-- if the claim has this qualifier

if qualifiers[qualid] then

-- it's here, let's check it out!

local items = {}

-- traverse all snaks in this qualifier

for _, qualsnak in ipairs( qualifiers[qualid] ) do

if qualsnak and pval[qualid] then

-- mw.log("qualsnak = " .. dump(qualsnak))

-- check if the snak is of the correct snaktype and datatype

local valid = qualsnak.snaktype == pval[qualid].types.snaktype

and qualsnak.datatype == pval[qualid].types.datatype

if valid then

-- now get the actual data

langcode = table.concat(getLanguageData('P305', 'Q'..qualsnak.datavalue.value['numeric-id']), '')

end

end

end

end

-- mw.log("langcode is now="..dump(langcode))

end

if string.find(langcode, "([pP]%d+)") then

-- we still don't have any langcode, so we default to "en"

langcode = nil

end

end

local stillvalid = true

-- we should check a couple of other qualifiers as well

-- first get any qualifiers

local qualifiers = claim.qualifiers or {}

for _, qualid in ipairs( otherqvalorder ) do

-- if the claim has this qualifier

if qualifiers[qualid] then

-- it's here, let's check it out!

local items = {}

-- traverse all snaks in this qualifier

for _, qualsnak in ipairs( qualifiers[qualid] ) do

if qualsnak and pval[qualid] then

-- mw.log("qualsnak = " .. dump(qualsnak))

-- check if the snak is of the correct snaktype and datatype

local valid = qualsnak.snaktype == pval[qualid].types.snaktype

and qualsnak.datatype == pval[qualid].types.datatype

if not valid then

-- sorry, this is not correct

mw.log("qualsnak = INCORRECT")

stillvalid = false

end

end

end

end

-- mw.log("langcode is now="..dump(langcode))

end

if stillvalid then

if preferred then

head[#head+1] = { value=stringFormatter(mainsnak.datavalue) }

if langcode and langcode ~= '' then

head[#head]['langcode'] = langcode

end

else

tail[#tail+1] = { value=stringFormatter(mainsnak.datavalue) }

if langcode and langcode ~= '' then

tail[#tail]['langcode'] = langcode

end

end

end

end

end

-- mw.log("getValuesFromWikidata returning head="..dump(head).." tail="..dump(tail))

return #head>0 and head or tail

end

local function findMainLinksOnWikidata(props, pagetitle, short_links)

local output = {}

local pid = nil

-- get the entity we are checking

local entity = mw.wikibase.getEntityObject()

-- to avoid deep tests

if not entity then

return nil

end

local values = getValuesFromWikidata(props)

for _, value in ipairs( values ) do

local verified_value = nil

if props.regex then

-- we have a local defined regex, so this will have to pass first

-- maybe we'll have to convert the regex to Lua-style

local regex = regexConverter(props.regex)

local test = string.match( value.value, '^'..regex..'$' )

--mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)

if test then

-- it matched, this is correct and overrides any other.

verified_value = value.value

end

else

verified_value = value.value

end

if verified_value then

local url = ''

output[#output+1] = {}

output[#output].langcode = value.langcode

output[#output].category = {}

if props.url_f then

-- we have a local defined url-formatter function, use it as first priority

url = props.url_f(verified_value)

if props.track and not string.find(props.langcode, "([pP]%d+)") then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()

elseif props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

elseif props.url then

-- we have a local defined url-formatter string, use it as second priority

url = mw.message.newRawMessage(props.url, verified_value):plain()

if props.track and not string.find(props.langcode, "([pP]%d+)") then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()

elseif props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

else

-- get the formatvalue from the property, if it exists

local formatterUrl = getFormatterUrl(props.prop, verified_value)

if formatterUrl ~= '' then

url = mw.message.newRawMessage(formatterUrl, verified_value):plain()

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

end

end

if url ~= '' then

local this_wiki = mw.getContentLanguage()

local this_wiki_code = this_wiki:getCode()

local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""

if short_links and props.short then

output[#output].text =

mw.message.newRawMessage(props.short,

getLabel(entity, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

else

output[#output].text =

mw.message.newRawMessage(props.message,

getLabel(entity, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

end

end

end

end

--mw.log("findMainLinksOnWikidata returning="..dump(output))

return output

end

local function getSitelinksFromWikidata(props, entity)

local output = {}

--mw.log("getSitelinksFromWikidata, props="..dump(props))

-- to avoid deep tests

if not entity then

entity = mw.wikibase.getEntityObject()

if not entity then

--mw.log("getSitelinksFromWikidata no entity")

return nil

end

end

local requested_sitelink = string.match(props.prop, "SL(%l+)")

local sitelinks = entity:getSitelink(requested_sitelink)

if sitelinks and sitelinks ~= '' then

output[#output+1] = { value = sitelinks }

end

--mw.log("getSitelinksFromWikidata returning output="..dump(output))

return output

end

local function findSiteLinksOnWikidata(props, pagetitle, short_links)

local output = {}

local pid = nil

-- get the entity we are checking

local entity = mw.wikibase.getEntityObject()

-- to avoid deep tests

if not entity then

return nil

end

local values = getSitelinksFromWikidata(props)

for _, value in ipairs( values ) do

local verified_value = nil

if props.regex then

-- we have a local defined regex, so this will have to pass first

-- maybe we'll have to convert the regex to Lua-style

local regex = regexConverter(props.regex)

local test = string.match( value.value, '^'..regex..'$' )

--mw.log("testing with "..regex.. " and test="..dump(test).." and value="..id)

if test then

-- it matched, this is correct and overrides any other.

verified_value = value.value

end

else

verified_value = value.value

end

if verified_value then

--mw.log("it's verified..")

local url = ''

output[#output+1] = {}

output[#output].langcode = value.langcode

output[#output].category = {}

if props.url_f then

-- we have a local defined url-formatter function, use it as first priority

url = props.url_f(verified_value)

if props.track and not string.find(props.langcode, "(SL%l+)") then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()

elseif props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

elseif props.url then

-- we have a local defined url-formatter string, use it as second priority

url = mw.message.newRawMessage(props.url, verified_value):plain()

if props.track and not string.find(props.langcode, "(SL%l+)") then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-wd'), props.prop):plain()

elseif props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

else

url = verified_value:gsub(' ','_')

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-wd'), props.prop):plain()

end

end

if url ~= '' then

local this_wiki = mw.getContentLanguage()

local this_wiki_code = this_wiki:getCode()

local langlink = (value.langcode and value.langcode ~= '' and value.langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), value.langcode, mw.language.fetchLanguageName(value.langcode, this_wiki_code)) or ""

if short_links and props.short then

output[#output].text =

mw.message.newRawMessage(props.short,

getLabel(entity, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

else

output[#output].text =

mw.message.newRawMessage(props.message,

getLabel(entity, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

end

end

end

end

--mw.log("findSiteLinksOnWikidata returning="..dump(output))

return output

end

local function findMainLinksLocal(props, pagetitle, short_links, local_value)

local output = {}

-- to avoid deep tests

if not props.prop then

return nil

end

if not local_value or local_value == '' then

-- bail out if no value is present

return output

end

-- get the formatvalue from the property

local verified_value = local_value

if props.regex and props.regex ~= '' then

-- let's verify the id

-- maybe we'll have to convert the regex to Lua-style

local regex = regexConverter(props.regex)

local test = string.match( local_value, '^'..regex..'$' )

if test then

-- it matched, this is correct

verified_value = local_value

else

verified_value = nil

end

end

if not verified_value then

return output

end

local wikidata_property = string.find(props.prop, "([pP]%d+)")

local wikidata_values = {}

if wikidata_property then

-- get any wikidata values to see if they are equal to local values

wikidata_values = getValuesFromWikidata(props)

end

if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then

output[#output+1] = {}

output[#output].langcode = string.find(props.langcode, "([pP]%d+)") and "" or props.langcode

--mw.log("findMainLinksLocal - props="..dump(props).." langcode="..output[#output].langcode)

output[#output].category = {}

local url = ''

if props.track and wikidata_property and wikidata_values and #wikidata_values then

local local_value_in_wikidata = false

for _,value in ipairs( wikidata_values ) do

if value.value == verified_value then

local_value_in_wikidata = true

end

end

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()

end

if wikidata_property and wikidata_values and #wikidata_values then

hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim

end

if props.url_f then

-- we have a local defined url-formatter function, use it as first priority

url = props.url_f(verified_value)

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()

end

elseif props.url then

-- we have a local defined url-formatter string, use it as second priority

url = mw.message.newRawMessage(props.url, verified_value):plain()

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()

end

elseif wikidata_property then

-- get the formatvalue from the property, if it exists

local formatterUrl = getFormatterUrl(props.prop, verified_value)

if formatterUrl ~= '' then

url = mw.message.newRawMessage(formatterUrl, verified_value):plain()

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()

end

end

else

-- no other choice, bail out

return {}

end

local this_wiki = mw.getContentLanguage()

local this_wiki_code = this_wiki:getCode()

local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""

if short_links and props.short then

output[#output].text =

mw.message.newRawMessage(props.short,

getLabel(nil, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

else

output[#output].text =

mw.message.newRawMessage(props.message,

getLabel(nil, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

end

end

--mw.log("findMainLinksLocal returning="..dump(output))

return output

end

local function findSiteLinksLocal(props, pagetitle, short_links, local_value)

local output = {}

-- to avoid deep tests

if not props.prop then

return nil

end

if not local_value or local_value == '' then

-- bail out if no value is present

return output

end

-- get the formatvalue from the property

local verified_value = local_value

if props.regex and props.regex ~= '' then

-- let's verify the id

-- maybe we'll have to convert the regex to Lua-style

local regex = regexConverter(props.regex)

local test = string.match( local_value, '^'..regex..'$' )

if test then

-- it matched, this is correct

verified_value = local_value

else

verified_value = nil

end

end

if not verified_value then

return output

end

local wikidata_property = string.find(props.prop, "(SL.+)")

local wikidata_values = {}

if wikidata_property then

-- get any wikidata values to see if they are equal to local values

wikidata_values = getSitelinksFromWikidata(props)

end

if wikidata_property or (props.url and props.url ~= '') or (props.url_f) then

output[#output+1] = {}

output[#output].langcode = string.find(props.langcode, "(SL.+)") and "" or props.langcode

--mw.log("findSiteLinksLocal - props="..dump(props).." langcode="..output[#output].langcode .." wikidata_values="..dump(wikidata_values))

output[#output].category = {}

local url = ''

if props.track and wikidata_property and wikidata_values and #wikidata_values then

local local_value_in_wikidata = false

for _,value in ipairs( wikidata_values ) do

if value.value == verified_value then

local_value_in_wikidata = true

end

end

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), (local_value_in_wikidata and 'track-cat-local-wd-equal' or 'track-cat-local-wd-unequal')), props.prop):plain()

end

if wikidata_property and wikidata_values and #wikidata_values then

hasdatafromwikidata = true -- signal up the chain this article has a wikidata claim

end

if props.url_f then

-- we have a local defined url-formatter function, use it as first priority

url = props.url_f(verified_value)

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()

end

elseif props.url then

-- we have a local defined url-formatter string, use it as second priority

url = mw.message.newRawMessage(props.url, verified_value):plain()

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-local-local'), props.prop):plain()

end

elseif wikidata_property then

url = verified_value:gsub(' ','_')

if props.track then

output[#output].category[#output[#output].category+1] = mw.message.newRawMessage(cmodule:getMessage(contLang:getCode(), 'track-cat-wd-local'), props.prop):plain()

end

else

-- no other choice, bail out

return {}

end

local this_wiki = mw.getContentLanguage()

local this_wiki_code = this_wiki:getCode()

local langlink = (output[#output].langcode and output[#output].langcode ~= '' and output[#output].langcode ~= this_wiki_code) and mw.message.newRawMessage(conf:g('msg-langcode'), props.langcode, mw.language.fetchLanguageName(props.langcode, this_wiki_code)) or ""

if short_links and props.short then

output[#output].text =

mw.message.newRawMessage(props.short,

getLabel(nil, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

else

output[#output].text =

mw.message.newRawMessage(props.message,

getLabel(nil, props.genitive, pagetitle),

url,

langlink,

verified_value,

mw.uri.encode(verified_value, 'PATH'))

:plain()

end

end

--mw.log("findSiteLinksLocal returning="..dump(output))

return output

end

local function addLinkback(str, property)

local id = mw.wikibase.getEntityObject()

if not id then

return str

end

if type(id) == 'table' then

id = id.id

end

local class = ''

local url = ''

if property then

class = 'wd_' .. string.lower(property)

url = mw.uri.fullUrl('d:' .. id .. '#' .. property)

url.fragment = property

else

url = mw.uri.fullUrl('d:' .. id )

end

local title = conf:g('wikidata-linkback-edit')

local icon = '[%s File:Blue pencil.svg ]'

url = tostring(url)

local v = mw.html.create('span')

:addClass(class)

:wikitext(str)

:tag('span')

:addClass('noprint plainlinks wikidata-linkback')

:css('padding-left', '.3em')

:wikitext(icon:format(url, title))

:allDone()

return tostring(v)

end

local function getArgument(frame, argument)

local args = frame.args

if args[1] == nil then

local pFrame = frame:getParent();

args = pFrame.args;

for k,v in pairs( frame.args ) do

args[k] = v;

end

end

if args[argument] then

return args[argument]

end

return nil

end

local function removeEntry(conf_claims, identifier, property)

for i, props in ipairs(conf_claims) do

if props[identifier] == property then

table.remove(conf_claims, i)

end

end

return conf_claims

end

function p.getLinks(frame)

local configured_conf = getArgument(frame, conf:a('arg-conf'))

if configured_conf then

cmodule = require ('Module:External_links/conf/'..configured_conf)

else

error(mw.message.newRawMessage(conf:g('missing-conf'), configured_conf):plain())

end

local output = {}

local category = {}

local conf_claims = cmodule:getConfiguredClaims(contLang:getCode())

local limits = cmodule:getLimits()

assert(limits, mw.message.newRawMessage(conf:g('missing-limits'), configured_conf):plain())

local links_shown = getArgument(frame, conf:a('arg-maxlink'))

local pagetitle = getArgument(frame, conf:a('arg-title'))

-- get a list of tracked properties from the article itself

local requested_tracking = getArgument(frame, conf:a('arg-track'))

if requested_tracking and requested_tracking ~= '' then

-- the properties should be written as P1234, P2345 and other

-- version corresponding to the applicable property-identifiers in the config

for track_prop in string.gmatch(requested_tracking,"([^ ,;:]+)") do

-- get the requested properties and be able to access them

-- like req_prop['P345'] to verify if it was requested

local remove_track = string.match(track_prop, "^\-(.*)")

for i,claim in ipairs ( conf_claims ) do

if remove_track == claim.prop or remove_track == conf:a('mod-filter-all') then

-- if a property starts with "-", then we'll simply remove that

-- property from the conf_claims

conf_claims[i]['track'] = false

elseif track_prop == claim.prop or track_prop == conf:a('mod-filter-all') then

conf_claims[i]['track'] = true

end

end

end

end

-- get a list of "approved" properties from the article itself

local requested_properties = getArgument(frame, conf:a('arg-properties'))

--mw.log("requested_properties="..dump(requested_properties))

-- assume all properties are allowed

local req_prop = {}

local no_req_prop = false -- we'll allow properties to be filtered for now

if requested_properties and requested_properties ~= '' then

-- the properties should be written as P1234, P2345 and other

-- version corresponding to the applicable property-identifiers in the config

for i in string.gmatch(requested_properties,"([^ ,;:]+)") do

-- get the requested properties and be able to access them

-- like req_prop['P345'] to verify if it was requested

if i == conf:a('mod-filter-all') then

-- this is a special modifier, saying we should ignore

-- all previous and future positive filters and remove the

-- filter (with exception of negative filters)

req_prop = {}

no_req_prop = true

end

local remove_prop = string.match(i, "^\-(.*)")

if remove_prop then

-- if a property starts with "-", then we'll simply remove that

-- property from the conf_claims

conf_claims = removeEntry(conf_claims, 'prop', remove_prop)

elseif not no_req_prop then -- only if we are allowing properties to be filtered

req_prop[i] = 1

-- cheat to make #req_prop indicate populated table

req_prop[1] = 1

end

end

end

local requested_langs = getArgument(frame, conf:a('arg-languages'))

--mw.log("requested_langs="..dump(requested_langs))

-- assume all languages are allowed

local req_lang = {}

local no_req_lang = false -- we'll allow languages to be filtered for now

if requested_langs and requested_langs ~= '' then

-- the languages should be written as langcodes as used in the conf_claims

for i in string.gmatch(requested_langs,"([^ ,;:]+)") do

-- get the requested languages and be able to access them

if i == conf:a('mod-filter-all') then

-- this is a special modifier, saying we should ignore

-- all previous and future positive filters and remove the

-- filter (with exception of negative filters)

req_lang = {}

no_req_lang = true

end

-- like req_lang['en'] to verify if it was requested

local remove_lang = string.match(i, "^\-(.*)")

if remove_lang then

-- if a language starts with "-", then we'll simply remove that

-- language from the conf_claims

conf_claims = removeEntry(conf_claims, 'langcode', remove_lang)

elseif not no_req_lang then -- only if we are allowing languages to be filtered

req_lang[i] = 1

-- cheat to make #req_lang indicate populated table

req_lang[1] = 1

end

end

end

local short_links = getArgument(frame, conf:a('arg-short'))

if short_links and short_links ~= '' then

short_links = true

else

short_links = false

end

local showinline = getArgument(frame, conf:a('arg-inline'))

if showinline and showinline ~= '' then

showinline = true

else

showinline = false

end

if not links_shown or links_shown == '' then

links_shown = limits['links-shown'] and limits['links-shown'] or 5

else

links_shown = tonumber(links_shown)

end

local somedataonwikidata = not short_links

--mw.log("conf_claims="..dump(conf_claims))

--mw.log("req_prop="..dump(req_prop))

--mw.log("req_lang="..dump(req_lang))

--mw.log("short_links="..dump(short_links))

for _, props in ipairs(conf_claims) do

-- if we're called with a list of approved properties or languages, check if this one is "approved"

if (#req_prop==0 or req_prop[props.prop]) and (#req_lang==0 or req_lang[props.langcode] or string.find(props.langcode, "([pP]%d+)")) then

--mw.log("checking claim="..dump(props))

local links = {}

local checkedonwikidata = false

-- get the any local overriding value from the call

local wikivalue = getArgument(frame, props.prop)

--mw.log("wikivalue="..dump(wikivalue))

if (not wikivalue or wikivalue == "") and string.find(props.prop, "([pP]%d+)") then

-- the property is a Pnnn type, and therefore on Wikidata

links = findMainLinksOnWikidata(props, pagetitle, short_links)

if links == nil then

-- a nil-value indicated no wikidata-link

haswikidatalink = false

links = {}

else

checkedonwikidata = true

end

elseif (not wikivalue or wikivalue == "") and string.find(props.prop, "(SL%l+)") then

-- this is a sitelink-type (SLspecieswiki)

--mw.log("finding sitelinks..")

links = findSiteLinksOnWikidata(props, pagetitle, short_links)

if links == nil then

-- a nil-value indicated no wikidata-link

haswikidatalink = false

links = {}

else

checkedonwikidata = true

end

elseif (wikivalue and wikivalue ~= "") and string.find(props.prop, "(SL%l+)") then

-- this is a sitelink-type (SLspecieswiki)

links = findSiteLinksLocal(props, pagetitle, short_links, wikivalue)

elseif wikivalue and wikivalue ~= '' then

-- the property is of another annotation, and therefore a local construct

links = findMainLinksLocal(props, pagetitle, short_links, wikivalue)

end

--mw.log("links="..dump(links))

for _,v in ipairs(links) do

-- we'll have to check langcodes again as they may have come from wikidata

if (#req_lang==0 or req_lang[v.langcode]) then

if checkedonwikidata and not hasdatafromwikidata then

-- add a general tracking category for articles with data from wikidata

hasdatafromwikidata = true

category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-data-cat')

elseif not checkedonwikidata and not hasdatafromlocal then

-- add a general tracking category for articles with data from template-calls in local articles

hasdatafromlocal = true

category[#category+1] = cmodule:getMessage(contLang:getCode(), 'with-local-cat')

end

if short_links and props.short and v.text and v.text ~= '' then

-- if short links were requested, and a short definition exists for this property, let's use it

if #output==0 then

output[#output+1] = v.text

else

output[#output] = output[#output] .. cmodule:getMessage(contLang:getCode(),'short-list-separator') .. v.text

end

somedataonwikidata = true

elseif not short_links and not showinline and v.text and v.text ~= '' then

-- only if short links were not requested

output[#output+1] = (#output>=1 and conf:g('msg-ul-prepend') or '') -- if this is the first link, we won't output a list-element (msg-ul-prepend)

.. (checkedonwikidata and addLinkback(v.text, props.prop) or v.text) -- if the link comes from wikidata, also output a linkback.

elseif not short_links and showinline and v.text and v.text ~= '' then

-- only if short links were not requested

output[#output+1] = v.text

end

if props.track and v.category and #v.category then

-- add category if tracking is on for this property and a category exists in the link-result.

for _,cats in ipairs( v.category ) do

category[#category+1] = cats

end

end

if links_shown>0 then

links_shown = links_shown - 1

else

break

end

end

end

if links_shown==0 then

break

end

end

end

local outtext = ""

if short_links and #output>0 then

-- if these are short links, output the whole thing with linkback to wikidata

--mw.log("somedataonwikidata="..dump(somedataonwikidata).." and output="..dump(output).." and #output="..dump(#output))

outtext = (somedataonwikidata

and addLinkback(table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')), nil)

or table.concat(output,cmodule:getMessage(contLang:getCode(),'short-list-separator')))

elseif not short_links and not showinline and #output>0 then

outtext = table.concat(output,"\n")

elseif not short_links and showinline and #output>0 then

outtext = table.concat(output,conf:g('msg-inline-separator'))

end

if not hasdatafromwikidata then

category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-data-cat')

if not hasdatafromlocal and not short_links then

outtext = cmodule:getMessage(contLang:getCode(), 'no-data-text')

end

end

if not haswikidatalink then

category[#category+1] = cmodule:getMessage(contLang:getCode(), 'no-wikilink-cat')

if not hasdatafromlocal and not short_links then

outtext = cmodule:getMessage(contLang:getCode(), 'no-wikilink')

end

end

local nocategory = getArgument(frame, conf:a('arg-no-categories'))

category = #category>0 and "\n" .. table.concat(category,"\n") or ""

--mw.log("nocategory="..dump(nocategory).." and outtext="..dump(outtext).." and category="..dump(category))

outtext = outtext .. (nocategory and '' or category)

return outtext

end

function p.getLanguageCode(frame)

local prop = getArgument(frame, conf:a('arg-properties'))

local output = getLanguageData(prop)

return table.concat(output, conf:a('mod-filter-separator'))

end

return p