Compare commits
25 Commits
abbreviati
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7b417f0d3 | ||
|
|
e008aa16f4 | ||
|
|
55545eeccc | ||
|
|
80844f5575 | ||
|
|
69ec9263a1 | ||
|
|
169c6c912d | ||
|
|
3304ab8f3e | ||
|
|
977810e8cd | ||
|
|
9e20916e37 | ||
|
|
e4726bbbbd | ||
|
|
04e327e5a1 | ||
|
|
34ae1b4df6 | ||
|
|
1eead20457 | ||
|
|
1753717dd8 | ||
|
|
9f48e3f9a7 | ||
|
|
c313590827 | ||
|
|
33862861a8 | ||
|
|
08c8f3871d | ||
|
|
42c97f6e80 | ||
|
|
c65665036d | ||
|
|
42c2651178 | ||
|
|
656597f120 | ||
|
|
090bf21e44 | ||
|
|
4dd6d27026 | ||
|
|
320f1ad0e5 |
9
CHANGELOG.md
Normal file
9
CHANGELOG.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## 0.2.0 (upcoming)
|
||||
|
||||
* renamed `numbered_gloss` to `numbered-gloss`, `gloss_count` to `gloss-count`, in light of the
|
||||
Typst style preference for kebab-case. Also renamed their arguments to use snake-case as well.
|
||||
* Documented standard abbreviations
|
||||
* Removed all default gloss line formatting
|
||||
@@ -9,8 +9,8 @@ generate a pdf file with examples and documentation. This command is also
|
||||
codified in the accompanying [justfile](https://github.com/casey/just) as `just
|
||||
build-example`.
|
||||
|
||||
The definitions intended for use by end users are the `#gloss` and
|
||||
`#numbered_gloss` functions.
|
||||
The definitions intended for use by end users are the `gloss` and
|
||||
`numbered-gloss` functions, and the `abbreviations` submodule.
|
||||
|
||||
|
||||
# Contributing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#import "linguistic-abbreviations.typ": *
|
||||
#import "abbreviations.typ": *
|
||||
|
||||
#let custom-abbreviations = (
|
||||
"FMNT": "Present/Future stem formant",
|
||||
@@ -7,7 +7,7 @@
|
||||
#let fmnt = emit-abbreviation("FMNT")
|
||||
|
||||
// An example function that uses `with-used-abbreviations`
|
||||
#let print_usage_chart = with-used-abbreviations.with(debug: false)(final-used-abbreviations => {
|
||||
#let print_usage_chart = with-used-abbreviations(final-used-abbreviations => {
|
||||
|
||||
show terms: t => {
|
||||
for t in t.children [
|
||||
|
||||
@@ -93,24 +93,15 @@
|
||||
|
||||
// Accepts a callback that accepts the state of the `used-abbreviations`
|
||||
// dictionary at the end of the document. Also an additional debug parameter
|
||||
#let with-used-abbreviations(callback, debug: false) = {
|
||||
#let with-used-abbreviations(callback) = {
|
||||
locate(loc => {
|
||||
let final_used-abbreviations = used-abbreviations.final(loc)
|
||||
|
||||
if debug {
|
||||
for (key, value) in final_used-abbreviations {
|
||||
[#key was used: #value]
|
||||
linebreak()
|
||||
}
|
||||
linebreak()
|
||||
}
|
||||
|
||||
callback(final_used-abbreviations)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
#let render-abbreviation(symbol) = smallcaps(lower(symbol))
|
||||
|
||||
// Public function. Given a symbol that is a string, emits
|
||||
// the lowercase version of that string in smallcaps format, and adds
|
||||
// its use to the `used-abbreviations` table
|
||||
@@ -123,7 +114,7 @@ locate(loc => {
|
||||
}
|
||||
|
||||
mark_used(symbol)
|
||||
smallcaps(lower(symbol))
|
||||
render-abbreviation(symbol)
|
||||
}
|
||||
|
||||
|
||||
373
documentation.typ
Normal file
373
documentation.typ
Normal file
@@ -0,0 +1,373 @@
|
||||
#set document(title: "typst leipzig-glossing documentation")
|
||||
#import "leipzig-gloss.typ": abbreviations, gloss, numbered-gloss, gloss-count
|
||||
|
||||
#show link: x => underline[*#x*]
|
||||
|
||||
#let codeblock-old(contents) = block(fill: luma(230), inset: 8pt, radius: 4pt, breakable: false, contents)
|
||||
|
||||
#let codeblock(contents, addl-bindings: (:), unevaled-first-line: none) = {
|
||||
let full-contents = if unevaled-first-line != none {
|
||||
unevaled-first-line + "\n" + contents
|
||||
} else {
|
||||
contents
|
||||
}
|
||||
|
||||
eval(contents, mode: "markup", scope: (gloss: gloss, numbered-gloss: numbered-gloss) + addl-bindings)
|
||||
block(fill: luma(230), inset: 8pt, radius: 4pt, breakable: false, raw(full-contents, lang: "typst"))
|
||||
}
|
||||
|
||||
// Abbreviations used in this document
|
||||
|
||||
#import abbreviations: poss, prog, sg, pl, sbj, obj, fut, neg, obl, gen, com, ins, all, pst, inf
|
||||
#import abbreviations: art, dat, du, A, P, prf
|
||||
|
||||
#let fmnt = abbreviations.emit-abbreviation("FMNT")
|
||||
|
||||
#align(center)[#text(17pt)[Typst `leipzig-glossing` Documentation]]
|
||||
|
||||
= Introduction
|
||||
|
||||
Interlinear morpheme-by-morpheme glosses are common in linguistic texts to give
|
||||
information about the meanings of individual words and morphemes in the
|
||||
language being studied. A set of conventions called the *Leipzig Glossing Rules*
|
||||
was developed to give linguists a general set of standards and principles for
|
||||
how to format these glosses. The most recent version of these rules can be
|
||||
found in PDF form at
|
||||
#link("https://www.eva.mpg.de/lingua/pdf/Glossing-Rules.pdf")[this link],
|
||||
provided by the Department of Linguistics at the Max Planck Institute for
|
||||
Evolutionary Anthropology.
|
||||
|
||||
There is a staggering variety of LaTex packages designed to properly align and
|
||||
format glosses (including `gb4e`, `ling-macros`, `linguex`, `expex`, and
|
||||
probably even more). These modules vary in the complexity of their syntax and
|
||||
the amount of control they give to the user of various aspects of formatting.
|
||||
The `typst-leipzig-glossing` module is designed to provide utilities for
|
||||
creating aligned Leipzig-style glosses in Typst, while keeping the syntax as
|
||||
intuitive as possible and allowing users as much control over how their glosses
|
||||
look as is feasible.
|
||||
|
||||
This PDF will show examples of the module's functionality and detail relevant
|
||||
parameters. For more information or to inform devs of a bug or other issue,
|
||||
visit the module's Github repository
|
||||
#link("https://github.com/neunenak/typst-leipzig-glossing")
|
||||
|
||||
#show raw: x => highlight(fill: luma(230), extent: 1pt)[#x]
|
||||
|
||||
= Basic glossing functionality
|
||||
|
||||
|
||||
As a first example, here is a gloss of a text in Georgian, along with the Typst code used to generate it:
|
||||
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
header: [from \"Georgian and the Unaccusative Hypothesis\", Alice Harris, 1982],
|
||||
source: ([ბავშვ-ი], [ატირდა]),
|
||||
transliteration: ([bavšv-i], [aṭirda]),
|
||||
morphemes: ([child-#smallcaps[nom]], [3S/cry/#smallcaps[incho]/II]),
|
||||
translation: [The child burst out crying],
|
||||
)", unevaled-first-line: "#import \"leipzig-gloss.typ\": gloss")
|
||||
|
||||
|
||||
And an example for English which exhibits some additional styling, and uses imports from another file
|
||||
for common glossing abbreviations:
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
source: ([I'm], [eat-ing], [your], [head]),
|
||||
source-style: (item) => text(fill: red)[#item],
|
||||
morphemes: ([1#sg.#sbj\=to.be], [eat-#prog], [2#sg.#poss], [head]),
|
||||
morphemes-style: text.with(size: 10pt, fill: blue),
|
||||
translation: text(weight: \"semibold\")[I'm eating your head!],
|
||||
translation-style: (item) => [\"#item\"],
|
||||
)
|
||||
", addl-bindings: (poss: poss, prog: prog, sg: sg, sbj: sbj))
|
||||
|
||||
|
||||
The `#gloss` function has three pre-defined parameters for glossing levels:
|
||||
`source`, `transliteration`, and `morphemes`. It also has two parameters
|
||||
for unaligned text: `header` for text that precedes the gloss, and
|
||||
`translation` for text that follows the gloss.
|
||||
|
||||
|
||||
The `morphemes` param can be skipped, if you just want to provide a source
|
||||
text and translation, without a gloss:
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
source: ([Trato de entender, debo comprender, qué es lo que ha hecho conmigo],),
|
||||
source-style: emph,
|
||||
translation: [I try to understand, I must comprehend, what she has done with me],
|
||||
)
|
||||
")
|
||||
|
||||
|
||||
Note that it is still necessary to wrap the `source` argument in an array of length one.
|
||||
|
||||
Here is an example of a lengthy gloss that forces a line break:
|
||||
|
||||
// adapted from https://brill.com/fileasset/downloads_static/static_publishingbooks_formatting_glosses_linguistic_examples.pdf
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
source: ([Ich],[arbeite],[ein],[Jahr],[um],[das],[Geld], [zu],[verdienen,],[das], [dein],[Bruder], [an],[einem],[Wochenende],[ausgibt.]),
|
||||
source-style: text.with(weight: \"bold\"),
|
||||
morphemes: ([I], [work],[ one], [year],[to],[the],[money],[to],[earn,], [that],[your],[brother],[on],[one], [weekend], [spends.]),
|
||||
translation: [\"I work one year to earn the money that your brother spends in one weekend\"]
|
||||
)", addl-bindings: (poss: poss, prog: prog, sg: sg, sbj: sbj))
|
||||
|
||||
|
||||
To add more than three glossing lines, there is an additional parameter
|
||||
`additional-lines` that can take a list of arbitrarily many more glossing
|
||||
lines, which will appear below those specified in the aforementioned
|
||||
parameters:
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
header: [Hunzib (van den Berg 1995:46)],
|
||||
source: ([ождиг],[хо#super[н]хе],[мукъер]),
|
||||
transliteration: ([oʒdig],[χõχe],[muqʼer]),
|
||||
morphemes: ([ož-di-g],[xõxe],[m-uq'e-r]),
|
||||
additional-lines: (
|
||||
([boy-#smallcaps[obl]-#smallcaps[ad]], [tree(#smallcaps[g4])], [#smallcaps[g4]-bend-#smallcaps[pret]]),
|
||||
([at boy], [tree], [bent]),
|
||||
),
|
||||
translation: [\"Because of the boy, the tree bent.\"]
|
||||
)
|
||||
")
|
||||
|
||||
//TODO add a custom numbering system that can handle example 18a-c of Kartvelian Morphosyntax and Number Agreement
|
||||
== Numbering Glosses
|
||||
|
||||
The `gloss` function takes a boolean parameter `numbering` which will add an incrementing
|
||||
count to each gloss. A function `numbered-gloss` is exported for convenience; this is
|
||||
defined as simply `#let numbered-gloss = gloss.with(numbering: true)`, and is called with the
|
||||
same arguments as `gloss`:
|
||||
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
source: ([გვ-ფრცქვნ-ი],),
|
||||
transliteration: ([gv-prtskvn-i],),
|
||||
morphemes: ([1#pl.#obj\-peel-#fmnt],),
|
||||
translation: \"You peeled us\",
|
||||
numbering: true,
|
||||
)
|
||||
|
||||
#numbered-gloss(
|
||||
source: ([მ-ფრცქვნ-ი],),
|
||||
transliteration: ([m-prtskvn-i],),
|
||||
morphemes: ([1#sg.#obj\-peel-#fmnt],),
|
||||
translation: \"You peeled me\",
|
||||
)
|
||||
|
||||
", addl-bindings: (pl: pl, obj: obj, sg: sg, fmnt: fmnt))
|
||||
|
||||
The displayed number for numbered glosses is iterated for each numbered gloss
|
||||
that appears throughout the document. Unnumbered glosses do not increment the
|
||||
counter for the numbered glosses.
|
||||
|
||||
The gloss count is controlled by the Typst counter variable `gloss-count`. This
|
||||
variable can be imported from the `leipzig-gloss` package and manipulated using the
|
||||
standard Typst counter functions to control gloss numbering:
|
||||
|
||||
#codeblock(
|
||||
"#gloss-count.update(20)
|
||||
|
||||
#numbered-gloss(
|
||||
header: [from _Standard Basque: A Progressive Grammar_ by Rudolf de Rijk, quoting P. Charriton],
|
||||
source: ([Bada beti guregan zorion handi baten nahia.],),
|
||||
translation: [There always is in us a will for a great happiness.],
|
||||
)", addl-bindings: (gloss-count: gloss-count))
|
||||
|
||||
|
||||
== Styling lines of a gloss
|
||||
|
||||
Each of the aforementioned text parameters has a corresponding style parameter,
|
||||
formed by adding `-style` to its name: `header-style`, `source-style`,
|
||||
`transliteration-style`, `morphemes-style`, and `translation-style`. These parameters
|
||||
allow you to specify formatting that should be applied to each entire line of
|
||||
the gloss. This is particularly useful for the aligned gloss itself, since
|
||||
otherwise one would have to modify each content item in the list individually.
|
||||
|
||||
In addition to these parameters, Typst’s usual content formatting can be applied
|
||||
to or within any given content block in the gloss. Formatting applied in this
|
||||
way will override any contradictory line-level formatting.
|
||||
|
||||
#codeblock(
|
||||
"#gloss(
|
||||
header: [This text is about eating your head.],
|
||||
header-style: text.with(weight: \"bold\", fill: green),
|
||||
source: (text(fill:black)[I'm], [eat-ing], [your], [head]),
|
||||
source-style: text.with(style: \"italic\", fill: red),
|
||||
morphemes: ([1#sg.#sbj\=to.be], text(fill:black)[eat-#prog], [2#sg.#poss], [head]),
|
||||
morphemes-style: text.with(fill: blue),
|
||||
translation: text(weight: \"bold\")[I'm eating your head!],
|
||||
)", addl-bindings: (prog: prog, sbj: sbj, poss: poss, sg: sg))
|
||||
|
||||
//TODO add `line_styles` param
|
||||
|
||||
= Standard Abbreviations
|
||||
|
||||
The Leipzig Glossing Rules define a commonly-used set of short abbreviations
|
||||
for grammatical terms used in glosses, such as #abbreviations.acc for
|
||||
"accusative (case)", or #abbreviations.ptcp for "participle" (see "Appendix:
|
||||
List of Standard Abbreviations in the Leipzig Glossing Rules document)
|
||||
|
||||
|
||||
By convention, these are typeset using #smallcaps[smallcaps]. This package
|
||||
contains a module value `abbreviations`. Individual abbreviations may be
|
||||
accessed either with Typst field access notation or by importing them from
|
||||
`abbreviations`:
|
||||
|
||||
|
||||
#codeblock(
|
||||
"#import abbreviations: obl, sg, prf
|
||||
|
||||
#gloss(
|
||||
header: [(from _Why Caucasian Languages?_, by Bernard Comrie, in _Endangered Languages of the Caucasus and Beyond_)],
|
||||
source: ([\[qálɐ-m], [∅-kw’-á\]], [ɬ’ə́-r]),
|
||||
morphemes: ([city-#obl], [3#sg\-go-#prf], [man-#abbreviations.abs]),
|
||||
translation: \"The man who went to the city.\"
|
||||
)", addl-bindings: (abbreviations: abbreviations), unevaled-first-line: "#import \"leipzig-gloss.typ\": abbreviations")
|
||||
|
||||
|
||||
The full list of abbreviations is as follows:
|
||||
|
||||
== Full list of abbreviations
|
||||
|
||||
#{
|
||||
for (abbreviation, description) in abbreviations.standard-abbreviations {
|
||||
[#abbreviations.render-abbreviation(abbreviation) - #raw(lower(abbreviation)) - #description ]
|
||||
linebreak()
|
||||
}
|
||||
}
|
||||
|
||||
== Custom abbreviations
|
||||
|
||||
Custom abbreviations may be defined using the `abbreviations.emit-abbreviation` function:
|
||||
|
||||
#codeblock(
|
||||
"#import abbreviations: obl, sg, prf, fut, emit-abbreviation
|
||||
|
||||
#let ts = emit-abbreviation(\"TS\")
|
||||
|
||||
#gloss(
|
||||
header: [(from _Georgian: A Structural Reference Grammar_, by George Hewitt)],
|
||||
source: ([g-nax-av-en],),
|
||||
morphemes: ([you#sub[2]-see(#fut)#sub[4]-#ts#sub[7]-they#sub[11]],),
|
||||
translation: \"they will see you\",
|
||||
)", addl-bindings: (abbreviations: abbreviations), unevaled-first-line: "#import \"leipzig-gloss.typ\": abbreviations")
|
||||
|
||||
== Building used-abbreviations pages
|
||||
|
||||
A user of `leipzig-glossing` might wish to generate an introductory page
|
||||
displaying which abbreviations were actually used in the document. The
|
||||
`abbreviations.with-used-abbreviations` function may be used for this purpose;
|
||||
see the `abbreviations-used-example.typ` file in `leipzig-glossing` source for an example.
|
||||
|
||||
= Further Example Glosses
|
||||
|
||||
These are the first twelve example glosses given in #link("https://www.eva.mpg.de/lingua/pdf/Glossing-Rules.pdf").
|
||||
along with the Typst markup needed to generate them:
|
||||
|
||||
#{
|
||||
gloss-count.update(0)
|
||||
}
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Indonesian (Sneddon 1996:237)],
|
||||
source: ([Mereka], [di], [Jakarta], [sekarang.]),
|
||||
morphemes: ([they], [in], [Jakarta], [now]),
|
||||
translation: \"They are in Jakarta now\",
|
||||
)")
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Lezgian (Haspelmath 1993:207)],
|
||||
source: ([Gila], [abur-u-n], [ferma], [hamišaluǧ], [güǧüna], [amuq’-da-č.]),
|
||||
morphemes: ([now], [they-#obl\-#gen], [farm], [forever], [behind], [stay-#fut\-#neg]),
|
||||
translation: \"Now their farm will not stay behind forever.\",
|
||||
)", addl-bindings: (fut: fut, neg: neg, obl: obl, gen:gen))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [West Greenlandic (Fortescue 1984:127)],
|
||||
source: ([palasi=lu], [niuirtur=lu]),
|
||||
morphemes: ([priest=and], [shopkeeper=and]),
|
||||
translation: \"both the priest and the shopkeeper\",
|
||||
)")
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Hakha Lai],
|
||||
source: ([a-nii -láay],),
|
||||
morphemes: ([3#sg\-laugh-#fut],),
|
||||
translation: [s/he will laugh],
|
||||
)", addl-bindings: (sg: sg, fut: fut))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Russian],
|
||||
source: ([My], [s], [Marko], [poexa-l-i], [avtobus-om], [v], [Peredelkino]),
|
||||
morphemes: ([1#pl], [#com], [Marko], [go-#pst\-#pl], [bus-#ins], [#all], [Peredelkino]),
|
||||
additional-lines: (([we], [with], [Marko], [go-#pst\-#pl], [bus-by], [to], [Peredelkino]),),
|
||||
translation: \"Marko and I went to Perdelkino by bus\",
|
||||
)", addl-bindings: (com: com, pl: pl, ins: ins, all: all, pst:pst))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Turkish],
|
||||
source: ([çık-mak],),
|
||||
morphemes: ([come.out-#inf],),
|
||||
translation: \"to come out\",
|
||||
)", addl-bindings: (inf: inf))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Latin],
|
||||
source: ([insul-arum],),
|
||||
morphemes: ([island-#gen\-#pl],),
|
||||
translation: \"of the islands\",
|
||||
)", addl-bindings: (gen:gen, pl: pl))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [French],
|
||||
source: ([aux], [chevaux]),
|
||||
morphemes: ([to-#art\-#pl],[horse.#pl]),
|
||||
translation: \"to the horses\",
|
||||
)",addl-bindings: (art:art, pl:pl))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [German],
|
||||
source: ([unser-n], [Väter-n]),
|
||||
morphemes: ([our-#dat\-#pl],[father.#pl\-#dat.#pl]),
|
||||
translation: \"to our fathers\",
|
||||
)", addl-bindings: (dat:dat, pl:pl))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Hittite (Lehmann 1982:211)],
|
||||
source: ([n=an], [apedani], [mehuni],[essandu.]),
|
||||
morphemes: ([#smallcaps[conn]=him], [that.#dat.#sg], [time.#dat.#sg], [eat.they.shall]),
|
||||
translation: \"They shall celebrate him on that date\",
|
||||
)", addl-bindings: (pl:pl, sg:sg, dat:dat))
|
||||
|
||||
#codeblock(
|
||||
"#numbered-gloss(
|
||||
header: [Jaminjung (Schultze-Berndt 2000:92)],
|
||||
source: ([nanggayan], [guny-bi-yarluga?]),
|
||||
morphemes: ([who], [2#du.#A.3#sg.#P\-#fut\-poke]),
|
||||
translation: \"Who do you two want to spear?\",
|
||||
)", addl-bindings: (du:du, sg:sg, fut:fut, A:A, P:P))
|
||||
|
||||
|
||||
#codeblock("
|
||||
#numbered-gloss(
|
||||
header: [Turkish (cf. 6)],
|
||||
source: ([çık-mak],),
|
||||
morphemes: ([come_out-#inf],),
|
||||
translation: ['to come out'],
|
||||
)", addl-bindings: (inf: inf))
|
||||
7
justfile
7
justfile
@@ -2,9 +2,10 @@ default:
|
||||
just --list
|
||||
|
||||
|
||||
build-example:
|
||||
typst compile leipzig-gloss-examples.typ
|
||||
|
||||
# Build the leipzig-glossing documentation PDF
|
||||
build-doc:
|
||||
typst compile documentation.typ
|
||||
|
||||
# Build the abbbreviations-used example
|
||||
build-abbreviations-example:
|
||||
typst compile abbreviations-used-example.typ
|
||||
|
||||
Binary file not shown.
@@ -1,282 +0,0 @@
|
||||
#import "leipzig-gloss.typ": gloss, numbered_gloss, gloss_count
|
||||
#import "linguistic-abbreviations.typ": *
|
||||
|
||||
#show link: x => underline[*#x*]
|
||||
//#show raw: x => text(fill: rgb("#43464b"))[#x]
|
||||
|
||||
#let codeblock(contents) = block(fill: luma(230), inset: 8pt, radius: 4pt, breakable: false, contents)
|
||||
|
||||
|
||||
= Introduction
|
||||
|
||||
Interlinear morpheme-by-morpheme glosses are common in linguistic texts to give
|
||||
information about the meanings of individual words and morphemes in the
|
||||
language being studied. A set of conventions called the *Leipzig Glossing Rules*
|
||||
was developed to give linguists a general set of standards and principles for
|
||||
how to format these glosses. The most recent version of these rules can be
|
||||
found in PDF form at
|
||||
#link("https://www.eva.mpg.de/lingua/pdf/Glossing-Rules.pdf")[this link],
|
||||
provided by the Department of Linguistics at the Max Planck Institute for
|
||||
Evolutionary Anthropology.
|
||||
|
||||
There is a staggering variety of LaTex packages designed to properly align and
|
||||
format glosses (including `gb4e`, `ling-macros`, `linguex`, `expex`, and
|
||||
probably even more). These modules vary in the complexity of their syntax and
|
||||
the amount of control they give to the user of various aspects of formatting.
|
||||
The `typst-leipzig-glossing` module is designed to provide utilities for
|
||||
creating aligned Leipzig-style glosses in Typst, while keeping the syntax as
|
||||
intuitive as possible and allowing users as much control over how their glosses
|
||||
look as is feasible.
|
||||
|
||||
This PDF will show examples of the module's functionality and detail relevant
|
||||
parameters. For more information or to inform devs of a bug or other issue,
|
||||
visit the module's Github repository
|
||||
#link("https://github.com/neunenak/typst-leipzig-glossing")[neunenak/typst-leipzig-glossing].
|
||||
|
||||
= Basic glossing functionality
|
||||
|
||||
|
||||
As a first example, here is a gloss of a text in Georgian, along with the Typst code used to generate it:
|
||||
|
||||
|
||||
#gloss(
|
||||
header_text: [from "Georgian and the Unaccusative Hypothesis", Alice Harris, 1982],
|
||||
source_text: ([ბავშვ-ი], [ატირდა]),
|
||||
transliteration: ([bavšv-i], [aṭirda]),
|
||||
morphemes: ([child-#smallcaps[nom]], [3S/cry/#smallcaps[incho]/II]),
|
||||
translation: [The child burst out crying],
|
||||
)
|
||||
|
||||
#codeblock[
|
||||
```typst
|
||||
#gloss(
|
||||
header_text: [from "Georgian and the Unaccusative Hypothesis", Alice Harris, 1982],
|
||||
source_text: ([ბავშვ-ი], [ატირდა]),
|
||||
transliteration: ([bavšv-i], [aṭirda]),
|
||||
morphemes: ([child-#smallcaps[nom]], [3S/cry/#smallcaps[incho]/II]),
|
||||
translation: [The child burst out crying],
|
||||
)
|
||||
```
|
||||
]
|
||||
|
||||
And an example for English which exhibits some additional styling, and uses imports from another file
|
||||
for common glossing abbreviations:
|
||||
|
||||
#gloss(
|
||||
source_text: ([I'm], [eat-ing], [your], [head]),
|
||||
source_text_style: (item) => text(fill: red)[#item],
|
||||
morphemes: ([1#sg.#sbj\=to.be], [eat-#prog], [2#sg.#poss], [head]),
|
||||
morphemes_style: text.with(fill: blue),
|
||||
translation: text(weight: "semibold")[I'm eating your head!],
|
||||
)
|
||||
|
||||
#codeblock[
|
||||
```typst
|
||||
#import "linguistic-abbreviations.typ": *
|
||||
|
||||
#gloss(
|
||||
source_text: ([I'm], [eat-ing], [your], [head]),
|
||||
source_text_style: (item) => text(fill: red)[#item],
|
||||
morphemes: ([1#sg.#subj\=to.be], [eat-#prog], [2#sg.#pos], [head]),
|
||||
morphemes_style: text.with(fill: blue),
|
||||
translation: text(weight: "semibold")[I'm eating your head!],
|
||||
)
|
||||
```
|
||||
]
|
||||
|
||||
|
||||
The `#gloss` function has three pre-defined parameters for glossing levels:
|
||||
`source_text`, `transliteration`, and `morphemes`. It also has two parameters
|
||||
for unaligned text: `header_text` for text that precedes the gloss, and
|
||||
`translation` for text that follows the gloss.
|
||||
|
||||
If one wishes to add more than three glossing lines, there is an additional
|
||||
parameter `additional_gloss_lines` that can take a list of arbitrarily many more glossing
|
||||
lines, which will appear below those specified in the aforementioned
|
||||
parameters:
|
||||
|
||||
#gloss(
|
||||
header_text: [Hunzib (van den Berg 1995:46)],
|
||||
source_text: ([ождиг],[хо#super[н]хе],[мукъер]),
|
||||
transliteration: ([oʒdig],[χõχe],[muqʼer]),
|
||||
morphemes: ([ož-di-g],[xõxe],[m-uq'e-r]),
|
||||
additional_gloss_lines: (
|
||||
([boy-#smallcaps[obl]-#smallcaps[ad]], [tree(#smallcaps[g4])], [#smallcaps[g4]-bend-#smallcaps[pret]]),
|
||||
([at boy], [tree], [bent]),
|
||||
),
|
||||
translation: ["Because of the boy, the tree bent."]
|
||||
)
|
||||
|
||||
#codeblock[
|
||||
```typst
|
||||
#gloss(
|
||||
header_text: [Hunzib (van den Berg 1995:46)],
|
||||
source_text: ([ождиг],[хо#super[н]хе],[мукъер]),
|
||||
transliteration: ([oʒdig],[χõχe],[muqʼer]),
|
||||
morphemes: ([ož-di-g],[xõxe],[m-uq'e-r]),
|
||||
additional_gloss_lines: (
|
||||
([boy-#smallcaps[obl]-#smallcaps[ad]], [tree(#smallcaps[g4])], [#smallcaps[g4]-bend-#smallcaps[pret]]),
|
||||
([at boy], [tree], [bent]),
|
||||
),
|
||||
translation: ["Because of the boy, the tree bent."]
|
||||
)
|
||||
```
|
||||
]
|
||||
|
||||
To number gloss examples, use `#numbered_gloss` in place of `gloss`. All other parameters remain the same.
|
||||
|
||||
#numbered_gloss(
|
||||
source_text: ([გვ-ფრცქვნ-ი],),
|
||||
source_text_style: none,
|
||||
transliteration: ([gv-prtskvn-i],),
|
||||
morphemes: ([1#pl.#obj\-peel-#fmnt],),
|
||||
translation: "You peeled us",
|
||||
)
|
||||
|
||||
#codeblock[
|
||||
```typst
|
||||
#import "linguistic-abbreviations.typ": *
|
||||
|
||||
#gloss(
|
||||
source_text: ([გვ-ფრცქვნ-ი],),
|
||||
source_text_style: none,
|
||||
transliteration: ([gv-prtskvn-i],),
|
||||
morphemes: ([1#pl.#obj\-peel-#fmnt],),
|
||||
translation: "You peeled us",
|
||||
```)]
|
||||
|
||||
The displayed number for numbered glosses is iterated for each numbered gloss
|
||||
that appears throughout the document. Unnumbered glosses do not increment the
|
||||
counter for the numbered glosses.
|
||||
|
||||
The gloss count is controlled by the Typst counter variable `gloss_count`. This
|
||||
variable can be imported from the `leipzig-gloss` package and reset using the
|
||||
standard Typst counter functions to control gloss numbering.
|
||||
|
||||
//TODO add examples here
|
||||
|
||||
|
||||
== Styling lines of a gloss
|
||||
|
||||
Each of the aforementioned text parameters has a corresponding style parameter,
|
||||
formed by adding `_style` to its name: `header_text_style`, `source_text_style`,
|
||||
`transliteration_style`, `morphemes_style`, and `translation_style`. These parameters
|
||||
allow you to specify formatting that should be applied to each entire line of
|
||||
the gloss. This is particularly useful for the aligned gloss itself, since
|
||||
otherwise one would have to modify each content item in the list individually.
|
||||
|
||||
In addition to these parameters, Typst’s usual content formatting can be applied
|
||||
to or within any given content block in the gloss. Formatting applied in this
|
||||
way will override any contradictory line-level formatting.
|
||||
|
||||
#gloss(
|
||||
header_text: [This text is about eating your head.],
|
||||
header_text_style: text.with(weight: "bold", fill: green),
|
||||
source_text: (text(fill:black)[I'm], [eat-ing], [your], [head]),
|
||||
source_text_style: text.with(style: "italic", fill: red),
|
||||
morphemes: ([1#sg.#sbj\=to.be], text(fill:black)[eat-#prog], [2#sg.#poss], [head]),
|
||||
morphemes_style: text.with(fill: blue),
|
||||
translation: text(weight: "bold")[I'm eating your head!],
|
||||
)
|
||||
#codeblock[
|
||||
```typst
|
||||
#gloss(
|
||||
header_text: [This text is about eating your head.],
|
||||
header_text_style: text.with(weight: "bold", fill: green),
|
||||
source_text: (text(fill:black)[I'm], [eat-ing], [your], [head]),
|
||||
source_text_style: text.with(style: "italic", fill: red),
|
||||
morphemes: ([1#sg.#sbj\=to.be], text(fill:black)[eat-#prog], [2#sg.#poss], [head]),
|
||||
morphemes_style: text.with(fill: blue),
|
||||
translation: text(weight: "bold")[I'm eating your head!],
|
||||
)
|
||||
```
|
||||
]
|
||||
//TODO add `line_styles` param
|
||||
|
||||
|
||||
== Further Example Glosses
|
||||
|
||||
These example glosses replicate the ones given in
|
||||
#link("https://www.eva.mpg.de/lingua/pdf/Glossing-Rules.pdf").
|
||||
|
||||
#{
|
||||
gloss_count.update(0)
|
||||
}
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Indonesian (Sneddon 1996:237)],
|
||||
source_text: ([Mereka], [di], [Jakarta], [sekarang.]),
|
||||
morphemes: ([they], [in], [Jakarta], [now]),
|
||||
translation: "They are in Jakarta now",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Lezgian (Haspelmath 1993:207)],
|
||||
source_text: ([Gila], [abur-u-n], [ferma], [hamišaluǧ], [güǧüna], [amuq’-da-č.]),
|
||||
morphemes: ([now], [they-#obl\-#gen], [farm], [forever], [behind], [stay-#fut\-#neg]),
|
||||
translation: "Now their farm will not stay behind forever.",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [West Greenlandic (Fortescue 1984:127)],
|
||||
source_text: ([palasi=lu], [niuirtur=lu]),
|
||||
morphemes: ([priest=and], [shopkeeper=and]),
|
||||
translation: "both the priest and the shopkeeper",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Hakha Lai],
|
||||
source_text: ([a-nii -láay],),
|
||||
morphemes: ([3#sg\-laugh-#fut],),
|
||||
translation: [s/he will laugh],
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Russian],
|
||||
source_text: ([My], [s], [Marko], [poexa-l-i], [avtobus-om], [v], [Peredelkino]),
|
||||
morphemes: ([1#pl], [#com], [Marko], [go-#pst\-#pl], [bus-#ins], [#all], [Peredelkino]),
|
||||
additional_gloss_lines: (([we], [with], [Marko], [go-#pst\-#pl], [bus-by], [to], [Peredelkino]),),
|
||||
translation: "Marko and I went to Perdelkino by bus",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Turkish],
|
||||
source_text: ([çık-mak],),
|
||||
morphemes: ([come.out-#inf],),
|
||||
translation: "to come out",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Latin],
|
||||
source_text: ([insul-arum],),
|
||||
morphemes: ([island-#gen\-#pl],),
|
||||
translation: "of the islands",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [French],
|
||||
source_text: ([aux], [chevaux]),
|
||||
morphemes: ([to-#art\-#pl],[horse.#pl]),
|
||||
translation: "to the horses",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [German],
|
||||
source_text: ([unser-n], [Väter-n]),
|
||||
morphemes: ([our-#dat\-#pl],[father.#pl\-#dat.#pl]),
|
||||
translation: "to our fathers",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Hittite (Lehmann 1982:211)],
|
||||
source_text: ([n=an], [apedani], [mehuni],[essandu.]),
|
||||
morphemes: ([#smallcaps[conn]=him], [that.#dat.#sg], [time.#dat.#sg], [eat.they.shall]),
|
||||
translation: "They shall celebrate him on that date",
|
||||
)
|
||||
|
||||
#numbered_gloss(
|
||||
header_text: [Jaminjung (Schultze-Berndt 2000:92)],
|
||||
source_text: ([nanggayan], [guny-bi-yarluga?]),
|
||||
morphemes: ([who], [2#du.#A.3#sg.#P\-#fut\-poke]),
|
||||
translation: "Who do you two want to spear?",
|
||||
)
|
||||
@@ -1,6 +1,8 @@
|
||||
#let gloss_count = counter("gloss_count")
|
||||
#import "abbreviations.typ"
|
||||
|
||||
#let build_gloss(spacing_between_items, formatters, gloss_line_lists) = {
|
||||
#let gloss-count = counter("gloss_count")
|
||||
|
||||
#let build_gloss(item-spacing, formatters, gloss_line_lists) = {
|
||||
assert(gloss_line_lists.len() > 0, message: "Gloss line lists cannot be empty")
|
||||
|
||||
let len = gloss_line_lists.at(0).len()
|
||||
@@ -28,86 +30,91 @@
|
||||
args.push(formatter_fn(item))
|
||||
}
|
||||
make_item_box(..args)
|
||||
h(spacing_between_items)
|
||||
h(item-spacing)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#let gloss(
|
||||
header_text: none,
|
||||
header_text_style: none,
|
||||
source_text: (),
|
||||
source_text_style: emph,
|
||||
header: none,
|
||||
header-style: none,
|
||||
source: (),
|
||||
source-style: none,
|
||||
transliteration: none,
|
||||
transliteration_style: none,
|
||||
morphemes: (),
|
||||
morphemes_style: none,
|
||||
additional_gloss_lines: (), //List of list of content
|
||||
transliteration-style: none,
|
||||
morphemes: none,
|
||||
morphemes-style: none,
|
||||
additional-lines: (), //List of list of content
|
||||
translation: none,
|
||||
translation_style: none,
|
||||
spacing_between_items: 1em,
|
||||
gloss_padding: 2.0em, //TODO document these
|
||||
translation-style: none,
|
||||
|
||||
item-spacing: 1em,
|
||||
gloss-padding: 2.0em, //TODO document these
|
||||
left_padding: 0.5em,
|
||||
numbering: false,
|
||||
breakable: false,
|
||||
) = {
|
||||
|
||||
assert(type(source_text) == "array", message: "source_text needs to be an array; perhaps you forgot to type `(` and `)`, or a trailing comma?")
|
||||
assert(type(morphemes) == "array", message: "morphemes needs to be an array; perhaps you forgot to type `(` and `)`, or a trailing comma?")
|
||||
assert(type(source) == "array", message: "source needs to be an array; perhaps you forgot to type `(` and `)`, or a trailing comma?")
|
||||
|
||||
assert(source_text.len() == morphemes.len(), message: "source_text and morphemes have different lengths")
|
||||
if morphemes != none {
|
||||
assert(type(morphemes) == "array", message: "morphemes needs to be an array; perhaps you forgot to type `(` and `)`, or a trailing comma?")
|
||||
assert(source.len() == morphemes.len(), message: "source and morphemes have different lengths")
|
||||
}
|
||||
|
||||
if transliteration != none {
|
||||
assert(transliteration.len() == source_text.len(), message: "source_text and transliteration have different lengths")
|
||||
assert(transliteration.len() == source.len(), message: "source and transliteration have different lengths")
|
||||
}
|
||||
|
||||
let gloss_items = {
|
||||
|
||||
if header_text != none {
|
||||
if header_text_style != none {
|
||||
header_text_style(header_text)
|
||||
if header != none {
|
||||
if header-style != none {
|
||||
header-style(header)
|
||||
} else {
|
||||
header_text
|
||||
header
|
||||
}
|
||||
linebreak()
|
||||
}
|
||||
|
||||
let formatters = (source_text_style,)
|
||||
let gloss_line_lists = (source_text,)
|
||||
let formatters = (source-style,)
|
||||
let gloss_line_lists = (source,)
|
||||
|
||||
if transliteration != none {
|
||||
formatters.push(transliteration_style)
|
||||
formatters.push(transliteration-style)
|
||||
gloss_line_lists.push(transliteration)
|
||||
}
|
||||
|
||||
formatters.push(morphemes_style)
|
||||
gloss_line_lists.push(morphemes)
|
||||
if morphemes != none {
|
||||
formatters.push(morphemes-style)
|
||||
gloss_line_lists.push(morphemes)
|
||||
}
|
||||
|
||||
for additional in additional_gloss_lines {
|
||||
for additional in additional-lines {
|
||||
formatters.push(none) //TODO fix this
|
||||
gloss_line_lists.push(additional)
|
||||
}
|
||||
|
||||
|
||||
build_gloss(spacing_between_items, formatters, gloss_line_lists)
|
||||
build_gloss(item-spacing, formatters, gloss_line_lists)
|
||||
|
||||
if translation != none {
|
||||
linebreak()
|
||||
|
||||
if translation_style == none {
|
||||
["#translation"]
|
||||
if translation-style == none {
|
||||
translation
|
||||
} else {
|
||||
translation_style(translation)
|
||||
translation-style(translation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if numbering {
|
||||
gloss_count.step()
|
||||
gloss-count.step()
|
||||
}
|
||||
|
||||
let gloss_number = if numbering {
|
||||
[(#gloss_count.display())]
|
||||
[(#gloss-count.display())]
|
||||
} else {
|
||||
none
|
||||
}
|
||||
@@ -118,7 +125,7 @@
|
||||
dir:ltr, //TODO this needs to be more flexible
|
||||
left_padding,
|
||||
[#gloss_number],
|
||||
gloss_padding - left_padding - measure([#gloss_number],styles).width,
|
||||
gloss-padding - left_padding - measure([#gloss_number],styles).width,
|
||||
[#gloss_items]
|
||||
)
|
||||
]
|
||||
@@ -126,4 +133,4 @@
|
||||
)
|
||||
}
|
||||
|
||||
#let numbered_gloss = gloss.with(numbering: true)
|
||||
#let numbered-gloss = gloss.with(numbering: true)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leipzig-glossing"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
entrypoint = "leipzig-gloss.typ"
|
||||
authors = ["Greg Shuflin", "Other open-source contributors"]
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user