Moduuli:käännöslajittelu/hiekkalaatikko

Tämän moduulin ohjeistuksen voi tehdä sivulle Moduuli:käännöslajittelu/hiekkalaatikko/ohje

local kielet = require("Module:kielikoodit")

local m = {}

-- vikailmoitus kun ei käytetä subst:ia
local VIKA = "Seuraavissa käännösmerkinnöissä on vikaa (väärä muoto tai kieltä ei ole lisätty tietokantaan):"
local VIKALUOKKA = "[[Luokka:Ongelmalliset käännökset]]"
local VIKALUOKKA_MUOTO = "[[Luokka:Ongelmalliset käännökset/virheellinen muoto]]"
-- vikailmoitus kun käytettään subst:ia
local VIKA_SUBST = "<!-- Seuraavissa käännöksissä on vikaa. Jos kirjoitit kielen nimen ja tunnuksen oikein, kieltä ei ole lisätty tietokantaan. Lisää se Module:kielikoodit tiedostoon tai sen keskustelusivulle. -->"

local function HUOMSPAN(text)  
	return '<' .. 'span style="width: 240px; padding-left: 20px; padding-right: 20px; background-color: pink; font-weight: normal; font-style: italic; color: black;">' .. text .. '</' .. 'span>'
end
	
-- Palauttaa annetun kielen nimen ja lajitteluarvon. Jos kieltä ei löydy palauttaa lajitteluarvona -1.
--  Parametri `key` voi olla kielikoodimalline, kielikoodi tai kielen koko nimi.
local function avaa(key)
    if kielet.tunnus(key) then      -- kokonainen nimi, *saksa: [[Störz]]
        return key, kielet.lajitteluarvo_nimelle(key)
    elseif kielet.nimi(key) then       -- pelkkä koodi, *de: [[Störz]]
        local kn = kielet.nimi(key)
        return kn, kielet.lajitteluarvo_nimelle(kn)
    else
        -- Huom. vain jos korvaus päällä, muuten jo laajennettu
        local m = string.match(key, "{{(%w+)}}")
        if m and kielet.nimi(m) then        -- kielikoodimalline, *{{de}}: [[Störz]]
            local kn = kielet.nimi(m)
            return kn, kielet.lajitteluarvo_nimelle(kn)
        end
    end
    return key, -1
end

local function kieliosa(nimi)
    tunnus = kielet.tunnus(nimi)
    if tunnus then
        --return "{{" .. tunnus .. "}}"
        return tunnus
    else
        return nimi
    end
end

