wccm 0.2.3__tar.gz

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.
wccm-0.2.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 B1narymask
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
wccm-0.2.3/PKG-INFO ADDED
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: wccm
3
+ Version: 0.2.3
4
+ Summary: Compact command-line conlang manager
5
+ Author: Wernasho
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ Wer's Compact Conlang Manager, or WCCM, is a simple command-line tool designed to make conlanging ever so slightly faster and easier by converting a simple, customizeable syntax into clean and readable conlang dictionaries.
12
+
13
+ I built this because spreadsheets had too much visual clutter and other existing tools were really overkill.
14
+ All you need to do is type your properties with shorthands you can customize, and you'll receive a nicely formatted text file.
15
+
16
+ For example, this:
17
+
18
+ ```
19
+ Agná
20
+ $agˈna
21
+ %noun
22
+ #animals
23
+ ?bird
24
+ ~Masculine
25
+ +ágnaya
26
+ ;gen :ágnand
27
+ ```
28
+
29
+ Turns into this:
30
+ ```
31
+ Agná
32
+ \[agˈna] bird, plural: ágnaya
33
+ Gender: Masculine
34
+ POS: Noun
35
+ Semantic field: animals
36
+ Cases:
37
+ gen: ágnand
38
+ ```
39
+ ## Installation
40
+
41
+ 1. install Python 3.6 or newer from [python.org](https://python.org)
42
+ 2. download or clone this repository
43
+ 3. no additional packages are needed, uses only python standard library!
44
+
45
+ # Usage:
46
+ Open up your console/terminal inside the wccm folder, and run this command:
47
+ ```bash
48
+ py wccm.py file.wccm
49
+ ```
50
+
51
+ Outputs to `Lexicon.txt`
52
+
53
+ # Syntax
54
+
55
+ WCCM uses symbols to represent different properties. Their order is irrelevant, as long as the plain word is always first.
56
+
57
+ ## Lexicon
58
+ (Lexicon-related syntax goes in `.wccm` files).
59
+
60
+ | Symbol | Field | Example |
61
+ | ------------ | --------------------- | -------------------------- |
62
+ | (None) | Word | **Kat** |
63
+ | `$` | IPA | **$kæt** |
64
+ | `#` | Semantic field | **\#animal** |
65
+ | `~` | Gender | **~M** |
66
+ | `?` | Translation | **?Cat** |
67
+ | `+` | Plural form(s) | **+Cats** |
68
+ | `;` and `:` | Case name / case form | **;gen :cat's** |
69
+ | `=` | Synonym(s) | **=feline** |
70
+ | `!` | Antonym(s) | **!dog** |
71
+ | `%` | Part of speech | **%noun** |
72
+ | `*` | Etymology | **\*from 'kaltnaen' ** |
73
+ | `\|` and `/` | Conjugations | **\|3rd sg present /does** |
74
+ | `@` and `:` | Custom | **@class :animte** |
75
+ ## Inventory
76
+ (Inventory-related information goes in `.cmi` files).
77
+
78
+ | Symbol | Field | Example |
79
+ | ------ | --------- | ------------ |
80
+ | `.` | consonant | **.tH** |
81
+ | `,` | vowel | **,3** |
82
+ | `^` | Tone | **\^rising** |
83
+
84
+ Don't like this set of symbols? That's completely fine! You can edit them anytime by going into `config.json`.
85
+
86
+ ## IPA
87
+ I know that typing IPA symbols can be tedious if you don't have the tools, which is why I implemented a function to let you map a character to an IPA sound, to make writing transcriptions easier!
88
+ # Configuration
89
+
90
+ `config.json` lets you customize:
91
+ - what each symbol means (which property it represents)
92
+ - IPA character mapping (e.g., `:` -> `ː`)
93
+ - default output file
94
+
95
+ ```json
96
+ {
97
+ "ipa": {
98
+ "S": "ʃ",
99
+ "T": "θ",
100
+ "R": "ɾ",
101
+ "B": "β",
102
+ "D": "ð",
103
+ "N": "ŋ",
104
+ "J": "ʲ",
105
+ "Z": "ʒ",
106
+ ":": "ː",
107
+ "'": "ˈ",
108
+ "ny": "ɲ",
109
+ "W": "ʷ",
110
+ "H": "ʰ",
111
+ "A": "ɑ",
112
+ "E": "ə",
113
+ "I": "ɪ",
114
+ "3": "ɛ",
115
+ "O": "ɔ",
116
+ "U": "ʊ",
117
+ "^": "ʌ",
118
+ "X": "χ"
119
+ },
120
+ "props": {
121
+ "$": "ipa",
122
+ "#": "field",
123
+ "%": "pos",
124
+ "_": "comment",
125
+ "~": "gender",
126
+ "=": "synonym",
127
+ "!": "antonym",
128
+ "+": "plural",
129
+ "?": "meaning",
130
+ "*": "etymology",
131
+ ";": "case",
132
+ "|": "conjugations",
133
+ "@": "custom"
134
+ },
135
+ "inv": {
136
+ ".": "consonant",
137
+ ",": "vowel",
138
+ "^": "tone"
139
+ },
140
+ "prefs": {
141
+ "output": {
142
+ "defaultFileName": "lexicon",
143
+ "defaultFormat": ".txt"
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ For the IPA replacement mapping, the character on the left is the character that the program will replace. So, essentially, if your IPA is "SaTaZ", with the default configurations (the ones showed above) it would turn into "ʃaθaʒ". You can add/remove as many as you want! (As long as you don't map 1 character to 2 symbols or use digraphs).
150
+
151
+ Same goes for the properties, although it is very important that you do **not** alter the keywords, otherwise the tool will break.
152
+
153
+ As you might've guessed, you can also choose the default name and format of the output file! The name can be anything you want, and the file extension can be either `.txt` or `.md`. A `lexicon.json` file is always automatically generated, which is why `.json` isn't an option in preferences.
154
+ ## Limitations
155
+
156
+ Currently, the case symbols (`;` and `:`) can't be customized, as well as the conjugation symbols (`|` and `/`).
157
+ If you ever want to remap a symbol, as said before, you're allowed (and encouraged) to do so! However, it is very important that you don't map `\` to anything. Since i don't want to confuse you with tech talk, basically, `\` is a special character and if you try to use it for mapping the configuration file is going to break.
158
+
159
+ Other than that, you should be able to change pretty much anything!
160
+
161
+ # About
162
+
163
+ WCCM started as just a little personal tool I developed because I'm stubborn and don't like any of the tools that already exist, and now I'm sharing it in case someone finds it useful as well.
164
+
165
+ # Feedback is appreciated!
166
+
167
+ This is my first time actually finishing and sharing a project, so I'd genuinely *love* to hear suggestions or ideas for future versions, as well as bug reports and other stuff like that.
168
+ You can contact me pretty much any time in [my twitter (I'm not calling it 'X')](https://x.com/wernasho)
wccm-0.2.3/README.md ADDED
@@ -0,0 +1,158 @@
1
+ Wer's Compact Conlang Manager, or WCCM, is a simple command-line tool designed to make conlanging ever so slightly faster and easier by converting a simple, customizeable syntax into clean and readable conlang dictionaries.
2
+
3
+ I built this because spreadsheets had too much visual clutter and other existing tools were really overkill.
4
+ All you need to do is type your properties with shorthands you can customize, and you'll receive a nicely formatted text file.
5
+
6
+ For example, this:
7
+
8
+ ```
9
+ Agná
10
+ $agˈna
11
+ %noun
12
+ #animals
13
+ ?bird
14
+ ~Masculine
15
+ +ágnaya
16
+ ;gen :ágnand
17
+ ```
18
+
19
+ Turns into this:
20
+ ```
21
+ Agná
22
+ \[agˈna] bird, plural: ágnaya
23
+ Gender: Masculine
24
+ POS: Noun
25
+ Semantic field: animals
26
+ Cases:
27
+ gen: ágnand
28
+ ```
29
+ ## Installation
30
+
31
+ 1. install Python 3.6 or newer from [python.org](https://python.org)
32
+ 2. download or clone this repository
33
+ 3. no additional packages are needed, uses only python standard library!
34
+
35
+ # Usage:
36
+ Open up your console/terminal inside the wccm folder, and run this command:
37
+ ```bash
38
+ py wccm.py file.wccm
39
+ ```
40
+
41
+ Outputs to `Lexicon.txt`
42
+
43
+ # Syntax
44
+
45
+ WCCM uses symbols to represent different properties. Their order is irrelevant, as long as the plain word is always first.
46
+
47
+ ## Lexicon
48
+ (Lexicon-related syntax goes in `.wccm` files).
49
+
50
+ | Symbol | Field | Example |
51
+ | ------------ | --------------------- | -------------------------- |
52
+ | (None) | Word | **Kat** |
53
+ | `$` | IPA | **$kæt** |
54
+ | `#` | Semantic field | **\#animal** |
55
+ | `~` | Gender | **~M** |
56
+ | `?` | Translation | **?Cat** |
57
+ | `+` | Plural form(s) | **+Cats** |
58
+ | `;` and `:` | Case name / case form | **;gen :cat's** |
59
+ | `=` | Synonym(s) | **=feline** |
60
+ | `!` | Antonym(s) | **!dog** |
61
+ | `%` | Part of speech | **%noun** |
62
+ | `*` | Etymology | **\*from 'kaltnaen' ** |
63
+ | `\|` and `/` | Conjugations | **\|3rd sg present /does** |
64
+ | `@` and `:` | Custom | **@class :animte** |
65
+ ## Inventory
66
+ (Inventory-related information goes in `.cmi` files).
67
+
68
+ | Symbol | Field | Example |
69
+ | ------ | --------- | ------------ |
70
+ | `.` | consonant | **.tH** |
71
+ | `,` | vowel | **,3** |
72
+ | `^` | Tone | **\^rising** |
73
+
74
+ Don't like this set of symbols? That's completely fine! You can edit them anytime by going into `config.json`.
75
+
76
+ ## IPA
77
+ I know that typing IPA symbols can be tedious if you don't have the tools, which is why I implemented a function to let you map a character to an IPA sound, to make writing transcriptions easier!
78
+ # Configuration
79
+
80
+ `config.json` lets you customize:
81
+ - what each symbol means (which property it represents)
82
+ - IPA character mapping (e.g., `:` -> `ː`)
83
+ - default output file
84
+
85
+ ```json
86
+ {
87
+ "ipa": {
88
+ "S": "ʃ",
89
+ "T": "θ",
90
+ "R": "ɾ",
91
+ "B": "β",
92
+ "D": "ð",
93
+ "N": "ŋ",
94
+ "J": "ʲ",
95
+ "Z": "ʒ",
96
+ ":": "ː",
97
+ "'": "ˈ",
98
+ "ny": "ɲ",
99
+ "W": "ʷ",
100
+ "H": "ʰ",
101
+ "A": "ɑ",
102
+ "E": "ə",
103
+ "I": "ɪ",
104
+ "3": "ɛ",
105
+ "O": "ɔ",
106
+ "U": "ʊ",
107
+ "^": "ʌ",
108
+ "X": "χ"
109
+ },
110
+ "props": {
111
+ "$": "ipa",
112
+ "#": "field",
113
+ "%": "pos",
114
+ "_": "comment",
115
+ "~": "gender",
116
+ "=": "synonym",
117
+ "!": "antonym",
118
+ "+": "plural",
119
+ "?": "meaning",
120
+ "*": "etymology",
121
+ ";": "case",
122
+ "|": "conjugations",
123
+ "@": "custom"
124
+ },
125
+ "inv": {
126
+ ".": "consonant",
127
+ ",": "vowel",
128
+ "^": "tone"
129
+ },
130
+ "prefs": {
131
+ "output": {
132
+ "defaultFileName": "lexicon",
133
+ "defaultFormat": ".txt"
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ For the IPA replacement mapping, the character on the left is the character that the program will replace. So, essentially, if your IPA is "SaTaZ", with the default configurations (the ones showed above) it would turn into "ʃaθaʒ". You can add/remove as many as you want! (As long as you don't map 1 character to 2 symbols or use digraphs).
140
+
141
+ Same goes for the properties, although it is very important that you do **not** alter the keywords, otherwise the tool will break.
142
+
143
+ As you might've guessed, you can also choose the default name and format of the output file! The name can be anything you want, and the file extension can be either `.txt` or `.md`. A `lexicon.json` file is always automatically generated, which is why `.json` isn't an option in preferences.
144
+ ## Limitations
145
+
146
+ Currently, the case symbols (`;` and `:`) can't be customized, as well as the conjugation symbols (`|` and `/`).
147
+ If you ever want to remap a symbol, as said before, you're allowed (and encouraged) to do so! However, it is very important that you don't map `\` to anything. Since i don't want to confuse you with tech talk, basically, `\` is a special character and if you try to use it for mapping the configuration file is going to break.
148
+
149
+ Other than that, you should be able to change pretty much anything!
150
+
151
+ # About
152
+
153
+ WCCM started as just a little personal tool I developed because I'm stubborn and don't like any of the tools that already exist, and now I'm sharing it in case someone finds it useful as well.
154
+
155
+ # Feedback is appreciated!
156
+
157
+ This is my first time actually finishing and sharing a project, so I'd genuinely *love* to hear suggestions or ideas for future versions, as well as bug reports and other stuff like that.
158
+ You can contact me pretty much any time in [my twitter (I'm not calling it 'X')](https://x.com/wernasho)
@@ -0,0 +1,17 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wccm"
7
+ version = "0.2.3"
8
+ description = "Compact command-line conlang manager"
9
+ authors = [{ name = "Wernasho" }]
10
+ readme = "README.md"
11
+ requires-python = ">=3.8"
12
+
13
+ [project.scripts]
14
+ wccm = "wccm.wccm:main"
15
+
16
+ [tool.setuptools.package-data]
17
+ wccm = ["*.json"]
wccm-0.2.3/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,52 @@
1
+ {
2
+ "ipa": {
3
+ "S": "ʃ",
4
+ "R": "ɾ",
5
+ "B": "β",
6
+ "D": "ð",
7
+ "N": "ŋ",
8
+ "J": "ʲ",
9
+ "Z": "ʒ",
10
+ ":": "ː",
11
+ "'": "ˈ",
12
+ "ny": "ɲ",
13
+ "W": "ʷ",
14
+ "H": "ʰ",
15
+ "A": "ɑ",
16
+ "T": "θ",
17
+ "E": "ə",
18
+ "I": "ɪ",
19
+ "3": "ɛ",
20
+ "O": "ɔ",
21
+ "U": "ʊ",
22
+ "^": "ʌ",
23
+ "X": "χ"
24
+ },
25
+ "props": {
26
+ "$": "ipa",
27
+ "#": "field",
28
+ "%": "pos",
29
+ "//": "comment",
30
+ "~": "gender",
31
+ "=": "synonym",
32
+ "!": "antonym",
33
+ "+": "plural",
34
+ "?": "meaning",
35
+ "*": "etymology",
36
+ ";": "case",
37
+ "|": "conjugations",
38
+ "@": "custom"
39
+ },
40
+ "inv": {
41
+ ".": "consonant",
42
+ ",": "vowel",
43
+ "^": "tone",
44
+ "-": "romanization"
45
+ },
46
+ "prefs": {
47
+ "output": {
48
+ "defaultFileName": "lexicon",
49
+ "defaultFormat": ".txt"
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,161 @@
1
+ from .storage import load
2
+
3
+ def Format(entry):
4
+ text = f'{entry["word"]}'
5
+
6
+ if "ipa" in entry:
7
+ text += f' [{entry["ipa"]}]\n'
8
+
9
+ if "meaning" in entry:
10
+ if len(entry["meaning"]) >= 2:
11
+ text+= "Meanings:\n"
12
+ for m in entry["meaning"]:
13
+ text += f' - {m}\n'
14
+ else:
15
+ text+=f"Meaning: {entry["meaning"][0]}\n"
16
+
17
+ if "plural" in entry:
18
+ text += f'plural: "{entry["plural"]}"'
19
+
20
+ text += '\n'
21
+
22
+ if "gender" in entry:
23
+ text += f'Gender: {entry["gender"]}\n'
24
+
25
+ if "synonym" in entry:
26
+ text += "Synonyms: \n"
27
+ for syn in entry["synonym"]:
28
+ text += f" - {syn}\n"
29
+
30
+ if "antonym" in entry:
31
+ text += "Antonyms: \n"
32
+ for ant in entry["antonym"]:
33
+ text += f" - {ant}\n"
34
+
35
+ if "pos" in entry:
36
+ if len(entry["pos"]) == 2:
37
+ text+="Parts of speech:\n"
38
+ text+=f" {entry["pos"][0]}, {entry["pos"][1]}\n"
39
+ elif len(entry["pos"]) == 1:
40
+ text += f'Part Of Speech:'
41
+ text+=f" {entry["pos"]}"
42
+ else:
43
+ text+="Parts of speech:\n"
44
+ for pos in entry["pos"]:
45
+ text+=f" {pos}"
46
+
47
+ if "field" in entry:
48
+ text += f'Semantic field: {entry["field"]}\n'
49
+
50
+ if "cases" in entry:
51
+ text += 'Cases:\n'
52
+ for case, form in entry["cases"].items():
53
+ text += f' - {case}: {form}\n'
54
+
55
+ if "conjugations" in entry:
56
+ text += 'Conjugations:\n'
57
+ for conjugation, form in entry["conjugations"].items():
58
+ text+=f" - {conjugation}: {form}\n"
59
+
60
+ if "custom" in entry:
61
+ for custom, prop in entry["custom"].items():
62
+ text+=f"{custom}: {prop}"
63
+
64
+ print("Done! formatting complete!")
65
+ return text
66
+
67
+ def markdown(entry):
68
+ text = f'{entry["word"]}'
69
+
70
+ if "ipa" in entry:
71
+ text += f' *\\[{entry["ipa"]}]*'
72
+ text += '\n'
73
+ if "meaning" in entry:
74
+ if len(entry["meaning"]) >= 2:
75
+ text+= "**Meanings:**\n"
76
+ for m in entry["meaning"]:
77
+ text += f' - *{m}*\n'
78
+ else:
79
+ text+=f"**Meaning:** {entry["meaning"][0]}"
80
+
81
+ if "plural" in entry:
82
+ text += f'plural: "{entry["plural"]}"'
83
+
84
+ text += '\n'
85
+
86
+ if "gender" in entry:
87
+ text += f'**Gender:** {entry["gender"]}\n'
88
+
89
+ if "synonym" in entry:
90
+ text += "**Synonyms:** \n"
91
+ for syn in entry["synonym"]:
92
+ text += f" - *{syn}*\n"
93
+
94
+ if "antonym" in entry:
95
+ text += "**Antonyms:** \n"
96
+ for ant in entry["antonym"]:
97
+ text += f" - *{ant}*\n"
98
+
99
+ if "pos" in entry:
100
+ text += f'**Part(s) Of Speech:**'
101
+ if len(entry["pos"]) == 2:
102
+ text+=f" {entry["pos"][0]}, {entry["pos"][1]}"
103
+ elif len(entry["pos"]) == 1:
104
+ text+=f" {entry["pos"]}"
105
+ else:
106
+ for pos in entry["pos"]:
107
+ text+=f" {pos},"
108
+ text+="\n"
109
+
110
+ if "field" in entry:
111
+ text += f'**Semantic field:** \\{entry["field"]}\n'
112
+
113
+ if "cases" in entry:
114
+ text += '**Cases:**\n'
115
+ for case, form in entry["cases"].items():
116
+ text += f' - **{case}:** {form}\n'
117
+
118
+ if "conjugations" in entry:
119
+ text += '**Conjugations:**\n'
120
+ for conjugation, form in entry["conjugations"].items():
121
+ text+=f" - **{conjugation}:** {form}\n"
122
+
123
+ if "custom" in entry:
124
+ for custom, prop in entry["custom"].items():
125
+ text+=f"- **{custom}:** {prop}"
126
+ # print("Done! formatting complete!")
127
+ return text
128
+
129
+ def inv_f(dic):
130
+ text = ""
131
+ if "consonant" in dic:
132
+ text += "Consonants: \n"
133
+ for sound in dic["consonant"]:
134
+ text+= f" - {sound}\n"
135
+
136
+ if "vowel" in dic:
137
+ text += "Vowels: \n"
138
+ for sound in dic["vowel"]:
139
+ text += f" - {sound}\n"
140
+
141
+ if "tone" in dic:
142
+ text+= "Tones: "
143
+ for tone in dic["tone"]:
144
+ text +=f"{tone} "
145
+
146
+ if "romanization" in dic:
147
+ text += "Romanization:\n"
148
+ for ipa_symbol, roman in dic["romanization"].items():
149
+ text += f" - {ipa_symbol} → {roman}\n"
150
+ # print("Done! formatting complete!")
151
+ return text
152
+
153
+ if __name__ == '__main__':
154
+ entries = load()
155
+
156
+ T = ""
157
+ for entry in entries:
158
+ T += Format(entry) + "\n"
159
+
160
+ with open("lexicon.txt", "w", encoding="utf-8") as f:
161
+ f.write(T)
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,52 @@
1
+ from .parse import ipa_replace
2
+ from .storage import config_load
3
+
4
+ config = config_load() # loads configurations from config.json
5
+
6
+ # function that parses the custom inventory syntax
7
+ def parse_inv(text, config):
8
+ props = config["inv"]
9
+ ipa = config["ipa"]
10
+
11
+ lines = text.splitlines()
12
+ inventory = {}
13
+ inventory["romanization"] = {}
14
+ inventory["vowel"] = []
15
+ inventory["consonant"] = []
16
+ inventory["tone"] = []
17
+ for line in lines:
18
+ line = line.strip()
19
+ if not line:
20
+ continue
21
+ symbol = line[0]
22
+
23
+ if symbol in props:
24
+ value = line[1:].strip()
25
+ prop_name = props[symbol]
26
+
27
+ key = prop_name
28
+ inventory[key]
29
+ if key == "romanization":
30
+ value = line[1:].strip()
31
+ try:
32
+ roman, ipa_symbol = value.split(":", 1)
33
+ ipa_symbol = ipa_symbol.strip()
34
+ ipa_symbol = ipa_replace(ipa_symbol, ipa)
35
+ roman = roman.strip()
36
+
37
+ if ipa_symbol and roman:
38
+ inventory["romanization"][roman] = ipa_symbol
39
+
40
+ except ValueError:
41
+ raise ValueError(f"Invalid romanization data: {line}")
42
+
43
+ elif key == "vowel" or key == "consonant" or key == "tone":
44
+ inventory[key].append(ipa_replace(value, ipa))
45
+
46
+ elif key not in inventory:
47
+ inventory[key] = []
48
+ if type(key) == list:
49
+ pass
50
+ #save(inventory, "info.json") # saves entries for... why do I save? Oh whatever it's already there.
51
+ print("Done! parse complete!")
52
+ return inventory
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,130 @@
1
+ import sys
2
+ from .storage import config_load
3
+ x = sys.argv[1]
4
+ settings = config_load()
5
+ def ipa_replace(text, config):
6
+ result = ""
7
+ i = 0
8
+ keys = sorted(config.keys(), key=len, reverse=True)
9
+ while i < len(text):
10
+ matched = False
11
+ for k in keys:
12
+ if text.startswith(k, i):
13
+ result += config[k]
14
+ i += len(k)
15
+ matched = True
16
+ break
17
+ if not matched:
18
+ result += text[i]
19
+ i += 1
20
+ return result
21
+
22
+ def LISTadd(entry, key, val):
23
+ if key not in entry:
24
+ entry[key] = []
25
+ entry[key].append(val)
26
+
27
+
28
+ def parse(name, text, config):
29
+ if not name.endswith(".wccm"):
30
+ print("Error: please use a .wccm file.")
31
+ exit()
32
+
33
+ props = config["props"]
34
+ IPA = config["ipa"]
35
+ symbol = sorted(props.keys(), key=len, reverse=True)
36
+ lines = text.splitlines()
37
+ entries = []
38
+ current = None
39
+
40
+ for line in lines:
41
+ line = line.strip()
42
+ if not line:
43
+ continue
44
+
45
+ # try to match any symbol at the start of the line
46
+ matched_symbol = None
47
+ for s in symbol:
48
+ if line.startswith(s):
49
+ matched_symbol = s
50
+ break
51
+
52
+ if matched_symbol:
53
+ value = line[len(matched_symbol):].strip()
54
+ prop_name = props[matched_symbol]
55
+
56
+ # check the first character of the line is mapped to anything
57
+ #if symbol in props:
58
+ # value = line[1:].strip()
59
+ # prop_name = props[symbol]
60
+
61
+ if current is None:
62
+ current = {}
63
+
64
+ if prop_name == "ipa":
65
+ current["ipa_raw"] = value
66
+ current["ipa"] = ipa_replace(value, IPA) # IPA mapping thing
67
+
68
+ elif prop_name == "field":
69
+ LISTadd(current, "field", value)
70
+ elif prop_name == "gender":
71
+ current["gender"] = value
72
+ elif prop_name == "pos":
73
+ LISTadd(current, "pos", value)
74
+ elif prop_name == "meaning":
75
+ LISTadd(current, "meaning", value)
76
+ elif prop_name == "plural":
77
+ current["plural"] = value
78
+ elif prop_name == "synonym":
79
+ LISTadd(current, "synonym", value)
80
+ elif prop_name == "antonym":
81
+ LISTadd(current, "antonym", value)
82
+ elif prop_name == "etymology":
83
+ current["etymology"] = value
84
+
85
+ # special case for grammatical cases (using ';')
86
+ elif prop_name == "cases":
87
+ case_, form = value.split(":", 1)
88
+ case_ = case_.strip()
89
+ form = form.strip()
90
+
91
+ if not case_ or not form:
92
+ raise ValueError(f"Invalid case data: {value}")
93
+
94
+ if "cases" not in current:
95
+ current["cases"] = {}
96
+ current["cases"][case_] = form
97
+
98
+ # special case 2, using '|' for conjugations
99
+ elif prop_name == "conjugations":
100
+ conjugation, form = value.split("/", 1)
101
+ conjugation = conjugation.strip()
102
+ form = form.strip()
103
+
104
+ if "conjugations" not in current:
105
+ current["conjugations"] = {}
106
+ current["conjugations"][conjugation] = form
107
+
108
+ if not conjugation or not form:
109
+ raise ValueError(f"Invalid conjugation data: {value}")
110
+
111
+ # special case 3: custom properties
112
+ elif prop_name == "custom":
113
+ custom, val = value.split(":", 1)
114
+ custom = custom.strip()
115
+ val = val.strip()
116
+
117
+ if "custom" not in current:
118
+ current["custom"] = {}
119
+ current["custom"][custom] = val
120
+ elif prop_name == "comment": continue
121
+ else:
122
+ # No property symbol found -> New word
123
+ if current:
124
+ entries.append(current)
125
+ current = {"word": line}
126
+
127
+ if current:
128
+ entries.append(current)
129
+
130
+ return entries
@@ -0,0 +1,12 @@
1
+ import json
2
+ import importlib.resources
3
+ def save(data, file="lexicon.json"):
4
+ with importlib.resources.open_text("wccm", file or "lexicon.json") as f:
5
+ json.dump(data, f, indent=2, ensure_ascii=False)
6
+ def load():
7
+ with importlib.resources.open_text("wccm", "lexicon.json") as f:
8
+ return json.load(f)
9
+
10
+ def config_load():
11
+ with importlib.resources.open_text("wccm", "config.json") as f:
12
+ return json.load(f)
@@ -0,0 +1,69 @@
1
+ from .parse import parse
2
+ from .formatter import Format, markdown, inv_f
3
+ import sys
4
+ from .storage import save, config_load
5
+ from .infoParse import parse_inv
6
+
7
+ def main():
8
+
9
+ config = config_load()
10
+ arg = sys.argv[1]
11
+ if len(sys.argv) >= 2:
12
+ output = sys.argv[2]
13
+
14
+ else:
15
+ output = f"{config["prefs"]["output"]["defaultFileName"]}.{config["prefs"]["output"]["defaultFormat"]}"
16
+
17
+ text = ""
18
+
19
+ if not arg:
20
+ print("Usage: py wccm.py file.wccm output.txt or py wccm.py file.cmi output.txt")
21
+ exit()
22
+
23
+ elif not (arg.endswith(".wccm") or arg.endswith(".cmi")):
24
+ print("Please use a valid file extension. Valid extensions: \n.wccm\n.cmi")
25
+ exit()
26
+
27
+ cm = False
28
+
29
+ if arg.endswith(".wccm"): cm = True
30
+
31
+ if not (output.endswith(".txt") or output.endswith(".md")):
32
+ print("Please select a valid output extension: .md or .txt")
33
+ print("a 'lexicon.json' file is automatically generated, if that's what you wish.")
34
+ exit()
35
+
36
+ with open(arg, "r", encoding="utf-8") as f:
37
+ text = f.read()
38
+ if cm:
39
+ entries = parse(arg, text, config)
40
+ formatted_text = ""
41
+ if not output or output.endswith(".txt"):
42
+ for entry in entries:
43
+ formatted_text += Format(entry) + "\n\n" + "----" + "\n"
44
+ elif output.endswith(".md"):
45
+ for entry in entries:
46
+ formatted_text += markdown(entry) + "\n\n" + "----" + "\n"
47
+
48
+ if not output:
49
+ with open(f"{config["prefs"]["output"]["defaultFileName"]}.{config["prefs"]["output"]["defaultFormat"]}", "w", encoding="utf-8") as f:
50
+ f.write(formatted_text)
51
+ elif output.endswith(".txt"):
52
+ with open(output, "w", encoding="utf-8") as f:
53
+ f.write(formatted_text)
54
+ elif output.endswith(".md"):
55
+ with open(output, "w", encoding="utf-8") as f:
56
+ f.write(formatted_text)
57
+ # saves data to master.json for... reasons...?? Idk man this is already here and I'm too lazy to change it
58
+ #save(entries)
59
+
60
+ print(f"Done! Created {output} with {len(entries)} entries.")
61
+ else:
62
+ inv = parse_inv(text, config)
63
+ formatted = inv_f(inv)
64
+
65
+ save(inv, "info.json")
66
+
67
+ with open(output, "w", encoding="utf-8") as f:
68
+ f.write(formatted)
69
+ print(f"Done! created {output}.")
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: wccm
3
+ Version: 0.2.3
4
+ Summary: Compact command-line conlang manager
5
+ Author: Wernasho
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Dynamic: license-file
10
+
11
+ Wer's Compact Conlang Manager, or WCCM, is a simple command-line tool designed to make conlanging ever so slightly faster and easier by converting a simple, customizeable syntax into clean and readable conlang dictionaries.
12
+
13
+ I built this because spreadsheets had too much visual clutter and other existing tools were really overkill.
14
+ All you need to do is type your properties with shorthands you can customize, and you'll receive a nicely formatted text file.
15
+
16
+ For example, this:
17
+
18
+ ```
19
+ Agná
20
+ $agˈna
21
+ %noun
22
+ #animals
23
+ ?bird
24
+ ~Masculine
25
+ +ágnaya
26
+ ;gen :ágnand
27
+ ```
28
+
29
+ Turns into this:
30
+ ```
31
+ Agná
32
+ \[agˈna] bird, plural: ágnaya
33
+ Gender: Masculine
34
+ POS: Noun
35
+ Semantic field: animals
36
+ Cases:
37
+ gen: ágnand
38
+ ```
39
+ ## Installation
40
+
41
+ 1. install Python 3.6 or newer from [python.org](https://python.org)
42
+ 2. download or clone this repository
43
+ 3. no additional packages are needed, uses only python standard library!
44
+
45
+ # Usage:
46
+ Open up your console/terminal inside the wccm folder, and run this command:
47
+ ```bash
48
+ py wccm.py file.wccm
49
+ ```
50
+
51
+ Outputs to `Lexicon.txt`
52
+
53
+ # Syntax
54
+
55
+ WCCM uses symbols to represent different properties. Their order is irrelevant, as long as the plain word is always first.
56
+
57
+ ## Lexicon
58
+ (Lexicon-related syntax goes in `.wccm` files).
59
+
60
+ | Symbol | Field | Example |
61
+ | ------------ | --------------------- | -------------------------- |
62
+ | (None) | Word | **Kat** |
63
+ | `$` | IPA | **$kæt** |
64
+ | `#` | Semantic field | **\#animal** |
65
+ | `~` | Gender | **~M** |
66
+ | `?` | Translation | **?Cat** |
67
+ | `+` | Plural form(s) | **+Cats** |
68
+ | `;` and `:` | Case name / case form | **;gen :cat's** |
69
+ | `=` | Synonym(s) | **=feline** |
70
+ | `!` | Antonym(s) | **!dog** |
71
+ | `%` | Part of speech | **%noun** |
72
+ | `*` | Etymology | **\*from 'kaltnaen' ** |
73
+ | `\|` and `/` | Conjugations | **\|3rd sg present /does** |
74
+ | `@` and `:` | Custom | **@class :animte** |
75
+ ## Inventory
76
+ (Inventory-related information goes in `.cmi` files).
77
+
78
+ | Symbol | Field | Example |
79
+ | ------ | --------- | ------------ |
80
+ | `.` | consonant | **.tH** |
81
+ | `,` | vowel | **,3** |
82
+ | `^` | Tone | **\^rising** |
83
+
84
+ Don't like this set of symbols? That's completely fine! You can edit them anytime by going into `config.json`.
85
+
86
+ ## IPA
87
+ I know that typing IPA symbols can be tedious if you don't have the tools, which is why I implemented a function to let you map a character to an IPA sound, to make writing transcriptions easier!
88
+ # Configuration
89
+
90
+ `config.json` lets you customize:
91
+ - what each symbol means (which property it represents)
92
+ - IPA character mapping (e.g., `:` -> `ː`)
93
+ - default output file
94
+
95
+ ```json
96
+ {
97
+ "ipa": {
98
+ "S": "ʃ",
99
+ "T": "θ",
100
+ "R": "ɾ",
101
+ "B": "β",
102
+ "D": "ð",
103
+ "N": "ŋ",
104
+ "J": "ʲ",
105
+ "Z": "ʒ",
106
+ ":": "ː",
107
+ "'": "ˈ",
108
+ "ny": "ɲ",
109
+ "W": "ʷ",
110
+ "H": "ʰ",
111
+ "A": "ɑ",
112
+ "E": "ə",
113
+ "I": "ɪ",
114
+ "3": "ɛ",
115
+ "O": "ɔ",
116
+ "U": "ʊ",
117
+ "^": "ʌ",
118
+ "X": "χ"
119
+ },
120
+ "props": {
121
+ "$": "ipa",
122
+ "#": "field",
123
+ "%": "pos",
124
+ "_": "comment",
125
+ "~": "gender",
126
+ "=": "synonym",
127
+ "!": "antonym",
128
+ "+": "plural",
129
+ "?": "meaning",
130
+ "*": "etymology",
131
+ ";": "case",
132
+ "|": "conjugations",
133
+ "@": "custom"
134
+ },
135
+ "inv": {
136
+ ".": "consonant",
137
+ ",": "vowel",
138
+ "^": "tone"
139
+ },
140
+ "prefs": {
141
+ "output": {
142
+ "defaultFileName": "lexicon",
143
+ "defaultFormat": ".txt"
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ For the IPA replacement mapping, the character on the left is the character that the program will replace. So, essentially, if your IPA is "SaTaZ", with the default configurations (the ones showed above) it would turn into "ʃaθaʒ". You can add/remove as many as you want! (As long as you don't map 1 character to 2 symbols or use digraphs).
150
+
151
+ Same goes for the properties, although it is very important that you do **not** alter the keywords, otherwise the tool will break.
152
+
153
+ As you might've guessed, you can also choose the default name and format of the output file! The name can be anything you want, and the file extension can be either `.txt` or `.md`. A `lexicon.json` file is always automatically generated, which is why `.json` isn't an option in preferences.
154
+ ## Limitations
155
+
156
+ Currently, the case symbols (`;` and `:`) can't be customized, as well as the conjugation symbols (`|` and `/`).
157
+ If you ever want to remap a symbol, as said before, you're allowed (and encouraged) to do so! However, it is very important that you don't map `\` to anything. Since i don't want to confuse you with tech talk, basically, `\` is a special character and if you try to use it for mapping the configuration file is going to break.
158
+
159
+ Other than that, you should be able to change pretty much anything!
160
+
161
+ # About
162
+
163
+ WCCM started as just a little personal tool I developed because I'm stubborn and don't like any of the tools that already exist, and now I'm sharing it in case someone finds it useful as well.
164
+
165
+ # Feedback is appreciated!
166
+
167
+ This is my first time actually finishing and sharing a project, so I'd genuinely *love* to hear suggestions or ideas for future versions, as well as bug reports and other stuff like that.
168
+ You can contact me pretty much any time in [my twitter (I'm not calling it 'X')](https://x.com/wernasho)
@@ -0,0 +1,16 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/wccm/config.json
5
+ src/wccm/formatter.py
6
+ src/wccm/info.json
7
+ src/wccm/infoParse.py
8
+ src/wccm/lexicon.json
9
+ src/wccm/parse.py
10
+ src/wccm/storage.py
11
+ src/wccm/wccm.py
12
+ src/wccm.egg-info/PKG-INFO
13
+ src/wccm.egg-info/SOURCES.txt
14
+ src/wccm.egg-info/dependency_links.txt
15
+ src/wccm.egg-info/entry_points.txt
16
+ src/wccm.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ wccm = wccm.wccm:main
@@ -0,0 +1 @@
1
+ wccm