Module:headword: difference between revisions

Definition from Wiktionary, the free dictionary
Jump to: navigation, search
m
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
local languages = mw.loadData("Module:languages")
 
local languages = mw.loadData("Module:languages")
  +
local m_links = require("Module:links")
   
 
local export = {}
 
local export = {}
Line 77: Line 78:
 
if term ~= "" then
 
if term ~= "" then
 
 
-- Does this term contain a link?
+
-- Apply processing to the term, for formatting links and such
-- Todo: Replace this by a call to [[Module:links]], which is more sophisticated.
+
term = m_links.language_link(term, nil, lang, langinfo.names[1])
if not term:find("[[", nil, true) then
 
-- If not, then link the term
 
term = "[[" .. term .. (term ~= PAGENAME and "#" .. langinfo.names[1] .. "|" .. term or "") .. "]]"
 
end
 
 
 
 
-- Format the term with the script code template
 
-- Format the term with the script code template
Line 121: Line 122:
 
head = SUBPAGENAME
 
head = SUBPAGENAME
 
end
 
end
  +
end
  +
  +
-- Apply processing to the headword, for formatting links and such
  +
if head:find("[[", nil, true) then
  +
head = m_links.language_link(head, nil, langinfo)
 
end
 
end
 
 

Revision as of 16:36, 16 July 2013

This module is used to show headword lines, along with any annotations like genders, transliterations and inflections. It's used by the template {{head}}, via the submodule Module:headword/templates. It's also used by many other headword modules; for a full list, see. Some of the data used by this module is found in Module:headword/data.

full_headword

This is the primary external entry point. NOTE: The values passed in below will be destructively modified. You are warned.

full_headword(data)

This is used by {{head}} and various language-specific headword templates (e.g. {{ru-adj}} for Russian adjectives, {{de-noun}} for German nouns, etc.) to display an entire headword line.

The sole argument, data, is a table containing the following items (WARNING: they will be destructively modified):

{
	lang = language_object,
	sc = script_object
	heads = { [1] = "head1", [2] = "head2", ... },
	translits = { [1] = "translit1", [2] = "translit2", ... },
	inflections = {
			{ label = "grammatical_category", "inflected_form" },
			...
		},
	genders = { "gender1", "gender2", ... },
	pos_category = "plural_part_of_speech",
	categories = { "category1", "category2", ... },
	sort_key = "sort_key",
}

Further explanation:

  • data.lang is required and is a Language object from Module:languages corresponding to a given language. For example, use require("Module:languages").getByCode("ru") to retrieve the object corresponding to Russian.
  • data.sc is a script object from Module:scripts corresponding to a given script. Most of the time you can omit this item, and Module:scripts will determine the script using the list of scripts in the language's data file.
  • data.heads is a table listing the heads of the headword, each of which is a string. An empty string means to use a default head based on the page name. It is also possible to pass in a single string for a single headword, or omit it entirely, which is equivalent to passing in a single empty string (i.e. only one head, based on the page name).
  • data.translits is a table listing the transliterations corresponding to each headword in data.heads. The Nth numbered entry should be either a string specifying the transliteration of headword N, or may be omitted to display no transliteration or to generate an automatic transliteration using the language's transliteration module. (For languages with a transliteration module, pass in "-" to suppress the transliteration entirely.) It is also possible to pass in a single string (equivalent to a one-element list) or omitted entirely (equivalent to an empty list). Note that, if there are multiple headwords, the table in data.translits might have entries in the middle of the list that are nil. A list of this sort cannot be created with table.insert(), as attempting to insert nil this way does nothing. Instead, each transliteration must be explicitly assigned using a number as index: { [1] = "string", [3] = "string", ... }. (Here, item 2 is nil, because no value was assigned to it.)
  • data.genders is a table listing the gender or number strings for the headwords. This can be omitted for no genders or numbers. The accepted values for genders or numbers are given in Module:gender and number. See format_genders below for an example of this argument.
  • data.inflections is a table listing the inflections to be displayed in the headword entry. The format of this table is somewhat complex and is described below under format_inflections.
  • data.pos_category is the part-of-speech category for the entry. This is one of the lemma and nonlemma parts of speech listed in Module:headword/data. It should be in the plural: for example, "nouns". If this item is omitted, the part of speech category must be included in as the first item in data.categories.
  • data.categories is a table listing the categories to which the entry containing the headword will be added. The first category should be a part-of-speech category, with the canonical name of the language at the beginning – "Russian nouns" – unless the part of speech is given in the field data.pos_category.
  • data.sort_key is a string specifying a sort key for the categories listed in data.categories. Sort keys should usually be omitted, because the format_categories function in Module:utilities will generate a suitable sortkey in most cases. The sortkey is used to ensure that the page is listed in the correct order in the categories to which it belongs.

