Module:European and national party data
require ('strict');
local get_args = require ('Module:Arguments').getArgs; -- function to fetch frame and parent frame arguments
local cfg = mw.loadData ('Module:European and national party data/config'); -- defines, configuration data, and i18n support
local namespace = mw.title.getCurrentTitle().namespace; -- used for categorization
--[[==========================< S E C T I O N _ 1 : F U N C T I O N A L _ F U N C T I O N S >=======================
These are generic functions to accomplish specific, non-party-related tasks.
]]
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
substitutes $1, $2, etc in
]]
local function substitute (message, data_t)
return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end
--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------
assembles an error message from template name, message text, help link, and error category.
]]
local function make_error_msg (msg, template_name, nocat)
local category;
local category_link = ((0 == namespace) and not nocat) and substitute ('Category:$1', {cfg.settings_t.err_category}) or '';
return substitute ('Error: {{$1}}: $2 ($3)$4',
{
template_name or cfg.settings_t.template_name or frame:getParent():getTitle(), -- the template name without namespace
msg, -- the error message
cfg.settings_t.help, -- help wikilink display text
category_link -- link to error category (main namespace only)
})
end
--[[--------------------------< R O U N D >--------------------------------------------------------------------
return the rounded value of the arguments with two decimals
]]
local function round (n)
return math.floor(100 * n + 0.5) / 100 -- round argument to two decimals
end
--[[--------------------------< S T R I P _ U R L >--------------------------------------------------------------------
return the stripped down URL with a hyperlink
]]
local function strip_URL (URL)
local new_URL = URL;
local patterns_t = {'^%[%[(.*)%]%]', '^https://www.', '^http://www.', '^https://', '^http://', '^www.', '/$'}; -- valid
for i, pattern in ipairs (patterns_t) do -- loop through the patterns in
new_URL = new_URL.gsub(new_URL, pattern, "");
end
return "[" .. URL .. " " .. new_URL .. "]";
end
--[[--------------------------< T R A N S L A T E >--------------------------------------------------------------------
translate a term based on the project language
]]
local function xlate (term)
if term then
--local new_term = string.gsub(term, " ", "_");
if 'en' == cfg.this_project_language then
return term;
elseif not cfg.xlate_t[cfg.this_project_language] then
return term;
elseif cfg.xlate_t[cfg.this_project_language][term] then
return cfg.xlate_t[cfg.this_project_language][term];
else
return term;
end
end
end
--[[--------------------------< T R A N S L A T E _ P A R A M >--------------------------------------------------------------------
translate a parameter based on the project language
]]
local function xlate_param (parameter)
if 'en' == cfg.this_project_language then
return parameter;
elseif not cfg.xlate_param_t[cfg.this_project_language] then
return parameter;
elseif cfg.xlate_param_t[cfg.this_project_language][parameter] then
return cfg.xlate_param_t[cfg.this_project_language][parameter];
else
return parameter;
end
end
--[[--------------------------< L O C A L _ P A R A M E T E R _ T O _ V A L U E _ O R _ B O O L E A N >--------------------------------------------------------------------
turns a given parameter into its local form and into a boolean
]]
local function local_parameter_to_value_or_boolean (frame, parameter, outcome) -- to test calls and functions, for verification purposes
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local localised_parameter = xlate_param (parameter); -- translate given parameter from English into local language
local argument = (args_t[tostring(localised_parameter)] and args_t[tostring(localised_parameter)]:lower()) or (args_t[parameter] and args_t[parameter]:lower()); -- get argument (in local language) matching parameter in local language
if outcome == 'boolean' then
if nil == argument then -- if no argument, return no
argument = false;
else
argument = xlate (argument); -- translate argument into English
argument = 'yes' == argument; -- turn argument into boolean
end
elseif nil ~= argument and argument:match ('^#') then
argument = argument.gsub(argument, "#", "#");
end
return argument;
end
--[[--------------------------< X L A T E _ W I K I D A T A >--------------------------------------------------------------------
call the {{wd}} or {{wikidata}} template based on language
arguments are as follows:
- data_requested: the type of data sought -- 'qualifier', 'property', 'references', 'label' -- compulsory
- qid: the Wikidata item on which data is sought -- e.g. Q208242 for the European People's Party -- not compulsory
- property_id: the property for which data is sought -- e.g. P1410 for number of seats in assembly -- compulsory
- qualifier_id: qualifier for property -- e.g. P194 for legislative body -- not compulsory
- value_of_qualifier: value of the qualifier -- e.g. P8889 for the European Parliament -- only compulsory if qualifier_id is provided
- reference: whether a reference should be displayed -- e.g. reference=yes to display the reference, anything else (preferably reference=no) otherwise; adding an "s" will display several references
- preferred: whether the preferred value should be displayed -- e.g. preferred=yes to display the preferred value, anything else (preferably preferred=no) otherwise
- raw: whether the qID should be displayed -- e.g. raw=yes to display the qID, anything else (preferably raw=no) otherwise
- linked: whether the value should be linked -- e.g. linked=yes to display the link, anything else (preferably linked=no) otherwise
]]
local function xlate_wikidata (data_requested, qid, property_id, qualifier_id, value_of_qualifier, reference, preferred, raw, linked)
mw.logObject( {data_requested, qid, property_id, qualifier_id, value_of_qualifier, reference, preferred, raw, linked}, "xlate_wikidata()" )
local local_reference = reference;
local local_preferred = preferred;
local local_raw = raw;
local local_linked = linked;
local Wd = require('Module:European_and_national_party_data/Wd')
if local_reference == 'reference=yes' then local_reference = 'reference' elseif local_reference == 'references=yes' then local_reference = 'references' else local_reference = '' end;
if local_preferred == 'preferred=yes' then local_preferred = 'preferred' else local_preferred = '' end;
if local_raw == 'raw=yes' then local_raw = 'raw' else local_raw = '' end;
if local_linked == 'linked=yes' then local_linked = 'linked' else local_linked = '' end;
local wdargs = {local_reference, local_preferred, local_raw, local_linked, property_id}
if qid then
table.insert(wdargs, 5, qid)
end
if '' ~= qualifier_id then
if '' ~= value_of_qualifier then
wdargs[qualifier_id] = value_of_qualifier;
else
table.insert(wdargs, qualifier_id)
end
end
mw.logObject( wdargs, "wdargs" )
return Wd['_' .. data_requested](wdargs);
end
--[[--------------------------< X L A T E _ C O M P O S I T I O N _ B A R >--------------------------------------------------------------------
call the {{composition bar}} template based on language
arguments are as follows:
- seats: the number of seats to be displayed;
- total_seats: the total number of seats of the institution in question;
- color: the color of the bar;
- width: the width of the bar;
- percentage: whether or not to display the percentage value;
- background_color: the background color of the bar;
- border: the color of the border;
]]
local function xlate_composition_bar (frame, seats, total_seats, color, width, percentage, background_color, border)
if 'fr' == cfg.this_project_language then
return frame:expandTemplate ({title='Infobox Parti politique/Sièges', args = {seats, total_seats, ['hex'] = color}});
elseif 'it' == cfg.this_project_language then
return frame:expandTemplate ({title='Seggi', args = {seats, total_seats, ['c'] = color}});
elseif 'es' == cfg.this_project_language then
return frame:expandTemplate ({title='Composition bar', args = {seats, total_seats, ['hex'] = color}});
elseif 'nl' == cfg.this_project_language then
local comp_bar_args_t = {
seats,
total_seats,
color,
width=width,
per=percentage,
['background-color'] = background_color,
border = border,
};
return frame:expandTemplate ({title='Percentagebalk', args = comp_bar_args_t});
else -- for all other languages the assumption is that the template is called composition bar
local comp_bar_args_t = {
seats,
total_seats,
color,
width=width,
per=percentage,
['background-color'] = background_color,
border = border,
};
return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t});
end
end
--[[==========================< S E C T I O N _ 2 : V A L I D A T I O N _ F U N C T I O N S >=======================
These are functions to ensure data validation and return error messages when relevant.
]]
--[[--------------------------< V A L I D A T E _ W I D T H >--------------------------------------------------
validates data format for the width parameter of composition bars; returns boolean true when valid; nil else
]]
local function validate_width (width)
local patterns_t = {'^%d+$', '^%d+px$', '^%d+%%$', '^%d+em$'}; -- valid
for i, pattern in ipairs (patterns_t) do -- loop through the patterns in
if width:match (pattern) then -- is there a match?
return true; -- yes, done
end
end
end
--[[--------------------------< H A R M O N I S E _ H O U S E _ T Y P E >----------------------------------------------
harmonises house type input (for calls relating to lower and upper houses)
]]
local function harmonise_lower_upper_house_name (house_type)
if house_type == "LOWER-HOUSE" or house_type == "LOWER" or house_type == "MS-LOWER-HOUSE"then -- the three accepted formats for input
return "LOWER_HOUSE"; -- format actually used in the code
elseif house_type == "UPPER-HOUSE" or house_type == "UPPER" or house_type == "MS-UPPER-HOUSE" then -- the three accepted formats for input
return "UPPER_HOUSE"; -- format actually used in the code
else
return house_type;
end
end
--[[--------------------------< V A L I D A T E _ I N S T I T U T I O N >----------------------------
when institution parameter exists, checkes that it is correct; returns boolean true when valid; error message else
]]
local function validate_institution (institution, template_name)
if institution and not cfg.institutions_t[institution] and not cfg.national_institutions_t[institution] then -- if institution is present, it must be known
return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}), template_name);
end
return true;
end
--[[==========================< S E C T I O N _ 3 : G E T _ F U N C T I O N S >=======================
These are functions to grab data from Wikidata
]]
--[[--------------------------< G E T _ D A T A >----------------------------------------------------------
general function to return data for the requested property for a party; required to expand {{wikidata}} template
]]
local function allpp_get_data (frame, party, property_id, option)
local template_name = frame:getParent():getTitle();
local args_t = get_args (frame);
local data = "";
local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean'); -- check verbose and make boolean
reference = (reference and option ~= "raw-noref") and 'references=yes' or ''; -- if reference is true, then the call will return a reference
local verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean'); -- check verbose and make boolean
local raw = (option == "raw" or option == "raw-noref") and "raw=yes" or "raw=no"; -- check raw and format correctly
local linked = (option == "linked") and "linked=yes" or "linked=no"; -- check linked and format correctly
local party_qid = ""; -- init party_qid
if not party then -- party is required
return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
elseif cfg.parties_t[party] then -- if party is a European party
party_qid = cfg.parties_t[party];
elseif cfg.alliances_t[party] then -- if party is a European alliance
party_qid = cfg.alliances_t[party];
elseif party:match ('^Q%d+$') then -- if party is a qID
party_qid = party;
elseif property_id == 'P465' and (party == "ALL" or party == "IND" or party == "NONE") then -- default colour for special parameters
return '#BBB';
elseif party ~= "THISPARTY" then -- error message if no party is provided
return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
end
if not party then -- direct call when no party is specified
party_qid = "" -- This should not be needed since the function
end -- should error out above if no party specified.
if property_id == "label" then -- if the label of the Wikidata element is requested
data = xlate_wikidata ('label', party_qid, , , '', 'reference=no', 'preferred=no', raw, linked);
elseif property_id == "individual members date" then -- special case
data = xlate_wikidata ('qualifier', party_qid, 'P2124', 'P585', '', 'reference=no', 'preferred=yes', raw, linked);
else -- for all other cases
data = xlate_wikidata ('property', party_qid, property_id, , , reference, 'preferred=no', raw, linked);
end
if property_id == cfg.data_prop_t.colour then -- if no colour, then default colour
if '' == data then
data = '#BBB';
else
data = '#' .. data;
end
elseif property_id == cfg.data_prop_t.website then -- if no website, then empty string
if '' == data then
data = "";
else
data = strip_URL (data);
end
end
if '' == data and verbose then -- if verbose, then error message
return make_error_msg (substitute (cfg.error_messages_t.no_data, {party_qid, property_id}));
end
return data;
end
--[[--------------------------< H O U S E _ Q I D _ F R O M _ M E M B E R _ S T A T E >----------------------------------------------------------
return the qID of a house based on its name (lower house or upper house) and its member state; required to expand {{wikidata}} template
]]
local function house_qid_from_member_state_qid (house_type, member_state_qid)
local house_qid = "";
for row, _ in ipairs (cfg.ms_data_t) do -- loop on table with lower/upper houses per member state
if member_state_qid == cfg.ms_data_t[row].member_state_qid then
if house_type == "LOWER_HOUSE" then
house_qid = cfg.ms_data_t[row].lower_house_qid; -- get the lower house qid
elseif house_type == "UPPER_HOUSE" then
house_qid = cfg.ms_data_t[row].upper_house_qid; -- get the upper house qid
end
end
end
return house_qid;
end
--[[--------------------------< I N S T I T U T I O N _ S I Z E >----------------------------------------------------------
return the size of an institution; required to expand {{wikidata}} template
]]
local function institution_size (frame, institution)
local institution_size = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- get the institution size
if '' == institution_size then -- if no institution size
return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}));
end
return institution_size;
end
--[[--------------------------< M E M B E R _ S T A T E _ D E L E G A T I O N _ S I Z E >----------------------------------------------------------
return the size of a member state's delegation in the European Parliament; required to expand {{wikidata}} template
]]
local function member_state_delegation_size (frame, member_state_qid)
local delegation_size = xlate_wikidata ('property', member_state_qid, 'P1410', 'P194', 'Q8889', 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- get the delegation size
if '' == delegation_size then -- if no delegation size
return make_error_msg (substitute (cfg.error_messages_t.not_member_state, {member_state_qid}));
end
return delegation_size;
end
--[[--------------------------< S I N G L E _ H O U S E _ S E A T S >------------------------------------------------
returns the number of seats in a given lower or upper house (identified by a row in the master table) from
wikidata. When
]]
local function single_house_seats (frame, row, house_type)
local house_qid;
if house_type == "LOWER_HOUSE" then
house_qid = cfg.ms_data_t[row].lower_house_qid; -- get the lower house qid
elseif house_type == "UPPER_HOUSE" then
house_qid = cfg.ms_data_t[row].upper_house_qid; -- get the upper house qid
end
return house_qid and xlate_wikidata ('property', house_qid, 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no') or 0; -- house_qid is nil when no upper or lower house
end
--[[--------------------------< T O T A L _ H O U S E _ S E A T S >------------------------------------------------
returns the total number of seats of all lower or upper houses in all member states.
]]
local function total_house_seats (frame, house_type)
local sum_seats = 0; -- init sum of seats of European party's member parties in house_type
for row, _ in ipairs (cfg.ms_data_t) do -- for all member states
sum_seats = sum_seats + single_house_seats (frame, row, house_type); -- increase sum_seats
end
return sum_seats;
end
--[[--------------------------< A L L P P _ S E A T S _ R E F >---------------------------------------------------------------
return the reference for a seat claim; required to expand {{wikidata}} template
]]
local function allpp_seats_ref (frame, party, institution)
local args_t = get_args (frame);
local party_type = args_t[1] and args_t[1]:lower(); -- force to lower case
party_type = xlate (party_type);
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
if party_type == 'european_entity' then
return '';
elseif party_type == 'national_party' then
if party == "THISPARTY" then
local member_state_qid = allpp_get_data (frame, mw.wikibase.getEntityIdForCurrentPage(), cfg.data_prop_t.country, 'raw-noref');
local house_qid = house_qid_from_member_state_qid (institution, member_state_qid)
return xlate_wikidata ('references', '', 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif party:match ('^Q%d+$') then
local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
local house_qid = house_qid_from_member_state_qid (institution, member_state_qid)
return xlate_wikidata ('references', party, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
end
end
elseif institution == 'EC' or institution == 'EUCO' then
if party == "THISPARTY" then
return xlate_wikidata ('references', '', 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif cfg.parties_t[party] then
return xlate_wikidata ('references', cfg.parties_t[party], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif cfg.alliances_t[party] then
return xlate_wikidata ('references', cfg.alliances_t[party], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif party:match ('^Q%d+$') then
return xlate_wikidata ('references', party, 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
end
else
if party == "THISPARTY" then
return xlate_wikidata ('references', '', 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif cfg.parties_t[party] then
return xlate_wikidata ('references', cfg.parties_t[party], 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif cfg.alliances_t[party] then
return xlate_wikidata ('references', cfg.alliances_t[party], 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif party:match ('^Q%d+$') then
return xlate_wikidata ('references', party, 'P1410', 'P194', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
end
end
end
local function allpp_get_seats_ref_qid (frame, institution_qid)
return xlate_wikidata ('references', '', 'P1410', 'P194', institution_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
end
--[[==========================< S E C T I O N _ 4 : S U M _ F U N C T I O N S >=======================
These functions are the ones providing seat numbers for European or national parties, in European institutions or national lower/upper houses
- functions starting with eupp apply to European parties;
- functions starting with npp apply to national political parties; and
- functions starting with allpp apply to all political parties.
]]
--[[--------------------------< A L L P P _ M A K E _ S H A R E _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------------
return the share of a party's seats relative to the total size of a given institution listed in
required to expand {{wikidata}} template
Note: P1342 is the property "number of seats", used to record an institution's number of seats
]]
local function allpp_make_share_in_eu_institutions (frame, party_seats, institution)
local args_t = get_args (frame);
local party_type = args_t[1] and args_t[1]:lower(); -- force to lower case
local party = args_t[3] and args_t[3]:upper(); -- force to lower case
local constituency = local_parameter_to_value_or_boolean (frame, 'constituency'); -- argument overriding the house's number of seats
party_type = xlate (party_type);
party = xlate (party);
if constituency then
return tonumber (party_seats) and round (100 * party_seats / constituency) or party_seats;
elseif party_type == "national_party" and institution == "EP" then
local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
return tonumber (party_seats) and round (100 * party_seats / member_state_delegation_size (frame, member_state_qid)) or party_seats;
else
return tonumber (party_seats) and round (100 * party_seats / xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no')) or party_seats;
end
end
--[[--------------------------< A L L P P _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >------------------------------------------------------------------
return the number of seats occupied by a political party in an
P194: legislative body
P208: executive body
required to expand {{wikidata}} template
Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
]]
local function allpp_seats_in_eu_institutions (frame, party, institution, body_prop)
local args_input_t = get_args (frame);
local verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean'); -- check verbose and make boolean
local args_t = {};
local retval = "";
if party == "THISPARTY" then -- flag used when module is called from the page of a European party; less expensive
retval = xlate_wikidata ('property', '', 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- init some of the {{wikidata}} parameters with THISPARTY (only when called from the page of a European party)
elseif cfg.alliances_t[party] then
retval = xlate_wikidata ('property', cfg.alliances_t[party], 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- init some of the {{wikidata}} parameters
elseif cfg.parties_t[party] then
retval = xlate_wikidata ('property', cfg.parties_t[party], 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- init some of the {{wikidata}} parameters
elseif party:match ('^Q%d+$') then
retval = xlate_wikidata ('property', party, 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- init some of the {{wikidata}} parameters
end
if '' == retval then -- {{wikidata}} returns empty string when
if party == "THISPARTY" then -- specific error message if the module was called with THISPARTY from the wrong page
return "";
elseif not party then
return make_error_msg (substitute (cfg.error_messages_t.party_req_share)), true;
else
return make_error_msg (substitute (cfg.error_messages_t.inst_unknown_party, {institution, party})), true;
end
end
return retval;
end
--[[--------------------------< E U P P _ S U M _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >------------------------------------------------------------------------
return the sum of seats for all European parties combined in an
property:
P194: legislative body
P208: executive body
required to expand {{wikidata}} template
Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
]]
local function eupp_sum_seats_in_eu_institutions (frame, institution, body_prop)
local sum = 0; -- init
for _, qid in pairs (cfg.parties_t) do -- loop through all parties in
local local_qid = qid; -- set the last {{wikidata}} parameter
sum = sum + xlate_wikidata ('property', local_qid, 'P1410', body_prop, cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- expand and tally
end
return sum;
end
--[[--------------------------< E U P P _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------------------
return a number of seats of a European party (or special parameter) in an
required to expand {{wikidata}} template
Note:
- P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
- P1342 is the property "number of seats", used to record an institution's number of seats
- P208 is the property "executive body"
- P194 is the property "legislative body"
]]
local function eupp_seats_in_eu_institutions (frame, party, institution)
if party == "IND" and institution == "EUCO" then -- special case of independent politicians on European Council
return xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
elseif party == "NONE" then -- returns seats not occupied by European parties
local retval = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no'); -- get number of seats in the institution
if institution == "EUCO" then -- if EUCO, use P208 and separate case to account for independent politicians
local ind = xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
return retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind);
else -- COR, EC, EP
return retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);
end
elseif party == "ALL" then -- returns seats occupied by all European parties combined
return eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);
elseif party:match ('^Q%d+$') then
local party_name = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
return allpp_seats_in_eu_institutions (frame, party_name, institution, cfg.body_prop_t[institution]);
else -- returns the number of seats occupied by one party in one institution
return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
end
end
--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------
return a share of seats of a European party (or special parameter) in an
required to expand {{wikidata}} template
Note:
- P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
- P1342 is the property "number of seats", used to record an institution's number of seats
- P208 is the property "executive body"
- P194 is the property "legislative body"
]]
local function eupp_seat_share_in_eu_institutions (frame, party, institution)
if party == "IND" and institution == "EUCO" then -- special case of independent politicians on European Council
return allpp_make_share_in_eu_institutions (frame, xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no'), institution);
elseif party == "NONE" then -- returns seats not occupied by European parties
local retval = xlate_wikidata ('property', cfg.institutions_t[institution], 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
if institution == "EUCO" then -- if EUCO, use P208 and separate case to account for independent politicians
local ind = xlate_wikidata ('property', cfg.misc_parties_t['IND'], 'P1410', 'P208', cfg.institutions_t[institution], 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
return allpp_make_share_in_eu_institutions (frame, retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind), institution);
else -- for COR, EC, EP
return allpp_make_share_in_eu_institutions (frame, retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);
end
elseif party == "ALL" then -- returns seats occupied by all European parties combined
return allpp_make_share_in_eu_institutions (frame, eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);
elseif party:match ('^Q%d+$') then
party = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
else -- returns the number of seats occupied by one party in one institution
return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
end
end
--[[--------------------------< N P P _ S E A T S _ P E R _ R O W >------------------------------
returns the number of seats occupied by a given party (identified by a given row in the master table) in the
lower or upper house of its member state from wikidata. When
does not have 'that' house, returns 0
]]
local function npp_seats_per_row (frame, row, house_type)
local house_qid = "";
local national_party_qid = cfg.tab_data_t[row].national_party_qid;
if house_type == "LOWER_HOUSE" then
house_qid = cfg.tab_data_t[row].lower_house_qid; -- get the qID of a lower house
elseif house_type == "UPPER_HOUSE" then
house_qid = cfg.tab_data_t[row].upper_house_qid; -- get the qID of an upper house
end
return house_qid and xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no') or 0;
end
--[[--------------------------< E U P P _ S E A T S _ I N _ N A T I O N A L _ I N S T I T U T I O N S >------------------------------
returns the sum of seats occupied by all national parties members of a given European party in the lower or upper house of its member state.
]]
local function eupp_seats_in_national_institutions (frame, party, house_type)
local sum_seats = 0; -- init sum of seats of European party's member parties in house_type
for row, _ in ipairs (cfg.tab_data_t) do
if party == "THISPARTY" then -- if called from the page of a European party
local thisparty_qid = mw.wikibase.getEntityIdForCurrentPage(); -- get party qiD
if thisparty_qid == cfg.tab_data_t[row]['european_party_qid'] then
sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type); -- increase sum_seats
end
elseif party == "ALL" or party == "NONE" then -- not accepted parameters
return make_error_msg (substitute (cfg.error_messages_t.all_none_unavailable, {party}));
elseif party == "IND" then -- not accepted parameter
return make_error_msg (substitute (cfg.error_messages_t.ind_only_euco));
elseif party:match ('^Q%d+$') then -- if party name is a qID
if party == cfg.tab_data_t[row]['european_party_qid'] then
sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type); -- increase sum_seats
end
else --for any other party name (already approved via party_type validation)
if party == cfg.tab_data_t[row]['european_party'] then
sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type); -- increase sum_seats
end
end
end
return sum_seats;
end
--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >--------------------------------------------------------
return a share of seats occupied by one or more entities listed in
required to expand {{wikidata}} template
]]
local function eupp_seat_share_in_national_institutions (frame, party, institution)
return round (100 * eupp_seats_in_national_institutions (frame, party, institution) / total_house_seats (frame, institution)); -- return share of seats by calling seat_share()
end
--[[--------------------------< N P P _ S E A T S _ A N D _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >------------------------------------------------
returns the sum or share of seats occupied by a national party in the lower or upper house of its member state.
]]
local function npp_seats_and_seat_share_in_national_institutions (frame, party, house_type, data)
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local party_qid = "";
local constituency = local_parameter_to_value_or_boolean (frame, 'constituency'); -- argument overriding the house's number of seats
if party == "THISPARTY" then
party_qid = mw.wikibase.getEntityIdForCurrentPage();
elseif party:match ('^Q%d+$') then
party_qid = party;
end
--[=[ data validation for party_qid ]=]
if party_qid == '' then
return make_error_msg (cfg.error_messages_t.no_qid, template_name); -- yep, abandon with error message
end
--[=[ get house_qid from party qid and house_seats ]=]
local member_state_qid = allpp_get_data (frame, party_qid, cfg.data_prop_t.country, 'raw-noref');
local house_qid = house_qid_from_member_state_qid (house_type, member_state_qid);
local npp_seats = house_qid and xlate_wikidata ('property', party_qid, 'P1410', 'P194', house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no') or 0;
local house_seats = house_qid and xlate_wikidata ('property', house_qid, 'P1342', , , 'reference=no', 'preferred=no', 'raw=no', 'linked=no') or 0;
if data == "seats" then
return npp_seats;
elseif data == "seat share" then
if constituency then
return round (100 * npp_seats / constituency);
else
return round (100 * npp_seats / house_seats);
end
elseif data == "house seats" then
return house_seats;
end
end
--[[--------------------------< A L L P P _ C O M P O S I T I O N _ B A R >------------------------------------------------
this function does whatever it is that {{composition bar}} does
implements {{EUPP composition bar}}
{{EUPP composition bar|
]]
local function allpp_composition_bar (frame, party, institution, party_type)
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local verbose = local_parameter_to_value_or_boolean (frame, 'verbose', 'boolean'); -- check verbose and make boolean
local percentage = local_parameter_to_value_or_boolean (frame, 'percent', 'boolean'); -- check percent and make boolean
local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean'); -- check reference and make boolean
local width = local_parameter_to_value_or_boolean (frame, 'width'); -- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
local constituency = local_parameter_to_value_or_boolean (frame, 'constituency'); -- argument overriding the house's number of seats
local institution_seats = 0;
local party_seats = 0;
local background_color = local_parameter_to_value_or_boolean (frame, 'background-color');
local border = local_parameter_to_value_or_boolean (frame, 'border');
if width and not validate_width (width) then
return make_error_msg (substitute (cfg.error_messages_t.parameter_invalid, {width}), template_name); -- yep, abandon with error message
end
--[=[ prepare arguments for composition bar ]=]
if party_type == "european_entity" then
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
party_seats = eupp_seats_in_national_institutions (frame, party, institution); -- get sum of seats occupied by members of a European party
institution_seats = total_house_seats(frame, institution); -- get total seats of lower or upper houses
else
party_seats = eupp_seats_in_eu_institutions (frame, party, institution); -- get total seats in
institution_seats = institution_size (frame, institution); -- get total seats in
end
elseif party_type == "national_party" then
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
party_seats = npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats");
institution_seats = constituency or npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "house seats")
elseif institution == "EP" then
local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
local has_error;
party_seats, has_error = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
if has_error then
return party_seats; --
end
institution_seats = constituency or member_state_delegation_size (frame, member_state_qid); -- get total seats in
else
local has_error;
party_seats, has_error = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
if has_error then
return party_seats; --
end
institution_seats = constituency or institution_size (frame, institution); -- get total seats in
end
end
local color = local_parameter_to_value_or_boolean (frame, 'bar-color') or allpp_get_data (frame, party, cfg.data_prop_t.colour); -- get color associated with
if == party_seats or == institution_seats then
if verbose then
return make_error_msg (substitute (cfg.error_messages_t.no_data_short));
else
return "";
end
elseif party_type == "european_entity" and (institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE") then
return xlate_composition_bar (frame, party_seats, institution_seats, color, width, percentage, background_color, border);
else
return xlate_composition_bar (frame, party_seats, institution_seats, color, width, percentage, background_color, border) .. ((reference and allpp_seats_ref (frame, party, institution)) or '');
end
end
--[[--------------------------< M A I N >----------------------------------------------------------------------
implements {{EUPP data}} and {{political party data}} (the templates hard-code the
carries out input error detection, reporting, and function dispatching
Module called by as follows:
{{EUPP data|
{{Political party data|
where
- seats
- seat share
- seat composition bar
- colour
- individual members
- acronym
- country
- name
- public funding
- website
- foundation date
]]
local function main(frame)
local template_name = frame:getParent():getTitle()
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local party_type = args_t[1] and args_t[1]:lower(); -- force to lower case
local data_type = args_t[2] and args_t[2]:lower(); -- force to lower case
local party = args_t[3] and args_t[3]:upper(); -- force to upper case
local institution = args_t[4] and args_t[4]:upper(); -- force to upper case
local party_qid = "";
local ref = "";
--[=[ translate arguments ]=]
party_type = xlate (party_type);
data_type = xlate (data_type);
party = xlate (party);
institution = xlate (institution);
--[=[ prepare arguments ]=]
local reference = local_parameter_to_value_or_boolean (frame, 'reference', 'boolean'); -- make a boolean
institution = harmonise_lower_upper_house_name (institution); -- "ms-lower-house" and "lower" are turned to "lower_house" (same for upper house)
party = harmonise_lower_upper_house_name (party); -- in case institution is entered as party
if cfg.institutions_t[party] or party == "LOWER_HOUSE" or party == "UPPER_HOUSE" then -- if the name of the party is actually the institution, then party is "thisparty"
institution = party;
party = "THISPARTY";
end
if not party then -- if party is missing, then it is "thisparty"
party = "THISPARTY";
end
--[=[ data validation party type ]=]
if party_type == "european_entity" and not (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or party == "THISPARTY") then
return make_error_msg (substitute (cfg.error_messages_t.not_valid_eupp_parameter, {party}), template_name);
elseif party_type == "european_entity" and party == "THISPARTY" and not (cfg.rev_parties_t[mw.wikibase.getEntityIdForCurrentPage()] or cfg.rev_alliances_t[mw.wikibase.getEntityIdForCurrentPage()]) then
return make_error_msg (substitute (cfg.error_messages_t.thisparty), template_name);
elseif party_type == "national_party" and (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or (party == "THISPARTY" and not mw.wikibase.getEntityIdForCurrentPage())) then
return make_error_msg (substitute (cfg.error_messages_t.not_valid_npp, {party}), template_name);
end
--[=[ data validation institution ]=]
local is_valid = false;
is_valid = validate_institution (institution, template_name);
if true ~= is_valid then -- boolean true when valid; error message else
return is_valid; -- yep, abandon with error message
end
--[=[ function dispatching ]=]
--[=[ send to seat functions ]=]
if data_type == "seats" then -- we look for a seat number
if not institution then -- institution is required
return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
end
if true == reference then
ref = allpp_seats_ref (frame, party, institution);
end
if party_type == "european_entity" then -- the party is a European party or European alliance (specified by the calling template, not by the user)
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then -- we look for seats aross lower or upper houses
return eupp_seats_in_national_institutions (frame, party, institution) .. ref; -- return the number of seats by calling eupp_seats_in_national_institutions
else -- we look for seats in a European institution
return eupp_seats_in_eu_institutions (frame, party, institution) .. ref; -- return the number of seats by calling eupp_seats_in_eu_institutions
end
elseif party_type == "national_party" then -- the party is a national party
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then -- we look for seats in a lower or upper house
return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats") .. ref; -- return the number of seats by calling ...
else -- we look for seats in a European institution
return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]) .. ref; -- return the number of seats by calling allpp_seats_in_eu_institutions
end
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
end
--[=[ send to seat share functions ]=]
elseif data_type == "seat share" then
if not institution then -- institution is required
return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
end
if party_type == "european_entity" then
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
return eupp_seat_share_in_national_institutions (frame, party, institution);
else
return eupp_seat_share_in_eu_institutions (frame, party, institution);
end
elseif party_type == "national_party" then
if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seat share");
else
return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution); -- return share of seats by calling seat_share()
end
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
end
--[=[ send to composition bar functions ]=]
elseif data_type == "seat composition bar" then
if not institution then -- institution is required
return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
end
return allpp_composition_bar (frame, party, institution, party_type);
--[=[ send to get_data functions ]=]
elseif data_type == "acronym" then
return allpp_get_data (frame, party, cfg.data_prop_t.acronym);
elseif data_type == "color" then
return allpp_get_data (frame, party, cfg.data_prop_t.colour);
elseif data_type == "country" then
return allpp_get_data (frame, party, cfg.data_prop_t.country, 'linked');
elseif data_type == "foundation date" then
return allpp_get_data (frame, party, cfg.data_prop_t.foundation_date);
elseif data_type == "foundation year" then
return mw.getContentLanguage():formatDate("Y",allpp_get_data (frame, party, cfg.data_prop_t.foundation_date, 'raw'));
elseif data_type == "individual members" then
return allpp_get_data (frame, party, cfg.data_prop_t.individual_members);
elseif data_type == "individual members date" then
return allpp_get_data (frame, party, 'individual members date');
elseif data_type == "individual members year" then
return mw.getContentLanguage():formatDate("Y",allpp_get_data (frame, party, 'individual members date', 'raw'));
elseif data_type == "label" then
return allpp_get_data (frame, party, 'label');
elseif data_type == "official name" then
return allpp_get_data (frame, party, cfg.data_prop_t.official_name);
elseif data_type == "parliamentary group" then
return allpp_get_data (frame, party, cfg.data_prop_t.parliamentary_group, 'linked');
elseif data_type == "public funding" then
return allpp_get_data (frame, party, cfg.data_prop_t.public_funding);
elseif data_type == "website" then
return allpp_get_data (frame, party, cfg.data_prop_t.website);
else
return make_error_msg (substitute (cfg.error_messages_t.unknown_data_type, {data_type}), template_name);
end
end
--[[--------------------------< E U _ I N S T I T U T I O N _ S E A T S >----------------------------------------------------------------------
]]
local function eu_institution_seats (frame)
local template_name = frame:getParent():getTitle()
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local institution = args_t[1] and args_t[1]:upper(); -- force to upper case
institution = xlate (institution);
institution = harmonise_lower_upper_house_name (institution); -- "ms-lower-house" and "lower" are turned to "lower_house" (same for upper house)
--[=[ data validation institution ]=]
local is_valid = false;
is_valid = validate_institution (institution, template_name);
if true ~= is_valid then -- boolean true when valid; error message else
return is_valid; -- yep, abandon with error message
end
--[=[ return value ]=]
if institution == 'LOWER_HOUSE' or institution == 'UPPER_HOUSE' then
return total_house_seats (frame, institution);
else
return institution_size (frame, institution);
end
end
--[[--------------------------< T E S T _ W I K I D A T A _ E N T R I E S >----------------------------------------------------------------------
]]
local function test_wikidata_entries (frame) -- to test calls and functions, for verification purposes
local wikidata_error = "Wikidata entries error(s):";
for row, _ in ipairs (cfg.tab_data_t) do
local national_party_qid = cfg.tab_data_t[row].national_party_qid;
local national_party_name = "";
if not cfg.tab_data_t[row].national_party then
national_party_name = cfg.tab_data_t[row].national_party_english;
else
national_party_name = cfg.tab_data_t[row].national_party;
end
local lower_house_qid = cfg.tab_data_t[row].lower_house_qid;
local lower_house_name = cfg.tab_data_t[row].lower_house;
local upper_house_qid = cfg.tab_data_t[row].upper_house_qid;
local upper_house_name = cfg.tab_data_t[row].upper_house;
local retval_lower = xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', lower_house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
local retval_upper = xlate_wikidata ('property', national_party_qid, 'P1410', 'P194', upper_house_qid, 'reference=no', 'preferred=no', 'raw=no', 'linked=no');
if '' == retval_lower then
wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. lower_house_name .. ")";
end
if '' == retval_upper then
wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. upper_house_name .. ")";
end
end
if wikidata_error == "Wikidata entries error(s):" then
wikidata_error = "Wikidata entries: all good!";
end
return wikidata_error;
end
--[[--------------------------< T E S T >----------------------------------------------------------------------
]]
local function test (frame) -- to test calls and functions, for verification purposes
local args_t = get_args (frame); -- get arguments; empty string or whitespace positional parameters set to nil
local parameter = args_t['parameter'] and args_t['parameter']:lower(); -- force to upper case
local outcome = args_t['outcome'] and args_t['outcome']:lower(); -- force to upper case
local localised_parameter = xlate_param (parameter); -- translate given parameter from English into local language
local argument = (args_t[tostring(localised_parameter)] and args_t[tostring(localised_parameter)]:lower()) or (args_t[parameter] and args_t[parameter]:lower()); -- get argument (in local language) matching parameter in local language
if outcome == 'boolean' then
if nil == argument then -- if no argument, return no
argument = false;
else
argument = xlate (argument); -- translate argument into English
argument = 'yes' == argument; -- turn argument into boolean
end
elseif argument:match ('^#') then
argument = argument.gsub(argument, "#", "#");
end
return argument;
--return "parameter: " .. parameter .. " - outcome: " .. tostring(outcome) .. " - localised parameter: " .. localised_parameter .. " - argument: " .. tostring(argument);
end
local function test2 (frame)
return cfg.this_project_language;
end
--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]
return {
main = main,
eu_institution_seats = eu_institution_seats,
test = test,
test2 = test2,
test_wikidata_entries = test_wikidata_entries,
-- xlate_wikidata = xlate_wikidata
}