Modül:çekim

Vikisözlük sitesinden
Modül belgelemesi [Düzenle] [Tazele]


local m_baglantilar = require("Modül:bağlantılar")
local m_tablo = require("Modül:table")
--local m_pos = mw.loadData("Modül:çekim/söz türü")
local m_fonksiyonlar = require("Modül:çekim/fonksiyonlar")

local ulen = mw.ustring.len
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split

local cikart = {}

--[=[

Bu modül başlıca {{çekim}} şablonunu ve bunun alt çeşitlerini desteklemektedir
İngilizce Vikisözlük'ten çevrilmiştir öncelikle, ama daha sonradan üzerinde
oynanarak farklılaşmıştır. {{çoğul ad}} şablonu da desteklenen alt şablonlardan
bir tanesidir. Ayrıca otomatik çekimleme karşılaştırma şablonları
{{tr-çekim}} ve {{ota-çekim}} de desteklenen şablonlar arasındadır.
Diğer ilgili bağlantılar:

* [[Modül:çekim/şablonlar]] şablonların arayüzlerinde çıktı veren tüm mantığı
  barındıran asıl sayfadır.
* [[Modül:çekim/veri]] çekimleme zamanları, halleri, cinsiyetleri,
  biçimleri vs. tüm bilgilerini barındırıp aynı zamanda
  kısayollarını ve vikiveri ID'lerini de içeren bir veri sayfasıdır.
  Bu sayfa, daha yaygın olan etiketleri içermektedir.
* [[Modül:çekim/veri2]] biçimi [[Modül:çekim/veri]] sayfası ile aynı
  olan ama daha az yaygın olan çekim verilerini barındıran sayfadır.
* [[Modül:çekim/kategoriler]] belirli çekimler eklendiği zaman dil-bazlı
  kategorilerin listesini barındırıp onları sayfalara eklemeye yarayan
  bir veri barındıran sayfadır.
* [[Modül:çekim/fonksiyonlar]] sayfası, [[Modül:çekim/veri]] ve
  [[Modül:çekim/kategoriler]] veri dosyalarında kullanılan fonksiyonları
  barındırır. Bu fonksiyonlar bu modülde barındırılmakta, çünkü veri
  modülleri kod barındırmamalı. Bu dosyadaki fonksiyonlar iki tiptedir:

  (1) Çok parçalı etiketlerin görünümleri için özelleştirme sağlarlar
      (aşağıya bakınız). Şu anda bu şekilde yalnızca bir tane sağlayıcı
      bulunmaktadır, o da şahıs etiketlerinin şu şekilde kullanımındadır:
	  '1//2//3'.
  (2) Kategori fonksiyonları daha karmaşık mantıkları içermektedir ve
      adlarına göre [[Modül:çekim/kategoriler]] sayfasında bahsedilmektedir.
	  Şu anda bu fonksiyonlar kullanım dışıdır.

Aşağıdaki terminoloji {{çekim}} şablonunda kullanılan tüm parametreler içindir:

* A TAG is a single grammatical item, as specified in a single numbered
  parameter of {{çekim}}. Examples are 'masculine', 'nominative',
  or 'first-person'. Tags may be abbreviated, e.g. 'm' for 'masculine',
  'nom' for 'nominative', or '1' for 'first-person'. Such abbreviations
  are called SHORTCUTS, and some tags have multiple equivalent shortcuts
  (e.g. 'p' or 'pl' for 'plural'). The full, non-abbreviated form of
  a tag is called its CANONICAL FORM.
* The DISPLAY FORM of a tag is the way it's displayed to the user. Usually
  the displayed text of the tag is the same as its canonical form, and it
  normally functions as a link to a glossary entry explaining the tag.
  Usually the link is to an entry in [[Appendix:Glossary]], but sometimes
  the tag is linked to an individual dictionary entry or to a Wikipedia
  entry. Occasionally, the display text differs from the canonical form of
  the tag. An example is the tag 'comparative case', which has the display
  text read as simply 'comparative'. Normally, tags referring to cases don't
  have the word "case" in them, but in this case the tag 'comparative' was
  already used as a shortcut for the tag 'comparative degree', so the tag was
  named 'comparative case' to avoid clashing. A similar situation occurs
  with 'adverbial case' vs. the grammar tag 'adverbial' (as in 'adverbial
  participle').
* A TAG SET is an ordered list of tags, which together express a single
  inflection, for example, '1|s|pres|ind', which can be expanded to
  canonical-form tags as 'first-person|singular|present|indicative'.
  Multiple tag sets can be specified in a single call to {{inflection of}}
  by separating the individual tag sets with a semicolon, e.g.
  '1|s|pres|ind|;|2|s|imp', which specifies two tag sets, '1|s|pres|ind'
  as above and '2|s|imp' (in canonical form,
  'second-person|singular|imperative').
* A MULTIPART TAG is a tag that embeds multiple tags within it, such as
  'f//n' or 'nom//acc//voc'. These are used in the case of [[syncretism]],
  when the same form applies to multiple inflections. Examples are the
  Spanish present subjunctive, where the first-person and third-person
  singular have the same form (e.g. [[siga]] from [[seguir]] "to follow"),
  or Latin third-declension adjectives, where the dative and ablative
  plural of all genders have the same form (e.g. [[omnibus]] from [[omnis]]
  "all"). These would be expressed respectively as '1//3|s|pres|sub'
  and 'dat//abl|m//f//n|p', where the use of the multipart tag compactly
  encodes the syncretism and avoids the need to individually list out
  all of the inflections. Multipart tags currently display as a list
  separated by "and", ''dative and ablative'' or
  ''masculine, feminine and neuter'' where each individual word is linked
  appropriately. As a special case, multipart tags involving persons display
  specially; for example, the multipart tag ''1//2//3'' displays as
  ''first-, second- and third-person'', with the word "person" occurring
  only once.
* A TWO-LEVEL MULTIPART TAG is a special type of multipart tag that
  joins two or more tag sets instead of joining individual tags. The tags
  within the tag set are joined by a colon, e.g. '1:s//3:p', which is
  displayed as ''first-person singular and third-person plural'', e.g.
  for use with the form [[μέλλον]] of the verb [[μέλλω]] "to intend",
  which uses the tag set '1:s//3:p|impf|actv|indc|unaugmented' to express
  the syncretism between the first singular and third plural forms of the
  imperfect active indicative unaugmented conjugation. Two-level multipart
  tags should be used sparingly; if in doubt, list out the inflections
  separately.
* A MULTIPART TAG SHORTCUT is a shortcut that expands into a multipart
  tag, for example '123', which expands to the multipart tag '1//2//3'.
  Only the most common such combinations exist as shortcuts.
* A LIST TAG SHORTCUT is a special type of shortcut that expands to a list
  of tags instead of a single tag. For example, the shortcut '1s' expands to
  '1|s' (first-person singular). Only the most common such combinations
  exist as shortcuts.
  
]=]

-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
	local retval = rsubn(term, foo, bar)
	return retval
end

-- FIXME! Change callers of this to directly call [[Modül:string araçları]].
function cikart.ucfirst(text)
	return require("Modül:string araçları").ucfirst(text)
end


function cikart.bicimlendir_cekimi(sozbilgi, aciklama)
	local kisimlar = {}
	table.insert(kisimlar, "<span class='cekim-aciklama use-with-mention'>")
	if sozbilgi then
		table.insert(kisimlar, "<span class='cekim-aciklama-bag'>")
		if type(sozbilgi) == "string" then
			table.insert(kisimlar, sozbilgi)
		else
			table.insert(kisimlar, m_baglantilar.tam_bag(sozbilgi, "sözcük", false))
		end
		table.insert(kisimlar, "</span>")
	end
	if aciklama then
		table.insert(kisimlar, aciklama)
	end
	table.insert(kisimlar, "</span>")
	return table.concat(kisimlar)
end


local function baglanti_mi_html_mi(tag)
	return tag:find("[[", nil, true) or tag:find("|", nil, true) or
		tag:find("<", nil, true)
end


-- Look up a tag (either a shortcut of any sort of a canonical long-form tag)
-- and return its expansion. The expansion will be a string unless the
-- shortcut is a list-tag shortcut such as "1s"; in that case, the expansion
-- will be a list. The caller must handle both cases. Only one level of
-- expansion happens; hence, "acc" expands to "accusative", "1s" expands to
-- {"1", "s"} (not to {"first", "singular"}) and "123" expands to "1//2//3".
-- The expansion will be the same as the passed-in tag in the following
-- circumstances:
--
-- 1. The tag is ";" (this is special-cased, and no lookup is done).
-- 2. The tag is a multipart tag such as "nom//acc" (this is special-cased,
--    and no lookup is done).
-- 3. The tag contains a raw link (this is special-cased, and no lookup is
--    done).
-- 4. The tag contains HTML (this is special-cased, and no lookup is done).
-- 5. The tag is already a canonical long-form tag.
-- 6. The tag is unrecognized.
--
-- This function first looks up in [[Module:form of/data]] (which includes
-- more common tags) and then (only if the tag is not recognized as a
-- shortcut or canonical tag, and is not of types 1-4 above) in
-- [[Module:form of/data2]].
--
-- If the expansion is a string and is different from the tag, track it if
-- DO_TRACK is true.
function cikart.ara_kisayol(etiket, yap_arama)
	-- If there is HTML or a link in the tag, return it directly; don't try
	-- to look it up, which will fail.
	if etiket == ";" or etiket:find("//", nil, true) or baglanti_mi_html_mi(etiket) then
		return etiket
	end
	local m_veri = mw.loadData("Modül:çekim/veri")
	-- If this is a canonical long-form tag, just return it, and don't
	-- check for shortcuts (which will cause [[Module:form of/data2]] to be
	-- loaded).
	if m_veri.etiketler[etiket] then
		return etiket
	end
	local genislet = m_veri.kisayollar[etiket]
	if not genislet then
		local m_veri2 = mw.loadData("Modül:çekim/veri2")
		genislet = m_veri2.kisayollar[etiket]
	end
	if not genislet then
		return etiket
	end
	-- Maybe track the expansion if it's not the same as the raw tag.
	if yap_arama and genislet ~= etiket and type(genislet) == "string" then
		--infl_track("tag/" .. tag)
	end
	return genislet
end


-- Look up a normalized/canonicalized tag and return the data object
-- associated with it. If the tag isn't found, return nil. This first looks up
-- in [[Module:form of/data]] (which includes more common tags) and then in
-- [[Module:form of/data2]].
function cikart.ara_etiket(etiket)
	local m_veri = mw.loadData("Modül:çekim/veri")
	local etinesne = m_veri.etiketler[etiket]
	if etinesne then
		return etinesne
	end
	local m_veri2 = mw.loadData("Modül:çekim/veri2")
	local etinesne2 = m_veri2.etiketler[etiket]
	if etinesne2 then
		return etinesne2
	end
	return nil
end


-- Normalize a single tag, which may be a shortcut but should not be a
-- multipart tag, a multipart-tag shortcut or a list-tag shortcut.
local function normallestir_tekli_etiket(etiket, yap_arama)
	local genislet = cikart.ara_kisayol(etiket, yap_arama)
	if type(genislet) ~= "string" then
		error(etiket .. "' etiketi bir kısayoldur, ki burada kısayol kullanmanıza izin yok")
	end
	etiket = genislet
	if not cikart.ara_etiket(etiket) and yap_arama then
		-- If after all expansions and normalizations we don't recognize
		-- the canonical tag, track it.
		--infl_track("unknown")
		--infl_track("unknown/" .. tag)
	end
	return etiket
end


-- Normalize a component of a multipart tag. This should not have any // in it,
-- but may join multiple individual tags with a colon, and may be a single
-- list-tag shortcut, which is treates as if colon-separated. If
-- RECOMBINE_TAGS isn't given, the return value may be a list of tags;
-- otherwise, it will always be a string, and multiple tags will be
-- represented as canonical-form tags joined by ":".
local function normallestir_cokparcali_eleman(etiket, birlestir_etiketleri, yap_arama)
	-- If there is HTML or a link in the tag, don't try to split on colon.
	-- A colon may legitimately occur in either one, and we don't want
	-- these things parsed. Note that we don't do this check before splitting
	-- on //, which we don't expect to occur in links or HTML; see comment
	-- in etiketi_normallestir().
	if baglanti_mi_html_mi(etiket) then
		return etiket
	end
	local elemanlar = rsplit(etiket, ":", true)
	if #elemanlar == 1 then
		-- We allow list-tag shortcuts inside of multipart tags, e.g.
		-- '1s//3p'. Check for this now.
		etiket = cikart.ara_kisayol(etiket, yap_arama)
		if type(etiket) == "table" then
			-- We found a list-tag shortcut; treat as if colon-separated.
			elemanlar = etiket
		else
			return normallestir_tekli_etiket(etiket, yap_arama)
		end
	end
	local normetiketler = {}
	for _, eleman in ipairs(elemanlar) do
		if yap_arama then
			-- There are multiple components; track each of the individual
			-- raw tags.
			--infl_track("tag/" .. component)
		end
		table.insert(normetiketler, normallestir_tekli_etiket(eleman, yap_arama))
	end

	if birlestir_etiketleri then
		return table.concat(normetiketler, ":")
	else
		return normetiketler
	end
end


-- Normalize a single tag. If RECOMBINE_TAGS isn't given, the return value
-- may be a list (in the case of multipart tags), which will contain nested
-- lists in the case of two-level multipart tags; otherwise, it will always
-- be a string, and multipart tags will be represented as canonical-form tags
-- joined by "//" and/or ":".
local function etiketi_normallestir(etiket, birlestir_cokluetiketleri, yap_arama)
	-- We don't check for links or HTML before splitting on //, which we
	-- don't expect to occur in links or HTML. Doing it this way allows for
	-- a tag like '{{lb|grc|Epic}}//{{lb|grc|Ionic}}' to function correctly
	-- (the template calls will be expanded before we process the tag, and
	-- will contain links and HTML). The only check we do is for a URL,
	-- which shouldn't normally occur, but might if the user tries to put
	-- an external link into the tag. URL's with // normally have the
	-- sequence ://, which should never normally occur when // and : are
	-- used in their normal ways.
	if etiket:find("://", nil, true) then
		return etiket
	end
	local ayri_etiketler = rsplit(etiket, "//", true)
	if #ayri_etiketler == 1 then
		local birdeg = normallestir_cokparcali_eleman(etiket, birlestir_cokluetiketleri,
			yap_arama)
		if type(birdeg) == "table" then
			-- The user gave a tag like '1:s', i.e. with colon but without
			-- //. Allow this, but we need to return a nested list. Note,
			-- this will never happen when RECOMBINE_TAGS is given.
			return {birdeg}
		end
		return birdeg
	end
	local normetiketler = {}
	for _, tekli_etiket in ipairs(ayri_etiketler) do
		if yap_arama then
			-- If the tag was a multipart tag, track each of individual raw tags.
			--infl_track("tag/" .. single_tag)
		end
		table.insert(normetiketler, normallestir_cokparcali_eleman(tekli_etiket,
			birlestir_cokluetiketleri, yap_arama))
	end
	if birlestir_cokluetiketleri then
		return table.concat(normetiketler, "//")
	else
		return normetiketler
	end
end


-- Normalize a tag set (a list of tags) into a list of canonical-form tags
-- (which -- may be larger due to the possibility of list-tag shortcuts).
-- If RECOMBINE_TAGS isn't given, the return list may itself contains lists;
-- in particular, multipart tags will be represented as lists. Specifically,
-- the list will consist of the elements of the multipart tag, which will
-- either be canonical-form strings or (in the case of two-level multipart
-- tags) nested lists of canonical-form strings. For example, the multipart
-- tag ''nom//acc//voc'' will expand to
--   {"nominative", "accusative", "vocative"}
-- and the two-level multipart tag ''1:s//3:p'' will expand to
--   {{"first-person", "singular"}, {"third-person", "plural"}}.
-- If RECOMBINE_TAGS is given, multipart tags will be represented in string
-- form, i.e. as canonical-form tags joined by "//" and/or ":".
function cikart.normallestir_etiketleri(tags, recombine_multitags, do_track)
	-- We track usage of shortcuts, normalized forms and (in the case of
	-- multipart tags or list tags) intermediate forms.
	local ntags = {}
	for _, tag in ipairs(tags) do
		if do_track then
			-- Track the raw tag.
			--infl_track("tag/" .. tag)
		end
		-- Expand the tag, which may generate a new tag (either a
		-- fully canonicalized tag, a multipart tag, or a list of tags).
		tag = cikart.ara_kisayol(tag, do_track)
		if type(tag) == "table" then
			for _, t in ipairs(tag) do
				if do_track then
					-- If the tag expands to a list of raw tags, track each of
					-- those.
					--infl_track("tag/" .. t)
				end
				table.insert(ntags, etiketi_normallestir(t, recombine_multitags,
					do_track))
			end
		else
			table.insert(ntags, etiketi_normallestir(tag, recombine_multitags,
				do_track))
		end
	end
	return ntags
end


local function normallestir_sozturu(pos)
	return m_pos[pos] or pos
end


-- Return the display form of a single canonical-form tag. The value
-- passed in must be a string (i.e. it cannot be a list describing a
-- multipart tag). To handle multipart tags, use getir_etiket_gorunum_bicimi().
local function getir_tekli_etiketi_gorunum_bicimi(normtag)
	local data = cikart.ara_etiket(normtag)

	-- If the tag has a special display form, use it
	if data and data.display then
		normtag = data.display
	end

	-- If there is a nonempty glossary index, then show a link to it
	if data and data.glossary then
		if data.glossary_type == "wikt" then
			normtag = "[[" .. data.glossary .. "|" .. normtag .. "]]"
		elseif data.glossary_type == "wp" then
			normtag = "[[w:" .. data.glossary .. "|" .. normtag .. "]]"
		else
			normtag = "[[Appendix:Glossary#" .. mw.uri.anchorEncode(data.glossary) .. "|" .. normtag .. "]]"
		end
	end
	return normtag
end


-- Turn a canonicalized tag spec (which describes a single, possibly
-- multipart tag) into the displayed form. The tag spec may be a string
-- (a canonical-form tag), or a list of canonical-form tags (in the
-- case of a simple multipart tag), or a list of mixed canonical-form
-- tags and lists of such tags (in the case of a two-level multipart tag).
-- JOINER indicates how to join the parts of a multipart tag, and can
-- be either "and" ("foo and bar", or "foo, bar and baz" for 3 or more),
-- "slash" ("foo/bar"), "en-dash" ("foo–bar") or nil, which uses the
-- global default found in multipart_join_strategy() in
-- [[Module:form of/functions]].
function cikart.getir_etiket_gorunum_bicimi(tagspec, joiner)
	if type(tagspec) == "string" then
		return getir_tekli_etiketi_gorunum_bicimi(tagspec)
	end
	-- We have a multipart tag. See if there's a display handler to
	-- display them specially.
	for _, handler in ipairs(m_fonksiyonlar.goruntu_halledicileri) do
		local displayval = handler(tagspec, joiner)
		if displayval then
			return displayval
		end
	end
	-- No display handler.
	local displayed_tags = {}
	for _, first_level_tag in ipairs(tagspec) do
		if type(first_level_tag) == "string" then
			table.insert(displayed_tags, getir_tekli_etiketi_gorunum_bicimi(first_level_tag))
		else
			-- A first-level element of a two-level multipart tag.
			-- Currently we just separate the individual components
			-- with spaces, but other ways are possible, e.g. using
			-- an underscore, colon, parens or braces.
			local components = {}
			for _, component in ipairs(first_level_tag) do
				table.insert(components, getir_tekli_etiketi_gorunum_bicimi(component))
			end
			table.insert(displayed_tags, table.concat(components, " "))
		end
	end
	return m_fonksiyonlar.birlestir_cokparcali(displayed_tags, joiner)
end


function cikart.yakala_dil_kategorileri(lang, tags, terminfo, POS)
	local m_cats = mw.loadData("Modül:çekim/kategoriler")

	local categories = {}

	local normalized_tags = cikart.normallestir_etiketleri(tags, "recombine multitags")
	POS = normallestir_sozturu(POS)

	local function yap_fonksiyon_tablosu()
		return {
			lang=lang,
			tags=normalized_tags,
			term=term,
			p=POS
		}
	end

	local function kontrol_et_durumu(spec)
		if type(spec) == "boolean" then
			return spec
		elseif type(spec) ~= "table" then
			error("Wrong type of condition " .. spec .. ": " .. type(spec))
		end
		local predicate = spec[1]
		if predicate == "has" then
			return m_tablo.contains(normalized_tags, etiketi_normallestir(spec[2])), 3
		elseif predicate == "hasall" then
			for _, tag in ipairs(spec[2]) do
				if not m_tablo.contains(normalized_tags, etiketi_normallestir(tag)) then
					return false, 3
				end
			end
			return true, 3
		elseif predicate == "hasany" then
			for _, tag in ipairs(spec[2]) do
				if m_tablo.contains(normalized_tags, etiketi_normallestir(tag)) then
					return true, 3
				end
			end
			return false, 3
		elseif predicate == "tags=" then
			local normalized_spec_tags = cikart.normallestir_etiketleri(spec[2],
				"recombine multitags")
			return m_tablo.deepEqualsList(normalized_tags, normalized_spec_tags), 3
		elseif predicate == "p=" then
			return POS == normallestir_sozturu(spec[2]), 3
		elseif predicate == "pany" then
			for _, specpos in ipairs(spec[2]) do
				if POS == normallestir_sozturu(specpos) then
					return true, 3
				end
			end
			return false, 3
		elseif predicate == "pexists" then
			return POS ~= nil, 2
		elseif predicate == "not" then
			local condval = kontrol_et_durumu(spec[2])
			return not condval, 3
		elseif predicate == "and" then
			local condval = kontrol_et_durumu(spec[2])
			if condval then
				condval = kontrol_et_durumu(spec[3])
			end
			return condval, 4
		elseif predicate == "or" then
			local condval = kontrol_et_durumu(spec[2])
			if not condval then
				condval = kontrol_et_durumu(spec[3])
			end
			return condval, 4
		elseif predication == "call" then
			local fn = m_fonksiyonlar.kat_fonksiyonlari[spec[2]]
			if not fn then
				error("No condition function named '" .. spec[2] .. "'")
			end
			return fn(yap_fonksiyon_tablosu()), 3
		else
			error("Unrecognized predicate: " .. predicate)
		end
	end

	local function durum_tahmini(spec)
		if not spec then
			return false
		elseif type(spec) == "string" then
			-- Substitute POS request with user-specified part of speech
			-- or default
			spec = rsub(spec, "<<p=(.-)>>", function(default)
				return POS or normallestir_sozturu(default)
			end)
			table.insert(categories, lang:getCanonicalName() .. " " .. spec)
			return true
		elseif type(spec) ~= "table" then
			error("Wrong type of specification " .. spec .. ": " .. type(spec))
		end
		local predicate = spec[1]
		if predicate == "multi" then
			-- WARNING! #spec doesn't work for objects loaded from loadData()
			for i, sp in ipairs(spec) do
				if i > 1 then
					durum_tahmini(sp)
				end
			end
			return true
		elseif predicate == "cond" then
			-- WARNING! #spec doesn't work for objects loaded from loadData()
			for i, sp in ipairs(spec) do
				if i > 1 and durum_tahmini(sp) then
					return true
				end
			end
			return false
		elseif predicate == "call" then
			local fn = m_fonksiyonlar.kat_fonksiyonlari[spec[2]]
			if not fn then
				error("No spec function named '" .. spec[2] .. "'")
			end
			return durum_tahmini(fn(yap_fonksiyon_tablosu()))
		else
			local condval, ifspec = kontrol_et_durumu(spec)
			if condval then
				durum_tahmini(spec[ifspec])
				return true
			else
				durum_tahmini(spec[ifspec + 1])
				return false
			end
		end
	end

	local langspecs = m_cats[lang:getCode()]
	if langspecs then
		for _, spec in ipairs(langspecs) do
			durum_tahmini(spec)
		end
	end
	if lang:getCode() ~= "und" then
		local langspecs = m_cats["und"]
		if langspecs then
			for _, spec in ipairs(langspecs) do
				durum_tahmini(spec)
			end
		end
	end
	return categories
end


function cikart.etiketlenmis_cekimler(tags, terminfo, notext, capfirst, posttext, joiner)
	local cur_infl = {}
	local inflections = {}
	local kategoriler = {}

	local ntags = cikart.normallestir_etiketleri(tags, nil, "do-track")
	
	for i, tagspec in ipairs(ntags) do
		if tagspec == "belirtilmemiş" then
			table.insert(kategoriler, "[[Kategori:Otomatik modüller tarafından henüz tanınmayan çekimler]]")
		end
		
		if tagspec == ";" then
			if #cur_infl > 0 then
				table.insert(inflections, table.concat(cur_infl))
			end

			cur_infl = {}
		else
			local to_insert = cikart.getir_etiket_gorunum_bicimi(tagspec, joiner)
			-- Maybe insert a space before inserting the display form
			-- of the tag. We insert a space if
			-- (a) we're not the first tag; and
			-- (b) the tag we're about to insert doesn't have the
			--     "no_space_on_left" property; and
			-- (c) the preceding tag doesn't have the "no_space_on_right"
			--     property.
			-- NOTE: We depend here on the fact that
			-- (1) all tags with either of the above properties set have the
			--     same display form as canonical form, and
			-- (2) all tags with either of the above properties set are
			--     single-character tags.
			-- The second property is an optimization to avoid looking up
			-- display forms resulting from multipart tags, which won't be
			-- found and which will trigger loading of [[Module:form of/data2]].
			-- If multichar punctuation is added in the future, it's ok to
			-- change the == 1 below to <= 2 or <= 3.
			--
			-- If the first property above fails to hold in the future, we
			-- need to track the canonical form of each tag (including the
			-- previous one) as well as the display form. This would also
			-- avoid the need for the == 1 check.
			if #cur_infl > 0 then
				local most_recent_tagobj = ulen(cur_infl[#cur_infl]) == 1 and
					cikart.ara_etiket(cur_infl[#cur_infl])
				local to_insert_tagobj = ulen(to_insert) == 1 and
					cikart.ara_etiket(to_insert)
				if (
					(not most_recent_tagobj or
					 not most_recent_tagobj.sagda_bosluk_yok) and
					(not to_insert_tagobj or
					 not to_insert_tagobj.solda_bosluk_yok)
				) then
					table.insert(cur_infl, " ")
				end
			end
			table.insert(cur_infl, to_insert)
		end
	end

	if #cur_infl > 0 then
		table.insert(inflections, table.concat(cur_infl))
	end

	if #inflections == 1 then
		return cikart.bicimlendir_cekimi(terminfo,
			notext and "" or ((terminfo and " sözcüğünün" or "") ..
				" " .. inflections[1] .. " çekimi") .. (kategoriler[1] and table.concat(kategoriler) or "")
		)
	else
		local link = cikart.bicimlendir_cekimi(terminfo,
			notext and "" or ((terminfo and " sözcüğünün" or "") ..
				" çekimi:")
		)
		return link .."\n## <span class='form-of-definition use-with-mention'>" .. table.concat(inflections, "</span>\n## <span class='form-of-definition use-with-mention'>") .. "</span>"
			.. (kategoriler[1] and table.concat(kategoriler) or "")
	end
end

function cikart.Vikiveri_IDsine(tags, skip_tags_without_ids)
	if type(tags) == "string" then
		tags = mw.text.split(tags, "|", true)
	end

	local ret = {}

	local function getir_vikiveri_id(tag)
		if tag == ";" and not skip_tags_without_ids then
			error("Semicolon is not supported for Wikidata IDs")
		else
			return nil
		end

		local data = cikart.ara_etiket(tag)

		if not data or not data.wikidata then
			if not skip_tags_without_ids then
				error("The tag \"" .. tag .. "\" does not have a Wikidata ID defined in [[Module:form of/data]]")
			else
				return nil
			end
		else
			return data.wikidata
		end
	end

	for i, tag in ipairs(cikart.normallestir_etiketleri(tags)) do
		if type(tag) == "table" then
			local ids = {}
			for _, onetag in ipairs(tag) do
				table.insert(ids, getir_vikiveri_id(onetag))
			end
			table.insert(ret, ids)
		else
			table.insert(ret, getir_vikiveri_id(tag))
		end
	end

	return ret
end


return cikart

-- For Vim, so we get 4-space tabs
-- vim: set ts=4 sw=4 noet: