Module:LuaTemplateTLD
Appearance
Documentation for this module may be created at Module:LuaTemplateTLD/doc
-- Module:LuaTemplateTLD
-- Renders TLD/ccTLD article templates with normalization and dynamic content. Features:
-- * Processes type/subtype values with canonical mapping
-- * Auto-detects IDN status and converts to punycode when needed
-- * Normalizes dates, countries, and website links
-- * Assigns categories based on country, PIC, and domain type
-- * Integrates social media and NTLDStats components
local p = {}
-- Dependencies
local CanonicalForms = require('Module:CanonicalForms')
local CountryData = require('Module:CountryData')
local dateNormalization = require('Module:NormalizationDate')
local linkParser = require('Module:LinkParser')
local punycode = require('Module:Punycode')
local socialFooter = require('Module:SocialMedia')
local TemplateStructure = require('Module:TemplateStructure')
local TemplateHelpers = require('Module:TemplateHelpers')
local SemanticAnnotations = require('Module:SemanticAnnotations')
local ConfigRepository = require('Module:ConfigRepository')
local SemanticCategoryHelpers = require('Module:SemanticCategoryHelpers')
--------------------------------------------------------------------------------
-- Configuration and Constants
--------------------------------------------------------------------------------
local Config = ConfigRepository.getStandardConfig('TLD')
--------------------------------------------------------------------------------
-- Helper Functions
--------------------------------------------------------------------------------
local IDNHelpers = {
processIDN = function(args, rawType)
if args["idn"] then
local idnVal = string.lower(args["idn"])
if idnVal == "yes" or idnVal == "true" then return true end
end
return string.find(string.lower(rawType), "idn") and true or false
end,
getASCII = function(pageName)
return "xn--" .. punycode.encode(pageName:gsub("^%.", ""))
end
}
-- Use TemplateHelpers for common functions
local getFieldValue = TemplateHelpers.getFieldValue
local splitMultiValueString = SemanticCategoryHelpers.splitMultiValueString
local normalizeWebsites = TemplateHelpers.normalizeWebsites
local normalizeDates = TemplateHelpers.normalizeDates
-- Wrapper for country normalization
local normalizeCountries = TemplateHelpers.normalizeCountries
--------------------------------------------------------------------------------
-- Block Rendering Functions
--------------------------------------------------------------------------------
local function renderTitleBlock(args)
local titleText = (args._type == "ccTLD") and "ccTLD" or "gTLD"
return TemplateHelpers.renderTitleBlock(args, "template-title template-title-tld", titleText, {
achievementSupport = false -- No achievement support for TLD template
})
end
local function renderLogoBlock(args)
return TemplateHelpers.renderLogoBlock(args, {
cssClass = "tld-logo"
})
end
local function renderFlairBlock(args)
local classes = {"tld-flair"}
if args._idnFlag then
table.insert(classes, args._type == "ccTLD" and "tld-template-idn-cctld" or "tld-template-idn-gtld")
elseif args["subtype"] and args["subtype"] ~= "" then
local _, css = CanonicalForms.normalize(args["subtype"], Config.mappings.subtype)
if css then table.insert(classes, css) end
end
return string.format('|-\n| colspan="2" class="%s" |', table.concat(classes, " "))
end
local function renderFieldsBlock(args)
-- Define field processors
local processors = {
type = function(value)
return select(1, CanonicalForms.normalize(value, Config.mappings.type)) or value
end,
subtype = function(value)
return select(1, CanonicalForms.normalize(value, Config.mappings.subtype)) or value
end,
website = normalizeWebsites,
date = function(value)
return TemplateHelpers.formatDateRange(value, nil, {
outputMode = "text"
})
end,
implemented = function(value)
return TemplateHelpers.formatDateRange(value, nil, {
outputMode = "text"
})
end,
introduced = function(value)
return TemplateHelpers.formatDateRange(value, nil, {
outputMode = "text"
})
end,
country = normalizeCountries,
territory = normalizeCountries,
RVC = function(value)
if value:match("^%d+$") then
return string.format("[https://gtldresult.icann.org/applicationstatus/applicationdetails/%s Here]", value)
end
return value
end,
PIC = function(value)
if value:match("^%d+$") then
return string.format("[https://gtldresult.icann.org/applicationstatus/applicationdetails/%s Here]", value)
end
return value
end
}
return TemplateHelpers.renderFieldsBlock(args, Config.fields, processors)
end
local function renderNTLDStatsBlock(args)
if args._type == "ccTLD" then return "" end
-- Get the current page name
local titleObj = mw.title.getCurrentTitle()
local pageName = titleObj and titleObj.text or ""
local tldName = pageName:gsub("^%.", "")
local tldExtension = tldName:match(Config.patterns.tldExtension)
if Config.constants.classicTLDs[mw.ustring.lower(tldName)] or (tldExtension and Config.constants.classicTLDs[mw.ustring.lower(tldExtension)]) then
return ""
end
local divider = TemplateHelpers.renderDividerBlock("Find out more:")
local stats = string.format('|-\n| colspan="2" | <div class="ntldstats icannwiki-centered">[[File:NTLDStatsLogo.png|100px|alt=NTLDStats|link=https://ntldstats.com/tld/%s]]</div>', tldName)
return divider .. "\n" .. stats
end
--------------------------------------------------------------------------------
-- Semantic Properties
--------------------------------------------------------------------------------
-- Generate semantic properties for the TLD
local function generateSemanticProperties(args)
-- Set basic properties using the transformation functions from Config
local semanticOutput = SemanticAnnotations.setSemanticProperties(
args,
Config.semantics.properties,
{transform = Config.semantics.transforms}
)
-- For non-SMW case, collect property HTML fragments in a table for efficient concatenation
local propertyHtml = {}
-- Handle special case for IDN flag
if args._idnFlag then
if mw.smw then
mw.smw.set({["Is IDN"] = "true"})
else
-- Collect HTML fragments instead of concatenating strings
table.insert(propertyHtml, '<div style="display:none;">')
table.insert(propertyHtml, ' {{#set: Is IDN=true }}')
table.insert(propertyHtml, '</div>')
end
end
-- Handle special case for multiple countries using CountryData
local countryValue = args["country"] or args["territory"]
semanticOutput = CountryData.addCountrySemanticProperties(countryValue, semanticOutput)
-- Process additional properties with multi-value support
-- Skip properties that are handled separately above
semanticOutput = SemanticCategoryHelpers.processAdditionalProperties(
args,
Config.semantics,
semanticOutput,
Config.semantics.skipProperties
)
-- For non-SMW case, concatenate all property HTML fragments at once
if not mw.smw and #propertyHtml > 0 then
semanticOutput = semanticOutput .. "\n" .. table.concat(propertyHtml, "\n")
end
return semanticOutput
end
--------------------------------------------------------------------------------
-- Category Assignment
--------------------------------------------------------------------------------
local function computeCategories(args)
local cats = {}
-- Process country categories from either country or territory key using CountryData
local countryValue = args["country"] or args["territory"]
if countryValue and countryValue ~= "" then
cats = SemanticCategoryHelpers.addMultiValueCategories(
countryValue,
function(value)
-- Use the new CountryData module directly
return CountryData.normalizeCountryName(value)
end,
cats
)
end
-- Process region categories using the generic function
if args["region"] and args["region"] ~= "" then
cats = SemanticCategoryHelpers.addMultiValueCategories(
args["region"],
function(region) return region:match("^%s*(.-)%s*$") end, -- Trim whitespace
cats
)
end
-- Add conditional categories from config
if Config.categories and Config.categories.conditional then
-- Check for RVC/PIC
if Config.categories.conditional.rvc and ((args["RVC"] and args["RVC"] ~= "") or (args["PIC"] and args["PIC"] ~= "")) then
table.insert(cats, Config.categories.conditional.rvc)
end
-- Check for IDN
if args._idnFlag then
if Config.categories.conditional.idn then
table.insert(cats, Config.categories.conditional.idn)
end
-- Special case for IDN ccTLDs
if args._type == "ccTLD" and Config.categories.conditional.idn_cctld then
table.insert(cats, Config.categories.conditional.idn_cctld)
end
end
end
-- Add type categories from mapping
local typeCategories = SemanticCategoryHelpers.addMappingCategories(args._type, Config.mappings.type)
for _, cat in ipairs(typeCategories) do
table.insert(cats, cat)
end
-- Add subtype categories
if args["subtype"] and args["subtype"] ~= "" then
local canonicalSubtype, _, subtypeCategory = CanonicalForms.normalize(args["subtype"], Config.mappings.subtype)
if subtypeCategory and subtypeCategory ~= "" then
table.insert(cats, subtypeCategory)
elseif canonicalSubtype and canonicalSubtype ~= "" then
table.insert(cats, canonicalSubtype)
end
end
return SemanticCategoryHelpers.buildCategories(cats)
end
--------------------------------------------------------------------------------
-- Main Render Function
--------------------------------------------------------------------------------
function p.render(frame)
local args = frame:getParent().args or {}
-- Normalize arguments for case-insensitivity
args = TemplateHelpers.normalizeArgumentCase(args)
local titleObj = mw.title.getCurrentTitle()
local pageName = titleObj and titleObj.text or ""
-- Process type and IDN status
local rawType = args["type"] or ""
args._type = select(1, CanonicalForms.normalize(rawType, Config.mappings.type))
args._idnFlag = IDNHelpers.processIDN(args, rawType)
-- Set ASCII value for IDN
if args._idnFlag and titleObj then
args["ascii"] = IDNHelpers.getASCII(pageName)
end
-- Configure block rendering
local config = {
blocks = {
function(a) return renderTitleBlock(a) end,
function(a) return renderLogoBlock(a) end,
function(a) return renderFlairBlock(a) end,
function(a) return renderFieldsBlock(a) end,
function(a) return socialFooter.render(a) or "" end,
function(a) return renderNTLDStatsBlock(a) end
}
}
-- Generate template output
local output = TemplateStructure.render(args, config)
-- Add categories
local categories = computeCategories(args)
if categories and categories ~= "" then
output = output .. "\n" .. categories
end
-- Add semantic properties
local semantics = generateSemanticProperties(args)
if semantics and semantics ~= "" then
output = output .. "\n" .. semantics
end
return output
end
return p