-- muotoilee ylä-mallineelle annettavat parametrit
local function muotoile_selite(lista)
    local ulos = {}
    ulos[2] = table.remove(lista, #lista)
    local selite = ulos[2] or ""
    
    if #lista > 0 and lista[1] ~= "" then
        ulos[1] = mw.text.listToText(lista, "., ", ". ja ") .. ((#lista > 0 and ".") or "")
        -- yhteensopivuuden edelliseen versioon takia -> jos parametrit on tyhjiä ei lisätä pistettä
    else
        ulos[1] = HUOMSPAN('Numero puuttuu.' .. '[[Luokka:Ei numeroa kohta-mallineessa]]')
    end
    
    if #selite > 150 then
        selite = selite .. "[[Luokka:Pitkät selitteet]]"
    end
    
    if #selite == 0 then
        selite = HUOMSPAN('Selite puuttuu.' .. '[[Luokka:Ei selitettä kohta-mallineessa]]')
    end
    
    if selite == mw.title.getCurrentTitle().text then
    	selite = selite .. '[[Luokka:Määriteltävä sana kohta-mallineessa]]'
    end
    
    ulos[2] = selite
    return ulos
end

local ulos = ''
local function println(t) ulos = ulos .. t .. '\n' end

-- Tulostaa muun tekstin taulukon tilalla (Kts.)
-- Parametrit: 
--   frame    frame-objekti
--   subst    1, jos käytetään subst:in kanssa, muuten 0
--   selite   taulukon numero(t) ja selite taulukkona
--   teksti   taulukon tilalle tulostettava teksti
--   luokka   taulukkoon liitettävä CSS-luokka
local function tulosta_muu(frame, subst, selite, teksti, luokka)
    ulos = ""    
    if not subst then
        println("<div class=\"käännöskohta" .. (luokka and (" " .. luokka)) .. "\" style=\"clear:both\">");
        println(frame:expandTemplate{title="ylä", args = muotoile_selite(selite)})
    else
        println(table.concat(selite, "|") .. (((#selite > 1) and "|") or ""))
    end
    
    println(teksti)
    
    if not subst then
        println(frame:expandTemplate{title="ala", args = {}})
        println("</div>");
    end
    
    return ulos
end


-- Parametrit: 
--   frame    frame-objekti
--   subst    1, jos käytetään subst:in kanssa, muuten 0
--   selite   taulukon numero(t) ja selite taulukkona
local function tulosta_kaannokset_puuttuvat(frame, subst, selite)
    ulos = ""
    println("<div class=\"käännöskohta\" style=\"clear:both\">");
    println(frame:expandTemplate{title="ylä", args = muotoile_selite(selite)})
    println(frame:expandTemplate{title="käännökset/puuttuvat", args = {}})
    println(frame:expandTemplate{title="ala", args = {}})
    println("</div>");
    return ulos
end

-- Tulostaa osataulukon jakaen sen kahteen osaan keskiviivalla.
--   frame      frame-objekti
--   subst      1, jos käytetään subst:in kanssa, muuten 0
--   taul       taulukko
--   tulostaja  tulostusfunktio
local function tulosta_alitaulukko(frame, subst, taul, tulostaja)
    -- tulostettujen rivien määrä
    local m = 0
    -- toisen sarakkeen ensimmäinen alkio
    local iv = 0
    
    for i = 1, #taul do
        tulostaja(subst, taul[i])
        m = m + taul[i].m
        if m >= (taul.yht / 2) then iv = i; break end
    end
    
    -- tulostetaan keskiviiva vain jos käytetään ilman subst:ia, koska sitä ei editointitilassa tarvitse ja 
    -- teksti muotoillaan joka tapauksessa uusiksi
    if not subst then
        println(frame:expandTemplate{title="keski", args = {}})
    end
    
    -- iv == 0 jos kaikki mahtui 1. sarakkeeseen
    if iv > 0 then
        for i = iv+1, (#taul) do
            tulostaja(subst, taul[i])
        end
    end 
end   

-- Koko taulukon tulostus.
--   frame      frame-objekti
--   subst      1, jos käytetään subst:in kanssa, muuten 0
--   selite   taulukon numero(t) ja selite taulukkona
--   rivit      parsitut taulukon rivit
--   oudot      vialliset rivit
local function tulosta_taulukko(frame, subst, selite, rivit, oudot)
    local function tulosta_kieli(subst, kieli) 
        println("*" .. kieli.kn .. ": " .. kieli.v) 
    end
    local function tulosta_raaka(subst, rivi) 
        println(rivi.t) 
    end
    
    if not subst then
        println("<div class=\"käännöskohta\" style=\"clear:both\">");
        println(frame:expandTemplate{title="ylä", args = muotoile_selite(selite)})
    else
        -- "{{kohta|" tulostetaan mallineessa
        println(table.concat(selite, "|") .. (((#selite > 1) and "|") or ""))
    end
    
    -- tulostetaan varsinainen taulukko
    tulosta_alitaulukko(frame, subst, rivit, tulosta_kieli)

    -- jos viallisia, tulostetaan toinen taulukko, jossa vialliset
    if #oudot > 0 then
        -- tulostetaan puuteilmoitukset vain kun ei korvata, koska muuten VIKA-rivi tulkitaan käännösriviksi
        if not subst then
            println("|- ") 
            println("| colspan=\"3\" | ") 
            println(VIKA)
            if oudot.kieli then
                println(VIKALUOKKA)
            end
            if oudot.muoto then
                println(VIKALUOKKA_MUOTO)
            end
            println(frame:expandTemplate{ title="keski-h", args = {} })  
        else 
            println(VIKA_SUBST)
        end 
        tulosta_alitaulukko(frame, subst, oudot, tulosta_raaka)
    end
    
    if not subst then
        println(frame:expandTemplate{title="ala", args = {}})
        println("</div>");
        -- "|loppu}}" tai "|}}" tulostetaan mallineessa
    end
    
    return ulos
end


-- Yhdistää rivit, joissa on sama kieli. Olettaa että rivit on lajiteltu.
-- rivit  parsittu rivitaulukko, jossa alkioiden muoto: 
--   .v = kohdan sisältämä teksti, .m = kohdan rivimäärä, 
--   .k = kielikoodi tai kieli, .j = lajitteluarvo
local function yhdista_samat(rivit) 
    local urivit = {}
    local ed = nil
    urivit.yht = rivit.yht
    
    for i = 1, #rivit do
        if rivit[i].kn == ed then
        	-- Lisätään aiempi rivi seuraavan perään, koska käännösten lisäyswidgetti lisää uuden käännöksen ensimmäiseksi.
        	-- Pysyykö järjestys lajittelussa??
            urivit[#urivit].v = rivit[i].v .. ", " .. urivit[#urivit].v
        else
            table.insert(urivit, rivit[i])

            -- TODO Epäselvää miten useampiriviset pitäisi yhdistää. Nyt jätetään yhdistämättä.
            if rivit[i].m == 1 then
                ed = rivit[i].kn
            else
                ed = nil
            end
        end
    end
    return urivit
end

-- Palauttaa taulukon `args` ensimmäisen sellaisen alkion numeron, joka alkaa rivinvaihdolla 
-- ts. parametrin joka sisältää käännösluettelon (eikä numeroa tai selitettä)
local function hae_tekstiparam(args)
    for i,v in ipairs(args) do
        if string.match(v, "^[ \t]*\n") then
            return i
        end 
    end
    return nil
end

-- Parsii tekstin teksti ja palauttaa sen järjestettynä ja {{keski}}-mallineella varustettuna.
local function parsi_taulukko(frame, subst, selite, teksti)
    -- alkioiden muoto: 
    --   .v = kohdan sisältämä teksti, .m = kohdan rivimäärä, 
    --   .k = kielikoodi tai kieli, .j = lajitteluarvo
    local rivit = {}  
    rivit.yht = 0
    local virheelliset = {}
    local oudot = {}
    oudot.yht = 0
    oudot.kieli = false    -- tuntematon kieli
    oudot.muoto = false    -- väärä muoto

    local sis = nil  -- sisennys
    local i = 0
    -- Käydään läpi rivi kerrallaan.
    for r in string.gmatch(teksti, "([^\n]*)\n") do
        -- ohitetaan tyhjät rivit ja keski-malline. Huom. keskimalline on avaamattomassa muodossa 
        -- vain subst:ia käytettäessä
        if r ~= '' and r ~= "{{keski}}" then
            -- Yritetään jakaa rivi kaksoispiteestä.
            s, k, v = string.match(r, "^([*:]*) *([^:]*): *(.*)")

            -- Tallennetaan ensimmäisen rivin sisennys vertailukohdaksi, koska joissain vanhoissa ylä-ala-merkinnöissä
            -- ei ole käytetty pallukkaa.
            if sis == nil then sis = s end 

            if k == nil then  -- ei kaksoispistettä -> rivi ei oikeaa muotoa
                table.insert(oudot, { t = r, m = 1 })
                oudot.yht = oudot.yht + 1
                oudot.muoto = true
            else
                -- Jos rivi on sisennetty (k='' tyhjä kun rivi alkaa :-merkillä) tai sisennetty enemmän kuin 
                -- eka rivi, lisätään edellisen perään.
                if k == '' or s:len() > sis:len() then 
                    local kn,j = avaa(k)
                    rivit[i].v = rivit[i].v .. '\n' .. s .. ((kn .. ": ") or "") .. v
                    rivit[i].m = rivit[i].m + 1
                    rivit.yht = rivit.yht + 1
                    -- Muuten lisätään uusi rivi.
                else
                    local kn,j = avaa(k)
                    -- kieltä ei löytynyt tietokannasta
                    if j == -1 then 
                        table.insert(oudot, { t = r, m = 1 })
                        oudot.yht = oudot.yht + 1
                        oudot.kieli = true
                    else
                        i = i + 1
                        rivit[i] = { kn = kn, j = j, v = v, m = 1 }
                        rivit.yht = rivit.yht + 1
                    end 
                end
            end
        end
    end
    
    local function comp(a, b) assert(b~= nil, "a: ".. a.kn); return a.j < b.j end
    table.sort(rivit, comp)
    rivit = yhdista_samat(rivit)
    return tulosta_taulukko(frame, subst, selite, rivit, oudot)
end


local function kopioi(lista, loppu)
    local ulos = {}
    for i = 1,loppu do
        table.insert(ulos, lista[i])
    end
    return ulos
end

local function parsi(frame, subst)
    -- käännöksen numero ja teksti
    local selite = {}
    -- käännösluettelo
    local teksti = ""
    -- sen parametrin numero, jossa käännösluettelo on
    local tp = hae_tekstiparam(frame.args)
    if tp == 2 then
    	error("Virheelliset parametrit. Käyttö: 1. määritelmän numero, 2. määritelmän kuvaus, 3. käännökset. " .. tp, 2)
	end
    if tp ~= nil then
        selite = kopioi(frame.args, tp-1)
        teksti = frame.args[tp]
    end
    
    -- tyhjä taulukko
    if teksti == nil or string.match(teksti, "^[ \t\n]*$") then
        if not subst then
            return tulosta_kaannokset_puuttuvat(frame, subst, selite);
        else
            return tulosta_muu(frame, subst, selite, "")
        end
    end
    
    -- katso-ohjaus
    local kts = string.match(teksti, "\n%*? *[Kk]a?t?so?%. *")
    if kts then
        alku = kts:len()+1
        return tulosta_muu(frame, subst, selite, "Kts. " .. string.sub(teksti, alku, teksti:len()-1), "käännöskohta_ohjaus")
    end
    
    -- normaalitilanne
    return parsi_taulukko(frame, subst, selite, teksti)
end

-- Parametrit: 
--  jos kutsutaan subst:in kanssa args[1] == 1
-- teksti luetaan ylämallineen parametreistä
function m.jarjesta(frame)
    return parsi(frame:getParent(), frame.args[1])
end

return m