Aller au contenu

Module:bac à sable/Darmo117/fr-flexion

Définition, traduction, prononciation, anagramme et synonyme sur le dictionnaire libre Wiktionnaire.

La documentation pour ce module peut être créée à Module:bac à sable/Darmo117/fr-flexion/Documentation

--- This module defines functions for use in French inflections tables.

local m_params = require("Module:paramètres")
local m_pron = require("Module:prononciation")
local m_table = require("Module:table")

local p = {}


----------------
-- Args class --
----------------


--- @class Args
local Args = {}
Args.__index = Args

function Args:new()
  local this = {}
  setmetatable(this, Args)

  this.title = nil

  this.ms = nil
  this.mp = {}
  this.m = nil

  this.fs = {}
  this.fp = {}
  this.f = nil

  this.msPronPrefixes = {}
  this.msProns = {}
  this.msPronRefs = {}

  this.mpPronPrefixes = {}
  this.mpProns = {}
  this.mpPronRefs = {}

  this.fsPronPrefixes = {}
  this.fsProns = {}
  this.fsPronRefs = {}

  this.fpPronPrefixes = {}
  this.fpProns = {}
  this.fpPronRefs = {}

  this.mPronPrefixes = {}
  this.mProns = {}

  this.fPronPrefixes = {}
  this.fProns = {}

  this.pronPrefixes = {}
  this.prons = {}

  this.noCat = false

  return this
end

-- Inflections

--- Returns the masculine singular form.
--- @return string
function Args:getMS()
  return self.ms or self.m
end

--- Returns the masculine plural form.
--- @return string
function Args:getMP()
  if self.mp[1] then
    return self.mp[1]
  elseif self.m then
    return self.m
  else
    return self:getMS() .. "s"
  end
end

--- Returns the other masculine plural forms.
--- @return table
function Args:getOtherMPs()
  return { unpack(self.mp, 2) }
end

--- Returns the feminine singular form.
--- @return string
function Args:getFS()
  if self.fs[1] then
    return self.fs[1]
  elseif self.f then
    return self.f
  else
    return self:getMS() .. "e"
  end
end

--- Returns the other feminine singular forms.
--- @return table
function Args:getOtherFSs()
  return { unpack(self.fs, 2) }
end

--- Returns the feminine plural form.
--- @return string
function Args:getFP()
  if self.fp[1] then
    return self.fp[1]
  elseif self.f then
    return self.f
  elseif self.fs[1] then
    return self.fs[1] .. "s"
  else
    return self:getMS() .. "es"
  end
end

--- Returns the other feminine plural forms.
--- @return table
function Args:getOtherFPs()
  return { unpack(self.fp, 2) }
end

-- Pronunciation prefixes

--- Returns the masculine singular pronunciation prefix.
--- @return string|nil
function Args:getMSPronPrefix(i)
  return self.msPronPrefixes[i] or self.mPronPrefixes[i] or self.pronPrefixes[i]
end

--- Returns the masculine plural pronunciation prefix.
--- @return string|nil
function Args:getMPPronPrefix(i)
  return self.mpPronPrefixes[i] or self.mPronPrefixes[i] or self.pronPrefixes[i]
end

--- Returns the feminine singular pronunciation prefix.
--- @return string|nil
function Args:getFSPronPrefix(i)
  return self.fsPronPrefixes[i] or self.fPronPrefixes[i] or self.pronPrefixes[i]
end

--- Returns the feminine plural pronunciation prefix.
--- @return string|nil
function Args:getFPPronPrefix(i)
  return self.fpPronPrefixes[i] or self.fPronPrefixes[i] or self.pronPrefixes[i]
end

-- Pronunciation

--- Returns the masculine singular pronunciation.
--- @return string|nil
function Args:getMSPron(i)
  return self.msProns[i] or self.mProns[i] or self.prons[i]
end

--- Returns the masculine plural pronunciation.
--- @return string|nil
function Args:getMPPron(i)
  return self.mpProns[i] or self.mProns[i] or self.prons[i]
end

--- Returns the feminine singular pronunciation.
--- @return string|nil
function Args:getFSPron(i)
  return self.fsProns[i] or self.fProns[i] or self.prons[i]
