Module:Mn-common

local export = {} local lang = require("Module:languages").getByCode( "mn" ) local links = require( "Module:links" ) table["reverse"] = require( "Module:table" ).reverse

local char = mw.ustring.char local find = mw.ustring.find local len = mw.ustring.len local match = mw.ustring.match local gmatch = mw.ustring.gmatch local sub = mw.ustring.sub local gsub = mw.ustring.gsub local lower = mw.ustring.lower local reverse = require( "Module:string" ).reverse

local function format_Mongolian_text(text) return "" .. text .. " " end

function export.see(frame) local params = { [1] = {},	}	local args = require("Module:parameters").process(frame:getParent.args, params) local title = args[1] local curr_title = mw.title.getCurrentTitle.subpageText local content = mw.title.new(title):getContent local senses = {} local sense_id = 0 local j, pos, s, section if title == curr_title then return error("The soft-directed item is the same as the page title.") end if content then if not match(content, "==Mongolian==") then categories = categories .. ""		elseif not match(content, "mn%-IPA") and not match(content, "mn%-see") then require("Module:debug").track("mn-see/unidirectional reference to variant") elseif not match(content, curr_title) then require("Module:debug").track("mn-see/unidirectional reference variant→orthodox") end end while true do		_, j, language_name, s = content:find("%f[=]==%s*([^=]+)%s*==(\n.-)\n==%f[^=]", pos) if j == nil then i, j, language_name, s = content:find("%f[=]==%s*([^=]+)%s*==(\n.+)", pos) end if j == nil then break else pos = j - 1 end if language_name == "Mongolian" then section = s		end end if not section then return "" end section = section:gsub("\n===+Etymology.-(\n==)", "%1") local text = {} for sense in section:gmatch("\n# ([^\n]+)") do		if not sense:match("rfdef") and not sense:match("defn") then sense_id = sense_id + 1 table.insert(senses, sense) end end table.insert(text, table.concat(senses, "\n# ")) table.insert(text, " ") return frame:preprocess( table.concat(text) ) end

function export.ipasee(frame) local params = { [1] = {},	}	local args = require("Module:parameters").process(frame:getParent.args, params) local title = args[1] local curr_title = mw.title.getCurrentTitle.subpageText local content = mw.title.new(title):getContent local senses = {} local sense_id = 0 local j, pos, s, section if title == curr_title then return error("The soft-directed item is the same as the page title.") end if content then if not match(content, "==Mongolian==") then categories = categories .. ""		elseif not match(content, "mn%-IPA") and not match(content, "mn%-see") and not match(content, "mn%-IPA-see") then require("Module:debug").track("mn-IPA-see/unidirectional reference to variant") elseif not match(content, curr_title) then require("Module:debug").track("mn-IPA-see/unidirectional reference variant→orthodox") end end while true do		_, j, language_name, s = content:find("%f[=]==%s*([^=]+)%s*==(\n.-)\n==%f[^=]", pos) if j == nil then i, j, language_name, s = content:find("%f[=]==%s*([^=]+)%s*==(\n.+)", pos) end if j == nil then break else pos = j - 1 end if language_name == "Mongolian" then section = s		end end if not section then return "" end section = section:gsub("\n===+Etymology.-(\n==)", "%1") local text = {} if section:match("") then return frame:expandTemplate{ title = "mn-IPA", args = { section:match("") } } else return frame:expandTemplate{ title = "mn-IPA", args = { title } } end end

--Breaks down a string into vowel harmonic segments function export.vowelharmony( text, params ) if not params then params = {} end local vh = {} local breaks = { 1 } if params.bor or match( text, char( 0x301 ) ) then vh[1] = {} local orig_text = text if params.bor == "Russian" then text = gsub( text, "у", "ү" ) end if match( text, "кило" .. char( 0x301 ) .. "?$" ) then -- irregular vh[1].a = "э" vh[1].location = find( text, "[ЭҮЕЮэүею]" ) vh[1].position = "front" vh[1].quality = "unrounded" elseif match( text, char( 0x301 ) ) and match( sub( text, find( text, char( 0x301 ) ) - 1, find( text, char( 0x301 ) ) - 1 ), "[АУЯауя]" ) then vh[1].a = "а" vh[1].location = find( text, char( 0x301 ) ) - 1 vh[1].position = "back" vh[1].quality = "unrounded" elseif match( text, char( 0x301 ) ) and match( sub( text, find( text, char( 0x301 ) ) - 1, find( text, char( 0x301 ) ) - 1 ), "[ОЁоё]" ) then vh[1].a = "о" vh[1].location = find( text, char( 0x301 ) ) - 1 vh[1].position = "back" vh[1].quality = "rounded" elseif match( text, "[АУЯОЁауяоё]" ) and find( text, "[АУЯОЁауяоё]" ) == find( text, "[АУЯауя]" ) then vh[1].a = "а" vh[1].location = find( text, "[АУЯауя]" ) vh[1].position = "back" vh[1].quality = "unrounded" elseif match( text, "[АУЯОЁауяоё]" ) and find( text, "[АУЯОЁауяоё]" ) == find( text, "[ОЁоё]" ) then vh[1].a = "о" vh[1].location = find( text, "[ОЁоё]" ) vh[1].position = "back" vh[1].quality = "rounded" elseif match( text, "[ЭҮЕЮӨэүеюө]" ) and find( text, "[ЭҮЕЮӨэүеюө]" ) == find( text, "[ЭҮЕЮэүею]" ) then vh[1].a = "э" vh[1].location = find( text, "[ЭҮЕЮэүею]" ) vh[1].position = "front" vh[1].quality = "unrounded" elseif match( text, "[ЭҮЕЮӨэүеюө]" ) and find( text, "[ЭҮЕЮӨэүеюө]" ) == find( text, "[Өө]" ) then vh[1].a = "ө" vh[1].location = find( text, "[Өө]" ) vh[1].position = "front" vh[1].quality = "rounded" elseif match( text, "[Ии]" ) then vh[1].a = "э" vh[1].location = find( text, "[Ии]" ) vh[1].position = "front" vh[1].quality = "unrounded" end if match( vh[1].a, "[ао]" ) then vh[1].ii = "ы" vh[1].u = "у" else vh[1].ii = "ий" vh[1].u = "ү" end if match( vh[1].a, "ө" ) then -- ө takes the diphthong эй not өй vh[1].ai = "эй" else vh[1].ai = vh[1].a .. "й" end vh[1].aa = vh[1].a .. vh[1].a vh[1].uu = vh[1].u .. vh[1].u		vh[1].substring = orig_text else local resets = { "уу", "үү", "юу" ,"юү", "яу", "ёу", "еү", "иу", "Уу", "Үү", "Юу" ,"Юү", "Яу", "Ёу", "Еү", "Иу", "%s" } local resets2 = { "аа", "оо", "өө", "ээ", "яа", "ёо", "еө", "еэ", "Аа", "Оо", "Өө", "Ээ", "Яа", "Ёо", "Еө", "Еэ" } for _, v in pairs( resets ) do			local c = 0 while c ~= nil do				c = find( text, v, c + 1 ) if c ~= nil and c ~= 1 then table.insert( breaks, c ) end end end for _,v in pairs( resets2 ) do if match( text, v .. "$" ) then table.insert( breaks, len( text ) - 1 ) end end table.sort( breaks ) for i, b in ipairs( breaks ) do			table.insert( vh, {} ) if i == #breaks then vh[i].substring = sub( text, b, len( text ) ) else vh[i].substring = sub( text, b, breaks[i + 1] - 1 ) end end local location local pattern for i,s in ipairs( vh ) do			local orig = s.substring s.substring = reverse( lower( s.substring ) ) local vowel = match( s.substring, "[аеёоөуүэюя]" ) location,_ = find( s.substring, "[аеёоөуүэюя]" ) if vh[i].a == nil then vh[i].a = "э" vh[i].position = "front" vh[i].quality = "unrounded" pattern = "и" end vh[i].a = lower( vh[i].a ) if vowel == "а" or vowel == "у" or vowel == "я" then vh[i].a = "а" vh[i].position = "back" vh[i].quality = "unrounded" pattern = "[ауюя]" if match( s.substring, "[еёоөүэ]" ) then vh[i].violation = true else vh[i].violation = false end elseif vowel == "о" or vowel == "ё" then vh[i].a = "о" vh[i].position = "back" vh[i].quality = "rounded" pattern = "[ёо]" if match( s.substring, "[аеөуүэюя]" ) then vh[i].violation = true else vh[i].violation = false end elseif vowel == "э" then vh[i].position = "front" if location and sub( s.substring, location-1, location-1 ) == "й" and match( s.substring, "[аеёоөуүэюя]", location+1 ) == "ө" then vh[i].a = "ө" vh[i].quality = "rounded" pattern = "[еө]" if match( s.substring, "[аёоуүэюя]" ) then vh[i].violation = true else vh[i].violation = false end else vh[i].a = "э" vh[i].quality = "unrounded" pattern = "[еүэю]" if match( s.substring, "[аёоөуя]" ) then vh[i].violation = true else vh[i].violation = false end end elseif vowel == "ү" then vh[i].a = "э" vh[i].position = "front" vh[i].quality = "unrounded" pattern = "[еүэю]" if match( s.substring, "[аёоөуя]" ) then vh[i].violation = true else vh[i].violation = false end elseif vowel == "ө" then vh[i].a = "ө" vh[i].position = "front" vh[i].quality = "rounded" pattern = "[еө]" if match( s.substring, "[аёоуүэюя]" ) then vh[i].violation = true else vh[i].violation = false end elseif vowel == "е" then vh[i].position = "front" if match( s.substring, "ө", location+1 ) then vh[i].a = "ө" vh[i].quality = "rounded" pattern = "[еө]" if match( s.substring, "[аёоуүэюя]" ) then vh[i].violation = true else vh[i].violation = false end else vh[i].a = "э" vh[i].quality = "unrounded" pattern = "[еүэю]" if match( s.substring, "[аёоөуя]" ) then vh[i].violation = true else vh[i].violation = false end end elseif vowel == "ю" then vh[i].quality = "unrounded" if match( s.substring, "[ауя]", location+1 ) then vh[i].a = "а" vh[i].position = "back" pattern = "[ауюя]" if match( s.substring, "[еёоөүэ]" ) then vh[i].violation = true else vh[i].violation = false end else vh[i].a = "э" vh[i].position = "front" pattern = "[еүэю]" if match( s.substring, "[аёоөуя]" ) then vh[i].violation = true else vh[i].violation = false end end end location = 0 local function prev_vowel( n ) return match( s.substring, "[аеёиоөуүэюя]", n+1 ) end local function prev_hvowel( n ) return match( s.substring, pattern, n+1 ) end while prev_vowel( location ) and ( prev_vowel( location ) == prev_hvowel( location ) or prev_vowel( location ) == "и" ) do				if prev_vowel( location ) == prev_hvowel( location ) then location = find( s.substring, pattern, location+1 ) else -- if и local icheck = location+1 while prev_vowel( icheck ) == "и" do						icheck = find( s.substring, "и", icheck+1 ) end if prev_vowel( icheck ) and prev_vowel( icheck ) == prev_hvowel( icheck ) then location = icheck elseif not prev_vowel( icheck ) and vowel == "э" then location = icheck elseif vowel == "э" and sub( s.substring, icheck-1, icheck-1 ) == "й" then location = icheck else break end end end if match( vh[i].a, "[ао]" ) then vh[i].ii = "ы" vh[i].u = "у" else vh[i].ii = "ий" vh[i].u = "ү" end if match( vh[i].a, "ө" ) then -- ө takes the diphthong эй not өй vh[i].ai = "эй" else vh[i].ai = vh[i].a .. "й" end vh[i].aa = vh[i].a .. vh[i].a vh[i].uu = vh[i].u .. vh[i].u			s.substring = orig vh[i].location = len( s.substring ) + breaks[i] - location end end return vh end

--Breaks down a string into syllables and returns a table function export.syllables( text ) local consonant = "[БВГДЖЗКЛМНПРСТФХЦЧШЩбвгджзклмнпрстфхцчшщ]" local vowel = "[АОУЭӨҮИЙЫЯЕЁЮаоуэөүийыяеёю]" local sign = "[ЪЬъь]" local iotated = "[ЯЕЁЮяеёю]" local punctuation = "[%s%p]" local final_clusters = require("Module:mn/data").syll_final_cons local chars = {} for v in gmatch( text, "[%w%s%p]" ) do -- strip diacritics table.insert( chars, v ) end text = table.concat( chars ) -- reform text without diacritics local breaks = {} for i,v in pairs( chars ) do		if i == 1 or match( chars[i-1], punctuation ) then -- first letter of word table.insert( breaks, i ) elseif i ~= #chars and match( v, consonant ) and match( chars[i+1], vowel ) then -- if followed by vowel (i.e. if lone/cluster-final), count backwards until vowel, punctuation/space or start of string is found; if a vowel is found first, then letter must be medial and lone/cluster-final, so is the break; if punctuation/start of string found first, letter is part of word-initial cluster, so is not the break (occurs in loanwords, e.g. трол|лей|бус ("trolleybus")) local j = i			while j > 1 and ( match( chars[j], consonant ) or match( chars[j], sign ) ) do				j = j - 1 if match( chars[j], vowel ) then table.insert( breaks, i ) end end elseif ( match( v, consonant ) or match( v, sign ) ) and ( i == #chars or match( chars[i+1], punctuation ) ) then -- if word-final consonant, count backwards until vowel, checking if each cluster is allowed as a word-final cluster; if it is, increase "stable" (the number of stable consonants (and signs) at the end) by one; if a vowel is found before an unstable cluster, the loop ends with no change; if an unstable cluster is found, "stable" will not iterate which will trigger an additional unvoweled syllable break at that consonant (occurs in loanwords, e.g. буд|ди|зм ("Buddhism"), ал|ге|бр ("algebra")) local j = i			local check = { chars[j] } local stable = 1 while j > 1 and j > i - #final_clusters and stable > i - j and ( match( chars[j-1], consonant ) or match( chars[j-1], sign ) ) do				j = j - 1 table.insert( check, chars[j] ) for k,cluster in ipairs( final_clusters[#check] ) do					if match( table.concat( table.reverse( check ) ), cluster ) then stable = stable + 1 break end end if stable == i - j then table.insert( breaks, j ) end end elseif match( v, vowel ) and match( chars[i-1], sign ) then -- vowel after Ь/Ъ table.insert( breaks, i ) elseif match( v, iotated ) and match( chars[i-1], vowel ) then -- iotated ("ya"-type) vowel after a vowel table.insert( breaks, i ) end end local syll = {} for i,v in ipairs( breaks ) do		if i == #breaks then table.insert( syll, sub( text, v ) ) else table.insert( syll, sub( text, v, breaks[i+1] - 1 ) ) end end return syll end

function export.voweldeletion( text, params ) if not params then params = {} end local vh = export.vowelharmony( text, params )[#export.vowelharmony( text, params )] local syllables = #export.syllables( text ) local reduced = text if ( syllables > 1 and match( text, "[бвгджзклмнпрстфхцчшщ][аоөэиь]$" ) ) or match( text, "ь$" ) then local matches = { not params.bor, match( text, "ь$" ), match( text, "[ауя][влмн]ба$" ), match( text, "[оё][влмн]бо$" ), match( text, "ө[влмн]бө$" ), match( text, "[эүе][влмн]бэ$" ), match( text, "[бвглмнр]" .. vh.a .. char( 0x301 ) .. "?" .. char( 0x300 ) .. "?н" .. vh.a .. "$" ), match( text, "[ауя]нга$" ), match( text, "[оё]нго$" ), match( text, "өнгө$" ), match( text, "[эүе]нгэ$" ) }		for _,v in pairs( matches ) do			if v then reduced = sub( text, 1, len( text ) - 1 ) end end elseif not params.proper and ( vh.location ~= len( text ) - 1 or vh.violation == false ) and not params.bor then -- exclude proper nouns, loanwords and terms where the deleted vowel determines the vowel harmony local matches = { -- CVC match( text, "[аеёийоөуүэюя][влмр]ь?[аиоөэ][гджзлмнрстцчш]$" ), -- not нVC match( text, "[аеёийоөуүэюя][вгджзнрстцчш]ь?[аиоөэ]в$" ), -- not [лм]Vв match( text, "[аеёийоөуүэюя]гь?[аиоөэ][лмнр]$" ) and vh.position == "front", -- гV[лмнр] if front vowel only -- CCVC match( text, "[аеёийоөуүэюя][вглмнр]?ь?[джзстхцчш]ь?[аиоөэ][гджзлмнрстцчш]$" ), match( text, "[аеёийоөуүэюя][вглмнр]?ь?[сх]ь?[тч]ь?[аиоөэ][вглмнр]$" ), match( text, "^билиг$" ) -- irregular }		local exclusions = { match( text, "[вдзлмрстхц]ь?и[вгджзлмнрстцчш]$" ), -- only [жчш]иC match( text, "[аеёийоөуүэюя][бвгджзлмнпрстхцчш][аиоөуүэ]?гь?[аиоөэ]н$" ), -- not гVн if 2nd & 3rd consecutive consonants (or more) match( text, "[аеёийоөуүэюя][бвгджзлмнпрстхцчш][аиоөуүэ]?[бвгджзлмнпрстхцчш][аиоөуүэ]?гь?[аиоөэ][вгджзлмнрстцчш]$" ) -- not гVC if г 3rd consecutive consonant (or more) }		for _,v in pairs( matches ) do			if v then reduced = sub( text, 1, len( text ) - 2 ) .. sub( text, len( text ), len( text ) ) end end for _,e in pairs( exclusions ) do			if e then reduced = text end end end return reduced end

function export.concat_forms_in_slot( forms ) if forms then local new_vals = {} for _, v in ipairs( forms ) do			local val = gsub( v.form, "|", "<!>" ) table.insert( new_vals, val ) end return table.concat( new_vals, "," ) else return nil end end

function export.combine_stem_ending( stem, ending ) if stem == "?" then return "?" else return stem .. ending end end

function export.generate_form( form, footnotes ) if type( footnotes ) == "string" then footnotes = { footnotes } end if footnotes then return { form = form, footnotes = footnotes } else return form end end return export