@heroiclands/package-build 23.12.8 → 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/README.md +3 -2
- package/assets/preview/gitea.ini +12 -7
- package/assets/styles/content-base.css +293 -24
- package/bin/content-commands.mjs +370 -213
- package/bin/package-build-preview.mjs +2 -2
- package/bin/package-build.mjs +3 -2
- package/ci/check-banners.mjs +7 -7
- package/config.mjs +21 -6
- package/content-config.mjs +199 -80
- package/docs/api.md +110 -89
- package/docs/authoring/links-and-markup.md +469 -97
- package/docs/commands.md +259 -78
- package/docs/configuration.md +211 -103
- package/docs/content-format.md +4 -4
- package/docs/diagnostics.md +44 -2
- package/docs/getting-started.md +1 -1
- package/docs/guides/icons.md +1 -1
- package/docs/guides/module-project.md +5 -8
- package/docs/guides/release-and-deploy.md +2 -2
- package/docs/guides/site.md +112 -23
- package/docs/guides/system-project.md +1 -1
- package/docs/guides/writing-in-invented-scripts.md +1247 -0
- package/docs/index.md +1 -0
- package/docs/project-setup.md +28 -30
- package/docs/reference/format-details.md +677 -319
- package/docs/reference/note-types.md +47 -10
- package/docs/reference/theme-pages.md +178 -108
- package/docs/source-preview.md +16 -2
- package/engine/anchors.mjs +2 -2
- package/engine/asset-shipping.mjs +22 -10
- package/engine/base-compiler.mjs +62 -104
- package/engine/changelog-lint.mjs +1 -1
- package/engine/code-fences.mjs +3 -3
- package/engine/content-address.mjs +1 -1
- package/engine/content-alerts.mjs +8 -4
- package/engine/content-blocks.mjs +29 -14
- package/engine/content-embeds.mjs +1 -1
- package/engine/content-expand.mjs +376 -0
- package/engine/content-figures.mjs +18 -11
- package/engine/content-format.yaml +8 -0
- package/engine/content-glyphs.mjs +213 -0
- package/engine/content-images.mjs +6 -7
- package/engine/content-index.mjs +1 -1
- package/engine/content-links.mjs +3 -3
- package/engine/content-lint.mjs +1 -1
- package/engine/content-render.mjs +453 -0
- package/engine/content-scripts.mjs +376 -43
- package/engine/content-spans.mjs +6 -3
- package/engine/content-styles.mjs +91 -0
- package/engine/content-symbols.mjs +186 -0
- package/engine/content-verse.mjs +738 -0
- package/engine/core-report.mjs +169 -0
- package/engine/core-vocabulary.mjs +208 -0
- package/engine/dictionary-html.mjs +119 -0
- package/engine/dictionary-rows.mjs +15 -4
- package/engine/field-reference.mjs +5 -5
- package/engine/first-use.mjs +17 -27
- package/engine/frontmatter-lint.mjs +1 -1
- package/engine/heading-attributes.mjs +89 -0
- package/engine/helpers.mjs +61 -101
- package/engine/homepage.mjs +17 -29
- package/engine/html-minify.mjs +70 -0
- package/engine/index.mjs +8 -5
- package/engine/key-case-collisions.mjs +136 -0
- package/engine/language-data.mjs +203 -6
- package/engine/language-rows.mjs +8 -2
- package/engine/language-terms.mjs +186 -16
- package/engine/language-words.mjs +12 -0
- package/engine/logographic.mjs +255 -0
- package/engine/map-lexicon.mjs +262 -47
- package/engine/map-places.mjs +5 -4
- package/engine/markdown-expressions.mjs +0 -2
- package/engine/markdownlint-run.mjs +9 -3
- package/engine/markup-validation.mjs +21 -0
- package/engine/metre-declaration.mjs +134 -0
- package/engine/names.mjs +36 -9
- package/engine/note-matter.mjs +66 -0
- package/engine/note-vocabulary.mjs +187 -3
- package/engine/pdf-build.mjs +69 -133
- package/engine/pdf-render.mjs +205 -58
- package/engine/post-fields.mjs +157 -0
- package/engine/preview-index.mjs +130 -0
- package/engine/preview-source.mjs +450 -0
- package/engine/project-init.mjs +5 -12
- package/engine/prose-config.mjs +3 -3
- package/engine/read-stdin.mjs +29 -0
- package/engine/run-rows.mjs +2 -2
- package/engine/run-words.mjs +6 -112
- package/engine/script-emphasis-terms.mjs +38 -0
- package/engine/script-emphasis.mjs +295 -0
- package/engine/script-font-delivery.mjs +4 -4
- package/engine/site-build.mjs +260 -315
- package/engine/site-config.mjs +26 -238
- package/engine/site-files.mjs +175 -0
- package/engine/site-index.mjs +9 -4
- package/engine/site-preview.mjs +52 -525
- package/engine/site-render.mjs +593 -0
- package/engine/site-root.mjs +22 -13
- package/engine/site-search.mjs +161 -0
- package/engine/site-serve.mjs +273 -0
- package/engine/site-theme-banner.mjs +154 -0
- package/engine/site-theme-urls.mjs +125 -0
- package/engine/site-theme.mjs +926 -0
- package/engine/sql-tables.mjs +20 -3
- package/engine/text-maps.mjs +57 -10
- package/engine/typographer.mjs +248 -0
- package/engine/verse-metre.mjs +357 -0
- package/engine/wikilink-syntax.mjs +29 -47
- package/engine/wikilinks.mjs +758 -279
- package/engine/word-forms.mjs +364 -0
- package/engine/word-rows.mjs +12 -2
- package/engine/word-terms.mjs +38 -4
- package/manifest.mjs +3 -4
- package/package.json +11 -8
- package/{hugo-theme → site-theme}/data/banners.yaml +6 -10
- package/site-theme/layouts/base.hbs +31 -0
- package/site-theme/layouts/blog-list.hbs +30 -0
- package/site-theme/layouts/blog-post.hbs +40 -0
- package/site-theme/layouts/home.hbs +35 -0
- package/site-theme/layouts/list.hbs +20 -0
- package/site-theme/layouts/not-found.hbs +31 -0
- package/site-theme/layouts/page.hbs +7 -0
- package/site-theme/partials/copy-buttons.hbs +37 -0
- package/site-theme/partials/draft-notice.hbs +5 -0
- package/site-theme/partials/exturl.hbs +2 -0
- package/{hugo-theme/layouts/partials/footer.html → site-theme/partials/footer.hbs} +10 -7
- package/site-theme/partials/header.hbs +44 -0
- package/site-theme/partials/hero-banner.hbs +11 -0
- package/site-theme/partials/infobox-entry.hbs +2 -0
- package/site-theme/partials/infobox-section.hbs +31 -0
- package/site-theme/partials/infobox-value.hbs +2 -0
- package/site-theme/partials/infobox.hbs +18 -0
- package/site-theme/partials/list-members.hbs +9 -0
- package/site-theme/partials/nav-links.hbs +5 -0
- package/site-theme/partials/page-body.hbs +48 -0
- package/site-theme/partials/page-list.hbs +14 -0
- package/site-theme/partials/related.hbs +24 -0
- package/site-theme/partials/search-meta.hbs +6 -0
- package/site-theme/partials/search-names.hbs +2 -0
- package/site-theme/partials/search.hbs +52 -0
- package/site-theme/partials/tags.hbs +4 -0
- package/site-theme/partials/toc.hbs +7 -0
- package/{hugo-theme → site-theme}/static/css/style.css +106 -14
- package/stage.mjs +1 -2
- package/types/config.d.mts +8 -4
- package/types/content-config.d.mts +15 -15
- package/types/engine/asset-shipping.d.mts +5 -2
- package/types/engine/base-compiler.d.mts +20 -2
- package/types/engine/code-fences.d.mts +3 -3
- package/types/engine/content-address.d.mts +1 -1
- package/types/engine/content-alerts.d.mts +8 -2
- package/types/engine/content-blocks.d.mts +11 -4
- package/types/engine/content-expand.d.mts +288 -0
- package/types/engine/content-figures.d.mts +11 -3
- package/types/engine/content-glyphs.d.mts +85 -0
- package/types/engine/content-images.d.mts +6 -7
- package/types/engine/content-links.d.mts +1 -1
- package/types/engine/content-render.d.mts +199 -0
- package/types/engine/content-scripts.d.mts +70 -4
- package/types/engine/content-spans.d.mts +1 -1
- package/types/engine/content-styles.d.mts +33 -0
- package/types/engine/content-symbols.d.mts +35 -0
- package/types/engine/content-verse.d.mts +240 -0
- package/types/engine/core-report.d.mts +45 -0
- package/types/engine/core-vocabulary.d.mts +53 -0
- package/types/engine/dictionary-html.d.mts +8 -0
- package/types/engine/dictionary-rows.d.mts +10 -0
- package/types/engine/field-reference.d.mts +2 -2
- package/types/engine/heading-attributes.d.mts +20 -0
- package/types/engine/helpers.d.mts +3 -10
- package/types/engine/homepage.d.mts +11 -24
- package/types/engine/html-minify.d.mts +9 -0
- package/types/engine/index.d.mts +2 -1
- package/types/engine/key-case-collisions.d.mts +28 -0
- package/types/engine/language-data.d.mts +0 -2
- package/types/engine/language-terms.d.mts +24 -2
- package/types/engine/logographic.d.mts +45 -0
- package/types/engine/map-lexicon.d.mts +66 -13
- package/types/engine/map-places.d.mts +8 -0
- package/types/engine/markdown-expressions.d.mts +0 -2
- package/types/engine/metre-declaration.d.mts +39 -0
- package/types/engine/names.d.mts +34 -3
- package/types/engine/note-matter.d.mts +48 -0
- package/types/engine/pdf-render.d.mts +6 -2
- package/types/engine/post-fields.d.mts +44 -0
- package/types/engine/preview-index.d.mts +72 -0
- package/types/engine/preview-source.d.mts +51 -0
- package/types/engine/read-stdin.d.mts +11 -0
- package/types/engine/run-rows.d.mts +2 -2
- package/types/engine/run-words.d.mts +0 -15
- package/types/engine/script-emphasis-terms.d.mts +21 -0
- package/types/engine/script-emphasis.d.mts +84 -0
- package/types/engine/script-font-delivery.d.mts +4 -4
- package/types/engine/site-build.d.mts +71 -113
- package/types/engine/site-config.d.mts +14 -134
- package/types/engine/site-files.d.mts +73 -0
- package/types/engine/site-index.d.mts +11 -3
- package/types/engine/site-preview.d.mts +15 -19
- package/types/engine/site-render.d.mts +171 -0
- package/types/engine/site-root.d.mts +12 -4
- package/types/engine/site-search.d.mts +54 -0
- package/types/engine/site-serve.d.mts +44 -0
- package/types/engine/site-theme-banner.d.mts +51 -0
- package/types/engine/site-theme-urls.d.mts +60 -0
- package/types/engine/site-theme.d.mts +127 -0
- package/types/engine/sql-tables.d.mts +4 -1
- package/types/engine/text-maps.d.mts +17 -3
- package/types/engine/typographer.d.mts +11 -0
- package/types/engine/verse-metre.d.mts +131 -0
- package/types/engine/wikilink-syntax.d.mts +30 -48
- package/types/engine/wikilinks.d.mts +330 -14
- package/types/engine/word-forms.d.mts +83 -0
- package/types/manifest.d.mts +3 -4
- package/types/stage.d.mts +1 -2
- package/types/vendor/markdownlint.d.mts +8 -0
- package/vendor/markdownlint.mjs +20388 -0
- package/engine/content-poetry.mjs +0 -240
- package/engine/web-wikilinks.mjs +0 -594
- package/hugo-theme/layouts/404.html +0 -85
- package/hugo-theme/layouts/_default/baseof.html +0 -67
- package/hugo-theme/layouts/_default/list.html +0 -139
- package/hugo-theme/layouts/_default/single.html +0 -4
- package/hugo-theme/layouts/blog/list.html +0 -54
- package/hugo-theme/layouts/blog-post/single.html +0 -36
- package/hugo-theme/layouts/index.html +0 -75
- package/hugo-theme/layouts/partials/banner-url.html +0 -141
- package/hugo-theme/layouts/partials/cdn-url.html +0 -36
- package/hugo-theme/layouts/partials/dictionary-lists.html +0 -58
- package/hugo-theme/layouts/partials/draft-notice.html +0 -41
- package/hugo-theme/layouts/partials/draft-state.html +0 -26
- package/hugo-theme/layouts/partials/header.html +0 -35
- package/hugo-theme/layouts/partials/hero-banner.html +0 -85
- package/hugo-theme/layouts/partials/infobox/entry.html +0 -18
- package/hugo-theme/layouts/partials/infobox/items.html +0 -26
- package/hugo-theme/layouts/partials/infobox/section.html +0 -56
- package/hugo-theme/layouts/partials/infobox/value.html +0 -43
- package/hugo-theme/layouts/partials/infobox.html +0 -57
- package/hugo-theme/layouts/partials/page-body.html +0 -152
- package/hugo-theme/layouts/partials/related.html +0 -138
- package/hugo-theme/layouts/partials/search.html +0 -84
- package/hugo-theme/layouts/partials/site-url.html +0 -32
- package/hugo-theme/layouts/partials/tags.html +0 -30
- package/hugo-theme/layouts/partials/toc.html +0 -28
- package/hugo-theme/layouts/partials/warn-missing-banner.html +0 -3
- package/hugo-theme/layouts/shortcodes/cartouche.html +0 -64
- package/hugo-theme/layouts/shortcodes/exturl.html +0 -12
- package/hugo-theme/layouts/shortcodes/glyph.html +0 -43
- package/hugo-theme/layouts/shortcodes/pagelist.html +0 -63
- package/hugo-theme/theme.toml +0 -11
- package/types/engine/content-poetry.d.mts +0 -58
- package/types/engine/web-wikilinks.d.mts +0 -107
- /package/{hugo-theme → site-theme}/data/banner-kinds.yaml +0 -0
- /package/{hugo-theme → site-theme}/static/css/sohl-icons.css +0 -0
- /package/{hugo-theme → site-theme}/static/fonts/game-icons-kb.woff2 +0 -0
- /package/{hugo-theme → site-theme}/static/img/banners/takheperu-hieroglyphs.svg +0 -0
- /package/{hugo-theme → site-theme}/static/img/cartouches/takheperu.svg +0 -0
- /package/{hugo-theme → site-theme}/static/js/inline-spoilers.js +0 -0
|
@@ -0,0 +1,1247 @@
|
|
|
1
|
+
---
|
|
2
|
+
shortcode: guidesinventedscripts
|
|
3
|
+
name: { full: "Write in invented languages and scripts" }
|
|
4
|
+
type: doc
|
|
5
|
+
subType: howto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Write in invented languages and scripts
|
|
9
|
+
|
|
10
|
+
A setting with invented languages needs three things from its notes: text that
|
|
11
|
+
reads as the language, text that is drawn in the language's own letters, and a
|
|
12
|
+
way to keep both honest. This guide explains how the toolchain does that, from
|
|
13
|
+
the model underneath to every finding it can report, for human authors and for
|
|
14
|
+
agents. The reference pages state each rule exactly: [links and
|
|
15
|
+
markup](../authoring/links-and-markup.md#marking-language-font-and-mapping),
|
|
16
|
+
[format details](../reference/format-details.md#text-marked-with-a-language-a-font-or-a-map),
|
|
17
|
+
[commands](../commands.md#package-build-transliterate-map-text),
|
|
18
|
+
[configuration](../configuration.md#languages) and
|
|
19
|
+
[diagnostics](../diagnostics.md). This guide ties them into one account and
|
|
20
|
+
works one example through from start to finish.
|
|
21
|
+
|
|
22
|
+
The examples write Vylari, a tongue spelled in roman letters and drawn in the
|
|
23
|
+
Semaron script. The lexicon and the notes in them are the guide's own sample.
|
|
24
|
+
|
|
25
|
+
## The model
|
|
26
|
+
|
|
27
|
+
These ideas carry everything else.
|
|
28
|
+
|
|
29
|
+
1. **A note records Unicode characters, and nothing else.** Which keyboard
|
|
30
|
+
typed them is the author's business. The markdown and the build neither
|
|
31
|
+
know nor care.
|
|
32
|
+
2. **A font draws glyphs for code points.** A code point a font lacks draws a
|
|
33
|
+
box, so the build refuses it before a box reaches a reader. A font states no
|
|
34
|
+
sounds and no spelling, just as a Unicode block chart states none.
|
|
35
|
+
3. **Each script has code points of its own,** as Runic and Ogham have their
|
|
36
|
+
own Unicode blocks. Semaron's `a` is not U+0061. Every face of one script
|
|
37
|
+
draws the same code points, so changing the face changes only the look. The
|
|
38
|
+
left-to-right scripts sit in plane 15, the Supplementary Private Use Area-A
|
|
39
|
+
(Semaron from U+F0200). The right-to-left scripts sit in unassigned code
|
|
40
|
+
points of plane 1 whose default direction is right to left, so their text
|
|
41
|
+
runs right to left in any editor, browser or typesetter with no control
|
|
42
|
+
characters.
|
|
43
|
+
4. **Sounds and spelling belong to the language.** A script is not a language:
|
|
44
|
+
several languages are written in one script, as many Earth languages share
|
|
45
|
+
the Latin alphabet. A mapping therefore belongs to a script and serves every
|
|
46
|
+
language written in it. What differs between languages is their dictionaries.
|
|
47
|
+
5. **Three optional keys mark text:** `lang=` says what language it is, `font=`
|
|
48
|
+
says how it is drawn, and `map=` names the mapping that rewrites it into the
|
|
49
|
+
script's code points. They are independent.
|
|
50
|
+
6. **Without `map=`, the characters reach the page exactly as written.**
|
|
51
|
+
Nothing is checked against a language.
|
|
52
|
+
7. **With `map=`, the build converts, and with `lang=` as well it checks.**
|
|
53
|
+
Each word is looked up in the language's dictionary first; a word the
|
|
54
|
+
dictionary does not write is spelled by the mapping's rows. A mapped run
|
|
55
|
+
with `lang=` must then consist of words of that language.
|
|
56
|
+
|
|
57
|
+
A script that writes meanings rather than sounds is **logographic**. It has no
|
|
58
|
+
sound rules, so every word is written from the dictionary and never guessed;
|
|
59
|
+
see [logographic scripts](#logographic-scripts).
|
|
60
|
+
|
|
61
|
+
One code path serves the build and its users. `package-build transliterate`
|
|
62
|
+
converts a passage exactly as the build does, and `package-build lexicon` lists
|
|
63
|
+
every word of a language with its native form; see
|
|
64
|
+
[the commands](#the-commands).
|
|
65
|
+
|
|
66
|
+
The pipeline for one marked run reads left to right:
|
|
67
|
+
|
|
68
|
+
| Stage | Reads | Reports |
|
|
69
|
+
| ------------- | ------------------------------------ | ------------------------------------------ |
|
|
70
|
+
| Keys | `lang=`, `font=`, `map=` | an unknown language, font or map |
|
|
71
|
+
| Dictionary | the language's `data.words[].native` | a native form the rows cannot capitalise |
|
|
72
|
+
| Rows | the mapping's `data.map.rows` | nothing: a character with no row passes on |
|
|
73
|
+
| Lexicon check | the language's words and register | a word the language does not hold |
|
|
74
|
+
| Face coverage | the face's `fonts.json` code points | a character the face does not draw |
|
|
75
|
+
| Element | the face, the tag and the direction | nothing |
|
|
76
|
+
|
|
77
|
+
## The three keys
|
|
78
|
+
|
|
79
|
+
The keys go in the attribute block that a span, a fenced div or a `verse`
|
|
80
|
+
fence already takes:
|
|
81
|
+
|
|
82
|
+
| Written | Meaning |
|
|
83
|
+
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `[Daimela, helthos.]{lang=vyl}` | Vylari, tagged `art-x-vyl`, in roman and in the page's font. Not checked. |
|
|
85
|
+
| `[…]{font=semaron-kuriale}` | The code points exactly as typed, drawn in Semaron Kuriale. Checked for coverage only. |
|
|
86
|
+
| `[Zaron lonak]{lang=vyl font=semaron-kuriale map=semaron}` | Vylari typed in roman, mapped through the dictionary and the rows into Semaron, and checked against Vylari. |
|
|
87
|
+
| `[…]{map=semaron}` with no `lang=` | The rows alone: no dictionary, no lexicon check. |
|
|
88
|
+
| `[ad astra]{lang=la font=serif}` | A real language's BCP 47 tag, unchecked, in the reader's serif. |
|
|
89
|
+
| `::: {lang=… font=… map=…}` … `:::` | The same keys for a passage of paragraphs. |
|
|
90
|
+
| a `verse` fence opened with `{lang=… font=… map=…}` | The same keys for a poem. |
|
|
91
|
+
|
|
92
|
+
**`lang=`** is read in this order. First a short name declared in the
|
|
93
|
+
configuration's `languages`; then a BCP 47 language tag for a real language
|
|
94
|
+
(`la`, `grc`, `en-GB`), checked for its form alone. A declared name wins over a
|
|
95
|
+
tag spelled the same way. A well-formed tag one edit from a declared name draws
|
|
96
|
+
a warning that names the declared one, since `vly` is a valid tag for another
|
|
97
|
+
language than `vyl`.
|
|
98
|
+
|
|
99
|
+
**`font=`** is a face of `@heroiclands/fonts`, named by its class without
|
|
100
|
+
`hl-` (`hl-semaron-kuriale` is `font=semaron-kuriale`), or one of the generic
|
|
101
|
+
families `mono`, `serif` and `sans`. A package that sets text in a face adds the
|
|
102
|
+
fonts to its own development dependencies:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install --save-dev @heroiclands/fonts
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The installed package's `fonts.json` lists every face and every code point it
|
|
109
|
+
draws, which is the list to write a mapping from. This prints Semaron Kuriale's:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
jq -r '.families[] | select(.class == "hl-semaron-kuriale") | .codepoints[] | [.codepoint, .kind, .glyph, .name] | @tsv' \
|
|
113
|
+
node_modules/@heroiclands/fonts/fonts.json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Each line is a code point, its kind (`letter`, `digraph`, `numeral`, `point`, `mark`
|
|
117
|
+
or `sign`), the glyph's name and the character's name; the glyph named `a` is the
|
|
118
|
+
letter that writes the sound `a`, and `a.long` the long vowel. Those names are
|
|
119
|
+
what a mapping's rows are written from.
|
|
120
|
+
|
|
121
|
+
On the site `serif` and `mono` are the site's own body and code faces and
|
|
122
|
+
`sans` is the reader's sans-serif; in Foundry they are the reader's generic
|
|
123
|
+
families; in a book they are the book's own serif, sans and mono. The generic
|
|
124
|
+
families are not checked for coverage.
|
|
125
|
+
|
|
126
|
+
**`map=`** is the `data.map.name` of a [mapping note](#mapping-notes). It
|
|
127
|
+
rewrites the run before anything else; a run's `font=` is then one of the faces
|
|
128
|
+
the mapping lists.
|
|
129
|
+
|
|
130
|
+
The `languages` block of `package-build.config.yaml` declares the short names:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
languages:
|
|
134
|
+
vyl: { tag: art-x-vyl, note: skill-vylarilng }
|
|
135
|
+
khel: { tag: art-x-khel, note: skill-khelathlng }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
A name is lowercase letters, digits and hyphens, starting with a letter. `tag`
|
|
139
|
+
is a BCP 47 tag; a constructed language takes `art-x-<name>`. `note` is the
|
|
140
|
+
address of the language's `skill` note of `subType: language`, whose
|
|
141
|
+
`data.words` is the dictionary and whose `data.register` is the names register.
|
|
142
|
+
Without `note`, `lang=` only tags: there is no dictionary and no lexicon check.
|
|
143
|
+
`package-build lint` checks at the key that `note` names a language note.
|
|
144
|
+
|
|
145
|
+
**A run inherits from its passage and overrides it.** A span inside a marked
|
|
146
|
+
div or fence takes the passage's keys, and its own keys win. A Khelathi phrase
|
|
147
|
+
inside a Vylari poem is checked against Khelathi's lexicon and tagged Khelathi
|
|
148
|
+
but still drawn through Semaron's rows:
|
|
149
|
+
|
|
150
|
+
```markdown
|
|
151
|
+
::: {lang=vyl font=semaron-kuriale map=semaron}
|
|
152
|
+
Zaron lonak, [Gar-Anlagh]{lang=khel}, lokamen zaron.
|
|
153
|
+
:::
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
To draw it in Qalezu instead, the span states its own face and mapping,
|
|
157
|
+
`[Gar-Anlagh]{lang=khel font=qalezu-hand map=qalezu}`. Qalezu runs right to left
|
|
158
|
+
inside the left-to-right line with no `dir=` written. To set a gloss in the
|
|
159
|
+
page's own font, `[an oath]{lang=en font=serif}` inside the passage drops both
|
|
160
|
+
the face and the map by naming new ones.
|
|
161
|
+
|
|
162
|
+
**What a run may hold.** A marked span or verse line is plain text: no
|
|
163
|
+
emphasis (other than the stars a face's run takes, see [emphasis in a
|
|
164
|
+
script](#emphasis-in-a-script)), link, image, footnote, wikilink, code or HTML.
|
|
165
|
+
A marked div holds paragraphs and line breaks only. The text is read as written,
|
|
166
|
+
so `[`, `]`, `"`, `<<`, `>>`, `!` and `@ # $ % ^ &` are characters; a bracket
|
|
167
|
+
pair is markup only when `(` makes a link, `{` a span or a second `[` a
|
|
168
|
+
wikilink, and an unbalanced bracket takes a backslash, `\[`. A code fence is
|
|
169
|
+
verbatim: `[…]{…}` inside it stays literal text. Text marked with a real
|
|
170
|
+
language's tag alone keeps its Markdown, so `[ad _astra_]{lang=la}` works.
|
|
171
|
+
|
|
172
|
+
The three keys are errors on a named block such as a secret block. Put a marked
|
|
173
|
+
div inside the block instead.
|
|
174
|
+
|
|
175
|
+
## Without a map
|
|
176
|
+
|
|
177
|
+
A run that names `font=` and no `map=` is set exactly as typed:
|
|
178
|
+
|
|
179
|
+
```markdown
|
|
180
|
+
The lintel is cut with []{font=semaron-kuriale}.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
where the run holds Semaron's own code points. The only check is face coverage:
|
|
184
|
+
after the run is read, every character must be one the face draws (or white
|
|
185
|
+
space), and any other is an error at the character it came from. Each character
|
|
186
|
+
is reported once per run:
|
|
187
|
+
|
|
188
|
+
> `` `x` (U+0078) is not drawn by the font `semaron-kuriale` ``
|
|
189
|
+
|
|
190
|
+
Fix: type the face's code points, or add `map=`. The face's `fonts.json` states
|
|
191
|
+
what it draws.
|
|
192
|
+
|
|
193
|
+
There are two ways to type the code points. The fonts package ships keyboard
|
|
194
|
+
layouts and Emacs input methods for its scripts, under its `keyboards/`; and an
|
|
195
|
+
editor font that carries the scripts draws them where they are typed. In
|
|
196
|
+
either case the note holds the characters and needs only `font=`. Typing roman
|
|
197
|
+
and letting `map=` convert it keeps the note's source readable and diffable and
|
|
198
|
+
is the usual choice for a language with a dictionary.
|
|
199
|
+
|
|
200
|
+
A run with `lang=` and no `font=` is tagged and nothing more.
|
|
201
|
+
|
|
202
|
+
## Mapping notes
|
|
203
|
+
|
|
204
|
+
A mapping note is a `doc` note whose `data.map` lists the rewrites. **There is
|
|
205
|
+
one mapping per script,** serving every language written in it. The note below
|
|
206
|
+
is complete; the rows are the Semaron letters this guide's sample uses.
|
|
207
|
+
|
|
208
|
+
**`assets/content/Lore/Semaron_Spelling.md`**
|
|
209
|
+
|
|
210
|
+
```markdown
|
|
211
|
+
---
|
|
212
|
+
shortcode: mapsemaron
|
|
213
|
+
name: { full: Semaron Spelling }
|
|
214
|
+
type: doc
|
|
215
|
+
subType: reference
|
|
216
|
+
data:
|
|
217
|
+
map:
|
|
218
|
+
name: semaron
|
|
219
|
+
vowels: "aeiou"
|
|
220
|
+
rows:
|
|
221
|
+
- ["a", ""] # U+F0230
|
|
222
|
+
- ["d", ""] # U+F0232
|
|
223
|
+
- ["e", ""] # U+F0233
|
|
224
|
+
- ["h", ""] # U+F0236
|
|
225
|
+
- ["i", ""] # U+F0237
|
|
226
|
+
- ["k", ""] # U+F0239
|
|
227
|
+
- ["l", ""] # U+F023A
|
|
228
|
+
- ["m", ""] # U+F023B
|
|
229
|
+
- ["n", ""] # U+F023C
|
|
230
|
+
- ["o", ""] # U+F023D
|
|
231
|
+
- ["r", ""] # U+F023F
|
|
232
|
+
- ["s", ""] # U+F0240
|
|
233
|
+
- ["t", ""] # U+F0241
|
|
234
|
+
- ["u", ""] # U+F0242
|
|
235
|
+
- ["z", ""] # U+F0246
|
|
236
|
+
- ["aa", ""] # U+F0248
|
|
237
|
+
- ["th", ""] # U+F0250
|
|
238
|
+
- ["Th", ""] # U+F0251
|
|
239
|
+
- ["L", ""] # U+F020A
|
|
240
|
+
- ["T", ""] # U+F0211
|
|
241
|
+
- ["Z", ""] # U+F0216
|
|
242
|
+
- { from: "y", to: "", before: vowel } # U+F0245
|
|
243
|
+
- ["y", ""] # U+F0237
|
|
244
|
+
- [".", ""] # U+F0268
|
|
245
|
+
- [",", ""] # U+F0268
|
|
246
|
+
fonts: [{ font: semaron-kuriale }]
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
Semaron Spelling writes roman spelling in the Semaron script. A passage marked with
|
|
250
|
+
`map=semaron` is converted by the rows of this note before it is set, so the note's
|
|
251
|
+
source stays in roman letters and the page shows the script. Every language written
|
|
252
|
+
in Semaron shares these rows.
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The keys of `data.map`:
|
|
256
|
+
|
|
257
|
+
| Key | Meaning |
|
|
258
|
+
| ------------- | -------------------------------------------------------------------------------------------- |
|
|
259
|
+
| `name` | What `map=` names it by: lowercase letters, digits and `-`, unique in the package. Required. |
|
|
260
|
+
| `rows` | The rewrites, in authored order. Required. |
|
|
261
|
+
| `fonts` | The faces the mapping is drawn in, each by its slug, at least one. Required. |
|
|
262
|
+
| `vowels` | The characters that `before: vowel` reads as vowels. Any other letter is a consonant. |
|
|
263
|
+
| `logographic` | `true` for a script that writes meanings; see [logographic scripts](#logographic-scripts). |
|
|
264
|
+
|
|
265
|
+
**Rows.** A row is `[from, to]`, or `{ from, to, before, at }` with the two
|
|
266
|
+
conditions optional. `from` is one or more characters; `to` is any number of
|
|
267
|
+
them, none included. A mapping that drops a language's vowels writes `[a, ""]`.
|
|
268
|
+
`rows` is a list, never a keyed map, so `A` and `a` are two rows.
|
|
269
|
+
|
|
270
|
+
**How a mapping reads text.**
|
|
271
|
+
|
|
272
|
+
- **The longest match wins.** In the note above `th` is one letter, and `t` and
|
|
273
|
+
`h` are read only where `th` does not match. Among rows of one length, a row
|
|
274
|
+
whose condition holds comes before a row with none, and otherwise the earlier
|
|
275
|
+
row wins.
|
|
276
|
+
- **A row whose condition fails is skipped.** `before: vowel` holds when the next
|
|
277
|
+
character is one of `vowels`; `before: consonant` when it is any other
|
|
278
|
+
letter; neither holds at the end of the text. `at: start` holds at the first
|
|
279
|
+
character of the run or after white space or punctuation; `at: end` holds at
|
|
280
|
+
the last character or before white space or punctuation. In the note above,
|
|
281
|
+
`y` is the consonant letter before a vowel and the vowel `i` elsewhere.
|
|
282
|
+
- **Capitals and marks need rows of their own.** A row matches the character as
|
|
283
|
+
written, so `L` and `l` are two rows, and a script with no capitals gives both
|
|
284
|
+
the same code point. The full stop and the comma are characters too: a run
|
|
285
|
+
that holds one needs a row for it, or the face-coverage check reports it.
|
|
286
|
+
- **A character no row matches passes through unchanged,** and the face-coverage
|
|
287
|
+
check then reports it. A mapping for a face that draws nothing on roman code
|
|
288
|
+
points lists every letter the spelling uses.
|
|
289
|
+
|
|
290
|
+
**Fonts.** `fonts` lists each face the mapping may be used with, as a list of
|
|
291
|
+
`{ font, rows }`. A face may carry rows of its own, which a run in that face
|
|
292
|
+
tries first (longest match among them) before the shared rows. That is the way
|
|
293
|
+
to write a sound differently in a variant face. The generic families `mono`,
|
|
294
|
+
`serif` and `sans` are not listed. The lint checks that every listed face draws
|
|
295
|
+
every code point that its own rows, the shared rows it can reach and the
|
|
296
|
+
lexicons' native forms for it write.
|
|
297
|
+
|
|
298
|
+
**Code points above U+FFFF in YAML.** A double-quoted YAML string writes a
|
|
299
|
+
code point by its escape, and the left-to-right scripts sit in plane 15, so
|
|
300
|
+
they take the eight-digit `\U`: `"\U000F0230"` is U+F0230, and the four-digit
|
|
301
|
+
`\u` reaches only code points up to U+FFFF. Both forms mean the same thing.
|
|
302
|
+
`package-build format --write` (Prettier) rewrites such an escape into the
|
|
303
|
+
character itself, so a mapping note on disk usually holds the raw Private Use
|
|
304
|
+
characters, as the note above does. Those read only in one of the fonts
|
|
305
|
+
package's faces or its editor fonts, and elsewhere show as boxes. The
|
|
306
|
+
convention is a trailing comment, `# U+F0230`, on every row, which keeps the
|
|
307
|
+
note readable in any editor and survives formatting. A row that writes several
|
|
308
|
+
code points lists them all in its comment.
|
|
309
|
+
|
|
310
|
+
**Where the checks sit.** Every key is checked at its own line and column:
|
|
311
|
+
|
|
312
|
+
> `` `data.map.name` is `Vyl_Semaron`; a map's name is lowercase letters, digits and `-` ``
|
|
313
|
+
|
|
314
|
+
> `` `data.map.rows[4]` has `before: consonant`, and the map states no `vowels` to read it by ``
|
|
315
|
+
|
|
316
|
+
> `` `data.map.rows[1]` has an empty `from`; a row matches one or more characters ``
|
|
317
|
+
|
|
318
|
+
> `` `data.map.fonts` is empty; a map lists each face it is drawn in ``
|
|
319
|
+
|
|
320
|
+
> `` `data.map.rows[5]` writes U+F0239, which the font `semaron-kuriale`, listed in `data.map.fonts`, does not draw ``
|
|
321
|
+
|
|
322
|
+
A row with a fault is left out of the map and the rest apply.
|
|
323
|
+
|
|
324
|
+
## How a mapping treats punctuation
|
|
325
|
+
|
|
326
|
+
The toolchain is used with one convention for marks: **mood, questions and
|
|
327
|
+
quotation are carried by words, not marks,** unless a language's note rules
|
|
328
|
+
otherwise. A mapping therefore lists the marks its script has and nothing more.
|
|
329
|
+
In the sample, a comma and a full stop are the script's one point:
|
|
330
|
+
|
|
331
|
+
```yaml
|
|
332
|
+
- [".", "\U000F0268"] # U+F0268
|
|
333
|
+
- [",", "\U000F0268"] # U+F0268
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
(Formatting rewrites the escapes, as above.) A character with no row passes
|
|
337
|
+
through unchanged, and the face does not draw it, so a question mark in a
|
|
338
|
+
mapped run is an error that names the mark and the mapping:
|
|
339
|
+
|
|
340
|
+
> `` `?` (U+003F) is not drawn by the font `semaron-kuriale`, and the map `semaron` has no row for it ``
|
|
341
|
+
|
|
342
|
+
The remedy is to write the question or the quotation in words, as the language
|
|
343
|
+
does, and leave the mark out of the run. A language whose note rules
|
|
344
|
+
otherwise gets rows for its marks in the mapping, and the check stops
|
|
345
|
+
reporting them. The same holds for the digits, the hyphen and the catch: a row
|
|
346
|
+
for each makes the mark part of the script; none leaves it out.
|
|
347
|
+
|
|
348
|
+
## The dictionary first
|
|
349
|
+
|
|
350
|
+
The sound rules belong to the script and the exceptions belong to the language.
|
|
351
|
+
With `lang=` naming a language that has a `note`, the build reads the
|
|
352
|
+
language's `data.words` before the rows.
|
|
353
|
+
|
|
354
|
+
**How a run is split into words.** A word is a run of letters, combining marks
|
|
355
|
+
and digits, with an apostrophe (`'` or `’`), a hyphen or an en dash joining two
|
|
356
|
+
such runs into one word. `k'aralzon` is one word and `zaron-lonak` is one word
|
|
357
|
+
for lookup. Everything between words is spelled by the rows.
|
|
358
|
+
|
|
359
|
+
**How a word is written.** The word is looked up as written, and then in
|
|
360
|
+
lowercase. A word that states a `native` form for the run's mapping (for the
|
|
361
|
+
run's face where an entry names one, else the one for no face) is written by it
|
|
362
|
+
whole. Every other word, with every derived form of an exception word, is
|
|
363
|
+
spelled by the rows. There are no stem-level exceptions: the plural of an
|
|
364
|
+
exception word is another word, and the rows spell it.
|
|
365
|
+
|
|
366
|
+
**A native form states only an exception.** `native` is a list of
|
|
367
|
+
`{ map, font, text }` on a word:
|
|
368
|
+
|
|
369
|
+
```yaml
|
|
370
|
+
- form: zaron
|
|
371
|
+
class: n
|
|
372
|
+
field: Law
|
|
373
|
+
gloss: an oath
|
|
374
|
+
native:
|
|
375
|
+
- { map: semaron, text: "\U000F0246\U000F0248\U000F023F\U000F023D\U000F023C" }
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
`map` is the mapping's `name`, `font` optionally limits the form to one face, and
|
|
379
|
+
`text` is the word as the script writes it. A form that the rows already give is
|
|
380
|
+
redundant, and the lint says so:
|
|
381
|
+
|
|
382
|
+
> `` `data.words[0].native[0]` states what the rows already give: the map `semaron` spells `zaron` so in the font `semaron-kuriale`; a native form is stated only where the rows spell the word differently ``
|
|
383
|
+
|
|
384
|
+
so a dictionary holds its exceptions and nothing else. The other checks of a
|
|
385
|
+
native form (an unknown map, a face the map is not for, a second form for one
|
|
386
|
+
map, a character the face does not draw) report at the entry:
|
|
387
|
+
|
|
388
|
+
> `` `data.words[0].native[0].map` is `semron`, which is not a map: a native form names the `data.map.name` of a mapping note; did you mean `semaron`? ``
|
|
389
|
+
|
|
390
|
+
> `` `data.words[0].native[2]` states a second native form for the map `semaron`; the first is `data.words[0].native[0]` ``
|
|
391
|
+
|
|
392
|
+
> `` `data.words[0].native[0]` holds U+F024F, which the font `semaron-kuriale`, listed in the map `semaron`, does not draw ``
|
|
393
|
+
|
|
394
|
+
**Capitals.** A capitalised word that is found only in lowercase takes its
|
|
395
|
+
capital from the rows: the rows spell the first sound as written and in
|
|
396
|
+
lowercase, and where the native form begins with the lowercase spelling, that
|
|
397
|
+
beginning is replaced by the capital. A native form that does not begin the way
|
|
398
|
+
the rows begin the word cannot be capitalised, and the capitalised word is an
|
|
399
|
+
error at its place in the run:
|
|
400
|
+
|
|
401
|
+
> `` `Orlan` is capitalised, and the native form the lexicon of `vyl` states for `orlan` under the map `semaron` does not begin as the rows spell its first letter, so the rows cannot capitalise it; state `Orlan` as a word of its own with its native form ``
|
|
402
|
+
|
|
403
|
+
The fix is the one the message names: a lexicon word `Orlan` with its own
|
|
404
|
+
native form, which the lookup as written finds first.
|
|
405
|
+
|
|
406
|
+
A character the face does not draw inside a native form reports at the word:
|
|
407
|
+
|
|
408
|
+
> `` `zaron` is written U+F024F by the lexicon of `vyl` for the map `semaron`, which the font `semaron-kuriale` does not draw ``
|
|
409
|
+
|
|
410
|
+
A run with `map=` and no `lang=`, a `lang=` that is a bare tag and a declared
|
|
411
|
+
language with no `note` are spelled by the rows alone.
|
|
412
|
+
|
|
413
|
+
## The checks
|
|
414
|
+
|
|
415
|
+
A run with `lang=` and `map=`, whose language has a `note`, is checked word by
|
|
416
|
+
word. The comparison is case folded and NFC, with `’` read as `'`. A word passes
|
|
417
|
+
when it is any of these:
|
|
418
|
+
|
|
419
|
+
1. **A lexicon word:** a `data.words[].form` of the language. A form listed in a
|
|
420
|
+
word's `variants` is a known word too. A multi-word or compound form
|
|
421
|
+
contributes each of its parts.
|
|
422
|
+
2. **A word of a registered name:** a word of a `name` in the language note's own
|
|
423
|
+
`data.register`, under any `tongue` but `translation`, which stands for an
|
|
424
|
+
English rendering and never counts. A name of several words is checked word
|
|
425
|
+
by word.
|
|
426
|
+
3. **A regular form of a lexicon word,** made by one rule the language states:
|
|
427
|
+
- a noun's plural, its own `plural` or the first `data.grammar.plural` row
|
|
428
|
+
that fits;
|
|
429
|
+
- a verb's form with one ending of `data.grammar.verbs.persons`, which takes
|
|
430
|
+
the place of a closing `data.grammar.verbs.replaces` where the pattern
|
|
431
|
+
states one;
|
|
432
|
+
- a suffix of `data.affixes` that states `replaces`, or its `front` form;
|
|
433
|
+
- an agreeing form or a participle; see
|
|
434
|
+
[agreement, participles and affixes](#agreement-participles-and-affixes).
|
|
435
|
+
|
|
436
|
+
A compound that is not a word whole is split at its hyphens and en dashes and
|
|
437
|
+
each part is checked, so `zaron-lonak` passes when `zaron` and `lonak` do. A
|
|
438
|
+
word with no letter, such as a numeral, is skipped. A prefix, and an affix that
|
|
439
|
+
states no `replaces`, make no form: `attaches` is prose.
|
|
440
|
+
|
|
441
|
+
Any other word is an error at its first character, reported once per run, and
|
|
442
|
+
it names the language as `lang=` writes it:
|
|
443
|
+
|
|
444
|
+
> `` `thiruthrimar` is not a word of the `vyl` lexicon, a registered name, or a regular form of one; coin it in the lexicon (or register the name) first ``
|
|
445
|
+
|
|
446
|
+
**Fix: coin the word,** add it to the language note's `data.words` with its
|
|
447
|
+
class, field and gloss, after the invented-word rules of the setting (palette,
|
|
448
|
+
Earth collisions and readability) have approved it:
|
|
449
|
+
|
|
450
|
+
```yaml
|
|
451
|
+
words:
|
|
452
|
+
- form: thiruthrimar
|
|
453
|
+
class: n
|
|
454
|
+
field: Law
|
|
455
|
+
gloss: a sworn witness
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**or register the name** with its tongue in the language's `data.register`:
|
|
459
|
+
|
|
460
|
+
```yaml
|
|
461
|
+
register:
|
|
462
|
+
- { name: Revothar Baremzator, tongue: vylari }
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**Foreign names.** A foreign name used in a Vylari run is first listed in
|
|
466
|
+
Vylari's own register as `other:<tongue>` or `exonym:<tongue>`, and that row is
|
|
467
|
+
checked against the tongue's own register in turn: the language note that a
|
|
468
|
+
`data.tongues` entry names by its `language` must list the same name under its
|
|
469
|
+
own tongue. A misspelt foreign name is caught where it is listed:
|
|
470
|
+
|
|
471
|
+
> `` `Dunharra` is registered as `other:vylari`, but the register of Vylari Language (skill-vylarilng) lists no `vylari` name `Dunharra`; correct the spelling, or register the name there first ``
|
|
472
|
+
|
|
473
|
+
Bare `other`, `kept`, `ancient` and `translation` rows are not checked.
|
|
474
|
+
|
|
475
|
+
**Nothing requires a form.** The check recognises forms and never demands one: a
|
|
476
|
+
noun stated with its own plural and the plural the rule gives both pass, and no
|
|
477
|
+
check asks that a word takes the right ending.
|
|
478
|
+
|
|
479
|
+
**Face coverage** follows the mapping. A character left over after the rows
|
|
480
|
+
reports once per run, at the start of the matched `from`:
|
|
481
|
+
|
|
482
|
+
> `` `x` (U+0078) is not drawn by the font `semaron-kuriale`, and the map `semaron` has no row for it ``
|
|
483
|
+
|
|
484
|
+
and a row that writes a code point the face lacks reports where it is applied:
|
|
485
|
+
|
|
486
|
+
> `` `ch` maps to U+F0299 in the map `semaron`, which the font `semaron-kuriale` does not draw ``
|
|
487
|
+
|
|
488
|
+
**Keys that name nothing.** A key that names nothing is the one finding, and
|
|
489
|
+
the run is not then checked against a face or a lexicon it cannot reach.
|
|
490
|
+
|
|
491
|
+
> `` `semaron-kurial` is not a font: `font=` names an installed face, or `mono`, `serif` or `sans`; did you mean `semaron-kuriale`? ``
|
|
492
|
+
|
|
493
|
+
> `` `semron` is not a map: `map=` names the `data.map.name` of a mapping note; did you mean `semaron`? ``
|
|
494
|
+
|
|
495
|
+
> `` `q` is not a declared language (`languages` in package-build.config.yaml) or a BCP 47 tag ``
|
|
496
|
+
|
|
497
|
+
> `` `thuravark-carved` is not a font of the map `semaron`; it is for `semaron-kuriale` ``
|
|
498
|
+
|
|
499
|
+
> `` `semaron-kuriale` is not a font: `font=` names `mono`, `serif` or `sans`, or a face of @heroiclands/fonts, which this package has not installed ``
|
|
500
|
+
|
|
501
|
+
The last one means `@heroiclands/fonts` is not installed. A near miss of a
|
|
502
|
+
declared language is a warning that fails nothing:
|
|
503
|
+
|
|
504
|
+
> `` `vly` is read as a BCP 47 tag; did you mean the declared language `vyl`? ``
|
|
505
|
+
|
|
506
|
+
## Agreement, participles and affixes
|
|
507
|
+
|
|
508
|
+
Three optional pieces of a language note let the word check accept more forms.
|
|
509
|
+
None is required, and none makes any check demand a form.
|
|
510
|
+
|
|
511
|
+
**Agreement** states which classes agree with a noun and the singular endings
|
|
512
|
+
they agree by, one per gender. A word of one of `classes` that closes on one of
|
|
513
|
+
`endings` (the longest that leaves a stem) also has that ending swapped for each
|
|
514
|
+
other one, and each of those forms takes the `plural` rule:
|
|
515
|
+
|
|
516
|
+
```yaml
|
|
517
|
+
grammar:
|
|
518
|
+
plural:
|
|
519
|
+
- { ending: os, becomes: oi }
|
|
520
|
+
- { ending: on, becomes: oi }
|
|
521
|
+
- { ending: a, becomes: ai }
|
|
522
|
+
agreement:
|
|
523
|
+
classes: [adj, pron]
|
|
524
|
+
endings: [os, a, on]
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Participles** attach to the verb root, which is the citation form less its
|
|
528
|
+
infinitive ending. A verb closing on one of `root` drops it, and each suffix of
|
|
529
|
+
`data.affixes` that `affixes` names attaches to what is left, as its own
|
|
530
|
+
`replaces` says or whole where it states none. A participle that closes on an
|
|
531
|
+
agreement ending agrees:
|
|
532
|
+
|
|
533
|
+
```yaml
|
|
534
|
+
affixes:
|
|
535
|
+
- { form: "-andar", gloss: "doing it: the present participle", replaces: vowel }
|
|
536
|
+
- { form: "-thos", gloss: "done, suffered: the past participle" }
|
|
537
|
+
grammar:
|
|
538
|
+
participles:
|
|
539
|
+
root: [athen, ethen]
|
|
540
|
+
affixes: ["-andar", "-thos"]
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**`attachesTo`** limits a suffix to words of the classes it lists, as in
|
|
544
|
+
`attachesTo: [n, adj]`; a suffix that states none attaches to a word of every
|
|
545
|
+
class. `replaces: vowel` takes the place of a closing vowel, letters such as
|
|
546
|
+
`replaces: a` take the place of those letters, and a stem that closes otherwise
|
|
547
|
+
takes the suffix whole.
|
|
548
|
+
|
|
549
|
+
With the note above, a run accepts:
|
|
550
|
+
|
|
551
|
+
| Lexicon word | Rule | Forms accepted |
|
|
552
|
+
| ----------------- | ----------- | ------------------------------------------------- |
|
|
553
|
+
| _alathos_, pron. | agreement | _alatha_, _alathon_, _alathoi_, _alathai_ |
|
|
554
|
+
| _lokathen_, v. | participles | _lokandar_, _lokthos_ |
|
|
555
|
+
| _lokathen_, v. | both | _loktha_, _lokthon_, _lokthoi_, _lokthai_ |
|
|
556
|
+
| _marendos_, n. m. | neither | _marendoi_ by the plural rule alone; no _marenda_ |
|
|
557
|
+
|
|
558
|
+
A near miss such as _alathe_ is still an unknown word. To see every form the
|
|
559
|
+
rules give, each beside the word it comes from, run
|
|
560
|
+
`package-build lexicon vyl --map semaron --derived`.
|
|
561
|
+
|
|
562
|
+
The keys are checked where they sit:
|
|
563
|
+
|
|
564
|
+
> `` `data.grammar.agreement.classes[0]` is `adjective`, which is not a word class; did you mean `adj`? ``
|
|
565
|
+
|
|
566
|
+
> `` `data.grammar.agreement.endings` must state at least two endings for a word to agree among ``
|
|
567
|
+
|
|
568
|
+
> `` `data.grammar.participles.affixes[2]` is `-zz`, which is not a suffix of `data.affixes` ``
|
|
569
|
+
|
|
570
|
+
> `` `data.grammar.participles.affixes[3]` is `an-`, a prefix; a participle is a suffix on the root ``
|
|
571
|
+
|
|
572
|
+
> `` `data.affixes[1].attachesTo[0]` is `verb`, which is not a word class; did you mean `v`? ``
|
|
573
|
+
|
|
574
|
+
## Logographic scripts
|
|
575
|
+
|
|
576
|
+
**A script that writes meanings is written from the dictionary, never by
|
|
577
|
+
sound.** Its mapping note states `logographic: true`, and every word of a run
|
|
578
|
+
under it comes from the language's lexicon. The rows write only the text
|
|
579
|
+
between words: spaces, points and anything else with no letter. A word never
|
|
580
|
+
falls through to the rows, so a word the lexicon gives no writing is an error
|
|
581
|
+
rather than a guess.
|
|
582
|
+
|
|
583
|
+
A word is written by the first of these that gives a writing, matched case
|
|
584
|
+
folded because the script has no capitals:
|
|
585
|
+
|
|
586
|
+
1. **Its own `native` entry** for the map (the run's face where an entry names
|
|
587
|
+
one, else the one for no face), or the entry of a set compound written its
|
|
588
|
+
own way.
|
|
589
|
+
2. **Its parts, joined.** The roots of the entry's `built` list in order; each
|
|
590
|
+
piece is a lexicon word or an affix of `data.affixes` with a `native` entry of
|
|
591
|
+
its own, resolved the same way down. A noun's plural and a verb's present
|
|
592
|
+
forms are the stem's writing followed by the ending's, which
|
|
593
|
+
`data.grammar.native` states once per ending: `plural`, or one of the persons
|
|
594
|
+
`I`, `you`, `heShe`, `we`, `youAll` and `they`.
|
|
595
|
+
3. **Its hyphenated parts,** each by these same steps, so `Gar-halzunet` is
|
|
596
|
+
`Gar-`'s writing followed by `halzunet`'s.
|
|
597
|
+
4. **Otherwise an error** at the word.
|
|
598
|
+
|
|
599
|
+
Forms outside the parts rule (a suffix that replaces a vowel, an agreeing form,
|
|
600
|
+
a participle) have no writing of their own. They are coined as lexicon words
|
|
601
|
+
with a writing, or written in signs.
|
|
602
|
+
|
|
603
|
+
```yaml
|
|
604
|
+
affixes:
|
|
605
|
+
- form: "-unet"
|
|
606
|
+
gloss: "a thing made of"
|
|
607
|
+
native:
|
|
608
|
+
- { map: zethu, text: "" }
|
|
609
|
+
grammar:
|
|
610
|
+
plural:
|
|
611
|
+
- { ending: "", becomes: "im" }
|
|
612
|
+
native:
|
|
613
|
+
- { ending: plural, map: zethu, text: "" }
|
|
614
|
+
words:
|
|
615
|
+
- form: halzi
|
|
616
|
+
class: n
|
|
617
|
+
field: The body
|
|
618
|
+
gloss: heart
|
|
619
|
+
native:
|
|
620
|
+
- { map: zethu, text: "" }
|
|
621
|
+
- form: halzunet
|
|
622
|
+
class: n
|
|
623
|
+
field: The body
|
|
624
|
+
gloss: the account
|
|
625
|
+
built: [halzi, -unet]
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
`[halzi halzunet halziim]{lang=khel font=khelathi-zethu-glyphs map=zethu}` is
|
|
629
|
+
written U+1EABB, then U+1EABB U+1EBC7, then U+1EABB U+1EBE1, with the spaces the
|
|
630
|
+
rows write between them. An affix's `native` and `data.grammar.native` are read
|
|
631
|
+
only under a logographic map; naming any other map is an error at the entry.
|
|
632
|
+
|
|
633
|
+
**Ambiguity.** One roman form that stands for entries written differently is an
|
|
634
|
+
error naming every entry's gloss, and so is one form with a writing for one
|
|
635
|
+
sense and none for another. Nothing is guessed. List the words with
|
|
636
|
+
`package-build lexicon khel --map zethu`: the third column says where each
|
|
637
|
+
writing comes from, `own` for a stored writing, `parts` for one the pieces give,
|
|
638
|
+
`none` for a word with no writing, and `ambiguous` for a form a run cannot
|
|
639
|
+
write. An ambiguous word's second column is still that entry's own writing, so
|
|
640
|
+
pick the entry by its gloss and write those signs directly in the run. Signs
|
|
641
|
+
typed in a run hold no letter, so they are no word and pass through as typed.
|
|
642
|
+
|
|
643
|
+
**Foreign names.** A registered name is written like any other word, so a name
|
|
644
|
+
with no writing is an error. A foreign name is written deliberately: its signs
|
|
645
|
+
typed directly, or through a mapping whose rows read a sign-by-sign notation
|
|
646
|
+
(sign ids and joiners, as in Manuel de Codage input), which an author writes the
|
|
647
|
+
way any other mapping is written, and used on a run with `map=` and no `lang=`.
|
|
648
|
+
|
|
649
|
+
**An unknown word gets two errors:** the lexicon check reports it is no word of
|
|
650
|
+
the language, and the writing check reports it has no writing.
|
|
651
|
+
|
|
652
|
+
> `` `zamlu` has no `zethu` writing in the `khel` lexicon, and its parts do not give one; state one, or write the word directly in signs ``
|
|
653
|
+
|
|
654
|
+
> `` `nelgir` stands for 2 words of the `khel` lexicon that the map `zethu` writes differently, “a god” and “god”; write the word directly in signs, choosing by its sense in `package-build lexicon khel --map zethu` ``
|
|
655
|
+
|
|
656
|
+
> `` `halzi` has no `zethu` writing: the map `zethu` is logographic, and the run names no `lang=` whose lexicon writes it; mark the run with its language, or write the word directly in signs ``
|
|
657
|
+
|
|
658
|
+
> `` `data.grammar.native[3]` writes the ending `they`, and `data.grammar.verbs` states no `persons` ``
|
|
659
|
+
|
|
660
|
+
## Emphasis in a script
|
|
661
|
+
|
|
662
|
+
Inside a run set in a face, `*…*` and `**…**` are written as in English. No
|
|
663
|
+
script marks a stressed word by a bold or a slant, so the build sets emphasis by
|
|
664
|
+
the scribal convention the text's language or script states:
|
|
665
|
+
|
|
666
|
+
| Convention | Site and Foundry | Book |
|
|
667
|
+
| ---------- | -------------------------------------------------- | --------------------- |
|
|
668
|
+
| `rubric` | `<em class="emph-rubric">`, in red | in the book's red ink |
|
|
669
|
+
| `overline` | `<em class="emph-overline">`, with a line above it | under an overline |
|
|
670
|
+
| none | `<em>` with no class, in the face's Regular | in the face's Regular |
|
|
671
|
+
|
|
672
|
+
`**…**` gives a `<strong>` in the same way. The element stays an `<em>` or a
|
|
673
|
+
`<strong>`, so a screen reader and a copied passage keep the emphasis. The face
|
|
674
|
+
keeps its Regular: no slant and no added weight. `_…_` is emphasis equal to
|
|
675
|
+
`*…*`, and `__…__` equal to `**…**`; a strikethrough is an error in a face.
|
|
676
|
+
|
|
677
|
+
**The convention is the language's, else the script's.** A language note may
|
|
678
|
+
state `data.emphasis` as `rubric`, `overline` or `words`. Otherwise the script
|
|
679
|
+
note that lists the run's face states it in `data.script`; otherwise there is
|
|
680
|
+
none. A script note is a `skill` note of `subType: script`:
|
|
681
|
+
|
|
682
|
+
```yaml
|
|
683
|
+
data:
|
|
684
|
+
script:
|
|
685
|
+
fonts: [semaron-kuriale]
|
|
686
|
+
emphasis: rubric
|
|
687
|
+
strongEmphasis: overline
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
`fonts` lists the faces of the script (a face belongs to one script),
|
|
691
|
+
`emphasis` sets both `*…*` and `**…**`, and `strongEmphasis` optionally sets
|
|
692
|
+
`**…**` alone. A tongue that states nothing takes its script's convention.
|
|
693
|
+
|
|
694
|
+
**A `words` language makes emphasis an error.** `data.emphasis: words` says the
|
|
695
|
+
language marks stress with a word, so stars in its runs are refused:
|
|
696
|
+
|
|
697
|
+
> `` `ban` marks emphasis with a word, not a mark; write the word ``
|
|
698
|
+
|
|
699
|
+
Underscores and strikethrough are errors in a face. A stressed word is best
|
|
700
|
+
enclosed whole: a star inside a word splits it, so a row or lexicon word that
|
|
701
|
+
crosses the star is not matched.
|
|
702
|
+
|
|
703
|
+
**The `--rubric` token.** The theme's `--rubric` is a warm red for its dark
|
|
704
|
+
ground, and the book prints its own. A rubric carries emphasis by colour alone,
|
|
705
|
+
so a contrast guard holds it to 4.5:1 against every ground the text sits on and
|
|
706
|
+
1.75:1 against the body text, so a reader who cannot see the hue still sees a
|
|
707
|
+
lighter or darker word. A site that overrides `--rubric` keeps both ratios.
|
|
708
|
+
|
|
709
|
+
The keys are checked where they sit:
|
|
710
|
+
|
|
711
|
+
> `` `data.script.emphasis` should be `rubric` or `overline`, but reads "rubrik". Did you mean "rubric"? ``
|
|
712
|
+
|
|
713
|
+
> `` `data.script.fonts` is empty; a script lists each face it is written in ``
|
|
714
|
+
|
|
715
|
+
> `` `data.emphasis` states how a language marks emphasis, and this note's `subType` is not `language` ``
|
|
716
|
+
|
|
717
|
+
## Verse
|
|
718
|
+
|
|
719
|
+
### A poem in a verse fence
|
|
720
|
+
|
|
721
|
+
A poem is written in a `verse` fence, whose lines and stanzas the build
|
|
722
|
+
preserves. The keys of the previous sections go on the fence. Prettier leaves
|
|
723
|
+
the contents of a fence byte for byte, which is why a poem is a fence and not
|
|
724
|
+
paragraphs: indentation, line breaks and spans survive formatting untouched.
|
|
725
|
+
|
|
726
|
+
````markdown
|
|
727
|
+
```verse {lang=vyl font=semaron-kuriale map=semaron}
|
|
728
|
+
Lokazor lonak,
|
|
729
|
+
lokamen zaron.
|
|
730
|
+
```
|
|
731
|
+
````
|
|
732
|
+
|
|
733
|
+
### Verse in columns
|
|
734
|
+
|
|
735
|
+
A poem can be set beside its translation, or in both script and roman, line
|
|
736
|
+
for line. `col1=` names what the left column shows and `col2=` what the right
|
|
737
|
+
shows, and each column stacks one or more **entries** joined by `:`. An entry
|
|
738
|
+
is `language[/mapping[/font]]`. A poem has at most two columns, and `numstep=N`
|
|
739
|
+
numbers the lines (`numstep=1` every line, `numstep=5` every fifth, `0` none).
|
|
740
|
+
`form=` records the poem's kind, such as `form=epic`; the build infers nothing
|
|
741
|
+
from it.
|
|
742
|
+
|
|
743
|
+
The body is **one fence, with interleaved `lang` spans.** Each verse line is a
|
|
744
|
+
group of lines separated from the next by a blank line; every line of a group is
|
|
745
|
+
a span giving the verse line in one language, `[text]{lang=…}`, or plain text in
|
|
746
|
+
the fence's own `lang=`. A line of only `***` breaks a stanza. The Vylari is
|
|
747
|
+
typed once, in roman, and each column picks what it needs: the first entry of
|
|
748
|
+
`col1=` maps it into Semaron, and the second entry of `col2=` sets the same line
|
|
749
|
+
in roman.
|
|
750
|
+
|
|
751
|
+
````markdown
|
|
752
|
+
```verse {numstep=1 lang=vyl col1=vyl/semaron/semaron-kuriale col2=en:vyl}
|
|
753
|
+
[Lokazor lonak zaron.]{lang=vyl}
|
|
754
|
+
[He walks the oath road.]{lang=en}
|
|
755
|
+
|
|
756
|
+
[Lokamen lonak zaron.]{lang=vyl}
|
|
757
|
+
[I walk the oath road.]{lang=en}
|
|
758
|
+
|
|
759
|
+
***
|
|
760
|
+
|
|
761
|
+
alathos lokazor.
|
|
762
|
+
[That one walks.]{lang=en}
|
|
763
|
+
```
|
|
764
|
+
````
|
|
765
|
+
|
|
766
|
+
In every column the first entry is set in the normal tone and each later one in
|
|
767
|
+
grey. Each target sets a verse line as one row that holds its columns level,
|
|
768
|
+
and a narrow screen stacks them. A part in a right-to-left face stays in its
|
|
769
|
+
column and runs right to left within it.
|
|
770
|
+
|
|
771
|
+
The rules of a verse in columns: `font=` and `map=` belong to the entries, not
|
|
772
|
+
to the poem; every verse line gives one span for each language its columns
|
|
773
|
+
name and none for a language they do not; a line is not indented and its span
|
|
774
|
+
takes only `lang=`. Each finding is an error at the text that is wrong:
|
|
775
|
+
|
|
776
|
+
```text
|
|
777
|
+
assets/content/Lore/Walking.md:14:1: error: this verse line has no `en` line, which `col2=` sets
|
|
778
|
+
assets/content/Lore/Walking.md:18:1: error: this verse line gives `en` twice; give each language once
|
|
779
|
+
assets/content/Lore/Walking.md:22:1: error: no column sets `khel`; a verse line gives the languages `col1=` and `col2=` name
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### Metre
|
|
783
|
+
|
|
784
|
+
`scan=` turns on a beat check. It names a metre declared once in the package,
|
|
785
|
+
as an entry of a `doc` note's `data.metres`:
|
|
786
|
+
|
|
787
|
+
```yaml
|
|
788
|
+
data:
|
|
789
|
+
metres:
|
|
790
|
+
- { name: trimeter, beats: 3, kind: accentual }
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
`name` is lowercase letters, digits and `-`, unique in the package; `beats` is
|
|
794
|
+
the beats of one line, a whole number above zero; `kind` is `accentual`, the
|
|
795
|
+
only kind: a beat falls on a stressed syllable and the length of a syllable is
|
|
796
|
+
not counted. A fence that states `scan=` with the declared name and a `lang=`
|
|
797
|
+
whose language note states `data.sounds.stress` is counted line by line:
|
|
798
|
+
|
|
799
|
+
````markdown
|
|
800
|
+
```verse {lang=vyl scan=trimeter}
|
|
801
|
+
Lokazor lonak zaron.
|
|
802
|
+
Lokamen lonak zaron.
|
|
803
|
+
```
|
|
804
|
+
````
|
|
805
|
+
|
|
806
|
+
**The stress rule** is `data.sounds.stress`, `{ two, longer, mark }`. `two`
|
|
807
|
+
(`first` or `last`) places the stress in a word of two syllables; `longer`
|
|
808
|
+
(`antepenultimate`, `penultimate` or `final`) places it in a word of three or
|
|
809
|
+
more, counted from its end; `mark` (`acute`, `grave` or `circumflex`) is a
|
|
810
|
+
diacritic that moves the stress to the syllable it sits on. Syllables are vowel
|
|
811
|
+
groups: a vowel is a letter whose base is `a`, `e`, `i`, `o` or `u`, and a pair
|
|
812
|
+
that the language lists in `data.sounds.syllables.vowelPairs` is one syllable.
|
|
813
|
+
|
|
814
|
+
**The beat convention, in plain words:**
|
|
815
|
+
|
|
816
|
+
- Every word of two or more syllables has one beat, on its stressed syllable.
|
|
817
|
+
- A one-syllable noun, verb, adjective, numeral or name has a beat. A
|
|
818
|
+
one-syllable particle, preposition, conjunction, adverb or pronoun has none.
|
|
819
|
+
The lexicon entry's class decides, and a form that the language's rules derive
|
|
820
|
+
takes its word's class. A word whose entries differ in class is a beat that
|
|
821
|
+
may be left out.
|
|
822
|
+
- A one-syllable word the lexicon does not hold is a content word and has a
|
|
823
|
+
beat; the word check reports the word separately.
|
|
824
|
+
- A word of four or more syllables may take a second, lighter beat on its first
|
|
825
|
+
syllable where the line needs it, unless its stress is already there.
|
|
826
|
+
- The caesura is not written.
|
|
827
|
+
|
|
828
|
+
A line scans when its count can be the metre's, choosing second beats as
|
|
829
|
+
needed. A line that cannot is a warning at that line, giving the count without
|
|
830
|
+
the second beats and, in brackets, with all of them:
|
|
831
|
+
|
|
832
|
+
> ``this line has 4 beats (5 with secondary beats); the metre `hexameter` has 6``
|
|
833
|
+
|
|
834
|
+
**The check is author-side.** Readers see nothing of it: the rendered fence
|
|
835
|
+
carries `data-metre` with the metre's name and nothing a reader sees. A fence
|
|
836
|
+
without `scan=` is not counted. `scan=` is refused where it cannot mean
|
|
837
|
+
anything, each an error:
|
|
838
|
+
|
|
839
|
+
> `` `hexamter` is not a declared metre: `scan=` names the `name` of a `data.metres` entry of a `doc` note; did you mean `hexameter`? ``
|
|
840
|
+
|
|
841
|
+
> `` `scan=` counts beats by a language's stress rule: the fence needs a `lang=` ``
|
|
842
|
+
|
|
843
|
+
> ``the language `vyl` states no `data.sounds.stress`, which `scan=` counts beats by``
|
|
844
|
+
|
|
845
|
+
> ``the language `vyl` is not a configured language with a `note`, so it has no stress rule for `scan=` to count beats by``
|
|
846
|
+
|
|
847
|
+
> `` `scan=` counts the beats of one language's lines; a verse in columns sets a line in each of two ``
|
|
848
|
+
|
|
849
|
+
A repeated metre name is an error too:
|
|
850
|
+
|
|
851
|
+
> `` `data.metres[1].name` is `trimeter`, which this note declares twice; a metre's name is unique ``
|
|
852
|
+
|
|
853
|
+
## The core vocabulary
|
|
854
|
+
|
|
855
|
+
A setting can name the concepts every one of its languages has a word for, and
|
|
856
|
+
measure each language against them from data. Three keys carry it:
|
|
857
|
+
|
|
858
|
+
| Key | On | Meaning |
|
|
859
|
+
| ---------------------- | --------------- | ------------------------------------------------------------------------------------ |
|
|
860
|
+
| `data.concepts` | a `doc` note | The concept list: `{ id, gloss, group }` entries, in the order the report lists them |
|
|
861
|
+
| `data.core` | a language note | `true` where the language must cover the list |
|
|
862
|
+
| `data.words[].concept` | a word | The id of the concept the word serves, or a list of ids for a word serving several |
|
|
863
|
+
|
|
864
|
+
**The list lives in the same package as the words that use it.** An `id` is
|
|
865
|
+
lowercase letters, digits and `-`, unique in the package; `gloss` and `group`
|
|
866
|
+
are not blank. A word's `concept` that names no entry of a list is an error at
|
|
867
|
+
the id, with the nearest id offered:
|
|
868
|
+
|
|
869
|
+
> `` `smel-noun` is not a core concept; did you mean `smell-noun`? ``
|
|
870
|
+
|
|
871
|
+
A daughter language reads the words of its `data.family` chain as its own, so a
|
|
872
|
+
parent's tagged word covers the daughter's concept. `data.core` is not
|
|
873
|
+
inherited: each language that must cover the list states it.
|
|
874
|
+
|
|
875
|
+
`package-build core [--language <name>] [--json]` reports, for each language
|
|
876
|
+
that states `core: true`, the concepts it has no word for, grouped and counted;
|
|
877
|
+
`--language` reports one language by name, shortcode or reference whether or
|
|
878
|
+
not it states `core`, and `--json` serves an agent working through it. **A
|
|
879
|
+
missing concept is never a lint failure:** the report is the work list, and the
|
|
880
|
+
exit status stays 0.
|
|
881
|
+
|
|
882
|
+
## Rendering and delivery
|
|
883
|
+
|
|
884
|
+
One pre-pass rewrites marked text at the head of every target: the site, the
|
|
885
|
+
Foundry compile, the book and the preview. It wraps the converted run in the
|
|
886
|
+
face's class (or a generic-family class), gives it the `lang` from the language's
|
|
887
|
+
tag, and gives a block in a right-to-left face `dir="rtl"`. It never writes
|
|
888
|
+
`<bdo>`, `<bdi>` or a Unicode direction control, because Foundry's editor strips
|
|
889
|
+
the first two and a right-to-left face carries its direction in its code points.
|
|
890
|
+
A run converted for a right-to-left face is hidden from the site's search index.
|
|
891
|
+
|
|
892
|
+
| Target | What a marked run becomes |
|
|
893
|
+
| ------- | ------------------------------------------------------------------------------------------ |
|
|
894
|
+
| Site | `<span class="script hl-semaron-kuriale" lang="art-x-vyl" data-pagefind-ignore="true">` |
|
|
895
|
+
| Foundry | the same classes and `lang`, with the font stylesheet in the module's `styles` |
|
|
896
|
+
| Book | the text set in the face; a real language's tag sets hyphenation, an invented tag does not |
|
|
897
|
+
|
|
898
|
+
Readers install nothing. When a note uses a face, the fonts are served from the
|
|
899
|
+
package's own output: the site copies `fonts.css`, the WOFF2 files and the
|
|
900
|
+
licence to `fonts/heroiclands/<version>/` beside the pages and links them from
|
|
901
|
+
every page; Foundry stages the same files; the book adds the TrueType files to
|
|
902
|
+
the typesetter's font search path. A package that has not installed the fonts, or
|
|
903
|
+
whose notes set no text in a face, ships none of it.
|
|
904
|
+
|
|
905
|
+
## The commands
|
|
906
|
+
|
|
907
|
+
`package-build transliterate <map> [--lang <language>] [--font <slug>] [--hex] [text..]`
|
|
908
|
+
maps a passage exactly as the build maps a run marked `map=<map> lang=<language>
|
|
909
|
+
font=<slug>`. The text is the words given; `-` or none reads standard input.
|
|
910
|
+
`--font` is required when the mapping lists more than one face, and `--hex`
|
|
911
|
+
prints `U+XXXX` code points separated by spaces.
|
|
912
|
+
|
|
913
|
+
```console
|
|
914
|
+
$ package-build transliterate semaron --lang vyl --hex zaron lonak
|
|
915
|
+
U+F0246 U+F0248 U+F023F U+F023D U+F023C U+0020 U+F023A U+F023D U+F023C U+F0230 U+F0239
|
|
916
|
+
$ package-build transliterate semaron --hex zaron
|
|
917
|
+
U+F0246 U+F0230 U+F023F U+F023D U+F023C
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
The first run writes `zaron` by its exception, and the second, with no
|
|
921
|
+
`--lang`, spells it by the rows.
|
|
922
|
+
|
|
923
|
+
`package-build lexicon <language> --map <map> [--font <slug>] [--derived] [--json]`
|
|
924
|
+
lists every word of the language with its native form, tab-separated: the form,
|
|
925
|
+
the native form, `exception` or `rows`, the class and the gloss. `--derived`
|
|
926
|
+
adds the forms the language's rules derive, each with the word it comes from,
|
|
927
|
+
`--json` prints an array instead, and under a logographic map the third column
|
|
928
|
+
is `own`, `parts`, `none` or `ambiguous`.
|
|
929
|
+
|
|
930
|
+
```console
|
|
931
|
+
$ package-build lexicon vyl --map semaron | cut -f1,3-
|
|
932
|
+
zaron exception n an oath
|
|
933
|
+
lonak rows n a road
|
|
934
|
+
lokathen rows v to walk
|
|
935
|
+
alathos rows pron he, that one
|
|
936
|
+
thiruthrimar rows n a sworn witness
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
`package-build core [--language <name>] [--json]` reports the core vocabulary
|
|
940
|
+
(see [the core vocabulary](#the-core-vocabulary)).
|
|
941
|
+
|
|
942
|
+
## A worked example
|
|
943
|
+
|
|
944
|
+
This builds a small package from nothing: a language, a script, a couplet and a
|
|
945
|
+
poem. It is the guide's own test: every file below is written into a project and
|
|
946
|
+
linted, and the findings printed are the ones the lint reports. The mapping note
|
|
947
|
+
is the one from [mapping notes](#mapping-notes).
|
|
948
|
+
|
|
949
|
+
Install the fonts, then write the configuration. A package that declares
|
|
950
|
+
dependencies in its configuration fetches their indexes with
|
|
951
|
+
`package-build deps fetch` before it lints; the sample declares none.
|
|
952
|
+
|
|
953
|
+
Install the fonts, then write the configuration:
|
|
954
|
+
|
|
955
|
+
```bash
|
|
956
|
+
npm install --save-dev @heroiclands/fonts
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
**`package-build.config.yaml`**
|
|
960
|
+
|
|
961
|
+
```yaml
|
|
962
|
+
contentPackage: demo
|
|
963
|
+
packageKind: modules
|
|
964
|
+
compatibility:
|
|
965
|
+
minimum: "14.359"
|
|
966
|
+
stats:
|
|
967
|
+
lastModifiedBy: demobuilder0000
|
|
968
|
+
packs:
|
|
969
|
+
- { name: journals, label: Journals, type: JournalEntry, default: true }
|
|
970
|
+
languages:
|
|
971
|
+
vyl: { tag: art-x-vyl, note: skill-vylarilng }
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
The concepts and the metre the sample uses live on a `doc` note:
|
|
975
|
+
|
|
976
|
+
**`assets/content/Docs/Core_Concepts.md`**
|
|
977
|
+
|
|
978
|
+
```markdown
|
|
979
|
+
---
|
|
980
|
+
shortcode: coreconcepts
|
|
981
|
+
name: { full: Core Concepts }
|
|
982
|
+
type: doc
|
|
983
|
+
subType: reference
|
|
984
|
+
data:
|
|
985
|
+
concepts:
|
|
986
|
+
- { id: walk-verb, gloss: to walk, group: motion }
|
|
987
|
+
- { id: road-noun, gloss: a road, group: places }
|
|
988
|
+
- { id: oath-noun, gloss: an oath, group: law }
|
|
989
|
+
- { id: see-verb, gloss: to see, group: senses }
|
|
990
|
+
metres:
|
|
991
|
+
- { name: trimeter, beats: 3, kind: accentual }
|
|
992
|
+
---
|
|
993
|
+
|
|
994
|
+
The concepts every language of the sample setting has a word for, and the metres
|
|
995
|
+
its poems keep. This note is the guide's own sample and carries no canon beyond
|
|
996
|
+
what the guide's examples need to run.
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
The language note holds the dictionary, the grammar, the stress rule and the
|
|
1000
|
+
core flag:
|
|
1001
|
+
|
|
1002
|
+
**`assets/content/Skills/Vylari.md`**
|
|
1003
|
+
|
|
1004
|
+
```markdown
|
|
1005
|
+
---
|
|
1006
|
+
shortcode: vylarilng
|
|
1007
|
+
name: { full: Vylari Language }
|
|
1008
|
+
type: skill
|
|
1009
|
+
subType: language
|
|
1010
|
+
data:
|
|
1011
|
+
core: true
|
|
1012
|
+
fields:
|
|
1013
|
+
- { name: Law, holds: "Oaths, seals and roads." }
|
|
1014
|
+
affixes:
|
|
1015
|
+
- {
|
|
1016
|
+
form: "-andar",
|
|
1017
|
+
gloss: "doing it: the present participle",
|
|
1018
|
+
replaces: vowel,
|
|
1019
|
+
attachesTo: [v],
|
|
1020
|
+
}
|
|
1021
|
+
- { form: "-thos", gloss: "done, suffered: the past participle" }
|
|
1022
|
+
grammar:
|
|
1023
|
+
plural:
|
|
1024
|
+
- { ending: os, becomes: oi }
|
|
1025
|
+
- { ending: on, becomes: oi }
|
|
1026
|
+
- { ending: a, becomes: ai }
|
|
1027
|
+
- { ending: "", becomes: oi }
|
|
1028
|
+
verbs:
|
|
1029
|
+
replaces: then
|
|
1030
|
+
persons: { I: men, you: zen, heShe: zor, we: mar, youAll: zar, they: zoi }
|
|
1031
|
+
agreement:
|
|
1032
|
+
classes: [adj, pron]
|
|
1033
|
+
endings: [os, a, on]
|
|
1034
|
+
participles:
|
|
1035
|
+
root: [athen, ethen]
|
|
1036
|
+
affixes: ["-andar", "-thos"]
|
|
1037
|
+
sounds:
|
|
1038
|
+
stress: { two: first, longer: penultimate }
|
|
1039
|
+
syllables:
|
|
1040
|
+
vowelPairs: [ai, au]
|
|
1041
|
+
words:
|
|
1042
|
+
- form: zaron
|
|
1043
|
+
class: n
|
|
1044
|
+
field: Law
|
|
1045
|
+
gloss: an oath
|
|
1046
|
+
concept: oath-noun
|
|
1047
|
+
native:
|
|
1048
|
+
- { map: semaron, text: "" }
|
|
1049
|
+
- { form: lonak, class: n, field: Law, gloss: a road, concept: road-noun }
|
|
1050
|
+
- { form: lokathen, class: v, field: Law, gloss: to walk, concept: walk-verb }
|
|
1051
|
+
- { form: alathos, class: pron, field: Law, gloss: "he, that one" }
|
|
1052
|
+
---
|
|
1053
|
+
|
|
1054
|
+
The imperial tongue of the sample setting, written in the Semaron script and
|
|
1055
|
+
read aloud at its court. The lexicon here is a small sample made for the guide.
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
A note with a run. The couplet uses a word the lexicon does not hold:
|
|
1059
|
+
|
|
1060
|
+
**`assets/content/Lore/Oath_Road.md`**
|
|
1061
|
+
|
|
1062
|
+
```markdown
|
|
1063
|
+
---
|
|
1064
|
+
shortcode: oathroad
|
|
1065
|
+
name: { full: The Oath Road }
|
|
1066
|
+
type: lore
|
|
1067
|
+
---
|
|
1068
|
+
|
|
1069
|
+
The lintel over the door of the oath road is cut with a couplet, and the
|
|
1070
|
+
stonecutter set the couplet in the script of the court, so that every traveller
|
|
1071
|
+
could read it as the court reads it.
|
|
1072
|
+
|
|
1073
|
+
[Lokazor lonak thiruthrimar, lokamen zaron.]{lang=vyl font=semaron-kuriale map=semaron}
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
Linting reports the unknown word, at its first character:
|
|
1077
|
+
|
|
1078
|
+
```text
|
|
1079
|
+
assets/content/Lore/Oath_Road.md:11:16: error: `thiruthrimar` is not a word of the `vyl` lexicon, a registered name, or a regular form of one; coin it in the lexicon (or register the name) first
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
The word is a coinage. It goes into the dictionary before it is used, so the
|
|
1083
|
+
language note gains an entry:
|
|
1084
|
+
|
|
1085
|
+
**`assets/content/Skills/Vylari.md`**
|
|
1086
|
+
|
|
1087
|
+
```markdown
|
|
1088
|
+
---
|
|
1089
|
+
shortcode: vylarilng
|
|
1090
|
+
name: { full: Vylari Language }
|
|
1091
|
+
type: skill
|
|
1092
|
+
subType: language
|
|
1093
|
+
data:
|
|
1094
|
+
core: true
|
|
1095
|
+
fields:
|
|
1096
|
+
- { name: Law, holds: "Oaths, seals and roads." }
|
|
1097
|
+
affixes:
|
|
1098
|
+
- {
|
|
1099
|
+
form: "-andar",
|
|
1100
|
+
gloss: "doing it: the present participle",
|
|
1101
|
+
replaces: vowel,
|
|
1102
|
+
attachesTo: [v],
|
|
1103
|
+
}
|
|
1104
|
+
- { form: "-thos", gloss: "done, suffered: the past participle" }
|
|
1105
|
+
grammar:
|
|
1106
|
+
plural:
|
|
1107
|
+
- { ending: os, becomes: oi }
|
|
1108
|
+
- { ending: on, becomes: oi }
|
|
1109
|
+
- { ending: a, becomes: ai }
|
|
1110
|
+
- { ending: "", becomes: oi }
|
|
1111
|
+
verbs:
|
|
1112
|
+
replaces: then
|
|
1113
|
+
persons: { I: men, you: zen, heShe: zor, we: mar, youAll: zar, they: zoi }
|
|
1114
|
+
agreement:
|
|
1115
|
+
classes: [adj, pron]
|
|
1116
|
+
endings: [os, a, on]
|
|
1117
|
+
participles:
|
|
1118
|
+
root: [athen, ethen]
|
|
1119
|
+
affixes: ["-andar", "-thos"]
|
|
1120
|
+
sounds:
|
|
1121
|
+
stress: { two: first, longer: penultimate }
|
|
1122
|
+
syllables:
|
|
1123
|
+
vowelPairs: [ai, au]
|
|
1124
|
+
words:
|
|
1125
|
+
- form: zaron
|
|
1126
|
+
class: n
|
|
1127
|
+
field: Law
|
|
1128
|
+
gloss: an oath
|
|
1129
|
+
concept: oath-noun
|
|
1130
|
+
native:
|
|
1131
|
+
- { map: semaron, text: "" }
|
|
1132
|
+
- { form: lonak, class: n, field: Law, gloss: a road, concept: road-noun }
|
|
1133
|
+
- { form: lokathen, class: v, field: Law, gloss: to walk, concept: walk-verb }
|
|
1134
|
+
- { form: alathos, class: pron, field: Law, gloss: "he, that one" }
|
|
1135
|
+
- { form: thiruthrimar, class: n, field: Law, gloss: a sworn witness }
|
|
1136
|
+
---
|
|
1137
|
+
|
|
1138
|
+
The imperial tongue of the sample setting, written in the Semaron script and
|
|
1139
|
+
read aloud at its court. The lexicon here is a small sample made for the guide.
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
The lint is now clean, and the conversion can be read. `package-build transliterate`
|
|
1143
|
+
prints the code points the build writes for the couplet:
|
|
1144
|
+
|
|
1145
|
+
```console
|
|
1146
|
+
$ package-build transliterate semaron --lang vyl --hex "Lokazor lonak, lokamen zaron."
|
|
1147
|
+
U+F020A U+F023D U+F0239 U+F0230 U+F0246 U+F023D U+F023F U+0020 U+F023A U+F023D U+F023C U+F0230 U+F0239 U+F0268 U+0020 U+F023A U+F023D U+F0239 U+F0230 U+F023B U+F0233 U+F023C U+0020 U+F0246 U+F0248 U+F023F U+F023D U+F023C U+F0268
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
The site sets the run as
|
|
1151
|
+
|
|
1152
|
+
```html
|
|
1153
|
+
<span class="script hl-semaron-kuriale" lang="art-x-vyl" data-pagefind-ignore="true"
|
|
1154
|
+
> </span
|
|
1155
|
+
>
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
where the characters are the code points above: `Lokazor` begins with the
|
|
1159
|
+
capital `L` of the rows, `zaron` is the exception's long vowel, and the comma
|
|
1160
|
+
and full stop are the script's one point.
|
|
1161
|
+
|
|
1162
|
+
A poem in columns and a poem with its metre checked sit on one note. Both parse
|
|
1163
|
+
with no finding: the first sets Vylari in Semaron beside the English over the
|
|
1164
|
+
Vylari in roman, and the second's lines each carry three beats.
|
|
1165
|
+
|
|
1166
|
+
**`assets/content/Lore/Walking.md`**
|
|
1167
|
+
|
|
1168
|
+
````markdown
|
|
1169
|
+
---
|
|
1170
|
+
shortcode: walking
|
|
1171
|
+
name: { full: The Walking }
|
|
1172
|
+
type: lore
|
|
1173
|
+
---
|
|
1174
|
+
|
|
1175
|
+
The walking of the oath road is sung in two settings. The first sets the poem
|
|
1176
|
+
beside its translation, and the second keeps the metre that the court keeps, so
|
|
1177
|
+
that a line with the wrong count is reported to the author who wrote it.
|
|
1178
|
+
|
|
1179
|
+
```verse {numstep=1 lang=vyl col1=vyl/semaron/semaron-kuriale col2=en:vyl}
|
|
1180
|
+
[Lokazor lonak zaron.]{lang=vyl}
|
|
1181
|
+
[He walks the oath road.]{lang=en}
|
|
1182
|
+
|
|
1183
|
+
[Lokamen lonak zaron.]{lang=vyl}
|
|
1184
|
+
[I walk the oath road.]{lang=en}
|
|
1185
|
+
|
|
1186
|
+
***
|
|
1187
|
+
|
|
1188
|
+
alathos lokazor.
|
|
1189
|
+
[That one walks.]{lang=en}
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
```verse {lang=vyl scan=trimeter}
|
|
1193
|
+
Lokazor lonak zaron.
|
|
1194
|
+
Lokamen lonak zaron.
|
|
1195
|
+
```
|
|
1196
|
+
````
|
|
1197
|
+
|
|
1198
|
+
A script note gives Semaron its emphasis convention, and a run with double stars then
|
|
1199
|
+
sets them in red:
|
|
1200
|
+
|
|
1201
|
+
**`assets/content/Skills/Scripts/Semaron.md`**
|
|
1202
|
+
|
|
1203
|
+
```markdown
|
|
1204
|
+
---
|
|
1205
|
+
shortcode: semaronscrpt
|
|
1206
|
+
name: { full: Semaron Script }
|
|
1207
|
+
type: skill
|
|
1208
|
+
subType: script
|
|
1209
|
+
data:
|
|
1210
|
+
script:
|
|
1211
|
+
fonts: [semaron-kuriale]
|
|
1212
|
+
emphasis: rubric
|
|
1213
|
+
---
|
|
1214
|
+
|
|
1215
|
+
The Semaron script, as the sample setting writes it. It marks a stressed word in
|
|
1216
|
+
red ink, the rubric of its scribes, and the guide's emphasis example depends on it.
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
**`assets/content/Lore/Marked_Door.md`**
|
|
1220
|
+
|
|
1221
|
+
```markdown
|
|
1222
|
+
---
|
|
1223
|
+
shortcode: markeddoor
|
|
1224
|
+
name: { full: The Marked Door }
|
|
1225
|
+
type: lore
|
|
1226
|
+
---
|
|
1227
|
+
|
|
1228
|
+
The door is marked with the same words as the lintel, and the scribe stressed the
|
|
1229
|
+
second word so that no one would read it as the first, which is how the script
|
|
1230
|
+
marks a stressed word.
|
|
1231
|
+
|
|
1232
|
+
[Lokazor **lonak**, zaron.]{lang=vyl font=semaron-kuriale map=semaron}
|
|
1233
|
+
```
|
|
1234
|
+
|
|
1235
|
+
Finally, the core report lists what the language still lacks:
|
|
1236
|
+
|
|
1237
|
+
```console
|
|
1238
|
+
$ package-build core --language vylarilng
|
|
1239
|
+
Vylari Language (skill-vylarilng): 1 of 4 core concepts have no word
|
|
1240
|
+
senses: 1 of 1
|
|
1241
|
+
see-verb to see
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
Everything in this package comes from the guide. A new script follows the same
|
|
1245
|
+
steps: a mapping note for its face, `languages` entries for the languages
|
|
1246
|
+
written in it, a language note with the dictionary, and runs marked with the
|
|
1247
|
+
three keys.
|