Modulo:mensb

El Vikivortaro
Salti al navigilo Salti al serĉilo
StopsignIndonesia.png Ĉi tiu modulo estas multfoje bindita.
Se vi konas la eblajn sekvojn, tiam vi povas zorgeme ekredakti.
Se vi ne kuraĝas redakti tiam vi povas proponi la deziratan ŝanĝon en la diskutejo.
Memtesto disponeblas sur la dokumentaĵa subpaĝo

--[===[

MODULE "MENSB" (english substantivo)

"eo.wiktionary.org/wiki/Modulo:mensb" <!--2021-Jan-19-->
"id.wiktionary.org/wiki/Modul:mensb"

Purpose: generates declension table for an English noun,
         correctly guessing the plural form for ca 99.9 % of words

Utilo: generas deklinacian tabelon por angla substantivo,
       divenas gxuste pluralan formon por ca 99.9 % da vortoj

Manfaat: menghasilkan tabel deklinasi untuk nomina Inggris,
         membuat bentuk jamak dengan benar untuk ca 99.9 % kata

Syfte: genererar en tabell foer ett engelskt substantiv,
       gissar raett pluralformen foer ca 99.9 % av ord

Used by templates / Uzata far sxablonoj /
Digunakan oleh templat / Anvaent av mallar:
- {{tf-en-sb}}

This module can accept parameters whether sent to itself (own frame) or
to the caller (caller's frame). If there is a parameter "caller=true"
on the own frame then that own frame is discarded in favor of the
caller's one.

Parameters: - 0 to 6 optional named parameters
              - "sa"  : alternative singular form
              - "pl"  : explicit plural form that replaces the
                        automatically generated one
              - "pa"  : alternative plural form
              - "paa" : alternative other plural form
              - "not" : notes
              - "pagenameoverridetestonly" : base form of the word, replaces
                                             peeking it from "pagename"

Returned: - one big string containing the complete table

Following rules are applied (this works only with lowercase letters):
- consonant + "y" -> drop "y" add "ies" (try -> tries)
- consonant + "o" -> add "es" (hero -> heroes)
- ends with "s" "x" "z" "ch" "sh" -> add "es"
  (virus, fix, ??, reach, clutch, bush)
- otherwise -> add "s"

The base word must contain at least 2 letters.

DO NOT use this module for inherently uncountable
nouns like "news".

NE UZU cxi tiun modulon por kerne nenombreblaj
substantivoj kiel "news".

JANGAN menggunakan modul ini untuk nomina tidak
terhitung seperti "news".

This module is unbreakable (when called with correct module name
and function name).

Cxi tiu modulo estas nerompebla (kiam vokita kun gxustaj nomo de modulo
kaj nomo de funkcio).

Usage examples with results / Ekzemploj de uzo
kun rezultoj / Contoh penggunaan dengan hasil:

* #T00 page "computer"
* expected result: "computers"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=computer}}"
* {{nevideblafinodesekcio}}

::* #T01
::* expected result: "tries"
::* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=try}}"
::* {{nevideblafinodesekcio}}

* #T02
* expected result: "plays"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=play}}"
* {{nevideblafinodesekcio}}

::* #T03
::* expected result: "heroes"
::* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=hero}}"
::* {{nevideblafinodesekcio}}

* #T04
* expected result: "loos"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=loo}}"
* {{nevideblafinodesekcio}}

::* #T05
::* expected result: "zeroes" (ungrammatical, use "pl" to override)
::* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=zero}}"
::* {{nevideblafinodesekcio}}

* #T06 "pl=zeros" override page "zero"
* expected result: "zeros"
* actual result: "{{#invoke:mensb|ek|pl=zeros|pagenameoverridetestonly=zero}}"
* {{nevideblafinodesekcio}}

::* #T07
::* expected result: "thiefs" (ungrammatical, use "pl" to override)
::* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=thief}}"
::* {{nevideblafinodesekcio}}

: ---------------------------------------

* #T10
* expected result: "HEROs" (dubious)
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=HERO}}"
* {{nevideblafinodesekcio}}

* #T11
* expected result: "viruses"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=virus}}"
* {{nevideblafinodesekcio}}

* #T12
* expected result: "fixes"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=fix}}"
* {{nevideblafinodesekcio}}

* #T13
* expected result: "reaches"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=reach}}"
* {{nevideblafinodesekcio}}

* #T14
* expected result: "bushes"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=bush}}"
* {{nevideblafinodesekcio}}

* #T15
* expected result: "paths" (good although difficult to pronounce)
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=path}}"
* {{nevideblafinodesekcio}}

: ---------------------------------------

* #T20 page "news"
* expected result: "newses" (ungrammatical, don't apply this module to uncountable nouns)
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=news}}"
* {{nevideblafinodesekcio}}

