Aller au contenu

« Module:Coordinates » : différence entre les versions

De Wreck
Modèle:Infobox>Od1n
chargement de ces modules de données seulement lorsqu'ils sont utilisés ; props 192616904 ; la sécurité pcall() est effectivement dispensable (si jamais le module de données est cassé il doit être réparé promptement) ; plusieurs appels de mw.loadData() si plusieurs pays (boucle for), mais l'overhead est faible et le cas de figure devrait être rare, cela ne justifierait pas de complexifier le code avec un système de "load only once"
m 153 versions importées
 
(5 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 55 : Ligne 55 :
radius in kilometers (especially imprecise for non spheric bodies)
radius in kilometers (especially imprecise for non spheric bodies)
defaultdisplay is currently disabled, activate it ?
defaultdisplay is currently disabled, activate it ?
]]--  
]]--
ariel = {radius = 580, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
ariel = {radius = 580, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
callisto =  {radius = 2410, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
callisto =  {radius = 2410, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
ceres =  {radius = 470, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
ceres =  {radius = 470, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
Ligne 64 : Ligne 64 :
enceladus =  {radius = 255, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
enceladus =  {radius = 255, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
ganymede =  {radius = 2634, defaultdisplay = 'dec west', trackingcat = 'sur Ganymède'},
ganymede =  {radius = 2634, defaultdisplay = 'dec west', trackingcat = 'sur Ganymède'},
earth = {radius = 6371, defaultdisplay = 'dms', trackingcat = 'sur Terre'},
earth = {radius = 6371, defaultdisplay = 'dms', trackingcat = 'sur Terre'},
europa =  {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
europa =  {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
hyperion =  {radius = 140, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
hyperion =  {radius = 140, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
Ligne 70 : Ligne 70 :
['io'] =  {radius = 1322, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
['io'] =  {radius = 1322, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
jupiter =  {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
jupiter =  {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
mars =  {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'sur Mars' },
mars =  {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'sur Mars'},
mercury =  {radius = 2439.7, defaultdisplay = 'dec west', trackingcat = 'sur Mercure'},
mercury =  {radius = 2439.7, defaultdisplay = 'dec west', trackingcat = 'sur Mercure'},
mimas =  {radius = 197, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
mimas =  {radius = 197, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
Ligne 85 : Ligne 85 :
tethys =  {radius = 530, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
tethys =  {radius = 530, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
titania =  {radius = 394, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
titania =  {radius = 394, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
triton = {radius = 1353, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
triton = {radius = 1353, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
umbriel =  {radius = 584, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
umbriel =  {radius = 584, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
uranus =  {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
uranus =  {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
Ligne 93 : Ligne 93 :
globedata[''] = globedata.earth
globedata[''] = globedata.earth


local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse se seuil (en kilomètes), une catégorie de maintenance est ajoutée
local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse ce seuil (en kilomètres), une catégorie de maintenance est ajoutée
local lang = mw.language.getContentLanguage()
local lang = mw.language.getContentLanguage()
local default_zoom = 13
local default_zoom = 13
Ligne 123 : Ligne 123 :
local function makeerror(args)
local function makeerror(args)
local errormessage = ''
local errormessage = ''
if args.message then  
if args.message then
errormessage = '<strong class="error"> Coordonnées' .. NBSP .. ': ' .. args.message .. '</strong>'  
errormessage = '<strong class="error"> Coordonnées' .. NBSP .. ': ' .. args.message .. '</strong>'
end
end
local errorcat = ''
local errorcat = ''
if mw.title.getCurrentTitle().namespace == 0 then  
if mw.title.getCurrentTitle().namespace == 0 then
errorcat = makecat(i18n.errorcat, args.sortkey)
errorcat = makecat(i18n.errorcat, args.sortkey)
end
end
Ligne 144 : Ligne 144 :


globe = string.lower(globe or 'earth')
globe = string.lower(globe or 'earth')
 
-- check arguments and converts degreees to radians
-- check arguments and converts degreees to radians
local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude
local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude
Ligne 156 : Ligne 156 :
return error('globe: ' .. globe .. 'is not supported')
return error('globe: ' .. globe .. 'is not supported')
end
end
 
-- calcul de la distance angulaire en radians
-- calcul de la distance angulaire en radians
local convratio = math.pi / 180 -- convertit en radians
local convratio = math.pi / 180 -- convertit en radians
Ligne 173 : Ligne 173 :
local args = frame.args
local args = frame.args
return p._distance(
return p._distance(
{latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)},  
{latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)},
{latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)},
{latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)},
args.globe)
args.globe)
Ligne 184 : Ligne 184 :
if tonumber(decLat) < 0 then
if tonumber(decLat) < 0 then
geohacklatitude = tostring(-tonumber(decLat)) .. '_S'
geohacklatitude = tostring(-tonumber(decLat)) .. '_S'
else  
else
geohacklatitude = decLat .. '_N'
geohacklatitude = decLat .. '_N'
end
end
Ligne 197 : Ligne 197 :
local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
-- concatenate parameteres for geohack
-- concatenate parameteres for geohack
return i18n.geohackurl ..  
return i18n.geohackurl ..
"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
"&params=" .. geohackparams ..
"&params=" .. geohackparams ..
Ligne 207 : Ligne 207 :
-- geohack url
-- geohack url
local url = geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)
local url = geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)
 
-- displayed coordinates
-- displayed coordinates
local displaycoords
local displaycoords
if string.sub(displayformat,1,3) == 'dec' then
if string.sub(displayformat, 1, 3) == 'dec' then
displaycoords = p.displaydec(decLat, decLong, displayformat)
displaycoords = p.displaydec(decLat, decLong, displayformat)
else
else
Ligne 218 : Ligne 218 :
}
}
end
end
 
-- build coordinate in h-geo / h-card microformat
-- build coordinate in h-geo / h-card microformat
local globeNode
local globeNode
Ligne 227 : Ligne 227 :
:done()
:done()
end
end
 
local coordNode = mw.html.create('')
local coordNode = mw.html.create('')
if objectname then
if objectname then
Ligne 240 : Ligne 240 :
:tag('span')
:tag('span')
:addClass('h-geo')
:addClass('h-geo')
:addClass('geo-' .. string.sub(displayformat,1,3))  
:addClass('geo-' .. string.sub(displayformat, 1, 3))
:tag('data')
:tag('data')
:addClass('p-latitude')
:addClass('p-latitude')
Ligne 254 : Ligne 254 :
:node( globeNode )
:node( globeNode )
:done()
:done()
 
-- buid GeoHack link
-- buid GeoHack link
local root = mw.html.create('span')
local root = mw.html.create('span')
Ligne 263 : Ligne 263 :
:wikitext("]")
:wikitext("]")
:done()
:done()
 
-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
local inlineText = displayinline and tostring(root) or ''
local inlineText = displayinline and tostring(root) or ''
Ligne 273 : Ligne 273 :
:node( root )
:node( root )
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
end
end
 
return inlineText .. titleText
return inlineText .. titleText
end
end
Ligne 284 : Ligne 284 :
return zoomParam
return zoomParam
end
end
 
local scale = extraparams:match( '%f[%w]scale: ?(%d+)' )
local scale = extraparams:match( '%f[%w]scale: ?(%d+)' )
if scale then
if scale then
return math.floor(math.log10( 1 / tonumber( scale ) ) * 3 + 25)
return math.floor(math.log10( 1 / tonumber( scale ) ) * 3 + 25)
end
end
 
local extraType = extraparams:match( '%f[%w]type: ?(%w+)' )
local extraType = extraparams:match( '%f[%w]type: ?(%w+)' )
if extraType then
if extraType then
Ligne 312 : Ligne 312 :
-- displayed coordinates
-- displayed coordinates
local displaycoords
local displaycoords
if string.sub(displayformat,1,3) == 'dec' then
if string.sub(displayformat, 1, 3) == 'dec' then
displaycoords = p.displaydec(decLat, decLong, displayformat)
displaycoords = p.displaydec(decLat, decLong, displayformat)
else
else
Ligne 320 : Ligne 320 :
}
}
end
end
 
-- JSON for maplink
-- JSON for maplink
local jsonParams = {
local jsonParams = {
type = 'Feature',
type = 'Feature',
geometry = {  
geometry = {
type ='Point',
type ='Point',
coordinates = {  
coordinates = {
math_mod._round( decLong, 6 ), -- max precision in GeoJSON format
math_mod._round( decLong, 6 ), -- max precision in GeoJSON format
math_mod._round( decLat, 6 )
math_mod._round( decLat, 6 )
Ligne 360 : Ligne 360 :
name = 'maplink',
name = 'maplink',
content = mw.text.jsonEncode( jsonParams ),
content = mw.text.jsonEncode( jsonParams ),
args = {  
args = {
text = displaycoords[1] .. ", " .. displaycoords[2],
text = displaycoords[1] .. ", " .. displaycoords[2],
zoom = zoom( extraparams ) or default_zoom,
zoom = zoom( extraparams ) or default_zoom,
Ligne 367 : Ligne 367 :
}
}
}
}
 
-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
local inlineText = displayinline and maplink or ''
local inlineText = displayinline and maplink or ''
Ligne 377 : Ligne 377 :
:wikitext( maplink )
:wikitext( maplink )
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
end
end
 
return inlineText .. titleText
return inlineText .. titleText
end
end
Ligne 406 : Ligne 406 :
end
end
degrees = lang:formatNum( valuetable.degrees ) .. i18n.degrees
degrees = lang:formatNum( valuetable.degrees ) .. i18n.degrees
 
if valuetable.minutes then
if valuetable.minutes then
minutes = twoDigit( valuetable.minutes ) .. i18n.minutes
minutes = twoDigit( valuetable.minutes ) .. i18n.minutes
Ligne 425 : Ligne 425 :
if direction == 'N' or direction == 'S' then
if direction == 'N' or direction == 'S' then
dimension = 'latitude'
dimension = 'latitude'
elseif direction == 'E' or direction == 'W' then  
elseif direction == 'E' or direction == 'W' then
dimension = 'longitude'
dimension = 'longitude'
else
else
Ligne 437 : Ligne 437 :
return false
return false
end
end
 
if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then
if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then
makeerror({message = i18n.invalidNS, sortkey = 'A'})
makeerror({message = i18n.invalidNS, sortkey = 'A'})
Ligne 446 : Ligne 446 :
return false
return false
end
end
 
if dimension == 'latitude' and degrees > 90 then
if dimension == 'latitude' and degrees > 90 then
makeerror({message = i18n.latitude90, sortkey = 'A'})
makeerror({message = i18n.latitude90, sortkey = 'A'})
return false
return false
end
end
 
if dimension == 'longitude' and degrees > 360 then
if dimension == 'longitude' and degrees > 360 then
makeerror({message = i18n.longitude360, sortkey = 'A'})
makeerror({message = i18n.longitude360, sortkey = 'A'})
return false
return false
end
end
 
if degrees < 0 or minutes < 0 or seconds < 0 then
if degrees < 0 or minutes < 0 or seconds < 0 then
makeerror({message = i18n.negativeCoode, sortkey = 'A'})
makeerror({message = i18n.negativeCoode, sortkey = 'A'})
return false
return false
end
end
 
if minutes > 60 or seconds > 60 then
if minutes > 60 or seconds > 60 then
makeerror({message = i18n.minSec60, sortkey = 'A'})
makeerror({message = i18n.minSec60, sortkey = 'A'})
return false
return false
end
end
if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then
if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then
makeerror({message = i18n.dmIntergers, sortkey = 'A'})
makeerror({message = i18n.dmIntergers, sortkey = 'A'})
Ligne 476 : Ligne 476 :
-- no error checking, done in function validdms
-- no error checking, done in function validdms
local dimensionobject = {}
local dimensionobject = {}
 
-- direction and dimension (= latitude or longitude)
-- direction and dimension (= latitude or longitude)
dimensionobject.direction = direction
dimensionobject.direction = direction
Ligne 486 : Ligne 486 :
dimensionobject.dimension = 'longitude'
dimensionobject.dimension = 'longitude'
end
end
 
-- degrees, minutes, seconds
-- degrees, minutes, seconds
dimensionobject.degrees = tonumber(degrees)
dimensionobject.degrees = tonumber(degrees)
Ligne 497 : Ligne 497 :
end
end


function p._parsedmsstring( str, dimension ) -- prend une séquence et donne des noms aux paramètres  
function p._parsedmsstring( str, dimension ) -- prend une séquence et donne des noms aux paramètres
-- output table: { latitude=, longitude = , direction =  }
-- output table: { latitude=, longitude = , direction =  }
if type( str ) ~= 'string' then
if type( str ) ~= 'string' then
Ligne 511 : Ligne 511 :
end
end
if not tonumber(str) and not string.find(str, '/') then
if not tonumber(str) and not string.find(str, '/') then
makeerror({message = i18n.invalidFormat, sortkey= 'A'})
makeerror({message = i18n.invalidFormat, sortkey = 'A'})
return nil
return nil
end
end
local args = mw.text.split(str, '/', true)
local args = mw.text.split(str, '/', true)
if #args > 4 then
if #args > 4 then
makeerror({message = i18n.tooManyParam, sortkey= 'A' })
makeerror({message = i18n.tooManyParam, sortkey = 'A'})
end
end
local direction = mw.text.trim(args[#args])
local direction = mw.text.trim(args[#args])
table.remove(args)
table.remove(args)
Ligne 533 : Ligne 533 :
local lat = lang:formatNum( latitude )
local lat = lang:formatNum( latitude )
local long = lang:formatNum( longitude )
local long = lang:formatNum( longitude )
 
if format == 'dec west' or  format == 'dec east' then
if format == 'dec west' or  format == 'dec east' then
local symbolNS, symbolEW = i18n.N, i18n.E
local symbolNS, symbolEW = i18n.N, i18n.E
if latitude < 0 then  
if latitude < 0 then
symbolNS = i18n.S
symbolNS = i18n.S
lat = lang:formatNum( -latitude )
lat = lang:formatNum( -latitude )
Ligne 543 : Ligne 543 :
symbolEW = i18n.W
symbolEW = i18n.W
end
end
if longitude < 0 then  
if longitude < 0 then
long = lang:formatNum( 360 + longitude )
long = lang:formatNum( 360 + longitude )
end
end
 
return { lat .. i18n.degrees .. symbolNS,  long ..  i18n.degrees .. symbolEW }
return { lat .. i18n.degrees .. symbolNS,  long ..  i18n.degrees .. symbolEW }
 
else  
else
return { lat, long }
return { lat, long }
end
end
Ligne 628 : Ligne 628 :
local degrees = dec % 360
local degrees = dec % 360
return degrees, minutes
return degrees, minutes
end  
end


local function dec2dms_dms(dec)
local function dec2dms_dms(dec)
Ligne 642 : Ligne 642 :
function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude
function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude
local degrees, minutes, seconds
local degrees, minutes, seconds
 
-- vérification du globe
-- vérification du globe
if not ( globe and globedata[ globe ] ) then
if not ( globe and globedata[ globe ] ) then
globe = 'earth'
globe = 'earth'
end
end
 
-- precision
-- precision
if not precision or precision == '' then
if not precision or precision == '' then
Ligne 656 : Ligne 656 :
end
end
local dec = tonumber(dec)
local dec = tonumber(dec)
 
-- direction  
-- direction
local direction
local direction
if coordtype == 'latitude' then  
if coordtype == 'latitude' then
if dec < 0 then
if dec < 0 then
direction = 'S'
direction = 'S'
else  
else
direction = 'N'
direction = 'N'
end
end
Ligne 668 : Ligne 668 :
if dec < 0 or globedata[globe].defaultdisplay == 'dec west' then
if dec < 0 or globedata[globe].defaultdisplay == 'dec west' then
direction = 'W'
direction = 'W'
else  
else
direction = 'E'
direction = 'E'
end
end
end
end
 
-- conversion
-- conversion
dec = math.abs(dec) -- les coordonnées en dms sont toujours positives
dec = math.abs(dec) -- les coordonnées en dms sont toujours positives
if precision == 'dms' then  
if precision == 'dms' then
degrees, minutes, seconds = dec2dms_dms(dec)
degrees, minutes, seconds = dec2dms_dms(dec)
elseif precision == 'dm' then
elseif precision == 'dm' then
Ligne 687 : Ligne 687 :
function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax
function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax
local args = frame.args
local args = frame.args
local dec = args[1]  
local dec = args[1]
if not tonumber(dec) then
if not tonumber(dec) then
makeerror({message = i18n.invalidFormat, sortkey = 'A'})
makeerror({message = i18n.invalidFormat, sortkey = 'A'})
Ligne 696 : Ligne 696 :
local precision = string.lower(args[4] or '')
local precision = string.lower(args[4] or '')
local displayformat, coordtype
local displayformat, coordtype
 
if dirpositive == 'n' or dirpositive == 'nord' then
if dirpositive == 'n' or dirpositive == 'nord' then
coordtype = 'latitude'
coordtype = 'latitude'
else  
else
coordtype = 'longitude'
coordtype = 'longitude'
end
end
Ligne 720 : Ligne 720 :
if not minutes then minutes = 0 end
if not minutes then minutes = 0 end
if not seconds then seconds = 0 end
if not seconds then seconds = 0 end
 
if direction == "N" or direction == "E" then
if direction == "N" or direction == "E" then
factor = 1
factor = 1
elseif direction == "W" or direction == "S" then
elseif direction == "W" or direction == "S" then
factor = -1
factor = -1
elseif not direction then  
elseif not direction then
makeerror({message = i18n.noCardinalDirection, sortkey = 'A'})
makeerror({message = i18n.noCardinalDirection, sortkey = 'A'})
return nil
return nil
Ligne 732 : Ligne 732 :
return nil
return nil
end
end
 
if dmsobject.seconds then -- vérifie la précision des données initiales
if dmsobject.seconds then -- vérifie la précision des données initiales
precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ?
precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ?
Ligne 740 : Ligne 740 :
precision = math.max( math_mod._precision(tostring(degrees), 0 ) )
precision = math.max( math_mod._precision(tostring(degrees), 0 ) )
end
end
 
local decimal = factor * (degrees+(minutes+seconds/60)/60)
local decimal = factor * (degrees+(minutes+seconds/60)/60)
return math_mod._round(decimal, precision)
return math_mod._round(decimal, precision)
Ligne 747 : Ligne 747 :
function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax
function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax
local args = frame.args
local args = frame.args
if tonumber(args[1]) then  
if tonumber(args[1]) then
return args[1] -- coordonnées déjà en décimal
return args[1] -- coordonnées déjà en décimal
elseif not args[2] then
elseif not args[2] then
Ligne 768 : Ligne 768 :
return showerrors()
return showerrors()
end
end
else  
else
return p._dms2dec({direction = args[1], degrees = tonumber(args[2]), minutes = tonumber(args[3]), seconds = tonumber(args[4])})
return p._dms2dec({direction = args[1], degrees = tonumber(args[2]), minutes = tonumber(args[3]), seconds = tonumber(args[4])})
end
end
Ligne 804 : Ligne 804 :
--catbase= Article géolocalisé sur Terre
--catbase= Article géolocalisé sur Terre
local entitycat = mw.wikibase.getEntity()
local entitycat = mw.wikibase.getEntity()
 
local basecat = 'Article géolocalisé'
local basecat = 'Article géolocalisé'
local finalcat = {}
local finalcat = {}
Ligne 812 : Ligne 812 :
  for i, badgeId in ipairs( entitycat.sitelinks['frwiki'].badges ) do
  for i, badgeId in ipairs( entitycat.sitelinks['frwiki'].badges ) do
if badgeId == 'Q17437796'  then
if badgeId == 'Q17437796'  then
basecat=string.gsub(basecat, "Article géolocalisé", "Article de qualité géolocalisé")
basecat = string.gsub(basecat, "Article géolocalisé", "Article de qualité géolocalisé")
end
end
if badgeId == 'Q17437798'  then
if badgeId == 'Q17437798'  then
basecat=string.gsub(basecat, "Article géolocalisé", "Bon article géolocalisé")
basecat = string.gsub(basecat, "Article géolocalisé", "Bon article géolocalisé")
end
end
end
end
Ligne 822 : Ligne 822 :
if globe == 'earth'  then
if globe == 'earth'  then
if entitycat and entitycat.claims  then
if entitycat and entitycat.claims  then
local country=entitycat.claims['P17']
local country = entitycat.claims['P17']
if not country then
if not country then
--pas pays à récupérer
--pas pays à récupérer
basecat=basecat .. ' sur Terre'
basecat = basecat .. ' sur Terre'
table.insert(finalcat,basecat)
table.insert(finalcat, basecat)
else
else
--parfois plusieurs pays
--parfois plusieurs pays
for i, paysId in ipairs( country ) do
for i, paysId in ipairs( country ) do
--on fait confiance au label wikidata
--on fait confiance au label wikidata
local gdataone,qid
local gdataone, qid
 
if paysId.mainsnak.snaktype == 'value' then
if paysId.mainsnak.snaktype == 'value' then
qid=paysId.mainsnak.datavalue.value['numeric-id']
qid = paysId.mainsnak.datavalue.value['numeric-id']
gdataone = mw.loadData("Module:Drapeau/Data").data[qid]
gdataone = mw.loadData("Module:Drapeau/Data").data[qid]
else
else
--Bir Tawil n'a pas de pays connu
--Bir Tawil n'a pas de pays connu
qid='?'
qid = '?'
end
end
if gdataone ~= nil then
if gdataone ~= nil then
local genre = mw.loadData("Module:Drapeau/Domaine").genre
local genre = mw.loadData("Module:Drapeau/Domaine").genre
local prep=genre[gdataone['genre']]['en'] or 'en '
local prep = genre[gdataone['genre']]['en'] or 'en '
local thecat=basecat .. ' '..prep ..mw.wikibase.label( 'Q'.. qid)
local thecat = basecat .. ' '..prep ..mw.wikibase.label('Q'.. qid)
if mw.title.new('category:'..thecat).exists then
if mw.title.new('category:'..thecat).exists then
table.insert(finalcat,thecat)
table.insert(finalcat, thecat)
else
else
--Dommage!
--Dommage!
Ligne 857 : Ligne 857 :
if #finalcat == 0 then
if #finalcat == 0 then
--pas pays à récupérer
--pas pays à récupérer
basecat=basecat .. ' sur Terre'
basecat = basecat .. ' sur Terre'
table.insert(finalcat,basecat)
table.insert(finalcat, basecat)
end
end
end
end
else
else
--pas wikidata
--pas wikidata
basecat=basecat .. ' sur Terre'
basecat = basecat .. ' sur Terre'
table.insert(finalcat,basecat)
table.insert(finalcat, basecat)
end
end
elseif globedata[globe] then
elseif globedata[globe] then
basecat=basecat .. ' ' .. globedata[globe].trackingcat
basecat = basecat .. ' ' .. globedata[globe].trackingcat
table.insert(finalcat,basecat)
table.insert(finalcat, basecat)
else
else
basecat=basecat .. ' extraterrestre'
basecat = basecat .. ' extraterrestre'
table.insert(finalcat,basecat)
table.insert(finalcat, basecat)
end
end
return finalcat
return finalcat
Ligne 879 : Ligne 879 :
function p._coord(args)
function p._coord(args)


-- I declare variable
-- I declare variable
local displayformat = args.format -- string: one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west'
local displayformat = args.format -- string: one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west'
local displayplace = string.lower(args.display or 'inline') --string: one of 'inline', 'title' or 'inline,title'  
local displayplace = string.lower(args.display or 'inline') --string: one of 'inline', 'title' or 'inline,title'
local displayinline = string.find(displayplace, 'inline') and true or false
local displaytitle = string.find(displayplace, 'title') and true or false
local objectname = (args.name ~= '') and args.name -- string: name of the title displayed in geohack
local objectname = (args.name ~= '') and args.name -- string: name of the title displayed in geohack
local notes = (' ' and args.notes) or '' -- string: notes to de displayed after coordinates
local notes = (' ' and args.notes) or '' -- string: notes to de displayed after coordinates
local wikidata = args.wikidata -- string: set to "true" if needed
local wikidata = args.wikidata -- string: set to "true" if needed
local wikidataquery = args.wikidataquery -- table: see [[Module:Wikidata]] see function wikidatacoords
local wikidataquery = args.wikidataquery -- table: see [[Module:Wikidata]] see function wikidatacoords
local dmslatitude, dmslongitude -- table (when created)
local dmslatitude, dmslongitude -- table (when created)
local extraparams = args.extraparams or '' -- string (legacy, corresponds to geohackparams)
local extraparams = args.extraparams or '' -- string (legacy, corresponds to geohackparams)
  local trackingstring = '' -- tracking cats except error cats (already in errorstring)
  local trackingstring = '' -- tracking cats except error cats (already in errorstring)
Ligne 895 : Ligne 897 :
local latitude, longitude, precision, dmslatitude, dmslongitude -- latitude and longitude in decimal / dmslatitude and dmslongitude: tables withdms coords
local latitude, longitude, precision, dmslatitude, dmslongitude -- latitude and longitude in decimal / dmslatitude and dmslongitude: tables withdms coords
local maplink = true -- use maplink whenever it is possible
local maplink = true -- use maplink whenever it is possible
local savegeodata = nil
if args.geodata ~= nil and args.geodata ~= '' then
savegeodata = require('Module:Yesno')(args.geodata)
end
if savegeodata == nil then -- args.geodata non renseigné ou valeur non reconnue
savegeodata = (displaytitle and mw.title.getCurrentTitle():inNamespaces(0, 14, 100))
end
 
-- II extract coordinates from Wikitext
-- II extract coordinates from Wikitext
if (rawlat or rawlong) then
if (rawlat or rawlong) then
Ligne 928 : Ligne 937 :
if wikidata == 'true' then
if wikidata == 'true' then
wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision = wikidatacoords(wikidataquery)
wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision = wikidatacoords(wikidataquery)
 
if wikidatalatitude and latitude and longitude then
if wikidatalatitude and latitude and longitude then
local maxdistance = tonumber(args.maxdistance) or wikidatathreshold
local maxdistance = tonumber(args.maxdistance) or wikidatathreshold
if p._distance({latitude = latitude, longitude= longitude}, {latitude = wikidatalatitude, longitude= wikidatalongitude}, wikidataglobe) < maxdistance then
if p._distance({latitude = latitude, longitude = longitude}, {latitude = wikidatalatitude, longitude = wikidatalongitude}, wikidataglobe) < maxdistance then
trackingstring = trackingstring .. makecat(i18n.sameaswikidata)
trackingstring = trackingstring .. makecat(i18n.sameaswikidata)
else
else
Ligne 942 : Ligne 951 :
trackingstring = trackingstring .. makecat(i18n.throughwikidata)
trackingstring = trackingstring .. makecat(i18n.throughwikidata)
end
end
 
if latitude and not wikidatalatitude then
if latitude and not wikidatalatitude then
if mw.title.getCurrentTitle().namespace == 0 then
if mw.title.getCurrentTitle().namespace == 0 then
Ligne 957 : Ligne 966 :


-- IV best guesses for missing parameters
-- IV best guesses for missing parameters
 
--- globe
--- globe
if globe == '' then
if globe == '' then
Ligne 970 : Ligne 979 :
maplink = false
maplink = false
end
end
 
--- diplayformat
--- diplayformat
if not displayformat or displayformat == '' then
if not displayformat or displayformat == '' then
displayformat = globedata[globe].defaultdisplay
displayformat = globedata[globe].defaultdisplay
end
end
 
-- displayinline/displaytitle
-- displayinline/displaytitle
local displayinline = string.find(displayplace, 'inline') and true or false
local displaytitle = string.find(displayplace, 'title') and true or false
if not displayinline and not displaytitle then
if not displayinline and not displaytitle then
displayinline = true
displayinline = true
if displayplace ~= '' then  
if displayplace ~= '' then
makeerror({sortkey = 'C'}) --error if display not empty, but not not a major error, continue
makeerror({sortkey = 'C'}) --error if display not empty, but not a major error, continue
end
end
end
end
if displaytitle and mw.title.getCurrentTitle().namespace == 0 then
if displaytitle and mw.title.getCurrentTitle().namespace == 0 then
--local cattoappend=globedata[globe].trackingcat
--local cattoappend = globedata[globe].trackingcat
--Récupération des badges
--Récupération des badges
local cats=wikidatacat(globe)
local cats = wikidatacat(globe)
for i, cat in ipairs( cats ) do
for i, cat in ipairs( cats ) do
trackingstring = trackingstring .. makecat(cat)
trackingstring = trackingstring .. makecat(cat)
end
end
 
end
end
 
-- V geodata
-- V geodata
local geodata = ''
local geodata = ''
if latitude and longitude then
if savegeodata and latitude and longitude then
local latstring, longstring = tostring(latitude), tostring(longitude)
local latstring, longstring = tostring(latitude), tostring(longitude)
local primary = ''
local primary = ''


local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
local geodataparams = {[1] = latstring, [2] = longstring, [3] = extraparams }
local geodataparams = {[1] = latstring, [2] = longstring, [3] = extraparams}
if displaytitle then
if displaytitle then
geodataparams[4] = 'primary'
geodataparams[4] = 'primary'
Ligne 1 009 : Ligne 1 016 :
geodataparams.name = objectname
geodataparams.name = objectname
end
end
geodata = frame:callParserFunction('#coordinates', geodataparams )
geodata = frame:callParserFunction('#coordinates', geodataparams)
if string.find(geodata, 'error') then -- the only error that has not been caught yet is primary key
if string.find(geodata, 'error') then -- the only error that has not been caught yet is primary key
geodata = ''
geodata = ''
Ligne 1 018 : Ligne 1 025 :
local mainstring = ''
local mainstring = ''
if maplink then
if maplink then
mainstring = buildMaplinkHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams )
mainstring = buildMaplinkHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
else
else
mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname,extraparams )
mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
end
end
 
return mainstring .. notes .. trackingstring .. geodata .. showerrors()
return mainstring .. notes .. trackingstring .. geodata .. showerrors()
end
end


function p.coord(frame) -- parrses the strange parameters of Template:Coord before sending them to p.coord
function p.coord(frame) -- parses the strange parameters of Template:Coord before sending them to p.coord
local args = frame.args
local args = frame.args
local numericargs = {}
local numericargs = {}

Dernière version du 22 février 2026 à 00:17

La documentation pour ce module peut être créée à Module:Coordinates/doc

local math_mod = require( "Module:Math" )

local p = {}

local NBSP = '\194\160' -- espace insécable (code UTF-8 sur deux octets)

local i18n = {
	N = 'N',
	Nlong = 'nord',
	W = 'O',
	Wlong = 'ouest',
	E = 'E',
	Elong = 'est',
	S = 'S',
	Slong = 'sud',
	degrees = '°' .. NBSP,
	minutes = '′' .. NBSP,
	seconds = '″' .. NBSP,
	geohackurl = 'http://tools.wmflabs.org/geohack/geohack.php?language=fr',
	tooltip = 'Cartes, vues aériennes, etc.',
	errorcat = 'Page avec des balises de coordonnées mal formées',
	sameaswikidata = 'Page avec coordonnées similaires sur Wikidata',
	notaswikidata = 'Page avec coordonnées différentes sur Wikidata',
	nowikidata = 'Page sans coordonnées Wikidata',
	throughwikidata = 'Page géolocalisée par Wikidata',
	invalidFormat = 'format invalide',                                          -- 'invalid coordinate format',
	invalidNSEW = 'orientation invalide, devrait être "N", "S", "E" or "W"',    -- 'invalid direction should be "N", "S", "E" or "W"',
	invalidNS = 'orientation de latitude invalide, devrait être "N" ou "S"',    -- 'could not find latitude direction (should be N or S)',
	invalidEW = 'orientation de longitude invalide, devrait être "E" ou "W"',   -- 'could not find longitude direction (should be W or E) ',
	noCardinalDirection = 'orientation cardinale non trouvée',                  -- 'no cardinal direction found in coordinates',
	invalidDirection = 'direction invalide',                                    -- 'invalid direction',
	latitude90 = 'latitude > 90',
	longitude360 = 'longitude > 360',
	minSec60 = 'minutes ou secondes > 60',
	negativeCoode = 'en format dms les degrés doivent être positifs',           -- 'dms coordinates should be positive',
	dmIntergers = 'degrés et minutes doivent être des nombres entiers',         -- 'degrees and minutes should be integers',
	tooManyParam = 'trop de paramètres pour la latitude ou la longitude',       -- 'too many parameters for coordinates',
	coordMissing = 'latitude ou longitude absente',                             -- 'latitude or longitude missing',
	invalidGlobe = 'globe invalide' .. NBSP .. ': ',                            -- 'invalid globe:',
}
local coordParse = {
	NORTH = 'N',
	NORD = 'N',
	EAST = 'E',
	EST = 'E',
	WEST = 'W',
	O = 'W',
	OUEST = 'W',
	SOUTH = 'S',
	SUD = 'S',
}

local globedata = 	{
	--[[ notes:
		radius in kilometers (especially imprecise for non spheric bodies)
		defaultdisplay is currently disabled, activate it ?
	]]--
	ariel =  {radius = 580, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	callisto =  {radius = 2410, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	ceres =  {radius = 470, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	charon =  {radius = 1214, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	deimos =  {radius = 7, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	dione =  {radius = 560, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	enceladus =  {radius = 255, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	ganymede =  {radius = 2634, defaultdisplay = 'dec west', trackingcat = 'sur Ganymède'},
	earth =  {radius = 6371, defaultdisplay = 'dms', trackingcat = 'sur Terre'},
	europa =  {radius = 1561, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	hyperion =  {radius = 140, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	iapetus =  {radius = 725, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	['io'] =  {radius = 1322, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	jupiter =  {radius = 68911, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	mars =  {radius = 3389.5, defaultdisplay = 'dec east', trackingcat = 'sur Mars'},
	mercury =  {radius = 2439.7, defaultdisplay = 'dec west', trackingcat = 'sur Mercure'},
	mimas =  {radius = 197, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	miranda =  {radius = 335, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	moon =  {radius = 1736, defaultdisplay = 'dec', trackingcat = 'sur la Lune'},
	neptune =  {radius = 24553, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	oberon =  {radius = 761, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	phoebe =  {radius = 110, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	phobos =  {radius = 11, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	pluto =  {radius = 1185, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	rhea =  {radius = 765, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	saturn =  {radius = 58232, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	titan =  {radius = 2575.5, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	tethys =  {radius = 530, defaultdisplay = 'dec west', trackingcat = 'extraterrestre'},
	titania =  {radius = 394, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	triton =  {radius = 1353, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	umbriel =  {radius = 584, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	uranus =  {radius = 25266, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'},
	venus =  {radius = 6051.8, defaultdisplay = 'dec east', trackingcat = 'sur Vénus'},
	vesta =  {radius = 260, defaultdisplay = 'dec east', trackingcat = 'extraterrestre'}
}
globedata[''] = globedata.earth

local wikidatathreshold = 10 -- si la distance entre coordonnées Wikipédia et Wikidata dépasse ce seuil (en kilomètres), une catégorie de maintenance est ajoutée
local lang = mw.language.getContentLanguage()
local default_zoom = 13

local function makecat(cat, sortkey)
	if type( sortkey ) == 'string' then
		return '[[Category:' .. cat .. '|' .. sortkey .. ']]'
	else
		return '[[Category:' .. cat .. ']]'
	end
end

----------------------------------------
--Error handling
	--[[ Notes:
	when errors occure a new error message is concatenated to errorstring
	an error message contains an error category with a sortkey
	For major errors, it can also display an error message (the error message will the usually be returned and the function terminated)
	More minor errors do only add a category, so that readers are not bothered with error texts
	sortkeys:
		* A: invalid latitude, longitude or direction
		* B: invalid globe
		* C: something wrong with other parameters
		* D: more than one primary coord
	]]--

local errorstring = ''

local function makeerror(args)
	local errormessage = ''
	if args.message then
		errormessage = '<strong class="error"> Coordonnées' .. NBSP .. ': ' .. args.message .. '</strong>'
	end
	local errorcat = ''
	if mw.title.getCurrentTitle().namespace == 0 then
		errorcat = makecat(i18n.errorcat, args.sortkey)
	end
	errorstring = errormessage .. errorcat -- reinitializes the string to avoid absurdly long messages
	return nil
end

local function showerrors()
	return errorstring
end



-- Distance computation
function p._distance(a, b, globe) -- calcule la [[distance orthodromique]] en kilomètres entre deux points du globe

	globe = string.lower(globe or 'earth')

	-- check arguments and converts degreees to radians
	local latA, latB, longA, longB = a.latitude, b.latitude, a.longitude, b.longitude
	if (not latA) or (not latB) or (not longA) or (not longB) then return
		error('coordinates missing, can\'t compute distance')
	end
	if type(latA) ~= 'number' or type(latB) ~= 'number' or type(longA) ~= 'number' or type(longB) ~= 'number' then
		error('coordinates are not numeric, can\'t compute distance')
	end
		if not globe or not globedata[globe] then
		return error('globe: ' .. globe .. 'is not supported')
	end

	-- calcul de la distance angulaire en radians
	local convratio = math.pi / 180 -- convertit en radians
	latA, latB, longA, longB = convratio * latA, convratio * latB, convratio * longA, convratio * longB
	local cosangle = math.sin(latA) * math.sin(latB) + math.cos(latA) * math.cos(latB) * math.cos(longB - longA)
	if cosangle >= 1 then -- may be above one because of rounding errors
		return 0
	end
	local angle = math.acos(cosangle)
	-- calcul de la distance en km
	local radius = globedata[globe].radius
	return radius * angle
end

function p.distance(frame)
	local args = frame.args
	return p._distance(
		{latitude = tonumber(args.latitude1), longitude = tonumber(args.longitude1)},
		{latitude = tonumber(args.latitude2), longitude = tonumber(args.longitude2)},
		args.globe)
end

local function geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)
	extraparams = extraparams or ''
	local geohacklatitude, geohacklongitude
	-- format latitude and longitude for the URL
	if tonumber(decLat) < 0 then
		geohacklatitude = tostring(-tonumber(decLat)) .. '_S'
	else
		geohacklatitude = decLat .. '_N'
	end
	if tonumber(decLong) < 0  then
		geohacklongitude = tostring(-tonumber(decLong)) .. '_W'
	elseif globedata[globe].defaultdisplay == 'dec west' then
		geohacklongitude = decLong .. '_W'
	else
		geohacklongitude = decLong .. '_E'
	end
	-- prepares the 'paramss=' parameter
	local geohackparams = geohacklatitude .. '_' .. geohacklongitude .. '_' ..extraparams
	-- concatenate parameteres for geohack
	return i18n.geohackurl ..
		"&pagename=" .. mw.uri.encode(mw.title.getCurrentTitle().prefixedText, "WIKI") ..
		"&params=" .. geohackparams ..
		(objectname and ("&title=" .. mw.uri.encode(objectname)) or "")
end

--HTML builder for a geohack link
local function buildHTML(decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
	-- geohack url
	local url = geoHackUrl(decLat, decLong, globe, displayformat, objectname, extraparams)

	-- displayed coordinates
	local displaycoords
	if string.sub(displayformat, 1, 3) == 'dec' then
		displaycoords = p.displaydec(decLat, decLong, displayformat)
	else
		displaycoords = {
			p.displaydmsdimension(dmsLat, displayformat),
			p.displaydmsdimension(dmsLong, displayformat),
		}
	end

	-- build coordinate in h-geo / h-card microformat
	local globeNode
	if globe and globe ~= 'earth' then
		globeNode = mw.html.create('data')
			:addClass('p-globe')
			:attr{ value = globe }
			:done()
	end

	local coordNode = mw.html.create('')
	if objectname then
		coordNode = mw.html.create('span')
			:addClass('h-card')
			:tag('data')
				:addClass('p-name')
				:attr{ value = objectname }
				:done()
	end
	coordNode
		:tag('span')
			:addClass('h-geo')
			:addClass('geo-' .. string.sub(displayformat, 1, 3))
			:tag('data')
				:addClass('p-latitude')
				:attr{ value = decLat }
				:wikitext( displaycoords[1] )
				:done()
			:wikitext(", ")
			:tag('data')
				:addClass('p-longitude')
				:attr{ value = decLong }
				:wikitext( displaycoords[2] )
				:done()
			:node( globeNode )
			:done()

	-- buid GeoHack link
	local root = mw.html.create('span')
		:addClass('plainlinks nourlexpansion')
		:attr('title', i18n.tooltip)
		:wikitext('[' .. url )
		:node(coordNode)
		:wikitext("]")
		:done()

	-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
	local inlineText = displayinline and tostring(root) or ''
	local titleText = ''
	if displaytitle then
		local htmlTitle = mw.html.create('span')
			:attr{ id = 'coordinates' }
			:addClass( displayinline and 'noprint' or nil )
			:node( root )
		local frame = mw.getCurrentFrame()
		titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
	end

	return inlineText .. titleText
end

local function zoom( extraparams )
	local zoomParam = extraparams:match( '%f[%w]zoom: ?(%d+)' )
	if zoomParam then
		return zoomParam
	end

	local scale = extraparams:match( '%f[%w]scale: ?(%d+)' )
	if scale then
		return math.floor(math.log10( 1 / tonumber( scale ) ) * 3 + 25)
	end

	local extraType = extraparams:match( '%f[%w]type: ?(%w+)' )
	if extraType then
		local zoomType = {
			country = 5,
			state = 6,
			adm1st = 7,
			adm2nd = 8,
			city = 9,
			isle = 10,
			mountain = 10,
			waterbody = 10,
			airport = 12,
			landmark = 13,
		}
		return zoomType[ extraType ]
	end
end

--HTML builder for a geohack link
local function buildMaplinkHTML( decLat, decLong, dmsLat, dmsLong, globe, displayformat, displayinline, displaytitle, objectname, extraparams )
	-- displayed coordinates
	local displaycoords
	if string.sub(displayformat, 1, 3) == 'dec' then
		displaycoords = p.displaydec(decLat, decLong, displayformat)
	else
		displaycoords = {
			p.displaydmsdimension(dmsLat, displayformat),
			p.displaydmsdimension(dmsLong, displayformat),
		}
	end

	-- JSON for maplink
	local jsonParams = {
		type = 'Feature',
		geometry = {
			type ='Point',
			coordinates = {
				math_mod._round( decLong, 6 ), -- max precision in GeoJSON format
				math_mod._round( decLat, 6 )
			}
		},
		properties = {
			['marker-color'] = "228b22",
		}
	}
	if objectname then
		jsonParams.properties.title = objectname
	end
	-- ajout de geoshape via externaldata
	local geoshape = extraparams:match( '%f[%w]geoshape: ?(Q%d+)' )
	if not geoshape and displaytitle and mw.wikibase.getEntity() then
		geoshape = mw.wikibase.getEntity().id
	end
	if geoshape then
		jsonParams = {
			jsonParams,
			{
				type = 'ExternalData',
				service = 'geoshape',
				ids = geoshape,
				properties = {
					['fill-opacity'] = 0.2
				}
			}
		}
	end

	local maplink = mw.getCurrentFrame():extensionTag{
		name = 'maplink',
		content = mw.text.jsonEncode( jsonParams ),
		args = {
			text = displaycoords[1] .. ", " .. displaycoords[2],
			zoom = zoom( extraparams ) or default_zoom,
			latitude = decLat,
			longitude = decLong,
		}
	}

	-- format result depending on args["display"] (nil, "inline", "title", "inline,title")
	local inlineText = displayinline and maplink or ''
	local titleText = ''
	if displaytitle then
		local htmlTitle = mw.html.create('span')
			:attr{ id = 'coordinates' }
			:addClass( displayinline and 'noprint' or nil )
			:wikitext( maplink )
		local frame = mw.getCurrentFrame()
		titleText = frame:extensionTag( 'indicator', tostring(htmlTitle), { name = 'coordinates' } )
	end

	return inlineText .. titleText
end

-- dms specific funcions

local function twoDigit( value )
	if ( value < 10 ) then
		value = '0' .. lang:formatNum( value )
	else
		value = lang:formatNum( value )
	end
	return value
end

function p.displaydmsdimension(valuetable, format) -- formate en latitude ou une longitude dms
	local str = ''
	local direction = valuetable.direction
	local degrees, minutes, seconds = '', '', ''
	local dimension

	if format == 'dms long' then
		direction = i18n[direction .. 'long']
	else
		direction = i18n[direction]
	end
	degrees = lang:formatNum( valuetable.degrees ) .. i18n.degrees

	if valuetable.minutes then
		minutes = twoDigit( valuetable.minutes ) .. i18n.minutes
	end
	if valuetable.seconds then
		seconds = twoDigit( valuetable.seconds ) .. i18n.seconds
	end
	return degrees .. minutes .. seconds .. direction
end

local function validdms(coordtable)
	local direction = coordtable.direction
	local degrees = coordtable.degrees or 0
	local minutes = coordtable.minutes or 0
	local seconds = coordtable.seconds or 0
	local dimension = coordtable.dimension
	if not dimension then
		if direction == 'N' or direction == 'S' then
			dimension = 'latitude'
		elseif direction == 'E' or direction == 'W' then
			dimension = 'longitude'
		else
			makeerror({message = i18n.invalidNSEW, sortkey = 'A'})
			return false
		end
	end

	if type(degrees) ~= 'number' or type(minutes) ~= 'number' or type(seconds) ~= 'number' then
		makeerror({message = i18n.invalidFormat, sortkey = 'A'})
		return false
	end

	if dimension == 'latitude' and direction ~= 'N' and direction ~= 'S' then
		makeerror({message = i18n.invalidNS, sortkey = 'A'})
		return false
	end
	if dimension == 'longitude' and direction ~= 'W' and direction ~= 'E' then
		makeerror({message = i18n.invalidEW, sortkey = 'A'})
		return false
	end

	if dimension == 'latitude' and degrees > 90 then
		makeerror({message = i18n.latitude90, sortkey = 'A'})
		return false
	end

	if dimension == 'longitude' and degrees > 360 then
		makeerror({message = i18n.longitude360, sortkey = 'A'})
		return false
	end

	if degrees < 0 or minutes < 0 or seconds < 0 then
		makeerror({message = i18n.negativeCoode, sortkey = 'A'})
		return false
	end

	if minutes > 60 or seconds > 60 then
		makeerror({message = i18n.minSec60, sortkey = 'A'})
		return false
	end
	if (math.floor(degrees) ~= degrees and minutes ~= 0) or (math.floor(minutes) ~= minutes and seconds ~= 0) then
		makeerror({message = i18n.dmIntergers, sortkey = 'A'})
		return false
	end
	return true
end

local function builddmsdimension(degrees, minutes, seconds, direction, dimension)
	-- no error checking, done in function validdms
	local dimensionobject = {}

	-- direction and dimension (= latitude or longitude)
	dimensionobject.direction = direction
	if dimension then
		dimensionobject.dimension = dimension
	elseif direction == 'N' or direction == 'S' then
		dimensionobject.dimension = 'latitude'
	elseif direction == 'E' or direction == 'W' then
		dimensionobject.dimension = 'longitude'
	end

	-- degrees, minutes, seconds
	dimensionobject.degrees = tonumber(degrees)
	dimensionobject.minutes = tonumber(minutes)
	dimensionobject.seconds = tonumber(seconds)
	if degrees and not dimensionobject.degrees then dimensionobject.degrees = 'error' end
	if minutes and not dimensionobject.minutes then dimensionobject.minutes = 'error' end
	if seconds and not dimensionobject.seconds then dimensionobject.seconds = 'error' end
	return dimensionobject
end

function p._parsedmsstring( str, dimension ) -- prend une séquence et donne des noms aux paramètres
	-- output table: { latitude=, longitude = , direction =  }
	if type( str ) ~= 'string' then
		return nil
	end
	str = mw.ustring.gsub( mw.ustring.upper( str ), '%a+', coordParse )
	if not tonumber( str ) and not str:find( '/' ) and str:find( '°' ) then
		local str2 = mw.ustring.gsub( str, '[°″′\"\'\194\160 ]+', '/' )
		-- avoid cases were there is degree ans seconds but no minutes
		if not mw.ustring.find( str, '[″"]' ) or mw.ustring.find( str, '%d[′\'][ \194\160%d]' ) then
			str = str2
		end
	end
	if not tonumber(str) and not string.find(str, '/') then
		makeerror({message = i18n.invalidFormat, sortkey = 'A'})
		return nil
	end
	local args = mw.text.split(str, '/', true)
	if #args > 4 then
		makeerror({message = i18n.tooManyParam, sortkey = 'A'})
	end
	local direction = mw.text.trim(args[#args])
	table.remove(args)
	local degrees, minutes, seconds = args[1], args[2], args[3]
	local dimensionobject = builddmsdimension(degrees, minutes, seconds, direction, dimension)
	if validdms(dimensionobject) then
		return dimensionobject
	else
		return nil
	end
end

--- decimal specific functions
function p.displaydec(latitude, longitude, format)
	local lat = lang:formatNum( latitude )
	local long = lang:formatNum( longitude )

	if format == 'dec west' or  format == 'dec east' then
		local symbolNS, symbolEW = i18n.N, i18n.E
		if latitude < 0 then
			symbolNS = i18n.S
			lat = lang:formatNum( -latitude )
		end
		if format == 'dec west' then
			symbolEW = i18n.W
		end
		if longitude < 0 then
			long = lang:formatNum( 360 + longitude )
		end

		return { lat .. i18n.degrees .. symbolNS,  long ..  i18n.degrees .. symbolEW }

	else
		return { lat, long }
	end
end


local function parsedec(dec, coordtype, globe) -- coordtype = latitude or longitude
	dec = mw.text.trim(dec)
	if not dec then
		return nil
	end
	if coordtype ~= 'latitude' and coordtype ~= 'longitude' then
		makeerror({'invalid coord type', sortkey = "A"})
		return nil
	end
	local numdec = tonumber(dec) -- numeric value, kept separated as it looses significant zeros
	if not numdec then -- tries the decimal + direction format
		dec = mw.ustring.gsub( mw.ustring.upper( dec ), '%a+', coordParse )
		local direction = mw.ustring.sub(dec, mw.ustring.len(dec), mw.ustring.len(dec))
		dec = mw.ustring.sub(dec, 1, mw.ustring.len(dec)-2) -- removes the /N at the end
		if not dec or not tonumber(dec) then
			return nil
		end
		if direction == 'N' or direction == 'E' or direction == 'W' and globedata[globe].defaultdisplay == 'dec west' then
			numdec = tonumber( dec )
		elseif direction == 'W' or direction == 'S' then
			dec = '-' .. dec
			numdec = tonumber( dec )
		else
			if coordtype == 'latitude' then
				makeerror({message = i18n.invalidNS, sortkey = 'A'})
			else
				makeerror({message = i18n.invalidEW, sortkey = 'A'})
			end
			return nil
		end
	end

	if coordtype == 'latitude' and math.abs(numdec) > 90 then
		makeerror({message = i18n.latitude90 , sortkey = 'A'})
		return nil
	end
	if coordtype == 'longitude' and math.abs(numdec) > 360 then
		makeerror({message = i18n.longitude360 , sortkey = 'A'})
		return nil
	end
	return dec
end

-- dms/dec conversion functions
local function convertprecision(precision) -- converts a decimal precision like "2" into "dm"
	if precision >= 3 then
		return 'dms'
	elseif precision >=1 then
		return 'dm'
	else
		return 'd'
	end
end

local function determinedmsprec(decs) -- returns the most precision for a dec2dms conversion, depending on the most precise value in the decs table
	local precision = 0
	for d, val in ipairs(decs) do
		precision = math.max(precision, math_mod._precision(val))
	end
	return convertprecision(precision)
end

local function dec2dms_d(dec)
	local degrees = math_mod._round( dec, 0 )
	return degrees
end

local function dec2dms_dm(dec)
	dec = math_mod._round( dec * 60, 0 )
	local minutes = dec % 60
	dec = math.floor( (dec - minutes) / 60 )
	local degrees = dec % 360
	return degrees, minutes
end

local function dec2dms_dms(dec)
	dec = math_mod._round( dec * 60 * 60, 0 )
	local seconds = dec % 60
	dec = math.floor( (dec - seconds) / 60 )
	local minutes = dec % 60
	dec = math.floor( (dec - minutes) / 60 )
	local degrees = dec % 360
	return degrees, minutes, seconds
end

function p._dec2dms(dec, coordtype, precision, globe) -- coordtype: latitude or longitude
	local degrees, minutes, seconds

	-- vérification du globe
	if not ( globe and globedata[ globe ] ) then
		globe = 'earth'
	end

	-- precision
	if not precision or precision == '' then
		precision = determinedmsprec({dec})
	end
	if precision ~= 'd' and precision ~= 'dm' and precision ~= 'dms' then
		return makeerror({sortkey = 'C'})
	end
	local dec = tonumber(dec)

	-- direction
	local direction
	if coordtype == 'latitude' then
		if dec < 0 then
			direction = 'S'
		else
			direction = 'N'
		end
	elseif coordtype == 'longitude' then
		if dec < 0 or globedata[globe].defaultdisplay == 'dec west' then
			direction = 'W'
		else
			direction = 'E'
		end
	end

	-- conversion
	dec = math.abs(dec) -- les coordonnées en dms sont toujours positives
	if precision == 'dms' then
		degrees, minutes, seconds = dec2dms_dms(dec)
	elseif precision == 'dm' then
		degrees, minutes = dec2dms_dm(dec)
	else
		degrees = dec2dms_d(dec)
	end
	return builddmsdimension(degrees, minutes, seconds, direction)
end

function p.dec2dms(frame) -- legacy function somewhat cumbersome syntax
	local args = frame.args
	local dec = args[1]
	if not tonumber(dec) then
		makeerror({message = i18n.invalidFormat, sortkey = 'A'})
		return showerrors()
	end
	local dirpositive = string.lower(args[2] or '')
	local dirnegative = string.lower(args[3] or '')
	local precision = string.lower(args[4] or '')
	local displayformat, coordtype

	if dirpositive == 'n' or dirpositive == 'nord' then
		coordtype = 'latitude'
	else
		coordtype = 'longitude'
	end
	if dirpositive == 'nord' or dirpositive == 'est' or dirnegative == 'ouest' or dirnegative == 'sud' then
		displayformat = 'dms long'
	end
	local coordobject = p._dec2dms(dec, coordtype, precision)
	if coordobject then
		return p.displaydmsdimension(coordobject, displayformat) .. showerrors()
	else
		return showerrors()
	end
end


function p._dms2dec(dmsobject) -- transforme une table degré minute secondes en nombre décimal
	local direction, degrees, minutes, seconds = dmsobject.direction, dmsobject.degrees, dmsobject.minutes, dmsobject.seconds
	local factor = 0
	local precision = 0
	if not minutes then minutes = 0 end
	if not seconds then seconds = 0 end

	if direction == "N" or direction == "E" then
		factor = 1
	elseif direction == "W" or direction == "S" then
		factor = -1
	elseif not direction then
		makeerror({message = i18n.noCardinalDirection, sortkey = 'A'})
		return nil
	else
		makeerror({message = i18n.invalidDirection, sortkey = 'A'})
		return nil
	end

	if dmsobject.seconds then -- vérifie la précision des données initiales
		precision = 5 + math.max( math_mod._precision(tostring(seconds), 0 ) ) -- passage par des strings assez tarabiscoté ?
	elseif dmsobject.minutes then
		precision = 3 + math.max( math_mod._precision(tostring(minutes), 0 ) )
	else
		precision = math.max( math_mod._precision(tostring(degrees), 0 ) )
	end

	local decimal = factor * (degrees+(minutes+seconds/60)/60)
	return math_mod._round(decimal, precision)
end

function p.dms2dec(frame) -- legacy function, somewhat bizarre syntax
	local args = frame.args
	if tonumber(args[1]) then
		return args[1] -- coordonnées déjà en décimal
	elseif not args[2] then
		local dmsobject = p._parsedmsstring(args[1])
		if dmsobject then
			return p._dms2dec(dmsobject) -- coordonnées sous la fore 23/22/N
		else
			local coordType
			if args[1]:match( '[NS]' ) then
				coordType = 'latitude'
			elseif args[1]:match( '[EWO]') then
				coordType = 'longitude'
			end
			if coordType then
				local result = parsedec( args[1],  coordType, args.globe or 'earth' )
				if result then
					return result
				end
			end
			return showerrors()
		end
	else
		return p._dms2dec({direction = args[1], degrees = tonumber(args[2]), minutes = tonumber(args[3]), seconds = tonumber(args[4])})
	end
end

-- Wikidata
local function convertwikidataprecision(precision) -- converts a decima like "0.1" into "dm"
	if precision < 0.016 then
		return 'dms'
	elseif precision < 1 then
		return 'dm'
	else
		return 'd'
	end
end

local function wikidatacoords(query)
	query = query or {property = 'p625'}
	query.formatting = 'raw'
	local wd = require('Module:Wikidata')
	local claim = wd.getClaims(query)
	if claim and claim[1] then -- redundant but more robust in case of a change in the code of Module:Wikidata
		local coords = wd.formatSnak(claim[1].mainsnak) -- todo: check for special values
		-- Wikidata does not handle correctly +West longitudes
		if globedata[ coords.globe ] and globedata[ coords.globe ].defaultdisplay == 'dec west' then
			coords.longitude = math.abs( coords.longitude )
		end
		return coords.latitude, coords.longitude, coords.globe or 'earth', convertwikidataprecision(coords.precision or .001)
	end
	return nil
end


local function wikidatacat(globe)
	--catbase= Article géolocalisé sur Terre
	local entitycat = mw.wikibase.getEntity()

	local basecat = 'Article géolocalisé'
	local finalcat = {}
	--BADGES
	if entitycat then
		--BADGES
	   	for i, badgeId in ipairs( entitycat.sitelinks['frwiki'].badges ) do
			if badgeId == 'Q17437796'  then
				basecat = string.gsub(basecat, "Article géolocalisé", "Article de qualité géolocalisé")
			end
			if badgeId == 'Q17437798'  then
				basecat = string.gsub(basecat, "Article géolocalisé", "Bon article géolocalisé")
			end
		end
	end

	if globe == 'earth'  then
		if entitycat and entitycat.claims  then
			local country = entitycat.claims['P17']
			if not country then
				--pas pays à récupérer
				basecat = basecat .. ' sur Terre'
				table.insert(finalcat, basecat)
			else
				--parfois plusieurs pays
				for i, paysId in ipairs( country ) do
					--on fait confiance au label wikidata
					local gdataone, qid

					if paysId.mainsnak.snaktype == 'value' then
						qid = paysId.mainsnak.datavalue.value['numeric-id']
						gdataone = mw.loadData("Module:Drapeau/Data").data[qid]
					else
						--Bir Tawil n'a pas de pays connu
						qid = '?'
					end
					if gdataone ~= nil then
						local genre = mw.loadData("Module:Drapeau/Domaine").genre
						local prep = genre[gdataone['genre']]['en'] or 'en '
						local thecat = basecat .. ' '..prep ..mw.wikibase.label('Q'.. qid)
						if mw.title.new('category:'..thecat).exists then
							table.insert(finalcat, thecat)
						else
							--Dommage!
							mw.log(thecat .. ' à créer')
						end
					else
						--pas d'id?
						mw.log(qid .. ' à paramétrer')
					end
				end
				if #finalcat == 0 then
					--pas pays à récupérer
					basecat = basecat .. ' sur Terre'
					table.insert(finalcat, basecat)
				end
			end
		else
			--pas wikidata
			basecat = basecat .. ' sur Terre'
			table.insert(finalcat, basecat)
		end
	elseif globedata[globe] then
		basecat = basecat .. ' ' .. globedata[globe].trackingcat
		table.insert(finalcat, basecat)
	else
		basecat = basecat .. ' extraterrestre'
		table.insert(finalcat, basecat)
	end
	return finalcat
end

 -- main function for displaying coordinates
function p._coord(args)

	-- I declare variable
	local displayformat = args.format -- string: one of: 'dms', 'dms long', 'dec', 'dec east' and 'dec west'
	local displayplace = string.lower(args.display or 'inline') --string: one of 'inline', 'title' or 'inline,title'
	local displayinline = string.find(displayplace, 'inline') and true or false
	local displaytitle = string.find(displayplace, 'title') and true or false
	local objectname = (args.name ~= '') and args.name -- string: name of the title displayed in geohack
	local notes = (' ' and args.notes) or '' -- string: notes to de displayed after coordinates
	local wikidata = args.wikidata -- string: set to "true" if needed
	local wikidataquery = args.wikidataquery -- table: see [[Module:Wikidata]] see function wikidatacoords
	local dmslatitude, dmslongitude -- table (when created)
	local extraparams = args.extraparams or '' -- string (legacy, corresponds to geohackparams)
 	local trackingstring = '' -- tracking cats except error cats (already in errorstring)
 	local rawlat, rawlong = args.latitude, args.longitude
 	if rawlat == '' then rawlat = nil end
 	if rawlong == '' then rawlong = nil end
 	local globe = string.lower( args.globe or extraparams:match('globe:(%a+)') or '' ) -- string: see the globedata table for accepted values
	local latitude, longitude, precision, dmslatitude, dmslongitude -- latitude and longitude in decimal / dmslatitude and dmslongitude: tables withdms coords
	local maplink = true -- use maplink whenever it is possible
	local savegeodata = nil
	if args.geodata ~= nil and args.geodata ~= '' then
		savegeodata = require('Module:Yesno')(args.geodata)
	end
	if savegeodata == nil then -- args.geodata non renseigné ou valeur non reconnue
		savegeodata = (displaytitle and mw.title.getCurrentTitle():inNamespaces(0, 14, 100))
	end

	-- II extract coordinates from Wikitext
	if (rawlat or rawlong) then
		if (not rawlat) or (not rawlong) then -- if latitude is provided so should be longitude
			makeerror({message = i18n.coordMissing, sortkey = 'A'})
			return showerrors()
		end
		latitude = parsedec(rawlat, 'latitude', globe)

		if latitude then -- if latitude is decimal
			longitude = parsedec(rawlong, 'longitude', globe) -- so should be longitude
			precision = determinedmsprec({latitude, longitude}) -- before conversion from string to number for trailing zeros
			if not latitude or not longitude then
				if errorstring == '' then
					makeerror({message = i18n.invalidFormat, sortkey = 'A'})
				end
				return showerrors()
			end
			dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe)
			latitude, longitude = tonumber(latitude), tonumber(longitude)
		else -- if latitude is not decimal try to parse it as a dms string
			dmslatitude, dmslongitude = p._parsedmsstring(args.latitude, 'latitude'), p._parsedmsstring(args.longitude, 'longitude')
			if not dmslatitude or not dmslongitude then
				return showerrors()
			end
			latitude, longitude = p._dms2dec(dmslatitude), p._dms2dec(dmslongitude)
		end
	end

	-- III extract coordinate data from Wikidata and compare them to local data
	local wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision
	if wikidata == 'true' then
		wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision = wikidatacoords(wikidataquery)

		if wikidatalatitude and latitude and longitude then
			local maxdistance = tonumber(args.maxdistance) or wikidatathreshold
			if p._distance({latitude = latitude, longitude = longitude}, {latitude = wikidatalatitude, longitude = wikidatalongitude}, wikidataglobe) < maxdistance then
				trackingstring = trackingstring .. makecat(i18n.sameaswikidata)
					else
				trackingstring = trackingstring .. makecat(i18n.notaswikidata)
			end
		end
		if wikidatalatitude and not latitude then
			latitude, longitude, globe, precision = wikidatalatitude, wikidatalongitude, wikidataglobe, wikidataprecision
			dmslatitude, dmslongitude = p._dec2dms(latitude, 'latitude', precision), p._dec2dms(longitude, 'longitude', precision, globe)
			trackingstring = trackingstring .. makecat(i18n.throughwikidata)
		end

		if latitude and not wikidatalatitude then
			if mw.title.getCurrentTitle().namespace == 0 then
				trackingstring = trackingstring .. makecat(i18n.nowikidata)
			end
		end
	end


	-- exit if stil no latitude or no longitude
	if not latitude and not longitude then
		return nil -- ne rien ajouter ici pour que l'appel à cette fonction retourne bien nil en l'absence de données
	end

	-- IV best guesses for missing parameters

	--- globe
	if globe == '' then
		globe = 'earth'
	end
	if not globedata[globe] then
		makeerror({message = i18n.invalidGlobe .. globe})
		globe = 'earth'
	end
	if globe ~= 'earth' then
		extraparams = extraparams .. '_globe:' .. globe -- pas de problème si le globe est en double
		maplink = false
	end

	--- diplayformat
	if not displayformat or displayformat == '' then
		displayformat = globedata[globe].defaultdisplay
	end

	-- displayinline/displaytitle
	if not displayinline and not displaytitle then
		displayinline = true
		if displayplace ~= '' then
			makeerror({sortkey = 'C'}) --error if display not empty, but not a major error, continue
		end
	end
	if displaytitle and mw.title.getCurrentTitle().namespace == 0 then
		--local cattoappend = globedata[globe].trackingcat
		--Récupération des badges
		local cats = wikidatacat(globe)
		for i, cat in ipairs( cats ) do
			trackingstring = trackingstring .. makecat(cat)
		end

	end

-- V geodata
	local geodata = ''
	if savegeodata and latitude and longitude then
		local latstring, longstring = tostring(latitude), tostring(longitude)
		local primary = ''

		local frame = mw.getCurrentFrame()
		local geodataparams = {[1] = latstring, [2] = longstring, [3] = extraparams}
		if displaytitle then
			geodataparams[4] = 'primary'
		end
		if objectname then
			geodataparams.name = objectname
		end
		geodata = frame:callParserFunction('#coordinates', geodataparams)
		if string.find(geodata, 'error') then -- the only error that has not been caught yet is primary key
			geodata = ''
			makeerror({sortkey='D'})
		end
	end
-- VI final output
	local mainstring = ''
	if maplink then
		mainstring = buildMaplinkHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
	else
		mainstring = buildHTML(latitude, longitude, dmslatitude, dmslongitude, globe, displayformat, displayinline, displaytitle, objectname, extraparams)
	end

	return mainstring .. notes .. trackingstring .. geodata .. showerrors()
end

function p.coord(frame) -- parses the strange parameters of Template:Coord before sending them to p.coord
	local args = frame.args
	local numericargs = {}
	for i, j in ipairs(args) do
		args[i] = mw.text.trim(j)
		if args[i] ~= '' then
			table.insert(numericargs, args[i])
		end
	end

	if #numericargs %2 == 1 then -- if the number of args is odd, the last one provides formatting parameters
		args.extraparams = numericargs[#numericargs]
		if #numericargs == 1 and tonumber(numericargs[1]) then
			makeerror({message = i18n.coordMissing, sortkey = 'A'})
			return showerrors()
		end
		table.remove(numericargs)
	end
	for i, j in ipairs(numericargs) do
		if i <= (#numericargs / 2) then
			if not args.latitude then
				args.latitude = j
			else
				args.latitude =	args.latitude .. '/' .. j
			end
		else
			if not args.longitude then
				args.longitude = j
			else
				args.longitude = args.longitude .. '/' .. j
			end
		end
	end

	if string.find(args.latitude or '', 'E') or string.find(args.latitude or '', 'W') then
		args.latitude, args.longitude = args.longitude, args.latitude
	end
	return p._coord(args)
end

function p.Coord(frame)
	return p.coord(frame)
end

function p.latitude(frame) -- helper function pour infobox, à déprécier
	local args = frame.args
	local latitude  = frame.args[1]
	if latitude and mw.text.trim(latitude) ~= '' then
		return latitude
	elseif frame.args['wikidata'] == 'true' then
		local lat, long = wikidatacoords()
		return lat
	end
end
function p.longitude(frame) -- helper function pour infobox, à déprécier
	local args = frame.args
	local longitude = frame.args[1]
	if longitude and mw.text.trim(longitude) ~= '' then
		return longitude
	elseif frame.args['wikidata'] == 'true' then
		local lat, long = wikidatacoords()
		return long
	end
end


return p