વિભાગ:Coordinates: આવૃત્તિઓ વચ્ચેનો તફાવત

Content deleted Content added
re-sync; call coordinates parser function again; no other apparent compatibility issues with other modules
major update to add support for new OSM maps and maintenance categories for comparing coordinates to Wikidata
લીટી ૧:
--[[
This module is intended to replace the functionality of {{Coord}} and related
templates. It provides several methods, including
 
This module is intended to provide functionality of {{location}} and related
{{#invoke:Coordinates | coord }} : General function formatting and displaying
templates.
coordinate values.
 
Please do not modify this code without applying the changes first at Module:Coordinates/sandbox and testing
{{#invoke:Coordinates | dec2dms }} : Simple function for converting decimal
at Module:Coordinates/sandbox/testcases and Module talk:Coordinates/sandbox/testcases.
degree values to DMS format.
Authors and maintainers:
* User:Jarekt
* User:Ebraminio
 
Functions:
{{#invoke:Coordinates | dms2dec }} : Simple function for converting DMS format
*function p.LocationTemplateCore(frame)
to decimal degree format.
**function p.GeoHack_link(frame)
 
***function p.lat_lon(frame)
{{#invoke:Coordinates | link }} : Export the link used to reach the tools
****function p._deg2dms(deg,lang)
***function p.externalLink(frame)
****function p._externalLink(site, globe, latStr, lonStr, lang, attributes)
**function p._getHeading(attributes)
**function p.externalLinksSection(frame)
***function p._externalLink(site, globe, latStr, lonStr, lang, attributes)
*function p.getHeading(frame)
*function p.deg2dms(frame)
 
]]
 
-- =======================================
require('Module:No globals')
-- === Dependencies ======================
-- =======================================
local i18n = require('Module:I18n/coordinates') -- get localized translations of site names
local yesno = require('Module:Yesno')
 
-- =======================================
local math_mod = require("Module:Math")
-- === Hardwired parameters ==============
local coordinates = {};
-- =======================================
 
-- Angles associated with each abriviation of compass point names. See [[:en:Points of the compass]]
local current_page = mw.title.getCurrentTitle()
local compass_points = {
local page_name = mw.uri.encode( current_page.prefixedText, 'WIKI' );
N = 0,
local coord_link = '//tools.wmflabs.org/geohack/geohack.php?pagename=' .. page_name .. '&params='
NBE = 11.25,
NNE = 22.5,
NEBN = 33.75,
NE = 45,
NEBE = 56.25,
ENE = 67.5,
EBN = 78.75,
E = 90,
EBS = 101.25,
ESE = 112.5,
SEBE = 123.75,
SE = 135,
SEBS = 146.25,
SSE = 157.5,
SBE = 168.75,
S = 180,
SBW = 191.25,
SSW = 202.5,
SWBS = 213.75,
SW = 225,
SWBW = 236.25,
WSW = 247.5,
WBS = 258.75,
W = 270,
WBN = 281.25,
WNW = 292.5,
NWBW = 303.75,
NW = 315,
NWBN = 326.25,
NNW = 337.5,
NBW = 348.75,
}
 
-- files to use for different headings
--[[ Helper function, replacement for {{coord/display/title}} ]]
local heading_icon = {
local function displaytitle(s, notes)
[ 1] = 'File:Compass-icon bb N.svg',
local l = "[[Geographic coordinate system|Coordinates]]: " .. s
[ 2] = 'File:Compass-icon bb NbE.svg',
local co = '<span id="coordinates">' .. l .. notes .. '</span>';
[ 3] = 'File:Compass-icon bb NNE.svg',
return '<span style="font-size: small;">' .. co .. '</span>';
[ 4] = 'File:Compass-icon bb NEbN.svg',
end
[ 5] = 'File:Compass-icon bb NE.svg',
[ 6] = 'File:Compass-icon bb NEbE.svg',
[ 7] = 'File:Compass-icon bb ENE.svg',
[ 8] = 'File:Compass-icon bb EbN.svg',
[ 9] = 'File:Compass-icon bb E.svg',
[10] = 'File:Compass-icon bb EbS.svg',
[11] = 'File:Compass-icon bb ESE.svg',
[12] = 'File:Compass-icon bb SEbE.svg',
[13] = 'File:Compass-icon bb SE.svg',
[14] = 'File:Compass-icon bb SEbS.svg',
[15] = 'File:Compass-icon bb SSE.svg',
[16] = 'File:Compass-icon bb SbE.svg',
[17] = 'File:Compass-icon bb S.svg',
[18] = 'File:Compass-icon bb SbW.svg',
[19] = 'File:Compass-icon bb SSW.svg',
[20] = 'File:Compass-icon bb SWbS.svg',
[21] = 'File:Compass-icon bb SW.svg',
[22] = 'File:Compass-icon bb SWbW.svg',
[23] = 'File:Compass-icon bb WSW.svg',
[24] = 'File:Compass-icon bb WbS.svg',
[25] = 'File:Compass-icon bb W.svg',
[26] = 'File:Compass-icon bb WbN.svg',
[27] = 'File:Compass-icon bb WNW.svg',
[28] = 'File:Compass-icon bb NWbW.svg',
[29] = 'File:Compass-icon bb NW.svg',
[30] = 'File:Compass-icon bb NWbN.svg',
[31] = 'File:Compass-icon bb NNW.svg',
[32] = 'File:Compass-icon bb NbW.svg'
}
 
-- URL definitions for different sites. Strings: $lat, $lon, $lang, $attr, $page will be
--[[ Helper function, Replacement for {{coord/display/inline}} ]]
-- replaced with latitude, longitude, language code, GeoHack attribution parameters and full-page-name strings.
local function displayinline(s, notes)
local SiteURL = {
return s .. notes
GeoHack = '//tools.wmflabs.org/geohack/geohack.php?pagename=$page&params=$lat_N_$lon_E_$attr&language=$lang',
end
GoogleEarth = '//tools.wmflabs.org/geocommons/earth.kml?latdegdec=$lat&londegdec=$lon&scale=10000&commons=1',
Proximityrama = '//tools.wmflabs.org/geocommons/proximityrama?latlon=$lat,$lon',
OpenStreetMap = '//tools.wmflabs.org/wiwosm/osm-on-ol/commons-on-osm.php?zoom=16&lat=$lat&lon=$lon',
GoogleMaps = {
Mars = '//www.google.com/mars/#lat=$lat&lon=$lon&zoom=8',
Moon = '//www.google.com/moon/#lat=$lat&lon=$lon&zoom=8',
Earth = '//maps.google.com/maps?ll=$lat,$lon&spn=0.01,0.01&t=k&q=http://tools.wmflabs.org/geocommons/web.kml&hl=$lang'
}
}
 
-- Categories
--[[ Helper function, used in detecting DMS formatting ]]
local functionCoorCat dmsTest(first,= second){
File = '[[Category:Media with locations]]',
if type(first) ~= 'string' or type(second) ~= 'string' then
Gallery = '[[Category:Galleries with coordinates]]',
return nil
Category = '[[Category:Categories with coordinates]]',
end
wikidata1 = '[[Category:Pages with local coordinates and matching wikidata coordinates]]',
local s = (first .. second):upper()
wikidata2 = '[[Category:Pages with local coordinates and similar wikidata coordinates]]',
return s:find('^[NS][EW]$') or s:find('^[EW][NS]$')
wikidata3 = '[[Category:Pages with local coordinates and mismatching wikidata coordinates]]',
end
globe = '[[Category:Media with %s locations]]',
default = '[[Category:Media with default locations]]',
attribute = '[[Category:Media with erroneous geolocation attributes]]',
erroneous = '[[Category:Media with erroneous locations]]<span style="color:red;font-weight:bold">Error: Invalid parameters!</span>\n'
}
 
local NoLatLonString = 'latitude, longitude'
 
local function langSwitch(list,lang)
--[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]]
local langList = mw.language.getFallbacksFor(lang)
local function makeInvokeFunc(funcName)
table.insert(langList,1,lang)
return function (frame)
for i,language in ipairs(langList) do
local args = require('Module:Arguments').getArgs(frame, {
if list[language] then
wrappers = 'Template:Coord'
return list[language]
})
end
return coordinates[funcName](args, frame)
end
end
 
local function add_maplink(lat, lon, marker, text)
--[[ Helper function, handle optional args. ]]
local tstr = ''
local function optionalArg(arg, supplement)
if text then
return arg and arg .. supplement or ''
tstr = string.format('text="%s" ', text)
end
 
--[[
Formats any error messages generated for display
]]
local function errorPrinter(errors)
local result = ""
for i,v in ipairs(errors) do
local errorHTML = '<strong class="error">Coordinates: ' .. v[2] .. '</strong>'
result = result .. errorHTML .. "<br />"
end
return string.format('<maplink %szoom="13" latitude="%f" longitude="%f">{'..
return result
' "type": "Feature",'..
' "geometry": { "type":"Point", "coordinates":[%f, %f] },'..
' "properties": { "marker-symbol":"%s", "marker-size": "large", "marker-color": "0050d0" }'..
'}</maplink>', tstr, lat, lon, lon, lat, marker)
end
 
local function info_box(text)
--[[
return string.format('<table class="messagebox plainlinks layouttemplate" style="border-collapse:collapse; border-width:2px; border-style:solid; width:100%%; clear: both; '..
Determine the required CSS class to display coordinates
'border-color:#f28500; background:#ffe;direction:ltr; border-left-width: 8px; ">'..
 
'<tr>'..
Usually geo-nondefault is hidden by CSS, unless a user has overridden this for himself
'<td class="mbox-image" style="padding-left:.9em;">'..
default is the mode as specificied by the user when calling the {{coord}} template
' [[File:Commons-emblem-issue.svg|class=noviewer|45px]]</td>'..
mode is the display mode (dec or dms) that we will need to determine the css class for
'<td class="mbox-text" style="">%s</td>'..
]]
'</tr></table>', text)
local function displayDefault(default, mode)
if default == "" then
default = "dec"
end
if default == mode then
return "geo-default"
else
return "geo-nondefault"
end
end
 
local function mergeWithWikidata(wikidata, lat1, lon1)
--[[
-- we are given wikidata q-code so look up the coordinates
specPrinter
local data = require('Module:Wikidata')
local args = {}
local cat = ''
args.property='P625'
args.item=wikidata
args.numval = 1
args.link = '-'
args.displayformat='latitude'
lat2 = data.formatStatements(args)
args.displayformat='longitude'
lon2 = data.formatStatements(args)
if not lat1 or not lon1 then -- wikidata coordinates only
return lat2, lon2, wikidata, cat
elseif lat1 and lon1 and not lat2 and not lon2 then
cat = string.format("The above coordinates are missing from linked Wikidata item [[d:%s|%s]]. Please copy them. "..
"You can use [http://tools.wmflabs.org/wikidata-todo/quick_statements.php QuickStatements] tool with string <code>%s P625 @%f/%f S143 Q565</code> after replacing spaces with tabs in a text editor. ",
wikidata, wikidata, wikidata, lat1, lon1)
cat = info_box(cat)
elseif lat1 and lon1 and lat2 and lon2 then
local dLat = math.rad(lat1-lat2)
local dLon = math.rad(lon1-lon2)
local d = math.pow(math.sin(dLat/2),2) + math.pow(math.sin(dLon/2),2) * math.cos(math.rad(lat1)) * math.cos(math.rad(lat2))
d = 2 * math.atan2(math.sqrt(d), math.sqrt(1-d)) -- angular distance in radians
d = 6371000 * d -- radians to meters conversion
local frame = mw.getCurrentFrame()
local info = frame:preprocess(add_maplink(lat2, lon2, 'marker')) -- fancy link to OSM
info = string.format("There is a discrepancy of %i meters between the above coordinates and the ones stored at linked Wikidata item [[d:%s|%s]] (%s). Please reconcile them. "..
"To copy Commons coordinates to Wikidata, you can use [http://tools.wmflabs.org/wikidata-todo/quick_statements.php QuickStatements] tool with string "..
"<code>%s P625 @%f/%f S143 Q565</code> after replacing spaces with tabs in a text editor. ",
math.floor(d+0.5), wikidata, wikidata, info, wikidata, lat1, lon1)
 
if d<20 then
Output formatter. Takes the structure generated by either parseDec
cat = CoorCat.wikidata1
or parseDMS and formats it for inclusion on Wikipedia.
elseif d<1000 then
]]
cat = CoorCat.wikidata2 .. info_box(info)
local function specPrinter(args, coordinateSpec)
else
local uriComponents = coordinateSpec["param"]
cat = CoorCat.wikidata3 .. info_box(info)
if uriComponents == "" then
end
-- RETURN error, should never be empty or nil
return "ERROR param was empty"
end
return lat1, lon1, wikidata, cat
if args["name"] then
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"])
end
local geodmshtml = '<span class="geo-dms" title="Maps, aerial photos, and other data for this location">'
.. '<span class="latitude">' .. coordinateSpec["dms-lat"] .. '</span> '
.. '<span class="longitude">' ..coordinateSpec["dms-long"] .. '</span>'
.. '</span>'
 
local lat = tonumber( coordinateSpec["dec-lat"] ) or 0
local geodeclat
if lat < 0 then
-- FIXME this breaks the pre-existing precision
geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°S"
else
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N"
end
 
local long = tonumber( coordinateSpec["dec-long"] ) or 0
local geodeclong
if long < 0 then
-- FIXME does not handle unicode minus
geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°W"
else
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E"
end
local geodechtml = '<span class="geo-dec" title="Maps, aerial photos, and other data for this location">'
.. geodeclat .. ' '
.. geodeclong
.. '</span>'
 
local geonumhtml = '<span class="geo">'
.. coordinateSpec["dec-lat"] .. '; '
.. coordinateSpec["dec-long"]
.. '</span>'
 
local inner = '<span class="' .. displayDefault(coordinateSpec["default"], "dms" ) .. '">' .. geodmshtml .. '</span>'
.. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">';
 
if not args["name"] then
inner = inner .. geodechtml
.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span></span>'
else
inner = inner .. '<span class="vcard">' .. geodechtml
.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span>'
.. '<span style="display:none">&#xfeff; (<span class="fn org">'
.. args["name"] .. '</span>)</span></span></span>'
end
 
return '<span class="plainlinks nourlexpansion">' ..
'[' .. coord_link .. uriComponents .. ' ' .. inner .. ']' .. '</span>'
end
 
-- =======================================
--[[ Helper function, convert decimal to degrees ]]
-- === Functions =========================
local function convert_dec2dms_d(coordinate)
-- =======================================
local d = math_mod._round( coordinate, 0 ) .. "°"
p = {}
return d .. ""
end
 
-- parse attribute variable returning desired field
--[[ Helper function, convert decimal to degrees and minutes ]]
local function convert_dec2dms_dmp.parseAttribute(coordinateframe)
return string.match(mw.text.decode(frame.args[1]), mw.text.decode(frame.args[2]) .. ':' .. '([^_]*)') or ''
coordinate = math_mod._round( coordinate * 60, 0 );
local m = coordinate % 60;
coordinate = math.floor( (coordinate - m) / 60 );
local d = coordinate % 360 .."°"
return d .. string.format( "%02d′", m )
end
 
--[[============================================================================
--[[ Helper function, convert decimal to degrees, minutes, and seconds ]]
Parse attribute variable returning heading field. If heading is a string than
local function convert_dec2dms_dms(coordinate)
try to convert it to an angle
coordinate = math_mod._round( coordinate * 60 * 60, 0 );
==============================================================================]]
local s = coordinate % 60
function p.getHeading(frame)
coordinate = math.floor( (coordinate - s) / 60 );
local m = coordinate % 60attributes
if frame.args[1] then
coordinate = math.floor( (coordinate - m) / 60 );
attributes = frame.args[1]
local d = coordinate % 360 .."°"
elseif frame.args.attributes then
 
attributes = frame.args.attributes
return d .. string.format( "%02d′", m ) .. string.format( "%02d″", s )
end
 
--[[
Helper function, convert decimal latitude or longitude to
degrees, minutes, and seconds format based on the specified precision.
]]
local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
local coord = tonumber(coordinate)
local postfix
if coord >= 0 then
postfix = firstPostfix
else
return ''
postfix = secondPostfix
end
local hNum = p._getHeading(attributes)
 
if hNum == nil then
precision = precision:lower();
return ''
if precision == "dms" then
return convert_dec2dms_dms( math.abs( coord ) ) .. postfix;
elseif precision == "dm" then
return convert_dec2dms_dm( math.abs( coord ) ) .. postfix;
elseif precision == "d" then
return convert_dec2dms_d( math.abs( coord ) ) .. postfix;
end
return tostring(hNum)
end
-- Helper core function for getHeading.
 
function p._getHeading(attributes)
--[[
if attributes == nil then
Convert DMS format into a N or E decimal coordinate
return nil
]]
local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str)
local degrees = tonumber(degrees_str)
local minutes = tonumber(minutes_str) or 0
local seconds = tonumber(seconds_str) or 0
local factor = 1
if direction == "S" or direction == "W" then
factor = -1
end
local hStr = string.match(mw.text.decode(attributes), 'heading:([^_]*)')
if hStr == nil then
local precision = 0
return nil
if seconds_str then
precision = 5 + math.max( math_mod._precision(seconds_str), 0 );
elseif minutes_str and minutes_str ~= '' then
precision = 3 + math.max( math_mod._precision(minutes_str), 0 );
else
precision = math.max( math_mod._precision(degrees_str), 0 );
end
local hNum = tonumber( hStr )
if hNum == nil then
local decimal = factor * (degrees+(minutes+seconds/60)/60)
hStr = string.upper (hStr)
return string.format( "%." .. precision .. "f", decimal ) -- not tonumber since this whole thing is string based.
hNum = compass_points[hStr]
end
 
--[[
Checks input values to for out of range errors.
]]
local function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong )
local errors = {};
lat_d = tonumber( lat_d ) or 0;
lat_m = tonumber( lat_m ) or 0;
lat_s = tonumber( lat_s ) or 0;
long_d = tonumber( long_d ) or 0;
long_m = tonumber( long_m ) or 0;
long_s = tonumber( long_s ) or 0;
 
if strong then
if lat_d < 0 then
table.insert(errors, {source, "latitude degrees < 0 with hemisphere flag"})
end
if long_d < 0 then
table.insert(errors, {source, "longitude degrees < 0 with hemisphere flag"})
end
--[[
#coordinates is inconsistent about whether this is an error. If globe: is
specified, it won't error on this condition, but otherwise it will.
For not simply disable this check.
if long_d > 180 then
table.insert(errors, {source, "longitude degrees > 180 with hemisphere flag"})
end
]]
end
if lat_d > 90 then
table.insert(errors, {source, "latitude degrees > 90"})
end
if lat_dhNum <~= -90nil then
hNum = hNum%360
table.insert(errors, {source, "latitude degrees < -90"})
end
return hNum
if lat_m >= 60 then
table.insert(errors, {source, "latitude minutes >= 60"})
end
if lat_m < 0 then
table.insert(errors, {source, "latitude minutes < 0"})
end
if lat_s >= 60 then
table.insert(errors, {source, "latitude seconds >= 60"})
end
if lat_s < 0 then
table.insert(errors, {source, "latitude seconds < 0"})
end
if long_d >= 360 then
table.insert(errors, {source, "longitude degrees >= 360"})
end
if long_d <= -360 then
table.insert(errors, {source, "longitude degrees <= -360"})
end
if long_m >= 60 then
table.insert(errors, {source, "longitude minutes >= 60"})
end
if long_m < 0 then
table.insert(errors, {source, "longitude minutes < 0"})
end
if long_s >= 60 then
table.insert(errors, {source, "longitude seconds >= 60"})
end
if long_s < 0 then
table.insert(errors, {source, "longitude seconds < 0"})
end
return errors;
end
 
--[[============================================================================
--[[
Convert degrees to degrees/minutes/seconds notation comonly used when displaying
parseDec
coordinates.
 
Inputs:
Transforms decimal format latitude and longitude into the
1) latitude or longitude angle in degrees
structure to be used in displaying coordinates
2) georeference precission in degrees
]]
3) language used in formating of the number
local function parseDec( lat, long, format )
==============================================================================]]
local coordinateSpec = {}
function p.deg2dms(frame)
local errors = {}
local deg = tonumber(frame.args[1])
local degPrec = tonumber(frame.args[2]) or 0-- precision in degrees
if not long then
local lang = frame.args.lang
return nil, {{"parseDec", "Missing longitude"}}
if not (lang and mw.language.isSupportedLanguage(lang)) then
elseif not tonumber(long) then
lang = frame:callParserFunction("int","lang") -- get user's chosen language
return nil, {{"parseDec", "Longitude could not be parsed as a number: " .. long}}
end
if deg==nil then
return frame.args[1];
errors = validate( lat, nil, nil, long, nil, nil, 'parseDec', false );
coordinateSpec["dec-lat"] = lat;
coordinateSpec["dec-long"] = long;
 
local mode = coordinates.determineMode( lat, long );
coordinateSpec["dms-lat"] = convert_dec2dms( lat, "N", "S", mode) -- {{coord/dec2dms|{{{1}}}|N|S|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
coordinateSpec["dms-long"] = convert_dec2dms( long, "E", "W", mode) -- {{coord/dec2dms|{{{2}}}|E|W|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}
if format then
coordinateSpec.default = format
else
return p._deg2dms(deg, degPrec, lang)
coordinateSpec.default = "dec"
end
 
return coordinateSpec, errors
end
 
--[[============================================================================
--[[
Helper core function for deg2dms. deg2dms can be called by templates, while
parseDMS
_deg2dms should be called from Lua.
Inputs:
* deg - positive coordinate in degrees
* degPrec - coordinate precission in degrees will result in different angle format
* lang - language to used when formating the number
==============================================================================]]
function p._deg2dms(deg, degPrec, lang)
local dNum, mNum, sNum, dStr, mStr, sStr, formatStr, secPrec, c, k
local Lang = mw.language.new(lang)
 
-- adjust number display based on precission
Transforms degrees, minutes, seconds format latitude and longitude
secPrec = degPrec*3600.0 -- coordinate precission in seconds
into the a structure to be used in displaying coordinates
if secPrec<0.05 then -- degPrec<1.3889e-05
]]
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS.SS″ format
local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format )
c = 360000
local coordinateSpec, errors, backward = {}, {}
elseif secPrec<0.5 then -- 1.3889e-05<degPrec<1.3889e-04
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS.S″ format
c = 36000
elseif degPrec*60.0<0.5 then -- 1.3889e-04<degPrec<0.0083
formatStr = '%s°&nbsp;%s′&nbsp;%s″' -- use DD° MM′ SS″ format
c = 3600
elseif degPrec<0.5 then -- 0.0083<degPrec<0.5
formatStr = '%s°&nbsp;%s′' -- use DD° MM′ format
c = 60
else -- if degPrec>0.5 then
formatStr = '%s°' -- use DD° format
c = 1
end
-- create degree, minute and seconds numbers and string
lat_f = lat_f:upper();
d = c/60
long_f = long_f:upper();
k = math.floor(c*(deg%360)+0.49) -- convert float to an integer. This step HAS to be identical for all conversions to avoid incorrect results due to different rounding
dNum = math.floor(k/c) % 360 -- degree number (integer in 0-360 range)
-- Check if specified backward
mNum = math.floor(k/d) % 60 -- minute number (integer in 0-60 range)
if lat_f == 'E' or lat_f == 'W' then
sNum = 3600*(k%d) / c -- seconds number (float in 0-60 range with 0, 1 or 2 decimal digits)
lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true;
dStr = Lang:formatNum(dNum) -- degree string
end
mStr = Lang:formatNum(mNum) -- minute string
sStr = Lang:formatNum(sNum) -- second string
errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true );
if not long_dmNum<10 then
mStr = '0' ..mStr -- pad with zero if a single digit
return nil, {{"parseDMS", "Missing longitude" }}
elseif not tonumber(long_d) then
return nil, {{"parseDMS", "Longitude could not be parsed as a number:" .. long_d }}
end
if sNum<10 then
sStr = '0' ..sStr -- pad with zero if less than ten
if not lat_m and not lat_s and not long_m and not long_s and #errors == 0 then
end
if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then
return string.format(formatStr, dStr, mStr, sStr);
if lat_f:upper() == 'S' then
lat_d = '-' .. lat_d;
end
if long_f:upper() == 'W' then
long_d = '-' .. long_d;
end
return parseDec( lat_d, long_d, format );
end
end
coordinateSpec["dms-lat"] = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. lat_f
coordinateSpec["dms-long"] = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. long_f
coordinateSpec["dec-lat"] = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) -- {{coord/dms2dec|{{{4}}}|{{{1}}}|0{{{2}}}|0{{{3}}}}}
coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}}
 
if format then
coordinateSpec.default = format
else
coordinateSpec.default = "dms"
end
 
return coordinateSpec, errors, backward
end
 
--[[============================================================================
--[[
Format coordinate location string, by creating and joining DMS strings for
Check the input arguments for coord to determine the kind of data being provided
latutude and longitude. Also convert precission from meters to degrees.
and then make the necessary processing.
INPUTS:
]]
* lat = latitude in degrees
local function formatTest(args)
* lon = longitude in degrees
local result, errors
* lang = language code
local backward, primary = false, false
* prec = geolocation precission in meters
 
==============================================================================]]
local function getParam(args, lim)
function p.lat_lon(frame)
local ret = {}
local lat = tonumber(frame.args.lat)
for i = 1, lim do
local lon = tonumber(frame.args.lon)
ret[i] = args[i] or ''
local prec = math.abs(tonumber(frame.args.prec) or 0) -- location precision in meters
if lon then -- get longitude t0 be in -180 to 180 range
lon=lon%360
if lon>180 then
lon = lon-360
end
return table.concat(ret, '_')
end
local lang = frame.args.lang
if not args[1](lang and mw.language.isSupportedLanguage(lang)) then
lang = frame:callParserFunction("int","lang") -- get user's chosen language
-- no lat logic
end
return errorPrinter( {{"formatTest", "Missing latitude"}} )
elseifif notlat==nil tonumber(args[1])or lon==nil then
return NoLatLonString
-- bad lat logic
return errorPrinter( {{"formatTest", "Unable to parse latitude as a number:" .. args[1]}} )
elseif not args[4] and not args[5] and not args[6] then
-- dec logic
result, errors = parseDec(args[1], args[2], args.format)
if not result then
return errorPrinter(errors);
end
result.param = table.concat({args[1], 'N', args[2] or '', 'E', args[3] or ''}, '_')
elseif dmsTest(args[4], args[8]) then
-- dms logic
result, errors, backward = parseDMS(args[1], args[2], args[3], args[4],
args[5], args[6], args[7], args[8], args.format)
if args[10] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 9)
elseif dmsTest(args[3], args[6]) then
-- dm logic
result, errors, backward = parseDMS(args[1], args[2], nil, args[3],
args[4], args[5], nil, args[6], args['format'])
if args[8] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 7)
elseif dmsTest(args[2], args[4]) then
-- d logic
result, errors, backward = parseDMS(args[1], nil, nil, args[2],
args[3], nil, nil, args[4], args.format)
if args[6] then
table.insert(errors, {'formatTest', 'Extra unexpected parameters'})
end
if not result then
return errorPrinter(errors)
end
result.param = getParam(args, 5)
else
local nsew = langSwitch(i18n.NSEW, lang) -- find set of localized translation of N, S, W and E in the desired language
-- Error
local SN, EW, latStr, lonStr, lon2m, lat2m, phi
return errorPrinter({{"formatTest", "Unknown argument format"}})
if lat<0 then SN = nsew.S else SN = nsew.N end -- choose S or N depending on latitude degree sign
end
if lon<0 then EW = nsew.W else EW = nsew.E end -- choose W or E depending on longitude degree sign
result.name = args.name
lat2m=1
lon2m=1
local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'}
if prec>0 then -- if user specified the precission of the geo location...
for _, v in ipairs(extra_param) do
phi = math.abs(lat)*math.pi/180 -- latitude in radiants
if args[v] then
lon2m = 6378137*math.cos(phi)*math.pi/180 -- see https://en.wikipedia.org/wiki/Longitude
table.insert(errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' })
lat2m = 111000 -- average latitude degree size in meters
end
latStr = p._deg2dms(math.abs(lat), prec/lat2m, lang) -- Convert latitude degrees to degrees/minutes/seconds
lonStr = p._deg2dms(math.abs(lon), prec/lon2m, lang) -- Convert longitude degrees to degrees/minutes/seconds
return string.format('%s&nbsp;%s, %s&nbsp;%s', latStr, SN, lonStr, EW)
--return string.format('<span class="latitude">%s %s</span>, <span class="longitude">%s %s</span>', latStr, SN, lonStr, EW)
end
local ret = specPrinter(args, result)
if #errors > 0 then
ret = ret .. ' ' .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]'
end
return ret, backward
end
 