* #T21 page "short story"
* expected result: "short stories" (multiword lemma)
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=short story}}"
* {{nevideblafinodesekcio}}

* #T22 page "ii"
* expected result: "iis" (nonsense)
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=ii}}"
* {{nevideblafinodesekcio}}

<pre>
* #T23 page "i"
* expected result: "bad usage"
* actual result: "{{#invoke:mensb|ek|pagenameoverridetestonly=i}}"
* {{nevideblafinodesekcio}}

* #T24 undesirable anonymous parameter
* expected result: "bad usage"
* actual result: "{{#invoke:mensb|ek|test|pagenameoverridetestonly=test}}"
* {{nevideblafinodesekcio}}
</pre>

: ---------------------------------------

* note that all tests depend on "nevideblafinodesekcio"
* note that tests #T23 #T24 cannot be reasonably executed on the docs subpage without help of "pate" or "debu"

]===]

local ensb = {}

---- CONSTANTS ----

  -- uncommentable EO vs ID constant strings (core site-related features)

  local constrpriv = "eo"                 -- EO (privileged site language)
  -- local constrpriv = "id"                 -- ID (privileged site language)

  -- constant table (surrogate transcoding table, only needed for EO)

  local contabtransiltable = {}
  contabtransiltable[ 67] = 0xC488 -- CX
  contabtransiltable[ 99] = 0xC489 -- cx
  contabtransiltable[ 71] = 0xC49C -- GX
  contabtransiltable[103] = 0xC49D -- gx
  contabtransiltable[ 74] = 0xC4B4 -- JX
  contabtransiltable[106] = 0xC4B5 -- jx
  contabtransiltable[ 83] = 0xC59C -- SX
  contabtransiltable[115] = 0xC59D -- sx
  contabtransiltable[ 85] = 0xC5AC -- UX breve
  contabtransiltable[117] = 0xC5AD -- ux breve

  -- constant strings (generic & misc)

  local constrfrco  = '707070'  -- table frame color (grey)
  local constrbkti  = 'B0D0F0'  -- title cell background color (light grey/blue)
  local constrtdsty = '<td style="border:0.25em solid #' .. constrfrco .. ';padding:0.4em;'
  local constrtdbg2 = constrtdsty .. '">'                                                                -- NOT centered
  local constrtdbg4 = constrtdsty .. 'text-align:center;" colspan="2">'                                  -- centered & cs 2
  local constrtdbg6 = constrtdsty .. 'background:#' .. constrbkti .. ';text-align:center;" colspan="2">' -- centered & bk & cs 2

  -- constant strings (error circumfixes)

  local constrkros  = '&nbsp;&#91;&#93;&nbsp;'   -- lagom -> huge " [] "
  local constrelabg = '<span class="error"><b>'  -- lagom whining begin
  local constrelaen = '</b></span>'              -- lagom whining end
  local constrehubg = constrkros .. constrelabg  -- huge whining begin
  local constrehuen = constrelaen .. constrkros  -- huge whining end

  -- uncommentable EO vs ID constant strings (error messages, depends from above "error circumfixes" section)

  local constrbadu = constrehubg .. 'Erara uzo de sxablono "tf-en-sb", legu gxian dokumentajxon' .. constrehuen   -- EO
  -- local constrbadu = constrehubg .. 'Penggunaan salah templat "tf-en-sb", bacalah dokumentasinya' .. constrehuen  -- ID

  local constrkates = '[[Kategorio:Erara uzo de sxablono]]'               -- EO
  local constrkatel = '[[Kategorio:Erara uzo de sxablono (tf-en-sb)]]'    -- EO
  -- local constrkates = '[[Kategori:Penggunaan salah templat]]'             -- ID
  -- local constrkatel = '[[Kategori:Penggunaan salah templat (tf-en-sb)]]'  -- ID

  -- uncommentable EO vs ID constant strings (misc)

  local constrtit = 'Angla substantivo<br><small>English noun</small>'   -- EO
  -- local constrtit = 'Nomina Inggris<br><small>English noun</small>'      -- ID

  local constrsng = '[[singularo|Singularo]]'                -- EO
  -- local constrsng = '[[bentuk tunggal|Tunggal (singular)]]'  -- ID
  local constrplu = '[[pluralo|Pluralo]]'                    -- EO
  -- local constrplu = '[[bentuk jamak|Jamak (plural)]]'        -- ID

  local constralt = 'alternative'  -- EO
  -- local constralt = 'alternatif'   -- ID

------------------------------------------------------------------------

---- ORDINARY LOCAL MATH FUNCTIONS ----

------------------------------------------------------------------------

