Changes
Jump to navigation
Jump to search
Module:NationAndOccupation (view source)
Revision as of 08:05, 29 October 2018
, 08:05, 29 October 2018+bg
--[[
__ __ _ _ _ _ _ _ _ _ ___ _ _
| \/ | ___ __| |_ _| | ___ _| \ | | __ _| |_(_) ___ _ __ / \ _ __ __| |/ _ \ ___ ___ _ _ _ __ __ _| |_(_) ___ _ __
| |\/| |/ _ \ / _` | | | | |/ _ (_) \| |/ _` | __| |/ _ \| '_ \ / _ \ | '_ \ / _` | | | |/ __/ __| | | | '_ \ / _` | __| |/ _ \| '_ \
| | | | (_) | (_| | |_| | | __/_| |\ | (_| | |_| | (_) | | | |/ ___ \| | | | (_| | |_| | (_| (__| |_| | |_) | (_| | |_| | (_) | | | |
|_| |_|\___/ \__,_|\__,_|_|\___(_)_| \_|\__,_|\__|_|\___/|_| |_/_/ \_\_| |_|\__,_|\___/ \___\___|\__,_| .__/ \__,_|\__|_|\___/|_| |_|
This module translates a person’s nationality and profession into user’s preferred language.
The template takes care for the right word order: {{NationAndOccupation|m|FR|painter|poet}}
gives “French painter and poet”, if the user’s preferred language is set to English, but
“pintor y poeta francés”, if the language is set to Spanish. This is especially useful with
the “Description” field of {{Creator}} templates.
]]
local p = {}
-- =======================================
-- === Dependencies ======================
-- =======================================
local conj = require('Module:Linguistic').conj
local Wikidata = require("Module:Wikidata label") -- used for creation of name based on wikidata
local q2iso = require("Module:NationAndOccupation/nationalityLUT")
local n2iso = require("Module:NationAndOccupation/CountryAdjective2iso")
local function langSwitch(list,lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList,1,lang)
for i,language in ipairs(langList) do
if list[language] then
return list[language]
end
end
return nil
end
local function getFemaleLabel(q, lang)
local label = {}
local entity = mw.wikibase.getEntity(q)
if entity.claims and entity.claims.P2521 then -- if we have wikidata item and item has the property
for _, statement in pairs( entity:getBestStatements( 'P2521' )) do
local v = statement.mainsnak.datavalue
if v then
v = v.value
label[v.language] = v.text
end
end
end
if label then
return langSwitch(label,lang)
else
return nil
end
end
--[[
Implementation of Template:NationAndOccupation/default
INPUTS:
* nationality - array of string in the form compatible with Template:Nationality
* occupation - array of already translated strings
* gender - single gender string "male" or "female"
* lang - users language
]]
local function assembleNaO(nationality, occupation, gender, lang)
-- Use LangSwitch to choose the style based on the language. That way [[template:Fallback]] is used
local style = langSwitch({
-- Occupation then nationality order
ca=10 , es=10, eu=10, fa=10, he=10, it=10, pt=10, ro=10, vi=10,
-- Occupation then nationality order with first nationality in a special form
fr=11,
-- Nationality then Occupation order
cs=20 , da=20, el=20, en=20, eo=20, et=20, hu=20, mk=20, ml=20, nl=20,
-- Nationality then Occupation order, no space
zh=21,
-- Nationality then Occupation order with 1st nationality in a special form and 2nd nationality upper case
nds=22, de=22 ,
-- Nationality then Occupation order with 1st nationality in a special form and 2nd nationality lower case
pl=23, ru=23, sl=23, bg=23}, lang)
-- create nationality string
gender = gender or 'male'
local frame = mw.getCurrentFrame()
local nStr=''
if nationality and #nationality==1 then --Single nationality case
nStr = frame:expandTemplate{ title='Nationality', args={nationality[1], gender, lang=lang} }
elseif nationality then --Double nationality case
local N2 = frame:expandTemplate{ title='Nationality', args={nationality[2], gender, lang=lang} }
if style==11 or style==22 or style==23 then -- nationality in a special form
gender = 's'
end
local N1 = frame:expandTemplate{ title='Nationality', args={nationality[1], gender, lang=lang} }
if style==23 then
N2 = mw.ustring.lower(N2)
end
nStr = N1 .. '-' .. N2
end
-- Create final string
if occupation then
local oStr = conj(occupation, lang, 'and')
if style<20 then -- Type 1: Occupation then nationality order
return oStr .. ' ' .. nStr
elseif style==21 then -- Type 1: Nationality then Occupation order, no space
return nStr .. oStr
else -- Type 2: Nationality then Occupation order
return nStr .. ' ' .. oStr
end
else
return nStr
end
end
--[[
Implementation of Template:NationAndOccupation
INPUTS:
* entity - wikidata entity
* lang - users language
OUTPUTS:
* data - data structure with data extracted from Wikidata, including fields:
* nationality - array of string in the form compatible with Template:Nationality
* occupation - array of already translated occupation strings
* occupationEN - array of occupation strings in english
* gender - single gender string "male" or "female"
]]
local function harvest_wikidata(entity, lang)
local occupation, occupationEN, nationality, gender
local data = {}
-- if wikidata q-code is provided than look up few properties
if entity then
-- harvest properties from wikidata
local property = {P21='gender', P27='country', P106='occupation', P172='ethnicity'}
for prop, field in pairs( property ) do
local n = 0;
if entity.claims and entity.claims[prop] then -- if we have wikidata item and item has the property
-- capture multiple "best" Wikidata value
for _, statement in pairs( entity:getBestStatements( prop )) do
if (statement.mainsnak.snaktype == "value") then
local v = statement.mainsnak.datavalue.value.id
n = n+1
if n==1 then data[field]={} end
data[field][n] = v
end
end
end
end
end
-- Look up gender
if data.gender then
if (data.gender[1]=='Q6581097' or data.gender[1]=='Q2449503') then
gender = 'male'
end
if (data.gender[1]=='Q6581072' or data.gender[1]=='Q1052281') then
gender = 'female'
end
end
-- Look up occupation
if data.occupation then -- from wikidata
local occItem = {}
occupationEN = {}
for i = 1,6 do
if data.occupation[i] and data.occupation[i]~='' then
table.insert(occItem, data.occupation[i])
table.insert(occupationEN, Wikidata._getLabel(data.occupation[i], 'en', "-"))
end
end
occupation = {}
if gender == 'female' then -- get localized (translated) occupation labels in female form
for i,occ in ipairs(occItem) do
table.insert(occupation, getFemaleLabel(occ, lang) or Wikidata._getLabel(occ, lang, "-"))
end
elseif lang=='en' then -- get English occupation labels in male form
occupation = occupationEN
else -- get localized (translated) occupation labels in male form
for i,occ in ipairs(occItem) do
table.insert(occupation, Wikidata._getLabel(occ, lang, "-"))
end
end
end
-- Look up nationality
if data.country or data.ethnicity then -- from wikidata
-- process P27/country and P172/ethnicity
local nTable = {}
for i, v in ipairs( data.country or {} ) do
table.insert(nTable, q2iso[v])
end
for i, v in ipairs( data.ethnicity or {} ) do
table.insert(nTable, q2iso[v])
end
-- find unique values
table.sort(nTable)
nationality = {}
if nTable[1] then
table.insert(nationality, nTable[1])
end
for i = 2, #nTable do
if (nTable[i-1]~=nTable[i]) and nTable[i] then
table.insert(nationality, nTable[i])
end
end
end
return {nationality=nationality, occupation=occupation, gender=gender, occupationEN=occupationEN}
end
--[[
Implementation of Template:NationAndOccupation
INPUTS:
* args.nationality - '/' separated string with substrings in the form compatible
with Template:Nationality
* args.occupation - '/' separated string with substrings with english names of
occupations compatible with Template:Occupations
* args.gender - single gender string "male" or "female"
* args.wikidata - wikidata q-code
* args.lang - users language
OUTPUTS:
* OutStr - string with transpaced phrase like "english writer"
* args - data structure with processed inputs
* data - data structure with data extracted from Wikidata
]]
function p._NationAndOccupation(args0)
local occupation, nationality, entity, occupationEN
-- if wikidata q-code is provided than look up few properties
local q = args0.wikidata
if q and type(q)=='string' and string.sub(q,1,1)=="Q" then --
entity = mw.wikibase.getEntity(q)
elseif q then
entity = q
end
local data = harvest_wikidata(entity, args0.lang)
local gender = args0.gender or data.gender
-- Look up occupation
if args0.occupation then -- from input arguments
local frame = mw.getCurrentFrame()
occupationEN = mw.text.split(args0.occupation or '', '/')
occupation = {}
for i = 1,6 do
if occupationEN[i] and occupationEN[i]~='' then
table.insert(occupation, frame:expandTemplate{ title='Occupation', args={occupationEN[i], gender, lang=args0.lang, category=category} })
end
end
end
-- Look up nationality
if args0.nationality then -- from input arguments
nationality = mw.text.split(args0.nationality or '', '/')
for i = 1,2 do -- if nationality is a word than see if we can find iso code
local N = string.lower(nationality[i] or '')
if #N>2 and n2iso[N] then
nationality[i] = n2iso[N]
end
end
end
local outStr = assembleNaO(nationality or data.nationality, occupation or data.occupation, gender, args0.lang)
local args = {nationality=nationality, occupation=occupation, gender=args0.gender, occupationEN=occupationEN}
return outStr, args, data
end
--[[
NationAndOccupation
This function is the core part of the NationAndOccupation template.
Usage:
{{#invoke:}}
Parameters:
*nationality - '/' separated string with substrings in the form compatible
with Template:Nationality
* occupation - '/' separated string with substrings with english names of
occupations compatible with Template:Occupations
* gender - single gender string "male" or "female"
* wikidata - wikidata q-code
* lang - users language
Error Handling:
]]
function p.NationAndOccupation(frame)
local args0 = {}
for name, value in pairs( frame.args ) do
value = string.gsub(value,"\/+$", "") -- remove /// on the end
value = string.gsub(value,"%s*$", "") -- remove whitespaces on the end
value = string.gsub(value,"^%s*", "") -- remove whitespaces at the beggining
if value ~= '' then -- nuke empty strings
local name1 = string.gsub( string.lower(name), ' ', '_')
args0[name1] = value
end
end
if not (args0.lang and mw.language.isSupportedLanguage(args0.lang)) then
args0.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
end
local outStr, args, data = p._NationAndOccupation(args0)
return outStr
end
return p
__ __ _ _ _ _ _ _ _ _ ___ _ _
| \/ | ___ __| |_ _| | ___ _| \ | | __ _| |_(_) ___ _ __ / \ _ __ __| |/ _ \ ___ ___ _ _ _ __ __ _| |_(_) ___ _ __
| |\/| |/ _ \ / _` | | | | |/ _ (_) \| |/ _` | __| |/ _ \| '_ \ / _ \ | '_ \ / _` | | | |/ __/ __| | | | '_ \ / _` | __| |/ _ \| '_ \
| | | | (_) | (_| | |_| | | __/_| |\ | (_| | |_| | (_) | | | |/ ___ \| | | | (_| | |_| | (_| (__| |_| | |_) | (_| | |_| | (_) | | | |
|_| |_|\___/ \__,_|\__,_|_|\___(_)_| \_|\__,_|\__|_|\___/|_| |_/_/ \_\_| |_|\__,_|\___/ \___\___|\__,_| .__/ \__,_|\__|_|\___/|_| |_|
This module translates a person’s nationality and profession into user’s preferred language.
The template takes care for the right word order: {{NationAndOccupation|m|FR|painter|poet}}
gives “French painter and poet”, if the user’s preferred language is set to English, but
“pintor y poeta francés”, if the language is set to Spanish. This is especially useful with
the “Description” field of {{Creator}} templates.
]]
local p = {}
-- =======================================
-- === Dependencies ======================
-- =======================================
local conj = require('Module:Linguistic').conj
local Wikidata = require("Module:Wikidata label") -- used for creation of name based on wikidata
local q2iso = require("Module:NationAndOccupation/nationalityLUT")
local n2iso = require("Module:NationAndOccupation/CountryAdjective2iso")
local function langSwitch(list,lang)
local langList = mw.language.getFallbacksFor(lang)
table.insert(langList,1,lang)
for i,language in ipairs(langList) do
if list[language] then
return list[language]
end
end
return nil
end
local function getFemaleLabel(q, lang)
local label = {}
local entity = mw.wikibase.getEntity(q)
if entity.claims and entity.claims.P2521 then -- if we have wikidata item and item has the property
for _, statement in pairs( entity:getBestStatements( 'P2521' )) do
local v = statement.mainsnak.datavalue
if v then
v = v.value
label[v.language] = v.text
end
end
end
if label then
return langSwitch(label,lang)
else
return nil
end
end
--[[
Implementation of Template:NationAndOccupation/default
INPUTS:
* nationality - array of string in the form compatible with Template:Nationality
* occupation - array of already translated strings
* gender - single gender string "male" or "female"
* lang - users language
]]
local function assembleNaO(nationality, occupation, gender, lang)
-- Use LangSwitch to choose the style based on the language. That way [[template:Fallback]] is used
local style = langSwitch({
-- Occupation then nationality order
ca=10 , es=10, eu=10, fa=10, he=10, it=10, pt=10, ro=10, vi=10,
-- Occupation then nationality order with first nationality in a special form
fr=11,
-- Nationality then Occupation order
cs=20 , da=20, el=20, en=20, eo=20, et=20, hu=20, mk=20, ml=20, nl=20,
-- Nationality then Occupation order, no space
zh=21,
-- Nationality then Occupation order with 1st nationality in a special form and 2nd nationality upper case
nds=22, de=22 ,
-- Nationality then Occupation order with 1st nationality in a special form and 2nd nationality lower case
pl=23, ru=23, sl=23, bg=23}, lang)
-- create nationality string
gender = gender or 'male'
local frame = mw.getCurrentFrame()
local nStr=''
if nationality and #nationality==1 then --Single nationality case
nStr = frame:expandTemplate{ title='Nationality', args={nationality[1], gender, lang=lang} }
elseif nationality then --Double nationality case
local N2 = frame:expandTemplate{ title='Nationality', args={nationality[2], gender, lang=lang} }
if style==11 or style==22 or style==23 then -- nationality in a special form
gender = 's'
end
local N1 = frame:expandTemplate{ title='Nationality', args={nationality[1], gender, lang=lang} }
if style==23 then
N2 = mw.ustring.lower(N2)
end
nStr = N1 .. '-' .. N2
end
-- Create final string
if occupation then
local oStr = conj(occupation, lang, 'and')
if style<20 then -- Type 1: Occupation then nationality order
return oStr .. ' ' .. nStr
elseif style==21 then -- Type 1: Nationality then Occupation order, no space
return nStr .. oStr
else -- Type 2: Nationality then Occupation order
return nStr .. ' ' .. oStr
end
else
return nStr
end
end
--[[
Implementation of Template:NationAndOccupation
INPUTS:
* entity - wikidata entity
* lang - users language
OUTPUTS:
* data - data structure with data extracted from Wikidata, including fields:
* nationality - array of string in the form compatible with Template:Nationality
* occupation - array of already translated occupation strings
* occupationEN - array of occupation strings in english
* gender - single gender string "male" or "female"
]]
local function harvest_wikidata(entity, lang)
local occupation, occupationEN, nationality, gender
local data = {}
-- if wikidata q-code is provided than look up few properties
if entity then
-- harvest properties from wikidata
local property = {P21='gender', P27='country', P106='occupation', P172='ethnicity'}
for prop, field in pairs( property ) do
local n = 0;
if entity.claims and entity.claims[prop] then -- if we have wikidata item and item has the property
-- capture multiple "best" Wikidata value
for _, statement in pairs( entity:getBestStatements( prop )) do
if (statement.mainsnak.snaktype == "value") then
local v = statement.mainsnak.datavalue.value.id
n = n+1
if n==1 then data[field]={} end
data[field][n] = v
end
end
end
end
end
-- Look up gender
if data.gender then
if (data.gender[1]=='Q6581097' or data.gender[1]=='Q2449503') then
gender = 'male'
end
if (data.gender[1]=='Q6581072' or data.gender[1]=='Q1052281') then
gender = 'female'
end
end
-- Look up occupation
if data.occupation then -- from wikidata
local occItem = {}
occupationEN = {}
for i = 1,6 do
if data.occupation[i] and data.occupation[i]~='' then
table.insert(occItem, data.occupation[i])
table.insert(occupationEN, Wikidata._getLabel(data.occupation[i], 'en', "-"))
end
end
occupation = {}
if gender == 'female' then -- get localized (translated) occupation labels in female form
for i,occ in ipairs(occItem) do
table.insert(occupation, getFemaleLabel(occ, lang) or Wikidata._getLabel(occ, lang, "-"))
end
elseif lang=='en' then -- get English occupation labels in male form
occupation = occupationEN
else -- get localized (translated) occupation labels in male form
for i,occ in ipairs(occItem) do
table.insert(occupation, Wikidata._getLabel(occ, lang, "-"))
end
end
end
-- Look up nationality
if data.country or data.ethnicity then -- from wikidata
-- process P27/country and P172/ethnicity
local nTable = {}
for i, v in ipairs( data.country or {} ) do
table.insert(nTable, q2iso[v])
end
for i, v in ipairs( data.ethnicity or {} ) do
table.insert(nTable, q2iso[v])
end
-- find unique values
table.sort(nTable)
nationality = {}
if nTable[1] then
table.insert(nationality, nTable[1])
end
for i = 2, #nTable do
if (nTable[i-1]~=nTable[i]) and nTable[i] then
table.insert(nationality, nTable[i])
end
end
end
return {nationality=nationality, occupation=occupation, gender=gender, occupationEN=occupationEN}
end
--[[
Implementation of Template:NationAndOccupation
INPUTS:
* args.nationality - '/' separated string with substrings in the form compatible
with Template:Nationality
* args.occupation - '/' separated string with substrings with english names of
occupations compatible with Template:Occupations
* args.gender - single gender string "male" or "female"
* args.wikidata - wikidata q-code
* args.lang - users language
OUTPUTS:
* OutStr - string with transpaced phrase like "english writer"
* args - data structure with processed inputs
* data - data structure with data extracted from Wikidata
]]
function p._NationAndOccupation(args0)
local occupation, nationality, entity, occupationEN
-- if wikidata q-code is provided than look up few properties
local q = args0.wikidata
if q and type(q)=='string' and string.sub(q,1,1)=="Q" then --
entity = mw.wikibase.getEntity(q)
elseif q then
entity = q
end
local data = harvest_wikidata(entity, args0.lang)
local gender = args0.gender or data.gender
-- Look up occupation
if args0.occupation then -- from input arguments
local frame = mw.getCurrentFrame()
occupationEN = mw.text.split(args0.occupation or '', '/')
occupation = {}
for i = 1,6 do
if occupationEN[i] and occupationEN[i]~='' then
table.insert(occupation, frame:expandTemplate{ title='Occupation', args={occupationEN[i], gender, lang=args0.lang, category=category} })
end
end
end
-- Look up nationality
if args0.nationality then -- from input arguments
nationality = mw.text.split(args0.nationality or '', '/')
for i = 1,2 do -- if nationality is a word than see if we can find iso code
local N = string.lower(nationality[i] or '')
if #N>2 and n2iso[N] then
nationality[i] = n2iso[N]
end
end
end
local outStr = assembleNaO(nationality or data.nationality, occupation or data.occupation, gender, args0.lang)
local args = {nationality=nationality, occupation=occupation, gender=args0.gender, occupationEN=occupationEN}
return outStr, args, data
end
--[[
NationAndOccupation
This function is the core part of the NationAndOccupation template.
Usage:
{{#invoke:}}
Parameters:
*nationality - '/' separated string with substrings in the form compatible
with Template:Nationality
* occupation - '/' separated string with substrings with english names of
occupations compatible with Template:Occupations
* gender - single gender string "male" or "female"
* wikidata - wikidata q-code
* lang - users language
Error Handling:
]]
function p.NationAndOccupation(frame)
local args0 = {}
for name, value in pairs( frame.args ) do
value = string.gsub(value,"\/+$", "") -- remove /// on the end
value = string.gsub(value,"%s*$", "") -- remove whitespaces on the end
value = string.gsub(value,"^%s*", "") -- remove whitespaces at the beggining
if value ~= '' then -- nuke empty strings
local name1 = string.gsub( string.lower(name), ' ', '_')
args0[name1] = value
end
end
if not (args0.lang and mw.language.isSupportedLanguage(args0.lang)) then
args0.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
end
local outStr, args, data = p._NationAndOccupation(args0)
return outStr
end
return p