--[[============================================================================
--[[
Create URL for different sites.
Generate Wikidata tracking categories.
INPUTS:
]]
* site = Possinle sites: GeoHack, GoogleEarth, Proximityrama,
local function makeWikidataCategories()
OpenStreetMap, GoogleMaps (for Earth, Mars and Moon)
local ret
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
if mw.wikibase and current_page.namespace == 0 then
Ganymede are also supported but are unused as of 2013.
local entity = mw.wikibase.getEntityObject()
* lat = latitude string or number
if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1] then
* lon = longitude string or number
local snaktype = entity.claims.P625[1].mainsnak.snaktype
* lang = language code
if snaktype == 'value' then
* attributes = attributes to be passed to GeoHack
-- coordinates exist both here and on Wikidata, and can be compared.
==============================================================================]]
ret = 'Coordinates on Wikidata'
function p.externalLink(frame)
elseif snaktype == 'somevalue' then
args = frame.args
ret = 'Coordinates on Wikidata set to unknown value'
local lang = frame.args.lang
elseif snaktype == 'novalue' then
if not (lang and mw.language.isSupportedLanguage(lang)) then
ret = 'Coordinates on Wikidata set to no value'
lang = frame:callParserFunction("int","lang") -- get user's chosen language
end
else
-- We have to either import the coordinates to Wikidata or remove them here.
ret = 'Coordinates not on Wikidata'
end
end
return p._externalLink(args.site or 'GeoHack', args.globe or 'Earth', args.lat, args.lon, lang, args.attributes or '')
if ret then
end
return string.format('[[Category:%s]]', ret)
else
--[[============================================================================
return ''
Helper core function for externalLink. Create URL for different sites:
INPUTS:
* site = Possinle sites: GeoHack, GoogleEarth, Proximityrama,
OpenStreetMap, GoogleMaps (for Earth, Mars and Moon)
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
Ganymede are also supported but are unused as of 2013.
* latStr = latitude string or number
* lonStr = longitude string or number
* lang = language code
* attributes = attributes to be passed to GeoHack
==============================================================================]]
function p._externalLink(site, globe, latStr, lonStr, lang, attributes)
local URLstr = SiteURL[site];
if site == 'GoogleMaps' then
URLstr = SiteURL.GoogleMaps[globe]
elseif site == 'GeoHack' then
attributes = string.format('globe:%s_%s', globe, attributes)
local pageName = mw.uri.encode( mw.title.getCurrentTitle().prefixedText, 'WIKI' )
pageName = mw.ustring.gsub( pageName, '%%', '%%%%')
URLstr = mw.ustring.gsub( URLstr, '$attr', attributes)
URLstr = mw.ustring.gsub( URLstr, '$page', pageName)
URLstr = mw.ustring.gsub( URLstr, ' ', '_')
end
URLstr = mw.ustring.gsub( URLstr, '$lat' , latStr)
URLstr = mw.ustring.gsub( URLstr, '$lon' , lonStr)
URLstr = mw.ustring.gsub( URLstr, '$lang', lang)
URLstr = mw.ustring.gsub( URLstr, '+', '')
return URLstr
end
 