local function mathdiv (xdividend, xdivisor)
  local resultdiv = 0 -- DIV operator lacks in LUA :-(
  resultdiv = math.floor (xdividend / xdivisor)
  return resultdiv
end--function mathdiv

local function mathmod (xdividendo, xdivisoro)
  local resultmod = 0 -- MOD operator is "%" and bitwise AND operator lack too
  resultmod = xdividendo % xdivisoro
  return resultmod
end--function mathmod

------------------------------------------------------------------------

---- ORDINARY LOCAL STRING FUNCTIONS ----

------------------------------------------------------------------------

local function lfnememlig (strmem,strtuff) -- prevents self-linking
  if (strmem~=strtuff) then
    strtuff = '[[' .. strtuff .. ']]'
  end--if
  return strtuff
end--function lfnememlig

------------------------------------------------------------------------

---- ORDINARY LOCAL HIGH LEVEL FUNCTIONS ----

------------------------------------------------------------------------

-- Local function LFKODEOSG

-- Transcode X-surrogates (without "\", thus for example "kacxo",
-- NOT "ka\cxo") to cxapeloj in a string (EO only)

-- Input  : * strsurr -- string (empty is useless but can't cause major harm)

-- Output : * strcxapeloj

-- We need const table "contabtransiltable".

-- This sub depends on "MATH FUNCTIONS"\"mathdiv"
-- and "MATH FUNCTIONS"\"mathmod".

local function lfkodeosg (strsurr)
  local varpeek = 0
  local strcxapeloj = ''
  local numinputl = 0
  local numininx = 0 -- ZERO-based source index
  local numknark = 0 -- current char (ZERO is NOT valid)
  local numknarp = 0 -- previous char (ZERO is NOT valid)
  local numlow = 0
  local numhaj = 0
  numinputl = string.len(strsurr)
  while (true) do
    if (numininx==numinputl) then
      break
    end--if
    numknark = string.byte(strsurr,(numininx+1),(numininx+1))
    numininx = numininx + 1
    numhaj = 0 -- pre-assume no translation
    if ((numknarp~=0) and ((numknark==88) or (numknark==120))) then -- got "x"
      varpeek = contabtransiltable[numknarp] -- UINT16 or nil
      if (varpeek~=nil) then
        numlow = mathmod (varpeek,256)
        numhaj = mathdiv (varpeek,256)
      end--if
    end--if
    if (numhaj~=0) then
      strcxapeloj = strcxapeloj .. string.char(numhaj,numlow)
      numknark = 0 -- invalidade current char
    else
      if (numknarp~=0) then -- add previous char only if valid
        strcxapeloj = strcxapeloj .. string.char(numknarp) -- add it
      end--if
    end--if
    numknarp = numknark -- copy to previous even if invalid
  end--while
  if (numknarp~=0) then -- add previous and last char only if valid
    strcxapeloj = strcxapeloj .. string.char(numknarp) -- add it
  end--if
  return strcxapeloj
end--function lfkodeosg

------------------------------------------------------------------------

---- MAIN EXPORTED FUNCTION ----

------------------------------------------------------------------------

function ensb.ek (arxframent)

  -- general unknown type

  local vartmp = 0    -- variable without type multipurpose

  -- special type "args" AKA "arx"

  local arxsomons = 0 -- metaized "args" from our own or caller's "frame"

  -- param str

  local strsa   = ""  -- this MUST be DIFFERENT from "strpgnm" otherwise ERROR
  local strpl   = ""
  local strpa   = ""
  local strpaa  = ""
  local strnot  = ""

  -- general str

  local strpgnm = ""  -- base form from "pagename" "pagenameoverridetestonly"
  local stralti = ""  -- "br" .. "small" .. alt .. "/small" .. "br"
  local strret  = ""  -- output string

  -- general num

  local numlength = 0  -- length of the input word
  local numlast = 0    -- last char
  local numbela = 0    -- char before the last one

  -- general boo

  local booerr = false  -- fatal error flag
  local boocon = true   -- char in "numbela" consonant flag (false if vowel)
  local boocut = false  -- cut off last letter flag
  local booiii = false  -- add "i" flag
  local booeee = false  -- add "e" flag

  ---- GET THE ARX (ONE OF TWO) ----

  if (booerr==false) then
    arxsomons = arxframent.args -- "args" from our own "frame"
    if (arxsomons['caller']=="true") then
      arxsomons = arxframent:getParent().args -- "args" from caller's "frame"
    end--if
  end--if

  ---- SEIZE 6 OPTIONAL NAMED PARAMS ----

  if ((arxsomons[1])~=nil) then
    booerr = true -- anonymous parameters NOT appreciated -> "bad usage"
  end--if

  if (booerr==false) then
    vartmp = arxsomons["sa"]
    if (type(vartmp)=="string") then
      strsa = vartmp
    end--if
    vartmp = arxsomons["pl"]
    if (type(vartmp)=="string") then
      strpl = vartmp
    end--if
    if (type(arxsomons["pa"])=="string") then
      strpa = arxsomons["pa"]
    end--if
    if (type(arxsomons["paa"])=="string") then
      strpaa = arxsomons["paa"]
    end--if
    if (type(arxsomons["not"])=="string") then
      strnot = arxsomons["not"]
    end--if
    if (type(arxsomons["pagenameoverridetestonly"])=="string") then
      strpgnm = arxsomons["pagenameoverridetestonly"]
    end--if
  end--if

  ---- SEIZE THE PAGENAME IF NEEDED ----

  if ((booerr==false) and (strpgnm=="")) then
    vartmp = mw.title.getCurrentTitle().text
    if (type(vartmp)=="string") then
      if (string.len(vartmp)~=0) then
        strpgnm = vartmp
      end--if
    end--if
    if (strpgnm=="") then
      booerr = true -- would result in "bad usage" but is hopefully impossible
    end--if
  end--if

  ---- TRANSCODE EO IF NEEDED ----

  if (constrpriv=="eo") then
    constrbadu  = lfkodeosg(constrbadu)
    constrkates = lfkodeosg(constrkates)
    constrkatel = lfkodeosg(constrkatel)
  end--if

  ---- CHECK WORD LENGTH (NO EN NOUN HAS ONLY 1 LETTER) AND MORE ----

  if (booerr==false) then
    numlength = string.len (strpgnm) -- length of the input word
    if ((numlength<2) or (strpgnm==strsa)) then
      booerr = true -- "bad usage"
    end--if
  end--if

  ---- BREW PLURAL FORM IF NEEDED ----

  if ((booerr==false) and (strpl=="")) then
      numlast = string.byte (strpgnm,numlength,numlength)
      numbela = string.byte (strpgnm,(numlength-1),(numlength-1))
      if ((numbela==97) or (numbela==101) or (numbela==105) or (numbela==111) or (numbela==117)) then
        boocon = false -- damn, it's a vowel
      end--if
      if (boocon==true) then
        if (numlast==121) then -- "y" -> "ies"
          boocut = true
          booiii = true
          booeee = true
        end--if
        if (numlast==111) then -- "o"
          booeee = true
        end--if
      end--if
      if ((numlast==115) or (numlast==120) or (numlast==122)) then
        booeee = true  -- "s" "x" "z"
      end--if
      if (numlast==104) then
        if ((numbela==99) or (numbela==115)) then
          booeee = true  -- "ch" "sh"
        end--if
      end--if
      if (boocut) then
        strpl = string.sub (strpgnm,1,(numlength-1)) -- omit last letter
      else
        strpl = strpgnm -- take it all
      end--if
      if (booiii==true) then
        strpl = strpl .. "i"
      end--if
      if (booeee==true) then
        strpl = strpl .. "e"
      end--if
      strpl = strpl .. "s" -- always add "s"
  end--if

  ---- BREW THE TABLE ----

  if (booerr==false) then
    stralti = '<br><small>' .. constralt .. '</small><br>'
    strret = '<table style="float:right;margin:0 0 1em 1em;border:0.25em solid #'
    strret = strret .. constrfrco .. ';border-collapse:collapse;">'
    strret = strret .. '<tr>' .. constrtdbg6 .. constrtit .. '</td></tr>'
    strret = strret .. '<tr>' .. constrtdbg2 .. '<b>' ..constrsng .. '</b></td>'
    strret = strret .. constrtdbg2 .. '<b>' .. constrplu .. '</b></td></tr>'
    strret = strret .. '<tr>' .. constrtdbg2 .. strpgnm
    if (strsa~="") then -- lfnememlig NOT needed here
      strret = strret .. stralti .. '[[' .. strsa .. ']]'
    end--if
    strret = strret .. '</td>' .. constrtdbg2 .. lfnememlig(strpgnm,strpl)
    if (strpa~="") then
      strret = strret .. stralti .. lfnememlig(strpgnm,strpa)
    end--if
    if (strpaa~="") then
      strret = strret .. stralti .. lfnememlig(strpgnm,strpaa)
    end--if
    strret = strret .. '</td></tr>'
    if (strnot~="") then
      strret = strret .. '<tr>' .. constrtdbg4 .. '<small>' .. strnot .. '</small></td></tr>'
    end--if
    strret = strret .. '</table>'
  else
    strret = constrbadu .. constrkates .. constrkatel -- "bad usage" and diag
  end--if

  ---- RETURN THE JUNK STRING ----

  return strret

end--function

  ---- RETURN THE JUNK TABLE ----

return ensb