end

--- Returns the feminine plural pronunciation.
--- @return string|nil
function Args:getFPPron(i)
  return self.fpProns[i] or self.fProns[i] or self.prons[i]
end


---------------------
-- Utils functions --
---------------------


--- Prepends the right character before the given API string
--- if needed (dot, space, liaison).
--- @param api string The string to prepend the character to.
--- @return string
local function addSeparatorBeforeInvPart(api)
  if not api then
    return ""
  end

  local firstChar = mw.ustring.sub(api, 1, 1)
  if firstChar == "." or firstChar == "‿" or firstChar == " " then
    return api
  end
  -- NBSP in UTF8 is 0xC2 0xA0
  if firstChar == "\194\160" then
    return " " .. mw.ustring.sub(api, 2)
  end
  -- nbsp HTML entity replaced by regular space
  if mw.ustring.sub(api, 1, 6) == " " then
    return " " .. mw.ustring.sub(api, 7)
  end

  -- In all other cases, add a space
  return " " .. api
end

--- Splits the first argument into 2 parts: the part before the suffix and the part after it.
--- @param word string The word to split.
--- @param ms string Ending for masculine singular.
--- @param mp string Ending for masculine plural.
--- @param fs string Ending for feminine singular.
--- @param fp string Ending for feminine plural.
--- @return (string,string) The text before and after the suffix.
local function splitWord(word, ms, mp, fs, fp)
  local wordStart = ""
  local wordEnd = ""

  -- Add space so that %s matches the end of the string
  local pageTitle1 = word .. " "
  -- Hyphen has to be escaped
  local matchStart, matchEnd = mw.ustring.find(pageTitle1, ms .. "[%s%-]")
  if not matchStart and mp then
    matchStart, matchEnd = mw.ustring.find(pageTitle1, mp .. "[%s%-]")
  end
  if not matchStart and fs then
    matchStart, matchEnd = mw.ustring.find(pageTitle1, fs .. "[%s%-]")
  end
  if not matchStart and fp then
    matchStart, matchEnd = mw.ustring.find(pageTitle1, fp .. "[%s%-]")
  end

  if matchStart then
    wordStart = mw.ustring.sub(word, 1, matchStart - 1)
    if matchEnd <= mw.ustring.len(word) then
      wordEnd = mw.ustring.sub(word, matchEnd) -- comprend le séparateur
    end
    return wordStart, wordEnd
  end

  return nil, nil
end

-- TODO reprendre
local function errorTable(message, noCat)
  local text = '{| class="flextable"\n' ..
      '|+ <span style="color:red"><b>Erreur&nbsp;!</b></span>\n' ..
      '|-\n' ..
      '! scope="col" | Singulier\n' ..
      '! scope="col" | Pluriel\n' ..
      '|-\n' ..
      '| scope="row" colspan="2" | <span style="color:red">' .. message .. '</span>\n' ..
      '|}'

  -- 2 = User
  if mw.title.getCurrentTitle().namespace ~= 2 and not noCat then
    text = text .. "[[Catégorie:Appels de modèles incorrects]]"
  end

  return text
end

--- Generates the inflection table using the given Args object.
--- @param argsObject Args
--- @return string
function p.generateTable(argsObject)
  local res = '{| class="flextable flextable-fr-mfsp"\n'

  if argsObject.title then
    res = res .. mw.ustring.format("|+ %s\n", argsObject.title)
  end

  res = res .. [[|-
| class="invisible" |
! scope="col" | Singulier
! scope="col" | Pluriel
|- class="flextable-fr-m"
! scope="row" | Masculin
]]

  local formatCell = function(inflection, class, colSpan)
    local upper = mw.ustring.upper(inflection)
    local inflectionsTable = { argsObject["get" .. upper](argsObject) }
    local otherInflections = argsObject["getOther" .. upper .. "s"]

    if otherInflections then
      inflectionsTable = { inflectionsTable[1], unpack(otherInflections(argsObject)) }
    end

    inflectionsTable = m_table.map(inflectionsTable, function(v)
      return mw.ustring.format("[[%s]]", v)
    end)

    local pronsTable = {}
    local done = false
    local i = 1

    while not done do
      local prefix = argsObject["get" .. upper .. "PronPrefix"](argsObject, i)
      local pron = argsObject["get" .. upper .. "Pron"](argsObject, i)
      local ref = argsObject[inflection .. "PronRefs"][i]

      if ref then
        -- FIXME modèle déprécié ?
        ref = mw.getCurrentFrame():expandTemplate { title = "réf", args = { ref } }
      else
        ref = ""
      end

      if pron then
        table.insert(
            pronsTable,
            (prefix or "") .. m_pron.lua_pron(pron, "fr") .. ref
        )
      else
        done = true
      end
      i = i + 1
    end

    if #pronsTable == 0 then
      table.insert(pronsTable, m_pron.lua_pron("", "fr"))
    end

    local inflections = table.concat(inflectionsTable, "<br/><small>ou</small> ")
    local prons = table.concat(pronsTable, "<br/><small>ou</small> ")

    return mw.ustring.format(
        '| colspan="%d" | <span class="flextable-fr-%s">%s<br/>%s</span>\n',
        colSpan, class, inflections, prons
    )
  end

  if argsObject:getMS() ~= argsObject:getMP() or argsObject:getMSPron(1) ~= argsObject:getMPPron(1) then
    res = res .. formatCell("ms", "ms", 1)
    res = res .. formatCell("mp", "mp", 1)
  else
    res = res .. formatCell("ms", "msp", 2)
  end

  res = res .. '|- class="flextable-fr-f"\n! scope="row" | Féminin\n'

  if argsObject:getFS() ~= argsObject:getFP() or argsObject:getFSPron(1) ~= argsObject:getFPPron(1) then
    res = res .. formatCell("fs", "fs", 1)
    res = res .. formatCell("fp", "fp", 1)
  else
    res = res .. formatCell("fs", "fsp", 2)
  end

  res = res .. "|}"

  if not argsObject.noCat then
    -- TODO catégoriser dans "Singuliers manquants en français" ou "Pluriels manquants en français" si nécessaire
  end

  return res
end

local function generateRootNotFoundMessage(templateName)
  local text = mw.ustring.format(
      "Usage erroné de %s.<br/>Le titre de la page ne comporte pas<br/>une des terminaisons attendues.",
      mw.getCurrentFrame():expandTemplate { title = 'M', args = { templateName } })
  return errorTable(text) .. "[[Catégorie:Appels de modèles incorrects/fr-flexion-lua]]"
end


------------------------
-- Template functions --
------------------------