Examples

A simple example

full_headword{
	lang = require("Module:languages").getByCode("en"),	-- language code
	heads = {"book"},									-- headwords
	inflections = {
		{label = "plural", "books"}						-- inflections
	},
	categories = {"English nouns"},					-- part-of-speech category
}

might give (depending on the page it's run on):

<strong class="Latn headword" lang="en">book</strong> (''plural'' <b class="Latn" lang="en">[[books#English|books]]</b>)[[Category:English lemmas|HEADWORD]][[Category:English nouns|HEADWORD]]

which displays as:

book (plural books)

A fuller example

full_headword{
	lang = require("Module:languages").getByCode("de"),
	heads = {"Hund"},
	genders = {"m"},
	inflections = {
		{label = "genitive", "Hundes", "Hunds"},
		{label = "diminutive",
			{term = "Hündchen", genders = {"n"}},
			{nolink=true, term = "Hündlein", genders = {"n"}}
		}
	},
	categories = {"German nouns"},
}

might give (depending on the page it's run on):

<strong class="Latn headword" lang="de">Hund</strong>&nbsp;<span class="gender"><abbr title="masculine gender">m</abbr></span> (''genitive'' <b class="Latn" lang="de">[[Hundes#German|Hundes]]</b> ''or'' <b class="Latn" lang="de">[[Hunds#German|Hunds]]</b>, ''plural'' <b class="Latn" lang="de">[[Hunde#German|Hunde]] </b>''or (nonstandard)''<b> [[Hünde#German|Hünde]]</b>, ''diminutive'' <b class="Latn" lang="de">[[Hündchen#German|Hündchen]]</b>&nbsp;<span class="gender"><abbr title="neuter gender">n</abbr></span> ''or'' <b class="Latn" lang="de">Hündlein</b>&nbsp;<span class="gender"><abbr title="neuter gender">n</abbr></span>)[[Category:German lemmas|HEADWORD]][[Category:German nouns|HEADWORD]]

which displays as:

Hund m (genitive Hundes or Hunds, plural Hunde or (nonstandard) Hünde, diminutive Hündchen n or Hündlein n)

An example in a non-Latin script

This example is in Russian, which has automatic transliteration:

full_headword{
	lang = require("Module:languages").getByCode("ru"),
	heads = {"кни́га"},
	genders = {"f-in"},
	inflections = {
		{label = "genitive", "кни́ги"},
		{label = "nominative plural", "кни́ги"},
		{label = "genitive plural", "книг"}
	},
	categories = {"Russian nouns"},
}

might give (depending on the page it's run on):

<strong class="Cyrl headword" lang="ru">кни́га</strong> [[Wiktionary:Russian transliteration|•]] (<span class="tr" lang=""><span class="tr" lang="">kníga</span></span>)&nbsp;<span class="gender"><abbr title="feminine gender">f</abbr>&nbsp;<abbr title="inanimate">inan</abbr></span> (''genitive'' <b class="Cyrl" lang="ru">[[книги#Russian|кни́ги]]</b>, ''nominative plural'' <b class="Cyrl" lang="ru">[[книги#Russian|кни́ги]]</b>, ''genitive plural'' <b class="Cyrl" lang="ru">[[книг#Russian|книг]]</b>)[[Category:Russian lemmas|HEADWORD]][[Category:Russian nouns|HEADWORD]]

which displays as

кни́га (knígaf inan (genitive кни́ги, nominative plural кни́ги, genitive plural книг)

A fuller example in a non-Latin script

This example is in Russian, with two headwords, each of which requires manual transliteration:

full_headword{
	lang = require("Module:languages").getByCode("ru"),
	heads = {"интервьюе́р", "интервью́ер"},
	translits = {"intɛrvʹjuér", "intɛrvʹjújer"},
	genders = {"m-an"},
	inflections = {
		{label = "genitive", "интервьюе́ра", "интервью́ера"},
		{label = "nominative plural", "интервьюе́ры", "интервью́еры"},
		{label = "genitive plural", "интервьюе́ров", "интервью́еров"},
	},
	categories = {"Russian nouns"},
}

might give (depending on the page it's run on):

<strong class="Cyrl headword" lang="ru">интервьюе́р</strong> ''or'' <strong class="Cyrl headword" lang="ru">интервью́ер</strong> [[Wiktionary:Russian transliteration|•]] (<span class="tr" lang=""><span class="tr" lang="">intɛrvʹjuér</span> ''or'' <span class="tr" lang="">intɛrvʹjújer</span></span>)&nbsp;<span class="gender"><abbr title="masculine gender">m</abbr>&nbsp;<abbr title="animate">anim</abbr></span> (''genitive'' <b class="Cyrl" lang="ru">[[интервьюера#Russian|интервьюе́ра]]</b> ''or'' <b class="Cyrl" lang="ru">[[интервьюера#Russian|интервью́ера]]</b>, ''nominative plural'' <b class="Cyrl" lang="ru">[[интервьюеры#Russian|интервьюе́ры]]</b> ''or'' <b class="Cyrl" lang="ru">[[интервьюеры#Russian|интервью́еры]]</b>, ''genitive plural'' <b class="Cyrl" lang="ru">[[интервьюеров#Russian|интервьюе́ров]]</b> ''or'' <b class="Cyrl" lang="ru">[[интервьюеров#Russian|интервью́еров]]</b>)[[Category:Russian lemmas|HEADWORD]][[Category:Russian nouns|HEADWORD]]

which displays as

интервьюе́р or интервью́ер (intɛrvʹjuér or intɛrvʹjújerm anim (genitive интервьюе́ра or интервью́ера, nominative plural интервьюе́ры or интервью́еры, genitive plural интервьюе́ров or интервью́еров)

Another fuller example in a non-Latin script

This example is in Arabic, with embedded links in the headword and manual transliteration in an inflection (note that Arabic also has automatic transliteration, and is one of the languages that will display automatic transliterations of inflections in the headword, unlike e.g. Russian):

full_headword{
	lang = require("Module:languages").getByCode("ar"),
	heads = {"[[غُدّة]] [[بَصَلِيّ|بَصَلِيّة]] [[إحْلِيلِيّ|إحْلِيلِيّة]]"},
	translits = {"ḡudda baṣaliyya ʾiḥlīliyya"},
	genders = {"f"},
	inflections = {
		{label = "plural", {term="غُدَد بَصَلِيَّة إِحْلِيلِيَة", translit="ḡudad baṣaliyya ʾiḥlīliyya"}},
	},
	categories = {"Arabic nouns"},
}

might give (depending on the page it's run on):

<strong class="Arab headword" lang="ar">[[غدة#Arabic|غُدّة]] [[بصلي#Arabic|بَصَلِيّة]] [[إحليلي#Arabic|إحْلِيلِيّة]]</strong> [[Wiktionary:Arabic transliteration|•]] (<span class="tr" lang=""><span class="tr" lang="">ḡudda baṣaliyya ʾiḥlīliyya</span></span>)&nbsp;<span class="gender"><abbr title="feminine gender">f</abbr></span> (''plural'' <b class="Arab" lang="ar">[[غدد بصلية إحليلية#Arabic|غُدَد بَصَلِيَّة إِحْلِيلِيَة]]</b> (<span lang="" class="tr">ḡudad baṣaliyya ʾiḥlīliyya</span>))[[Category:Arabic lemmas|HEADWORD]][[Category:Arabic nouns|HEADWORD]]

which displays as

غُدّة بَصَلِيّة إحْلِيلِيّة (ḡudda baṣaliyya ʾiḥlīliyyaf (plural غُدَد بَصَلِيَّة إِحْلِيلِيَة (ḡudad baṣaliyya ʾiḥlīliyya))

format_headword

Text-x-generic with pencil.svg This documentation is out of date.
The documentation on this page or section no longer reflects its current state, and some information may be missing or incorrect. Please help by editing the documentation page, and adding information about undocumented features, while removing information that is no longer applicable.

format_headword(data)

Formats a headword, using the format appropriate for the language object and script (see Module:script utilities#tag_text) contained in the data table.

The sole argument is a table containing the same items as the table supplied to full_headword. Only a subset of the items in the table are used by this function: the heads, lang, sc, translits.

The data.heads parameter can either be a single string or a table of strings. If it's a table, then each string in the table is shown as a headword, separated by "or". This allows you to show multiple alternative headwords, such as when the same written form can be accented in different ways.

It has special behaviour in certain cases as well:

  • If an item in the heads parameter contains wikilinks, they are converted into language-section links for the given language (using Module:links#language_link, which is also used by {{l}}). For example, giving "[[give]] [[up]]", if the language provided is English, will produce: "[[give#English|give]] [[up#English|up]]". If string is prefixed with * or if any of the links are, then they are interpreted as reconstructed terms and it will create links to the Reconstruction namespace as appropriate.
  • If heads is empty (nil or the empty table), it will default to the subpage name (mw.title.getCurrentTitle().subpageText, equivalent to the magic word {{SUBPAGENAME}}).
    • If the page name contains spaces or punctuation marks (except for punctuation marks that are used inside of words), it is split and each individual word is automatically wikilinked as above.
    • If the current page is in the appendix namespace, and the language's type (in Module:languages) is not "appendix-constructed", then an asterisk "*" will be prepended to the headword to indicate that it is a reconstructed term.

format_transliteration

Text-x-generic with pencil.svg This documentation is out of date.
The documentation on this page or section no longer reflects its current state, and some information may be missing or incorrect. Please help by editing the documentation page, and adding information about undocumented features, while removing information that is no longer applicable.

format_transliteration(tr, lang)

If the transliteration is specified and non-empty, adds some stuff before and after it. For example, if the transliteration is "foo" and the language is Hebrew, produces
 [[Wiktionary:Hebrew transliteration|•]] (<span lang="">foo</span>)
which looks like “ (foo)”.

(Note: the bullet linking to a transliteration policy page is only added if the page actually exists.)

format_genders

NOTE: This documentation is up-to-date. Keep in mind, however, that this function is not currently exported, and the contents of the argument data will be overwritten.

format_genders(data)

Format gender specifications using Module:gender and number. For example:

format_genders({genders = {"m-in", "m-an-p"}, 
	lang=require("Module:languages").getByCode("ru")})

gives:

&nbsp;<span class="gender"><abbr title="masculine gender">m</abbr>&nbsp;<abbr title="inanimate">inan</abbr>, <abbr title="masculine gender">m</abbr>&nbsp;<abbr title="animate">anim</abbr>&nbsp;<abbr title="plural number">pl</abbr></span>

displays as:

 m inan, m anim pl

The argument is a table, consisting of elements .genders and .lang. NOTE: The table will be overwritten!!!

The value of .genders is a list of gender/number strings, in the form required by Module:gender and number.

format_inflections

NOTE: This documentation is up-to-date. Keep in mind, however, that this function is not currently exported, and the contents of the argument data will be overwritten.

format_inflections(data)

Format a list (table) of inflections, which are then concatenated together with commas and surrounded by parentheses. For example:

format_inflections({inflections = {
	{label = "diminutive", "Hündchen"}
	}, lang=require("Module:languages").getByCode("de")})

gives:

(''diminutive'' <b class="Latn" lang="de">[[Hündchen#German|Hündchen]]</b>)

displays as:

(diminutive Hündchen)

The argument is a table, consisting of elements .inflections, .lang, and optionally .sc. NOTE: The table will be overwritten!!!

The value of .inflections is a list of labeled inflections, each of which is a table:

  • The table must have a .label value which contains the label. It is displayed in italics and not linked.
  • Value of .enable_auto_translit may be set if transliteration of inflections is desired (it is off by default).
  • The table may optionally have a .accel value. This value is used to support accelerated entry creation using WT:ACCEL. The "form-of" and "lang-(code)" classes are added automatically, so only the "(form)-form-of" class needs to be given, along with any other classes that may be needed.
  • Numbered values in the table are the actual forms. They are normally formatted in bold text and converted to a link to the term (but see below). If a term already contains a link, it is converted into a section link using Module:links#language_link, just like in format_headword.
  • Forms are optional. If the table contains only the .label, then just the label is shown with no forms. If there is more than one form, they are shown with "or" between them.

For example:

format_inflections({inflections = {
	{label = "present", "krama"},
	{label = "past", "kramade"},
	{label = "past participle", "kramat"}
	}, lang=require("Module:languages").getByCode("sv")})

format_inflections({inflections = {
	{label = "plural", accel = "plural-form-of", "voorbeelden"},
	}, lang=require("Module:languages").getByCode("nl")})

gives:

(''present'' <b class="Latn" lang="sv">[[krama#Swedish|krama]]</b>, ''past'' <b class="Latn" lang="sv">[[kramade#Swedish|kramade]]</b>, ''past participle'' <b class="Latn" lang="sv">[[kramat#Swedish|kramat]]</b>)
 (''plural'' <span class="form-of lang-nl plural-form-of "><b class="Latn" lang="nl">[[voorbeelden#Dutch|voorbeelden]]</b></span>)

displays as:

(present krama, past kramade, past participle kramat)
(plural voorbeelden)

It is also possible, but optional, to supply a table instead of a term. This table can contain the keys .term (the actual term), .alt (alternative display form), .sc (script), .translit (transliteration), .id (sense id), .genders (list of genders), .nolink (if true, the function will not link to the term, but only display it boldfaced), .hypothetical (if true, the function will not link to the term, but display it italicized and preceded by a *), .accel (same as .accel in the outer table but applies only to the given term; if both accelerators are specified, both will appear as CSS classes). Most of these are used the same way as for full_link in Module:links, and are passed directly to it.

Example:

format_inflections({inflections = {
	{label = "diminutive",
	{term = "Hündchen", genders = {"n"}},
	{nolink=true, term = "Hündlein", genders = {"n"}}
	}}, lang=require("Module:languages").getByCode("de")})

gives:

(''diminutive'' <b class="Latn" lang="de">[[Hündchen#German|Hündchen]]</b>&nbsp;<span class="gender"><abbr title="neuter gender">n</abbr></span> ''or'' <b class="Latn" lang="de">Hündlein</b>&nbsp;<span class="gender"><abbr title="neuter gender">n</abbr></span>)

displays as:

(diminutive Hündchen n or Hündlein n)

Proposed/planned changes

  • Checking for invalid genders, given a list of genders that are valid for a particular language.

local languages = mw.loadData("Module:languages")
local m_links = require("Module:links")

local export = {}

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
    local args = frame:getParent().args
    PAGENAME = mw.title.getCurrentTitle().text
    SUBPAGENAME = mw.title.getCurrentTitle().subpageText
    NAMESPACE = mw.title.getCurrentTitle().nsText
    local ret = ""
    local categories = {}
    
    -- Get language and script information
    local lang = args[1] or (NAMESPACE == "Template" and "und")  or error("Language code has not been specified. Please pass parameter 1 to the module invocation.")
    local langinfo = languages[lang] or error("The language code \"" .. lang .. "\" is not valid.")
    local sc = args["sc"] or ""; if sc == "" then sc = langinfo.scripts[1] end
    
    -- Gather basic parameters
    local head = args["head"]; if head == "" then head = nil end
    local sort_key = args["sort"]; if sort_key == "" then sort_key = nil end
    local pos = args[2]; if pos == "" then pos = nil end
    local cat2 = args["cat2"]; if cat2 == "" then cat2 = nil end
    local cat3 = args["cat3"]; if cat3 == "" then cat3 = nil end
    local tr = args["tr"]; if tr == "" then tr = nil end
    
    -- Get/set categories
    if pos then
        -- Make the plural form of the part of speech
        if pos:find("x$") then
            pos = pos .. "es"
        elseif pos ~= "punctuation" or pos ~= "phrasebook" then
            pos = pos .. "s"
        end
        
        table.insert(categories, langinfo.names[1] .. " " .. pos)
    end
    
    if cat2 then
        table.insert(categories, langinfo.names[1] .. " " .. cat2)
    end
    
    if cat3 then
        table.insert(categories, langinfo.names[1] .. " " .. cat3)
    end
    
    -- Gather gender and number specifications
    -- Iterate over all gn parameters (g2, g3 and so on) until one is empty
    local genders = {}
    local g = args["g"] or ""
    local i = 2
    
    while g ~= "" do
        -- If any of the specifications contains a "?", add the entry
        -- to a cleanup category.
        if g:find("?", nil, true) then
            table.insert(categories, langinfo.names[1] .. " terms with incomplete gender")
        end
        
        table.insert(genders, g)
        g = args["g" .. i] or ""
        i = i + 1
    end
    
    -- Gather inflected forms
    local inflections = {}
    
    local i = 3
    local label = args[i] or ""
    local term = args[i+1] or ""
    local parts = {}
    
    while label ~= "" do
        table.insert(parts, label)
        
        if term ~= "" then
            
            -- Apply processing to the term, for formatting links and such
            term = m_links.language_link(term, nil, lang, langinfo.names[1])
            
            -- Format the term with the script code template
            term = frame:expandTemplate{ title = sc, args = { term, lang = lang, face = "bold" } }
            
            table.insert(parts, term)
        end
        
        i = i + 2
        label = args[i] or ""
        term = args[i+1] or ""
        
        -- If the next label is "or" then continue adding to the current parts list.
        -- Otherwise, insert the previous one and create a new one.
        if label ~= "or" then
            table.insert(inflections, parts)
            parts = {}
        end
    end
    
    table.insert(inflections, part)
    
    -- Format and return all the gathered information
    return
        export.format_headword(head, lang, sc) ..
        export.format_transliteration(tr) ..
        export.format_genders(genders) ..
        export.format_inflections(inflections, lang, sc) ..
        export.format_categories(categories, sort_key)
end

-- Format a headword
function export.format_headword(head, lang, sc)
    if not head then
        NAMESPACE = NAMESPACE or mw.title.getCurrentTitle().nsText
        SUBPAGENAME = SUBPAGENAME or mw.title.getCurrentTitle().subpageText
        local langinfo = languages[lang] or error("The language code \"" .. lang .. "\" is not valid.")
        
        if NAMESPACE == "Appendix" and langinfo.type ~= "appendix-constructed" then
            head = "*" .. SUBPAGENAME
        else
            head = SUBPAGENAME
        end
    end
    
    -- Apply processing to the headword, for formatting links and such
    if head:find("[[", nil, true) then
        head = m_links.language_link(head, nil, langinfo)
    end
    
    -- Call the script code template
    return mw.getCurrentFrame():expandTemplate{ title = sc, args = { head, lang = lang, face = "head" } }
end

-- Format transliteration
function export.format_transliteration(tr)
    if tr then
        return " (" .. tr .. ")"
    else
        return ""
    end
end

function export.format_genders(genders, lang)
    if #genders > 0 then
        local gen = require("Module:gender and number")
        return " " .. gen.format_list(genders)
    else
        return ""
    end
end

-- Format the inflections following the headword
function export.format_inflections(inflections, lang, sc)
    if #inflections > 0 then
        -- Format each inflection "part" individually
        for key, part in ipairs(inflections) do
            -- If this "part" is a table, it contains alternating label-term pairs.
            -- Format them too.
            if type(part) == "table" then
                for key2, text in ipairs(part) do
                    -- Odd-numbered keys are labels, even-numbered keys are terms
                    if key2 % 2 == 1 then
                        part[key2] = "''" .. text .. "''"
                    end
                end
                
                inflections[key] = table.concat(part, " ")
            end
        end

        return " (" .. table.concat(inflections, ", ") .. ")"
    else
        return ""
    end
end

-- Format the categories with the appropriate sort key
function export.format_categories(categories, sort_key)
    NAMESPACE = NAMESPACE or mw.title.getCurrentTitle().nsText
    
    if NAMESPACE == "" or NAMESPACE == "Appendix" then
        PAGENAME = PAGENAME or mw.title.getCurrentTitle().text
        SUBPAGENAME = SUBPAGENAME or mw.title.getCurrentTitle().subpageText
        
        -- Generate a default sort key
        if not sort_key then
            sort_key = mw.ustring.gsub(SUBPAGENAME, "^[-־]", "")
        end
        
        -- If the key is the same as the wiki software's default, remove it
        if sort_key == PAGENAME then
            sort_key = nil
        end
        
        for key, cat in ipairs(categories) do
            categories[key] = "[[Category:" .. cat .. (sort_key and "|" .. sort_key or "") .. "]]"
        end
        
        return table.concat(categories, "")
    else
        return ""
    end
end

return export