--[[============================================================================
--[[
Adjust GeoHack attributes depending on the template that calls it
link
INPUTS:
 
* attributes = attributes to be passed to GeoHack
Simple function to export the coordinates link for other uses.
* mode = set by each calling template
 
==============================================================================]]
Usage:
function p.alterAttributes(attributes, mode)
{{#invoke:Coordinates | link }}
-- indicate which template called it
if mode=='camera' then -- Used by {{Location}} and {{Location dec}}
]]
if string.find(attributes, 'type:camera')==nil then
function coordinates.link(frame)
attributes = 'type:camera_' .. attributes
return coord_link;
end
elseif mode=='object'or mode =='globe' then -- Used by {{Object location}}
if string.find(attributes, 'class:object')==nil then
attributes = 'class:object_' .. attributes
end
elseif mode=='inline' then -- Used by {{Inline coordinates}} (actually that template does not set any attributes at the moment)
elseif mode=='user' then -- Used by {{User location}}
attributes = 'type:user_location'
elseif mode=='institution' then --Used by {{Institution/coordinates}} (categories only)
attributes = 'type:institution'
end
return attributes
end
 
--[[
dec2dms
 
Wrapper to allow templates to call dec2dms directly.
 
Usage:
{{#invoke:Coordinates | dec2dms | decimal_coordinate | positive_suffix |
negative_suffix | precision }}
--[[============================================================================
decimal_coordinate is converted to DMS format. If positive, the positive_suffix
Create link to GeoHack tool which displays latitude and longitude coordinates
is appended (typical N or E), if negative, the negative suffix is appended. The
in DMS format
specified precision is one of 'D', 'DM', or 'DMS' to specify the level of detail
INPUTS:
to use.
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan,
]]
Ganymede are also supported but are unused as of 2013.
coordinates.dec2dms = makeInvokeFunc('_dec2dms')
* lat = latitude in degrees
function coordinates._dec2dms(args)
* lon = longitude in degrees
local coordinate = args[1]
* lang = language code
local firstPostfix = args[2] or ''
* prec = geolocation precission in meters
local secondPostfix = args[3] or ''
* attributes = attributes to be passed to GeoHack
local precision = args[4] or ''
==============================================================================]]
 
function p.GeoHack_link(frame)
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)
-- create link and coordintate string
end
local latlon = p.lat_lon(frame)
 
if latlon==NoLatLonString then
--[[
return latlon
Helper function to determine whether to use D, DM, or DMS
format depending on the precision of the decimal input.
]]
function coordinates.determineMode( value1, value2 )
local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) );
if precision <= 0 then
return 'd'
elseif precision <= 2 then
return 'dm';
else
frame.args.site = 'GeoHack'
return 'dms';
local url = p.externalLink(frame)
return string.format('<span class="plainlinksneverexpand">[%s %s]</span>', url, latlon) --<span class="plainlinks nourlexpansion">
end
end
 
--[[
dms2dec
 
Wrapper to allow templates to call dms2dec directly.
 
Usage:
{{#invoke:Coordinates | dms2dec | direction_flag | degrees |
minutes | seconds }}
Converts DMS values specified as degrees, minutes, seconds too decimal format.
direction_flag is one of N, S, E, W, and determines whether the output is
positive (i.e. N and E) or negative (i.e. S and W).
]]
coordinates.dms2dec = makeInvokeFunc('_dms2dec')
function coordinates._dms2dec(args)
local direction = args[1]
local degrees = args[2]
local minutes = args[3]
local seconds = args[4]
 
return convert_dms2dec(direction, degrees, minutes, seconds)
end
 
--[[============================================================================
--[[
Create full external links section of {{Location}} or {{Object location}}
coord
templates, based on:
 
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan, Ganymede are also supported but are unused as of 2013.
Main entry point for Lua function to replace {{coord}}
* mode = Possible options:
 
- camera - call from {{location}}
Usage:
- object - call from {{Object location}}
{{#invoke:Coordinates | coord }}
- globe - call from {{Globe location}}
{{#invoke:Coordinates | coord | lat | long }}
* lat = latitude in degrees
{{#invoke:Coordinates | coord | lat | lat_flag | long | long_flag }}
* lon = longitude in degrees
...
* lang = language code
* namespace = namespace name: File, Category, (Gallery)
==============================================================================]]
function p.externalLinksSection(frame)
local args = frame.args
local lang = frame.args.lang
if not (lang and mw.language.isSupportedLanguage(lang)) then
lang = frame:callParserFunction("int","lang") -- get user's chosen language
end
if not args.namespace then
args.namespace = mw.title.getCurrentTitle().namespace
end
local str, link1, link2
Refer to {{coord}} documentation page for many additional parameters and
if args.globe=='Earth' then -- Earth locations will have 3 or 4 links
configuration options.
link1 = p._externalLink('OpenStreetMap', 'Earth', args.lat, args.lon, lang, '')
link2 = p._externalLink('GoogleEarth' , 'Earth', args.lat, args.lon, lang, '')
Note: This function provides the visual display elements of {{coord}}. In
-- GoogleMap link no longer works due to changes in the website software
order to load coordinates into the database, the {{#coordinates:}} parser
-- link3 = p._externalLink('GoogleMaps' , 'Earth', args.lat, args.lon, lang, '') %langSwitch(i18n.GoogleMaps, lang)
function must also be called, this is done automatically in the Lua
str = string.format('[%s %s] - [%s %s]',
version of {{coord}}.
link1, langSwitch(i18n.OpenStreetMaps, lang),
]]
link2, langSwitch(i18n.GoogleEarth, lang))
coordinates.coord = makeInvokeFunc('_coord')
if args.namespace=="Category" then
function coordinates._coord(args)
link1 = p._externalLink('Proximityrama', 'Earth', args.lat, args.lon, lang, '')
if not args[1] and not args[2] and mw.wikibase.getEntityObject() then
str = string.format('%s - [%s %s]', str, link1, langSwitch(i18n.Proximityrama, lang))
local entity = mw.wikibase.getEntityObject()
if entityend
elseif args.globe=='Mars' or args.globe=='Moon' then
and entity.claims
link1 = p._externalLink('GoogleMaps', args.globe, args.lat, args.lon, lang, '')
and entity.claims.P625
str = string.format('[%s %s]', link1, langSwitch(i18n.GoogleMaps, lang))
and entity.claims.P625[1].mainsnak.snaktype == 'value'
then
local precision = entity.claims.P625[1].mainsnak.datavalue.value.precision
args[1]=entity.claims.P625[1].mainsnak.datavalue.value.latitude
args[2]=entity.claims.P625[1].mainsnak.datavalue.value.longitude
if precision then
precision=-math_mod._round(math.log(precision)/math.log(10),0)
args[1]=math_mod._round(args[1],precision)
args[2]=math_mod._round(args[2],precision)
end
end
end
return str
local contents, backward = formatTest(args)
end
local Notes = args.notes or ''
local Display = args.display and args.display:lower() or 'inline'
 
--[[============================================================================
local function isInline(s)
Core section of template:Location, template:Object location and template:Globe location.
-- Finds whether coordinates are displayed inline.
This method requires several arguments to be passed to it or it's parent metchod/template:
return s:find('inline') ~= nil or s == 'i' or s == 'it' or s == 'ti'
* globe = Possible options: Earth, Mars or Moon. Venus, Mercury, Titan, Ganymede are also supported but are unused as of 2013.
* mode = Possible options:
- camera - call from {{location}}
- object - call from {{Object location}}
- globe - call from {{Globe location}}
* lat = latitude in degrees
* lon = longitude in degrees
* attributes = attributes
* lang = language code
* namespace = namespace: File, Category, Gallery
* prec = geolocation precission in meters
==============================================================================]]
function p.LocationTemplateCore(frame)
-- prepare arguments
args = frame.args
if not args or not args.lat then -- if no arguments provided than use parent arguments
args = mw.getCurrentFrame():getParent().args
end
if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then
local function isInTitle(s)
args.lang = frame:callParserFunction("int","lang") -- get user's chosen language
-- Finds whether coordinates are displayed in the title.
return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti'
end
if not (args.namespace) then -- if namespace not provided than look it up
args.namespace = mw.title.getCurrentTitle().namespace
local function coord_wrapper(in_args)
-- Calls the parser function {{#coordinates:}}.
return mw.getCurrentFrame():callParserFunction('#coordinates', in_args) or ''
end
if args.namespace=='' then -- if empty than it is a gallery
args.namespace = 'Gallery'
local text = ''
if isInline(Display) then
text = text .. displayinline(contents, Notes)
end
local bare = yesno(args.bare,false)
if isInTitle(Display) then
local Status = 'primary' -- used by {{#coordinates:}}
text = text
if yesno(args.secondary,false) then
.. displaytitle(contents, Notes)
Status = 'secondary'
.. makeWikidataCategories()
end
args.attributes = p.alterAttributes(args.attributes or '', args.mode)
if not args.nosave then
local page_title, count = mw.title.getCurrentTitle(), 1
-- Convert coordinates from string to numbers
if backward then
local tmplat = {}tonumber(args.lat)
local lon = tonumber(args.lon)
while not string.find((args[count-1] or ''), '[EW]') do tmp[count] = (args[count] or ''); count = count+1 end
if lon then -- get longitude to be in -180 to 180 range
tmp.count = count; count = 2*(count-1)
lon=lon%360
while count >= tmp.count do table.insert(tmp, 1, (args[count] or '')); count = count-1 end
if lon>180 then
for i, v in ipairs(tmp) do args[i] = v end
lon = lon-360
else
while count <= 9 do args[count] = (args[count] or ''); count = count+1 end
end
if isInTitle(Display) and not page_title.isTalkPage and page_title.subpageText ~= 'doc' and page_title.subpageText ~= 'testcases' then args[10] = 'primary' end
args.notes, args.format, args.display = nil
text = text .. coord_wrapper(args)
end
return text
-- If wikidata link provided than compare coordinates
end
local Categories, geoMicroFormat, coorTag, wikidata_link = '', '', '', ''
if args.wikidata and args.wikidata~='' then
-- if lat/lon is not provided but we are given wikidata q-code than look up the coordinates
lat, lon, q, Categories = mergeWithWikidata(args.wikidata, lat, lon)
wikidata_link = string.format("\n[[File:Wikidata-logo.svg|20px|Edit coordinates on Wikidata|link=wikidata:%s]]",q,q);
end
 
args.lat = string.format('%010.6f', lat or 0)
--[[
args.lon = string.format('%011.6f', lon or 0)
coord2text
frame.args = args
 
-- Categories, {{#coordinates}} and geoMicroFormat will be only added to File, Category and Gallery pages
Extracts a single value from a transclusion of {{Coord}}.
if (args.namespace == 'File' or args.namespace == 'Category' or args.namespace == 'Gallery') then
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.
if lat and lon then -- if lat and lon are numbers...
if lat==0 and lon==0 then -- lat=0 and lon=0 is a common issue when copying from flickr and other sources
Categories = Categories .. CoorCat.default
end
if frame.args.attributes and string.find(frame.args.attributes, '=') then
Categories = Categories .. CoorCat.attribute
end
if args.error=='1' or (math.abs(lat)>90) then -- check for errors ({{#coordinates:}} also checks for errors )
Categories = Categories .. CoorCat.erroneous
end
local cat = CoorCat[args.namespace]
if cat then -- add category based on namespace
Categories = Categories .. cat
end
-- if not earth than add a category for each globe
if args.mode and args.globe and args.mode=='globe' and args.globe~='Earth' then
Categories = Categories .. string.format(CoorCat[args.mode], args.globe)
end
-- add <span class="geo"> Geo (microformat) code: it is included for machine readability
geoMicroFormat = string.format('<span class="geo" style="display:none">%10.6f; %11.6f</span>',lat, lon)
-- add {{#coordinates}} tag, see https://www.mediawiki.org/wiki/Extension:GeoData
if args.namespace == 'File' and Status == 'primary' and args.mode=='camera' then
coorTag = string.format('{{#coordinates:primary|%10.6f|%11.6f|%s}}', lat, lon, args.attributes)
end
else -- if lat and lon are not numbers then add error category
Categories = Categories .. CoorCat.erroneous
end
 
end
Usage:
 
-- Call helper functions to render different parts of the template
{{#invoke:Coordinates | coord2text | {{Coord}} | parameter }}
local coor, info_link, inner_table, heading, OSM = '','','','','','',''
 
coor = p.GeoHack_link(frame) -- the p and link to GeoHack
Valid values for the second parameter are: lat (signed integer), long (signed integer), type, scale, dim, region, globe, source
heading = p._getHeading(frame.args.attributes) -- get heading arrow section
 
if heading then
]]
local k = math.fmod(math.floor(0.5+math.fmod(heading+360,360)/11.25),32)+1
function coordinates.coord2text(frame)
local fname = heading_icon[k]
if frame.args[1] == '' or frame.args[2] == '' or not frame.args[2] then return nil end
coor = string.format('%s&nbsp;&nbsp;<span title="%s°">[[%s|25px|link=|alt=Heading=%s°]]</span>', coor, heading, fname, heading)
frame.args[2] = mw.text.trim(frame.args[2])
end
if frame.args[2] == 'lat' or frame.args[2] == 'long' then
if args.globe=='Earth' then
local result, negative = mw.text.split((mw.ustring.match(frame.args[1],'%d+.?%d*°[NS] %d+.?%d*°[EW]') or ''), ' ')
iflocal frame.args[2]icon == 'latmarker' then
if args.mode=='camera' then
result, negative = result[1], 'S'
icon = 'camera'
else
result, negative = result[2], 'W'
end
OSM = frame:preprocess(add_maplink(args.lat, args.lon, icon, '[[File:Openstreetmap logo.svg|20px|link=]]')) -- fancy link to OSM
result = mw.text.split(result, '°')
end
if result[2] == negative then result[1] = '-'..result[1] end
external_link = p.externalLinksSection(frame) -- external link section
return result[1]
if external_link then
external_link = langSwitch(i18n.LocationTemplateLinkLabel, args.lang) .. ' ' .. external_link -- header of the link section
end
info_link = string.format('[[File:Circle-information.svg|18x18px|alt=info|link=%s]]', langSwitch(i18n.COM_GEO, args.lang) )
inner_table = string.format('<td style="border:none;">%s&nbsp;%s</td><td style="border:none;">%s</td><td style="border:none;">%s%s%s</td>',
coor, OSM, external_link or '', info_link, wikidata_link, geoMicroFormat)
-- combine strings into a table
local templateText
if bare then
templateText = string.format('<table style="width:100%%"><tr>%s</tr></table>', inner_table)
else
-- choose name of the field
return mw.ustring.match(frame.args[1], 'params=.-_'..frame.args[2]..':(.-)[ _]')
local field_name = 'Location'
end
if args.mode=='camera' then
end
field_name = langSwitch(i18n.CameraLocation, args.lang)
 
elseif args.mode=='object' then
--[[
field_name = langSwitch(i18n.ObjectLocation, args.lang)
coordinsert
elseif args.mode=='globe' then
 
field_list = langSwitch(i18n.GlobeLocation, args.lang)
Injects some text into the Geohack link of a transclusion of {{Coord}} (if that text isn't already in the transclusion). Outputs the modified transclusion of {{Coord}}.
if args.globe and i18n.GlobeLocation['en'][args.globe] then -- verify globe is provided and is recognized
IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.
field_name = field_list[args.globe]
 
end
Usage:
 
{{#invoke:Coordinates | coordinsert | {{Coord}} | parameter:value | parameter:value | … }}
 
Do not make Geohack unhappy by inserting something which isn't mentioned in the {{Coord}} documentation.
 
]]
function coordinates.coordinsert(frame)
for i, v in ipairs(frame.args) do
if i ~= 1 then
if not mw.ustring.find(frame.args[1], (mw.ustring.match(frame.args[i], '^(.-:)') or '')) then frame.args[1] = mw.ustring.gsub(frame.args[1], '(params=.-)_? ', '%1_'..frame.args[i]..' ') end
end
--Create HTML text
local dir, text_align
if mw.language.new( args.lang ):isRTL() then
dir = 'rtl'
text_align = 'right'
else
dir = 'ltr'
text_align = 'left'
end
local style = string.format('class="toccolours mw-content-%s layouttemplate commons-file-information-table" cellpadding="2" style="width: 100%%; direction:%s;" lang="%s"',
args.lang, dir, text_align, args.lang)
templateText = string.format('<table lang="%s" %s><tr><th class="type fileinfo-paramfield">%s</th>%s</tr></table>',
args.lang, style, field_name, inner_table)
end
return templateText .. Categories .. coorTag
return frame.args[1]
end
 
return coordinatesp