-- TODO utile ?
----------------------------------------------------------------------------------------
-- récupération prononciation en param 2 ou 1 selon syntaxe ancienne/nouvelle
-- retourne PronRadic, PronFinInvar
-- fonction à usage transitoire, en attendant l'abandon définitif de l'ancienne syntaxe
----------------------------------------------------------------------------------------
-- tableau des cas possibles, hors cas particuliers :
--         entrées       :         sorties
--    radical arg1 arg2  : radical PronRad PronInv
-- (1)    R     -    -   :     R      -       -      (nouvelle)
-- (2)    R     R    -   :     R      -       -      (ancienne)
-- (3)    R     P    -   :     R      P       -      (nouvelle)
-- (4)    R     R    P   :     R      P       -      (ancienne)
-- (5)    R     P    I   :     R      P       I      (nouvelle)
local function nouvelle_ancienne_syntaxe_radic4(radic, args)
  if (not args[1]) or (args[1] == '') then
    --(1) syntaxe nouvelle, sans prononciation ou avec param nommés
    --(c’était une erreur dans l’ancienne syntaxe)
    return args["pron"] or '', addSeparatorBeforeInvPart(args["pinv"])

  elseif (radic ~= args[1]) then
    --(3,5) syntaxe nouvelle, cas général : le param 1 n’est pas le radical, donc c’est la prononciation
    --(sinon c’est une erreur à corriger à la main)
    return args[1], addSeparatorBeforeInvPart(args[2] or args["pinv"])

  elseif (radic == 'b') then
    --cas particuliers des radicaux monosyllabes identiques à leur API où le test précédent échoue (comme pour "beau")
    -- liste des radicaux potentiellement concernés (WT:QT/décembre 2014#Problème métaphysique avec Modèle:fr-accord-eau + Module:fr-flexion) :
    -- b, bl, d, f, (k), (kl), l, m, n, p, pl, ps, s, t, ts, v, w, z.
    if args[2] and (args[2] ~= radic) then
      --(5) nouvelle syntaxe avec "prononciation partie invar" en args[2]
      return radic, addSeparatorBeforeInvPart(args[2])

    else
      --(2,4) ancienne syntaxe sans ou avec pron en args[2] (de tte façon dévinée comme égale à radic)
      --(3) nouvelle sans "prononciation partie invar" en args[2]
      return radic, addSeparatorBeforeInvPart(args["pinv"])

    end
  else
    --(2,4) syntaxe ancienne sans ou avec pron en args[2]
    return args[2] or '', addSeparatorBeforeInvPart(args["pinv"])

  end
end

function p.errorBox(frame)
  -- TODO supprimer ? utilisée uniquement dans [[Wiktionnaire:Gestion des modèles/2014#Boites de flexions en français]]
  local msg = frame.args[1] or frame:getParent().args[1] or "erreur inconnue"
  local nocat = frame.args["nocat"] or frame:getParent().args["nocat"]
  return errorTable(msg, nocat)
end

function p.inflectionRegular(frame)
  local args = m_params.process(frame.args, {
    ["type flexion"] = { required = true },
    ["autre param"] = {},
  })

  local inflectionType = args["type flexion"]
  local otherParamName = args["autre param"]

  local argsDefinition = {
    ["préfpron"] = {}, ["préfpron2"] = {}, ["préfpron3"] = {},
    ["pron"] = {}, ["pron2"] = {}, ["pron3"] = {},
    [1] = { alias_of = "pron" },

    ["pinv"] = {},
    [2] = { alias_of = "pinv" },

    ["mot"] = { default = mw.title.getCurrentTitle().text },
    ["titre"] = {},
  }

  if otherParamName then
    argsDefinition[otherParamName] = { type = "boolean" }
  end

  local parentArgs = m_params.process(frame:getParent().args, argsDefinition)

  local pronPrefix1 = parentArgs["préfpron"]
  local pronPrefix2 = parentArgs["préfpron2"]
  local pronPrefix3 = parentArgs["préfpron3"]
  local pronRoot1 = parentArgs["pron"]
  local pronRoot2 = parentArgs["pron2"]
  local pronRoot3 = parentArgs["pron3"]
  local word = parentArgs["mot"]
  local tableTitle = parentArgs["titre"]

  -- Inflections detection
  local inflections = mw.loadData("Module:bac à sable/Darmo117/fr-flexion/data")[inflectionType] -- TEMP nom data
  local alternateF = parentArgs[otherParamName]
  local fIndex = alternateF and otherParamName or 1

  local suffixMS = inflections.ms[1]
  local suffixMP = inflections.mp[1]
  local suffixFS = inflections.fs[fIndex]
  local suffixFP = inflections.fp[fIndex]

  local pronSuffixMS = inflections.ms[2]
  local pronSuffixMP = inflections.mp[2]
  local pronSuffixFS = inflections.fs[2]
  local pronSuffixFP = inflections.fp[2]

  -- Word root extraction
  local root, invariablePart = splitWord(word, suffixMS, suffixMP, suffixFS, suffixFP)
  -- No root found, abort
  if not root then
    return generateRootNotFoundMessage("fr-accord-" .. inflectionType)
  end

  local invariablePronPart = addSeparatorBeforeInvPart(parentArgs["pinv"])

  local argsObject = Args:new()

  argsObject.title = tableTitle
  argsObject.ms = root .. suffixMS .. invariablePart
  argsObject.mp = { root .. suffixMP .. invariablePart }
  argsObject.fs = { root .. suffixFS .. invariablePart }
  argsObject.fp = { root .. suffixFP .. invariablePart }

  local generateProns = function(pronRoot, pronPrefix)
    table.insert(argsObject.msProns, pronRoot .. pronSuffixMS .. invariablePronPart)
    table.insert(argsObject.mpProns, pronRoot .. pronSuffixMP .. invariablePronPart)
    table.insert(argsObject.fsProns, pronRoot .. pronSuffixFS .. invariablePronPart)
    table.insert(argsObject.fpProns, pronRoot .. pronSuffixFP .. invariablePronPart)
    if pronPrefix then
      table.insert(argsObject.msPronPrefixes, pronPrefix)
      table.insert(argsObject.mpPronPrefixes, pronPrefix)
      table.insert(argsObject.fsPronPrefixes, pronPrefix)
      table.insert(argsObject.fpPronPrefixes, pronPrefix)
    end
  end

  if pronRoot1 then
    generateProns(pronRoot1, pronPrefix1)
    if pronRoot2 then
      generateProns(pronRoot2, pronPrefix2)
      if pronRoot3 then
        generateProns(pronRoot3, pronPrefix3)
      end
    end
  end

  return p.generateTable(argsObject)
end

function p.inflectionBoxGeneric(frame)
  local args = m_params.process(frame:getParent().args, {
    ["titre"] = {},

    ["ms"] = { default = mw.title.getCurrentTitle().text },
    ["mp"] = {}, ["mp2"] = {},
    ["m"] = {},

    ["fs"] = {}, ["fs2"] = {},
    ["fp"] = {}, ["fp2"] = {},
    ["f"] = {},

    ["préfpms"] = {}, ["pms"] = {}, ["réfpms"] = {},
    ["préfpms2"] = {}, ["pms2"] = {}, ["réfpms2"] = {},
    ["préfpms3"] = {}, ["pms3"] = {}, ["réfpms3"] = {},

    ["préfpmp"] = {}, ["pmp"] = {}, ["réfpmp"] = {},
    ["préfpmp2"] = {}, ["pmp2"] = {}, ["réfpmp2"] = {},
    ["préfpmp3"] = {}, ["pmp3"] = {}, ["réfpmp3"] = {},

    ["préfpm"] = {}, ["pm"] = {}, ["réfpm"] = {},
    ["préfpm2"] = {}, ["pm2"] = {}, ["réfpm2"] = {},
    ["préfpm3"] = {}, ["pm3"] = {}, ["réfpm3"] = {},

    ["préfpfs"] = {}, ["pfs"] = {}, ["réfpfs"] = {},
    ["préfpfs2"] = {}, ["pfs2"] = {}, ["réfpfs2"] = {},
    ["préfpfs3"] = {}, ["pfs3"] = {}, ["réfpfs3"] = {},

    ["préfpfp"] = {}, ["pfp"] = {}, ["réfpfp"] = {},
    ["préfpfp2"] = {}, ["pfp2"] = {}, ["réfpfp2"] = {},
    ["préfpfp3"] = {}, ["pfp3"] = {}, ["réfpfp3"] = {},

    ["préfpf"] = {}, ["pf"] = {}, ["réfpf"] = {},
    ["préfpf2"] = {}, ["pf2"] = {}, ["réfpf2"] = {},
    ["préfpf3"] = {}, ["pf3"] = {}, ["réfpf3"] = {},

    ["préfpron"] = {}, ["préfpron2"] = {}, ["préfpron3"] = {},
    ["pron"] = {}, ["pron2"] = {}, ["pron3"] = {},
    [1] = { alias_of = "pron" },

    ["nocat"] = { type = "boolean" },
    ["inv"] = {}, -- XXX ?
  })

  local argsObject = Args:new()

  argsObject.title = args["titre"]

  -- TODO extraire les paramètres

  argsObject.pronPrefixes = { args["pron"], args["pron2"], args["pron3"] }
  argsObject.prons = { args["préfpron"], args["préfpron2"], args["préfpron3"] }

  argsObject.noCat = args["nocat"]
end

function p.inflectionBox4(frame)
  -- TODO
end

function p.inflectionBox3(frame)
  -- TODO
end

function p.inflectionBox2(frame)
  -- TODO
end

p.Args = Args -- TEMP

return p