Модуль:NationAndOccupation

    Матеріал з Релігія в огні

    Документацію для цього модуля можна створити у Модуль:NationAndOccupation/документація

    --[[  
      __  __           _       _        _   _       _   _                _              _  ___                             _   _             
     |  \/  | ___   __| |_   _| | ___ _| \ | | __ _| |_(_) ___  _ __    / \   _ __   __| |/ _ \  ___ ___ _   _ _ __   __ _| |_(_) ___  _ __  
     | |\/| |/ _ \ / _` | | | | |/ _ (_)  \| |/ _` | __| |/ _ \| '_ \  / _ \ | '_ \ / _` | | | |/ __/ __| | | | '_ \ / _` | __| |/ _ \| '_ \ 
     | |  | | (_) | (_| | |_| | |  __/_| |\  | (_| | |_| | (_) | | | |/ ___ \| | | | (_| | |_| | (_| (__| |_| | |_) | (_| | |_| | (_) | | | |
     |_|  |_|\___/ \__,_|\__,_|_|\___(_)_| \_|\__,_|\__|_|\___/|_| |_/_/   \_\_| |_|\__,_|\___/ \___\___|\__,_| .__/ \__,_|\__|_|\___/|_| |_|
    
     
    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.
    
    ]]
    
    -- =======================================
    -- === Dependencies ======================
    -- =======================================
    local core  = require("Module:core")
    local conj  = require('Module:Linguistic').conj
    local q2iso = require("Module:NationAndOccupation/nationalityLUT")
    local n2iso = require("Module:NationAndOccupation/CountryAdjective2iso")
    
    -- ==================================================
    -- === Internal functions ===========================
    -- ==================================================
    
    -------------------------------------------------------------------------------
    local function getBareLabel(id, userLang) 
    -- code equivalent to require("Module:Wikidata label")._getLabel with Wikidata=- option
    	local label, link
    	-- build language fallback list
    	local langList = mw.language.getFallbacksFor(userLang)
    	table.insert(langList, 1, userLang)
    	for _, lang in ipairs(langList) do  -- loop over language fallback list looking for label in the specific language
    		label = mw.wikibase.getLabelByLang(id, lang)
    		if label then break end                    -- label found and we are done
    	end	
    	return label or id
    end
    
    ------------------------------------------------------------------------------
    -- straight union of two arrays (tables)
    local function union ( a, b )
        local result = {}
        for _,v in pairs ( a or {} ) do
            table.insert( result, v )
        end
        for _,v in pairs ( b or {} ) do
             table.insert( result, v )
        end
        return result
    end
    
    ------------------------------------------------------------------------------
    -- get female forms of occupation using " female form of label (P2521) " property
    local function getFemaleLabel(item, lang)
    	local label = {}
    	for _, statement in pairs( mw.wikibase.getBestStatements( item, 'P2521' )) do
    		local v = statement.mainsnak.datavalue.value
    		if v then 
    			label[v.language] = v.text
    		end
    	end
    	if label then
    		label = core.langSwitch(label,lang)
    	end
    	if not label then
    		label = getBareLabel(item, lang)
    	end
    	return label
    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)
    
    	local styleLUT = { -- language dependent order
    		-- 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}
        -- Use LangSwitch to choose the style based on the language. That way language fallback chain is used
    	local style = core.langSwitch(styleLUT, 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 and #nationality>1 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, 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
    			if entity.claims and entity.claims[prop] then -- if we have wikidata item and item has the property
    				-- capture multiple "best" Wikidata value
    				data[field] = core.parseStatements(entity:getBestStatements( prop ), nil)
    			end
    		end
    	end
    	
    	-- Look up gender
    	if data.gender then	
    		local LUT = { Q6581097='male', Q2449503='male', Q6581072='female', Q1052281='female' }
    		gender = LUT[data.gender[1]]
    	end
    	if gender~='male' and gender~='female' then
    		gender = 'male'
    	end
    	
    	-- Look up occupation
    	local occ
    	for i, oItem in ipairs(data.occupation or {}) do
    		if i>6 then
    			break -- only 6 occupations are allowed
    		end
    		local occEN = mw.wikibase.getLabelByLang(oItem, 'en')
    		if gender == 'female' then -- get localized (translated) occupation labels in female form
    			occ = getFemaleLabel(oItem, lang) 
    		elseif lang=='en' then     -- get English occupation labels in male form
    			occ = occEN
    		else                       -- get localized (translated) occupation labels in male form
    			occ = getBareLabel(oItem, lang)
    		end
    		table.insert(occupation  , occ) 
    		table.insert(occupationEN, occEN)
    	end
    	
    	-- Look up nationality
    	if data.country or data.ethnicity then -- from wikidata
    		-- process P27/country and P172/ethnicity
    		local nTable = {} -- table of unique nationality iso codes stored as keys
    		for _, v in ipairs( union(data.country, data.ethnicity) ) do
    			for iso in mw.text.gsplit( q2iso[v] or '', '/', true ) do
    				nTable[ iso ] = 1
    			end
    		end
    		for nat, _ in pairs(nTable) do
    			table.insert(nationality, nat)
    		end
    	end
    	data = {nationality=nationality, occupation=occupation, gender=gender, occupationEN=occupationEN}
    	return data
    end
    
    -- ==================================================
    -- === External functions ===========================
    -- ==================================================
    local p = {}
    
    -- ===========================================================================
    -- === Version of the function to be called from other LUA codes
    -- ===========================================================================
    
    --[[
    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()
    		local occArray = mw.text.split(args0.occupation, '/')
    		occupation = {}
    		for i = 1,6 do 
    			if occArray[i] and occArray[i]~='' then 
    				local args={occArray[i], gender, lang=args0.lang}
    				table.insert(occupation, frame:expandTemplate{ title='Occupation', args=args })
    			end
    		end
    		if #occupation==0 then
    			occupation = nil
    		end
    	end
    	
    	-- Look up nationality
    	if args0.nationality then -- from input arguments
    		nationality = mw.text.split(args0.nationality, '/')
    		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
    		if #nationality==0 then
    			nationality = nil
    		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}
        --outStr = outStr .. '\n' .. mw.text.jsonEncode(data) .. '\n' .. mw.text.jsonEncode(args)
    	return outStr, args, data
    end
    
    -- ===========================================================================
    -- === Version of the functions to be called from template namespace
    -- ===========================================================================
    
    --[[
    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 = core.getArgs(frame)
    	local outStr, args, data = p._NationAndOccupation(args0)
    	return outStr
    end
    
    return p