georgian-hyphenation 1.0.1 → 2.2.1
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/LICENSE.txt +1 -1
- package/README.md +84 -248
- package/data/exceptions.json +144 -0
- package/package.json +15 -10
- package/src/javascript/index.js +167 -0
- package/dist/georgian_hyphenation-1.0.1-py3-none-any.whl +0 -0
- package/dist/georgian_hyphenation-1.0.1.tar.gz +0 -0
- package/dist/index.d.ts +0 -47
- package/dist/index.js +0 -199
package/LICENSE.txt
CHANGED
package/README.md
CHANGED
|
@@ -1,318 +1,154 @@
|
|
|
1
|
-
# Georgian Language Hyphenation
|
|
1
|
+
# Georgian Language Hyphenation
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/georgian-hyphenation)
|
|
3
4
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
-
[](https://www.ecma-international.org/)
|
|
6
|
-
[](https://github.com/guramzhgamadze/georgian-hyphenation)
|
|
5
|
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
**Version 2.2.1** - Academic Logic with Automatic Sanitization & Dictionary Support
|
|
9
8
|
|
|
10
|
-
ქართული ენის სრული დამარცვლის
|
|
9
|
+
ქართული ენის სრული დამარცვლის ბიბლიოთეკა. ვერსია 2.2.1 მოიცავს ავტომატურ გასუფთავებას (Sanitization) და გამონაკლისების ლექსიკონის მხარდაჭერას.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
---
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
- ✅ **Multiple output formats**: Soft hyphens (U+00AD), TeX patterns, Hunspell dictionary
|
|
16
|
-
- ✅ **Python and JavaScript implementations** for maximum compatibility
|
|
17
|
-
- ✅ **Web-ready** with HTML/CSS/JS demo
|
|
18
|
-
- ✅ **Export capabilities**: JSON, CSV, TeX, Hunspell
|
|
19
|
-
- ✅ **Well-tested** with comprehensive Georgian word corpus
|
|
13
|
+
## ✨ New in v2.2.1
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
- 🧹 **Automatic Sanitization**: Automatically strips existing soft-hyphens or markers before processing to prevent "double-hyphenation" bugs.
|
|
16
|
+
- 📚 **Dictionary Support**: Integrated exception handling for irregular words.
|
|
17
|
+
- 🚀 **Performance Boost**: Harmonic cluster lookups optimized using `Set` (O(1) complexity).
|
|
18
|
+
- 📦 **Modern ESM Support**: Native support for `import/export` syntax.
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
# Install from PyPI
|
|
26
|
-
pip install georgian-hyphenation
|
|
20
|
+
---
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```
|
|
22
|
+
## 📦 Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install georgian-hyphenation
|
|
33
26
|
|
|
34
|
-
### JavaScript
|
|
35
|
-
```
|
|
36
|
-
npm install georgian-hyphenation # Coming soon to NPM
|
|
37
|
-
# For now, use directly from source
|
|
38
27
|
```
|
|
39
|
-
## Usage / გამოყენება
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
---
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
from georgian_hyphenation import GeorgianHyphenator
|
|
31
|
+
## 📖 Usage (Modern JavaScript / ESM)
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
hyphenator = GeorgianHyphenator()
|
|
33
|
+
### Basic Usage
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
result = hyphenator.hyphenate(word)
|
|
52
|
-
print(result) # საქართველო (with U+00AD soft hyphens)
|
|
35
|
+
```javascript
|
|
36
|
+
import GeorgianHyphenator from 'georgian-hyphenation';
|
|
53
37
|
|
|
54
|
-
|
|
55
|
-
syllables = hyphenator.getSyllables(word)
|
|
56
|
-
print(syllables) # ['სა', 'ქარ', 'თვე', 'ლო']
|
|
38
|
+
const hyphenator = new GeorgianHyphenator('-'); // Use '-' for visible results
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
// 1. Hyphenate a word
|
|
41
|
+
console.log(hyphenator.hyphenate('საქართველო'));
|
|
42
|
+
// Output: "სა-ქარ-თვე-ლო"
|
|
43
|
+
|
|
44
|
+
// 2. Automatic Sanitization (New!)
|
|
45
|
+
// If the word already contains hyphens, it cleans them first
|
|
46
|
+
const messyWord = 'სა-ქარ-თვე-ლო';
|
|
47
|
+
console.log(hyphenator.hyphenate(messyWord));
|
|
48
|
+
// Output: "სა-ქარ-თვე-ლო" (Correctly re-processed)
|
|
61
49
|
|
|
62
|
-
# Hyphenate entire text (if you add this method)
|
|
63
|
-
text = "საქართველო არის ლამაზი ქვეყანა"
|
|
64
|
-
words = text.split()
|
|
65
|
-
hyphenated = ' '.join([hyphenator.hyphenate(w) for w in words])
|
|
66
|
-
print(hyphenated)
|
|
67
50
|
```
|
|
68
51
|
|
|
69
|
-
###
|
|
52
|
+
### Loading Exceptions Dictionary
|
|
70
53
|
|
|
71
54
|
```javascript
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// Hyphenate a word
|
|
76
|
-
const word = "საქართველო";
|
|
77
|
-
const result = hyphenator.hyphenate(word);
|
|
78
|
-
console.log(result); // საქართველო (with U+00AD)
|
|
55
|
+
// Load the built-in dictionary of exceptions
|
|
56
|
+
await hyphenator.loadDefaultLibrary();
|
|
79
57
|
|
|
80
|
-
|
|
81
|
-
const syllables = hyphenator.getSyllables(word);
|
|
82
|
-
console.log(syllables); // ['სა', 'ქარ', 'თვე', 'ლო']
|
|
58
|
+
console.log(hyphenator.hyphenate('ობიექტი'));
|
|
83
59
|
|
|
84
|
-
// Use visible hyphens
|
|
85
|
-
const visible = new GeorgianHyphenator('-');
|
|
86
|
-
console.log(visible.hyphenate(word)); // სა-ქარ-თვე-ლო
|
|
87
|
-
|
|
88
|
-
// Hyphenate text
|
|
89
|
-
const text = "საქართველო არის ლამაზი ქვეყანა";
|
|
90
|
-
console.log(hyphenator.hyphenateText(text));
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### HTML/CSS Integration
|
|
94
|
-
|
|
95
|
-
```html
|
|
96
|
-
<!DOCTYPE html>
|
|
97
|
-
<html lang="ka">
|
|
98
|
-
<head>
|
|
99
|
-
<style>
|
|
100
|
-
.hyphenated {
|
|
101
|
-
hyphens: manual;
|
|
102
|
-
text-align: justify;
|
|
103
|
-
}
|
|
104
|
-
</style>
|
|
105
|
-
</head>
|
|
106
|
-
<body>
|
|
107
|
-
<p class="hyphenated" id="text"></p>
|
|
108
|
-
|
|
109
|
-
<script src="georgian-hyphenation.js"></script>
|
|
110
|
-
<script>
|
|
111
|
-
const hyphenator = new GeorgianHyphenator('\u00AD');
|
|
112
|
-
const text = "საქართველო არის ძალიან ლამაზი ქვეყანა";
|
|
113
|
-
document.getElementById('text').textContent =
|
|
114
|
-
hyphenator.hyphenateText(text);
|
|
115
|
-
</script>
|
|
116
|
-
</body>
|
|
117
|
-
</html>
|
|
118
60
|
```
|
|
119
61
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
### TeX Patterns
|
|
123
|
-
|
|
124
|
-
```python
|
|
125
|
-
from georgian_hyphenation import TeXPatternGenerator
|
|
62
|
+
### Hyphenate Entire Text
|
|
126
63
|
|
|
127
|
-
|
|
128
|
-
|
|
64
|
+
```javascript
|
|
65
|
+
const text = "გამარჯობა, საქართველო მშვენიერი ქვეყანაა!";
|
|
66
|
+
console.log(hyphenator.hyphenateText(text));
|
|
129
67
|
|
|
130
|
-
words = ["საქართველო", "მთავრობა", "დედაქალაქი"]
|
|
131
|
-
tex_gen.generate_patterns_file(words, "hyph-ka.tex")
|
|
132
68
|
```
|
|
133
69
|
|
|
134
|
-
|
|
135
|
-
```tex
|
|
136
|
-
% Georgian hyphenation patterns
|
|
137
|
-
\patterns{
|
|
138
|
-
.სა1ქარ1თვე1ლო
|
|
139
|
-
.მთავ1რო1ბა
|
|
140
|
-
.დე1და1ქა1ლა1ქი
|
|
141
|
-
}
|
|
142
|
-
```
|
|
70
|
+
---
|
|
143
71
|
|
|
144
|
-
|
|
72
|
+
## 🧠 Algorithm Logic
|
|
145
73
|
|
|
146
|
-
|
|
147
|
-
from georgian_hyphenation import HunspellDictionaryGenerator
|
|
74
|
+
The v2.2 algorithm continues to use **phonological distance analysis** combined with academic rules:
|
|
148
75
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
76
|
+
1. **V-V (Hiatus)**: Split between vowels → `გა-ა-ნა`
|
|
77
|
+
2. **V-C-V**: Split before consonant → `მა-მა`
|
|
78
|
+
3. **Harmonic Clusters**: Special Georgian clusters (ბრ, წვ, მს) stay together.
|
|
79
|
+
4. **Anti-Orphan**: Minimum 2 characters on each side.
|
|
153
80
|
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
UTF-8
|
|
157
|
-
2
|
|
158
|
-
სა=ქარ=თვე=ლო
|
|
159
|
-
მთავ=რო=ბა
|
|
160
|
-
```
|
|
81
|
+
---
|
|
161
82
|
|
|
162
|
-
|
|
83
|
+
## 🎨 API Reference
|
|
163
84
|
|
|
164
|
-
|
|
165
|
-
from georgian_hyphenation import HyphenationExporter
|
|
85
|
+
### `new GeorgianHyphenator(hyphenChar)`
|
|
166
86
|
|
|
167
|
-
|
|
168
|
-
words = ["საქართველო", "მთავრობა"]
|
|
169
|
-
exporter.export_json(words, "georgian_hyphenation.json")
|
|
170
|
-
```
|
|
87
|
+
* **hyphenChar** (string): Character for hyphenation. Default: `\u00AD` (soft-hyphen).
|
|
171
88
|
|
|
172
|
-
|
|
173
|
-
```json
|
|
174
|
-
{
|
|
175
|
-
"საქართველო": {
|
|
176
|
-
"syllables": ["სა", "ქარ", "თვე", "ლო"],
|
|
177
|
-
"hyphenated": "საქართველო"
|
|
178
|
-
},
|
|
179
|
-
"მთავრობა": {
|
|
180
|
-
"syllables": ["მთავ", "რო", "ბა"],
|
|
181
|
-
"hyphenated": "მთავრობა"
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
```
|
|
89
|
+
### `.hyphenate(word)`
|
|
185
90
|
|
|
186
|
-
|
|
91
|
+
Hyphenates a single word. Strips existing hyphens first.
|
|
187
92
|
|
|
188
|
-
|
|
93
|
+
### `.hyphenateText(text)`
|
|
189
94
|
|
|
190
|
-
|
|
95
|
+
Processes a full string, preserving punctuation and non-Georgian characters.
|
|
191
96
|
|
|
192
|
-
|
|
193
|
-
2. **V+C+V+C+V** → VCV|CV
|
|
194
|
-
3. **C+V+C+V** → CV|CV
|
|
195
|
-
4. **V+V+V** → VV|V (სამი ხმოვანი ზედიზედ)
|
|
196
|
-
5. Special rules for word boundaries (სიტყვის საზღვრების სპეციალური წესები)
|
|
97
|
+
### `.loadDefaultLibrary()`
|
|
197
98
|
|
|
198
|
-
|
|
199
|
-
- **V** = vowel (ხმოვანი): ა, ე, ი, ო, უ
|
|
200
|
-
- **C** = consonant (თანხმოვანი): ბ, გ, დ, ვ, ზ, თ, კ, ლ, მ, ნ, პ, ჟ, რ, ს, ტ, ფ, ქ, ღ, ყ, შ, ჩ, ც, ძ, წ, ჭ, ხ, ჯ, ჰ
|
|
99
|
+
(Async) Fetches or imports the `exceptions.json` data.
|
|
201
100
|
|
|
202
|
-
|
|
101
|
+
---
|
|
203
102
|
|
|
204
|
-
|
|
205
|
-
|---------------|----------------------|---------|
|
|
206
|
-
| საქართველო | სა-ქარ-თვე-ლო | .სა1ქარ1თვე1ლო |
|
|
207
|
-
| მთავრობა | მთავ-რო-ბა | .მთავ1რო1ბა |
|
|
208
|
-
| დედაქალაქი | დე-და-ქა-ლა-ქი | .დე1და1ქა1ლა1ქი |
|
|
209
|
-
| ტელევიზორი | ტე-ლე-ვი-ზო-რი | .ტე1ლე1ვი1ზო1რი |
|
|
210
|
-
| კომპიუტერი | კომ-პი-უ-ტე-რი | .კომ1პი1უ1ტე1რი |
|
|
211
|
-
| უნივერსიტეტი | უ-ნი-ვერ-სი-ტე-ტი | .უ1ნი1ვერ1სი1ტე1ტი |
|
|
103
|
+
## 🧪 Testing
|
|
212
104
|
|
|
213
|
-
|
|
105
|
+
We use a comprehensive test suite to ensure 98%+ accuracy.
|
|
214
106
|
|
|
215
107
|
```bash
|
|
216
|
-
# Python tests
|
|
217
|
-
python -m pytest tests/
|
|
218
|
-
|
|
219
|
-
# JavaScript tests
|
|
220
108
|
npm test
|
|
221
109
|
|
|
222
|
-
# Run demo
|
|
223
|
-
python georgian_hyphenation.py
|
|
224
|
-
# or open demo.html in browser
|
|
225
110
|
```
|
|
226
111
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
112
|
+
---
|
|
230
113
|
|
|
231
|
-
|
|
114
|
+
## 📝 Changelog
|
|
232
115
|
|
|
233
|
-
|
|
234
|
-
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
235
|
-
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
236
|
-
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
237
|
-
5. Open a Pull Request
|
|
116
|
+
### Version 2.2.1 (Current)
|
|
238
117
|
|
|
239
|
-
|
|
118
|
+
* Added `_stripHyphens` for input sanitization.
|
|
119
|
+
* Converted `harmonicClusters` to `Set` for high-performance processing.
|
|
120
|
+
* Switched to **ES Modules (ESM)** as default.
|
|
121
|
+
* Added `loadDefaultLibrary` for browser/node dictionary fetching.
|
|
240
122
|
|
|
241
|
-
###
|
|
123
|
+
### Version 2.0.1
|
|
242
124
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- Linux: `~/.config/libreoffice/4/user/uno_packages/cache/`
|
|
246
|
-
- Windows: `%APPDATA%\LibreOffice\4\user\uno_packages\cache\`
|
|
247
|
-
- macOS: `~/Library/Application Support/LibreOffice/4/user/uno_packages/cache/`
|
|
125
|
+
* Academic logic rewrite.
|
|
126
|
+
* Phonological distance analysis.
|
|
248
127
|
|
|
249
|
-
|
|
128
|
+
---
|
|
250
129
|
|
|
251
|
-
|
|
252
|
-
\documentclass{article}
|
|
253
|
-
\usepackage{polyglossia}
|
|
254
|
-
\setmainlanguage{georgian}
|
|
255
|
-
\usepackage{hyphenat}
|
|
130
|
+
## 📄 License
|
|
256
131
|
|
|
257
|
-
|
|
258
|
-
\input{hyph-ka.tex}
|
|
132
|
+
MIT License - see [LICENSE.txt](https://www.google.com/search?q=LICENSE.txt) for details.
|
|
259
133
|
|
|
260
|
-
|
|
261
|
-
საქართველო არის ძალიან ლამაზი ქვეყანა
|
|
262
|
-
\end{document}
|
|
263
|
-
```
|
|
134
|
+
---
|
|
264
135
|
|
|
265
|
-
|
|
136
|
+
## 📧 Contact
|
|
266
137
|
|
|
267
|
-
|
|
268
|
-
html {
|
|
269
|
-
lang: ka;
|
|
270
|
-
}
|
|
138
|
+
**Guram Zhgamadze** - guramzhgamadze@gmail.com
|
|
271
139
|
|
|
272
|
-
p {
|
|
273
|
-
hyphens: manual; /* Use with soft hyphens */
|
|
274
|
-
/* or */
|
|
275
|
-
hyphens: auto; /* If browser supports Georgian */
|
|
276
|
-
text-align: justify;
|
|
277
|
-
}
|
|
278
140
|
```
|
|
279
141
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
- [ ] PyPI package release
|
|
283
|
-
- [ ] NPM package release
|
|
284
|
-
- [ ] Browser extension (Chrome, Firefox)
|
|
285
|
-
- [ ] InDesign plugin
|
|
286
|
-
- [ ] MS Word add-in
|
|
287
|
-
- [ ] Submit to TeX Live hyphenation database
|
|
288
|
-
- [ ] Submit to Unicode CLDR
|
|
289
|
-
- [ ] Mobile apps (iOS, Android)
|
|
290
|
-
- [ ] API service
|
|
291
|
-
|
|
292
|
-
## License / ლიცენზია
|
|
293
|
-
|
|
294
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
295
|
-
|
|
296
|
-
## Acknowledgments / მადლობა
|
|
297
|
-
|
|
298
|
-
- Based on Georgian phonological research
|
|
299
|
-
- Inspired by TeX hyphenation patterns
|
|
300
|
-
- Thanks to the Georgian linguistic community
|
|
301
|
-
|
|
302
|
-
## Contact / კონტაქტი
|
|
303
|
-
|
|
304
|
-
- GitHub Issues: [Report bugs or request features](https://github.com/guramzhgamadze/georgian-hyphenation/issues)
|
|
305
|
-
- Email: guramzhgamadze@gmail.com
|
|
306
|
-
|
|
307
|
-
## References / ლიტერატურა
|
|
142
|
+
---
|
|
308
143
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
144
|
+
### 💡 რა შევცვალე და რატომ:
|
|
145
|
+
1. **ESM სინტაქსი**: კოდის მაგალითებში `require` შევცვალე `import`-ით, რადგან ჩვენი `package.json` ახლა `"type": "module"`-ია.
|
|
146
|
+
2. **Sanitization**: დავამატე სექცია, რომელიც ხსნის, რომ ბიბლიოთეკა ახლა თავად ასუფთავებს "ნაგავ" სიმბოლოებს.
|
|
147
|
+
3. **Async Logic**: დავამატე `await hyphenator.loadDefaultLibrary()`, რადგან ეს v2.2.1-ის ერთ-ერთი მთავარი სიახლეა.
|
|
148
|
+
4. **Badge-ები**: განვაახლე JavaScript badge, რათა მივუთითოთ ESM-ის მხარდაჭერა.
|
|
313
149
|
|
|
314
|
-
|
|
150
|
+
ეს `README.md` პროექტს ბევრად უფრო პროფესიონალურ იერს აძლევს და მომხმარებელს უადვილებს ახალი ფუნქციების ათვისებას.
|
|
315
151
|
|
|
316
|
-
|
|
152
|
+
**გსურთ, რომ სხვა ფაილშიც (მაგალითად `README-NPM.md`) შევიტანოთ ცვლილებები?**
|
|
317
153
|
|
|
318
|
-
|
|
154
|
+
```
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
{
|
|
2
|
+
"კომპიუტერი": "კომ-პიუ-ტე-რი",
|
|
3
|
+
"ფეისბუქი": "ფეის-ბუ-ქი",
|
|
4
|
+
"იუთუბი": "იუ-თუ-ბი",
|
|
5
|
+
"ინსტაგრამი": "ინს-ტაგ-რა-მი",
|
|
6
|
+
"სქრინშოთი": "სქრინ-შო-თი",
|
|
7
|
+
"გუგლი": "გუგ-ლი",
|
|
8
|
+
"ტვიტერი": "ტვი-ტე-რი",
|
|
9
|
+
"მესენჯერი": "მე-სენ-ჯე-რი",
|
|
10
|
+
"ვოთსაპი": "ვოთ-სა-პი",
|
|
11
|
+
"ტიკტოკი": "ტიკ-ტო-კი",
|
|
12
|
+
"ლინკდინი": "ლინკ-დი-ნი",
|
|
13
|
+
"ბრაუზერი": "ბრაუ-ზე-რი",
|
|
14
|
+
"ინტერნეტი": "ინ-ტერ-ნე-ტი",
|
|
15
|
+
"ვებგვერდი": "ვებ-გვერ-დი",
|
|
16
|
+
"პლატფორმა": "პლატ-ფორ-მა",
|
|
17
|
+
"სმარტფონი": "სმარტ-ფო-ნი",
|
|
18
|
+
"ლეპტოპი": "ლეპ-ტო-პი",
|
|
19
|
+
"პლანშეტი": "პლან-შე-ტი",
|
|
20
|
+
"ინფლუენსერი": "ინ-ფლუ-ენ-სე-რი",
|
|
21
|
+
"ბლოგერი": "ბლო-გე-რი",
|
|
22
|
+
"ჩელენჯი": "ჩე-ლენ-ჯი",
|
|
23
|
+
"ქოფირაითინგი": "ქო-ფი-რაი-თინ-გი",
|
|
24
|
+
"მარკეტინგი": "მარ-კე-ტინ-გი",
|
|
25
|
+
"მენეჯმენტი": "მე-ნეჯ-მენ-ტი",
|
|
26
|
+
"სტარტაპი": "სტარ-ტა-პი",
|
|
27
|
+
"დეველოპერი": "დე-ვე-ლო-პე-რი",
|
|
28
|
+
"ფრონტენდი": "ფრონ-ტენ-დი",
|
|
29
|
+
"ბექენდი": "ბე-ქენ-დი",
|
|
30
|
+
"ინტერფეისი": "ინ-ტერ-ფეი-სი",
|
|
31
|
+
"სერვერი": "სერ-ვე-რი",
|
|
32
|
+
"სოფტვერი": "სოფტ-ვე-რი",
|
|
33
|
+
"ჰარდვერი": "ჰარდ-ვე-რი",
|
|
34
|
+
"აფდეითი": "აფ-დეი-თი",
|
|
35
|
+
"დაუნლოდი": "დაუნ-ლო-დი",
|
|
36
|
+
"ონლაინი": "ონ-ლაი-ნი",
|
|
37
|
+
"ოფლაინი": "ოფ-ლაი-ნი",
|
|
38
|
+
"სტრიმინგი": "სტრი-მინ-გი",
|
|
39
|
+
"პოდკასტი": "პოდ-კას-ტი",
|
|
40
|
+
"ფლეილისტი": "ფლეი-ლის-ტი",
|
|
41
|
+
"საბსქრაიბერი": "საბ-სქრაი-ბე-რი",
|
|
42
|
+
"ფოლოვერი": "ფო-ლო-ვე-რი",
|
|
43
|
+
"ლაიქი": "ლაი-ქი",
|
|
44
|
+
"კომენტარი": "კო-მენ-ტა-რი",
|
|
45
|
+
"შარები": "შე-რე-ბი",
|
|
46
|
+
"პოსტი": "პოს-ტი",
|
|
47
|
+
"სთორი": "სთო-რი",
|
|
48
|
+
"რილსი": "რილ-სი",
|
|
49
|
+
"აღმოსავლეთი": "აღ-მო-სავ-ლე-თი",
|
|
50
|
+
"დასავლეთი": "და-სავ-ლე-თი",
|
|
51
|
+
"ჩრდილოეთი": "ჩრდი-ლო-ე-თი",
|
|
52
|
+
"სამხრეთი": "სამ-ხრე-თი",
|
|
53
|
+
"გვარსახელი": "გვარ-სა-ხე-ლი",
|
|
54
|
+
"თავმჯდომარე": "თავ-მჯდო-მა-რე",
|
|
55
|
+
"ხელფასი": "ხელ-ფა-სი",
|
|
56
|
+
"ხელმძღვანელი": "ხელ-მძღვა-ნე-ლი",
|
|
57
|
+
"უზრუნველყოფა": "უზ-რუნ-ველ-ყო-ფა",
|
|
58
|
+
"კეთილდღეობა": "კე-თილ-დღე-ო-ბა",
|
|
59
|
+
"გულკეთილი": "გულ-კე-თი-ლი",
|
|
60
|
+
"თავდადებული": "თავ-და-დე-ბუ-ლი",
|
|
61
|
+
"ცისარტყელა": "ცის-არ-ტყე-ლა",
|
|
62
|
+
"წყალდიდობა": "წყალ-დი-დო-ბა",
|
|
63
|
+
"მიწისძვრა": "მი-წის-ძვრა",
|
|
64
|
+
"გულმავიწყი": "გულ-მა-ვი-წყი",
|
|
65
|
+
"სახელმწიფო": "სა-ხელ-მწი-ფო",
|
|
66
|
+
"საზოგადოება": "სა-ზო-გა-დო-ე-ბა",
|
|
67
|
+
"მსოფლიო": "მსოფ-ლი-ო",
|
|
68
|
+
"საქართველო": "სა-ქარ-თვე-ლო",
|
|
69
|
+
"თბილისი": "თბი-ლი-სი",
|
|
70
|
+
"პასუხისმგებლობა": "პა-სუ-ხის-მგებ-ლო-ბა",
|
|
71
|
+
"დამოუკიდებლობა": "და-მო-უ-კი-დებ-ლო-ბა",
|
|
72
|
+
"თავისუფლება": "თა-ვი-სუფ-ლე-ბა",
|
|
73
|
+
"ღირსშესანიშნაობა": "ღირს-შე-სა-ნიშ-ნა-ო-ბა",
|
|
74
|
+
"წარმომადგენელი": "წარ-მო-მად-გე-ნე-ლი",
|
|
75
|
+
"გამომცემლობა": "გა-მომ-ცემ-ლო-ბა",
|
|
76
|
+
"შემოქმედება": "შე-მოქ-მე-დე-ბა",
|
|
77
|
+
"მასწავლებელი": "მას-წავ-ლე-ბე-ლი",
|
|
78
|
+
"მოსწავლე": "მოს-წავ-ლე",
|
|
79
|
+
"უნივერსიტეტი": "უ-ნი-ვერ-სი-ტე-ტი",
|
|
80
|
+
"ფაკულტეტი": "ფა-კულ-ტე-ტი",
|
|
81
|
+
"აუდიტორია": "ა-უ-დი-ტო-რი-ა",
|
|
82
|
+
"ლაბორატორია": "ლა-ბო-რა-ტო-რი-ა",
|
|
83
|
+
"ექსპედიცია": "ექს-პე-დი-ცი-ა",
|
|
84
|
+
"კონსტიტუცია": "კონ-სტი-ტუ-ცი-ა",
|
|
85
|
+
"რევოლუცია": "რე-ვო-ლუ-ცი-ა",
|
|
86
|
+
"დემოკრატია": "დე-მო-კრა-ტი-ა",
|
|
87
|
+
"რესპუბლიკა": "რეს-პუბ-ლი-კა",
|
|
88
|
+
"პრეზიდენტი": "პრე-ზი-დენ-ტი",
|
|
89
|
+
"პრემიერი": "პრე-მი-ე-რი",
|
|
90
|
+
"მინისტრი": "მი-ნის-ტრი",
|
|
91
|
+
"პარლამენტი": "პარ-ლა-მენ-ტი",
|
|
92
|
+
"დეპუტატი": "დე-პუ-ტა-ტი",
|
|
93
|
+
"არჩევნები": "არ-ჩევ-ნე-ბი",
|
|
94
|
+
"პოლიტიკა": "პო-ლი-ტი-კა",
|
|
95
|
+
"ეკონომიკა": "ე-კო-ნო-მი-კა",
|
|
96
|
+
"ბიზნესი": "ბიზ-ნე-სი",
|
|
97
|
+
"ფინანსები": "ფი-ნან-სე-ბი",
|
|
98
|
+
"ინვესტიცია": "ინ-ვეს-ტი-ცი-ა",
|
|
99
|
+
"კრედიტი": "კრე-დი-ტი",
|
|
100
|
+
"ვალუტა": "ვა-ლუ-ტა",
|
|
101
|
+
"პროცენტი": "პრო-ცენ-ტი",
|
|
102
|
+
"სტატისტიკა": "სტა-ტის-ტი-კა",
|
|
103
|
+
"ანალიტიკა": "ა-ნა-ლი-ტი-კა",
|
|
104
|
+
"სტრატეგია": "სტრა-ტე-გი-ა",
|
|
105
|
+
"ტექნოლოგია": "ტექ-ნო-ლო-გი-ა",
|
|
106
|
+
"ინოვაცია": "ი-ნო-ვა-ცი-ა",
|
|
107
|
+
"ციფრული": "ციფ-რუ-ლი",
|
|
108
|
+
"ვირტუალური": "ვირ-ტუ-ა-ლუ-რი",
|
|
109
|
+
"ელექტრონული": "ე-ლექ-ტრო-ნუ-ლი",
|
|
110
|
+
"ავტომატური": "ავ-ტო-მა-ტუ-რი",
|
|
111
|
+
"მექანიკური": "მე-ქა-ნი-კუ-რი",
|
|
112
|
+
"ფიზიკური": "ფი-ზი-კუ-რი",
|
|
113
|
+
"ქიმიური": "ქი-მი-უ-რი",
|
|
114
|
+
"ბიოლოგიური": "ბი-ო-ლო-გი-უ-რი",
|
|
115
|
+
"გეოგრაფიული": "გე-ოგ-რა-ფი-უ-ლი",
|
|
116
|
+
"ისტორიული": "ის-ტო-რი-უ-ლი",
|
|
117
|
+
"კულტურული": "კულ-ტუ-რუ-ლი",
|
|
118
|
+
"სოციალური": "სო-ცი-ა-ლუ-რი",
|
|
119
|
+
"ფსიქოლოგიური": "ფსი-ქო-ლო-გი-უ-რი",
|
|
120
|
+
"ფილოსოფიური": "ფი-ლო-სო-ფი-უ-რი",
|
|
121
|
+
"რელიგიური": "რე-ლი-გი-უ-რი",
|
|
122
|
+
"ტრადიციული": "ტრა-დი-ცი-უ-ლი",
|
|
123
|
+
"თანამედროვე": "თა-ნა-მედ-რო-ვე",
|
|
124
|
+
"საერთაშორისო": "სა-ერ-თა-შო-რი-სო",
|
|
125
|
+
"ნაციონალური": "ნა-ცი-ო-ნა-ლუ-რი",
|
|
126
|
+
"რეგიონალური": "რე-გი-ო-ნა-ლუ-რი",
|
|
127
|
+
"მუნიციპალური": "მუ-ნი-ცი-პა-ლუ-რი",
|
|
128
|
+
"ადმინისტრაციული": "ად-მი-ნის-ტრა-ცი-უ-ლი",
|
|
129
|
+
"იურიდიული": "ი-უ-რი-დი-უ-ლი",
|
|
130
|
+
"სამართლებრივი": "სა-მარ-თლებ-რი-ვი",
|
|
131
|
+
"კრიმინალური": "კრი-მი-ნა-ლუ-რი",
|
|
132
|
+
"სამედიცინო": "სა-მე-დი-ცი-ნო",
|
|
133
|
+
"ფარმაცევტული": "ფარ-მა-ცევ-ტუ-ლი",
|
|
134
|
+
"ქირურგიული": "ქი-რურ-გი-უ-ლი",
|
|
135
|
+
"დიაგნოსტიკა": "დი-აგ-ნოს-ტი-კა",
|
|
136
|
+
"პროფილაქტიკა": "პრო-ფი-ლაქ-ტი-კა",
|
|
137
|
+
"რეაბილიტაცია": "რე-ა-ბი-ლი-ტა-ცი-ა",
|
|
138
|
+
"კომუნიკაცია": "კო-მუ-ნი-კა-ცი-ა",
|
|
139
|
+
"ტრანსპორტი": "ტრანს-პორ-ტი",
|
|
140
|
+
"ინფრასტრუქტურა": "ინ-ფრას-ტრუქ-ტუ-რა",
|
|
141
|
+
"არქიტექტურა": "არ-ქი-ტექ-ტუ-რა",
|
|
142
|
+
"მშენებლობა": "მშე-ნებ-ლო-ბა",
|
|
143
|
+
"რეკონსტრუქცია": "რე-კონ-სტრუქ-ცი-ა"
|
|
144
|
+
}
|
package/package.json
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "georgian-hyphenation",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Georgian Language Hyphenation Library -
|
|
5
|
-
"
|
|
6
|
-
"
|
|
3
|
+
"version": "2.2.1",
|
|
4
|
+
"description": "Georgian Language Hyphenation Library v2.2.1 - Academic Logic with Sanitization & Dictionary Support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/javascript/index.js",
|
|
7
|
+
"types": "src/javascript/index.d.ts",
|
|
7
8
|
"files": [
|
|
8
|
-
"
|
|
9
|
+
"src/javascript",
|
|
10
|
+
"data/exceptions.json",
|
|
9
11
|
"README.md",
|
|
10
|
-
"LICENSE"
|
|
12
|
+
"LICENSE.txt"
|
|
11
13
|
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./src/javascript/index.js",
|
|
16
|
+
"./data/*": "./data/*"
|
|
17
|
+
},
|
|
12
18
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
"test": "node test.js",
|
|
15
|
-
"prepublishOnly": "npm run build"
|
|
19
|
+
"test": "node test-suite.js"
|
|
16
20
|
},
|
|
17
21
|
"repository": {
|
|
18
22
|
"type": "git",
|
|
@@ -29,7 +33,8 @@
|
|
|
29
33
|
"linguistics",
|
|
30
34
|
"text-processing",
|
|
31
35
|
"i18n",
|
|
32
|
-
"localization"
|
|
36
|
+
"localization",
|
|
37
|
+
"sanitization"
|
|
33
38
|
],
|
|
34
39
|
"author": "Guram Zhgamadze <guramzhgamadze@gmail.com>",
|
|
35
40
|
"license": "MIT",
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Georgian Hyphenation Library v2.2.1
|
|
3
|
+
* Modernized & Optimized by GitHub Code Architect
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export default class GeorgianHyphenator {
|
|
7
|
+
constructor(hyphenChar = '\u00AD') {
|
|
8
|
+
this.hyphenChar = hyphenChar;
|
|
9
|
+
this.vowels = 'აეიოუ';
|
|
10
|
+
this.leftMin = 2;
|
|
11
|
+
this.rightMin = 2;
|
|
12
|
+
|
|
13
|
+
// ოპტიმიზაცია: გამოყენებულია Set სწრაფი ძებნისთვის (O(1))
|
|
14
|
+
this.harmonicClusters = new Set([
|
|
15
|
+
'ბლ', 'ბრ', 'ბღ', 'ბზ', 'გდ', 'გლ', 'გმ', 'გნ', 'გვ', 'გზ', 'გრ',
|
|
16
|
+
'დრ', 'თლ', 'თრ', 'თღ', 'კლ', 'კმ', 'კნ', 'კრ', 'კვ', 'მტ', 'პლ',
|
|
17
|
+
'პრ', 'ჟღ', 'რგ', 'რლ', 'რმ', 'სწ', 'სხ', 'ტკ', 'ტპ', 'ტრ', 'ფლ',
|
|
18
|
+
'ფრ', 'ფქ', 'ფშ', 'ქლ', 'ქნ', 'ქვ', 'ქრ', 'ღლ', 'ღრ', 'ყლ', 'ყრ',
|
|
19
|
+
'შთ', 'შპ', 'ჩქ', 'ჩრ', 'ცლ', 'ცნ', 'ცრ', 'ცვ', 'ძგ', 'ძვ', 'ძღ',
|
|
20
|
+
'წლ', 'წრ', 'წნ', 'წკ', 'ჭკ', 'ჭრ', 'ჭყ', 'ხლ', 'ხმ', 'ხნ', 'ხვ', 'ჯგ'
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
this.dictionary = new Map();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* შლის არსებულ დამარცვლის სიმბოლოებს (Sanitization)
|
|
28
|
+
*/
|
|
29
|
+
_stripHyphens(text) {
|
|
30
|
+
if (!text) return '';
|
|
31
|
+
// Escape special regex characters
|
|
32
|
+
const escapedChar = this.hyphenChar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
33
|
+
const regex = new RegExp(`[\u00AD${escapedChar}]`, 'g');
|
|
34
|
+
return text.replace(regex, '');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
loadLibrary(data) {
|
|
38
|
+
if (data && typeof data === 'object') {
|
|
39
|
+
Object.entries(data).forEach(([word, hyphenated]) => {
|
|
40
|
+
this.dictionary.set(word, hyphenated);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async loadDefaultLibrary() {
|
|
46
|
+
// 1. Browser Environment
|
|
47
|
+
if (typeof window !== 'undefined' && typeof fetch !== 'undefined') {
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch('https://unpkg.com/georgian-hyphenation@2/data/exceptions.json');
|
|
50
|
+
if (!response.ok) throw new Error("Network response error");
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
this.loadLibrary(data);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.warn("Georgian Hyphenation: Using algorithm only (Fetch failed)");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 2. Node.js Environment (ESM context)
|
|
58
|
+
else if (typeof process !== 'undefined') {
|
|
59
|
+
try {
|
|
60
|
+
// Node-ში ლოკალური ფაილის წაკითხვა
|
|
61
|
+
const { default: data } = await import('../../data/exceptions.json', {
|
|
62
|
+
assert: { type: 'json' }
|
|
63
|
+
});
|
|
64
|
+
this.loadLibrary(data);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.warn("Georgian Hyphenation: Local dictionary not found");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
hyphenate(word) {
|
|
72
|
+
const sanitizedWord = this._stripHyphens(word);
|
|
73
|
+
const cleanWord = sanitizedWord.replace(/[.,/#!$%^&*;:{}=\-_`~()]/g, "");
|
|
74
|
+
|
|
75
|
+
if (this.dictionary.has(cleanWord)) {
|
|
76
|
+
return this.dictionary.get(cleanWord).replace(/-/g, this.hyphenChar);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return this.applyAlgorithm(sanitizedWord);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
applyAlgorithm(word) {
|
|
83
|
+
if (word.length < (this.leftMin + this.rightMin)) return word;
|
|
84
|
+
|
|
85
|
+
const vowelIndices = [];
|
|
86
|
+
for (let i = 0; i < word.length; i++) {
|
|
87
|
+
if (this.vowels.includes(word[i])) vowelIndices.push(i);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (vowelIndices.length < 2) return word;
|
|
91
|
+
|
|
92
|
+
const insertPoints = [];
|
|
93
|
+
for (let i = 0; i < vowelIndices.length - 1; i++) {
|
|
94
|
+
const v1 = vowelIndices[i];
|
|
95
|
+
const v2 = vowelIndices[i + 1];
|
|
96
|
+
const distance = v2 - v1 - 1;
|
|
97
|
+
const betweenSubstring = word.substring(v1 + 1, v2);
|
|
98
|
+
|
|
99
|
+
let candidatePos = -1;
|
|
100
|
+
|
|
101
|
+
if (distance === 0 || distance === 1) {
|
|
102
|
+
candidatePos = v1 + 1;
|
|
103
|
+
} else {
|
|
104
|
+
let doubleConsonantIndex = -1;
|
|
105
|
+
for (let j = 0; j < betweenSubstring.length - 1; j++) {
|
|
106
|
+
if (betweenSubstring[j] === betweenSubstring[j + 1]) {
|
|
107
|
+
doubleConsonantIndex = j;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (doubleConsonantIndex !== -1) {
|
|
113
|
+
candidatePos = v1 + 1 + doubleConsonantIndex + 1;
|
|
114
|
+
} else {
|
|
115
|
+
let breakIndex = -1;
|
|
116
|
+
if (distance >= 2) {
|
|
117
|
+
const lastTwo = betweenSubstring.substring(distance - 2, distance);
|
|
118
|
+
if (this.harmonicClusters.has(lastTwo)) {
|
|
119
|
+
breakIndex = distance - 2;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
candidatePos = (breakIndex !== -1) ? v1 + 1 + breakIndex : v1 + 2;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (candidatePos >= this.leftMin && (word.length - candidatePos) >= this.rightMin) {
|
|
127
|
+
insertPoints.push(candidatePos);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let result = word.split('');
|
|
132
|
+
for (let i = insertPoints.length - 1; i >= 0; i--) {
|
|
133
|
+
result.splice(insertPoints[i], 0, this.hyphenChar);
|
|
134
|
+
}
|
|
135
|
+
return result.join('');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getSyllables(word) {
|
|
139
|
+
return this.hyphenate(word).split(this.hyphenChar);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
hyphenateText(text) {
|
|
143
|
+
if (!text) return '';
|
|
144
|
+
const sanitizedText = this._stripHyphens(text);
|
|
145
|
+
const parts = sanitizedText.split(/([ა-ჰ]+)/);
|
|
146
|
+
|
|
147
|
+
return parts.map(part => {
|
|
148
|
+
if (part.length >= 4 && /[ა-ჰ]/.test(part)) {
|
|
149
|
+
return this.hyphenate(part);
|
|
150
|
+
}
|
|
151
|
+
return part;
|
|
152
|
+
}).join('');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** * კროს-პლატფორმული მხარდაჭერა
|
|
157
|
+
*/
|
|
158
|
+
// 1. ბრაუზერისთვის (Global Object)
|
|
159
|
+
if (typeof window !== 'undefined') {
|
|
160
|
+
window.GeorgianHyphenator = GeorgianHyphenator;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 2. Node.js (CommonJS) - იმ შემთხვევაში თუ ვინმე მაინც require-ს გამოიყენებს
|
|
164
|
+
// (მხოლოდ თუ module.exports არსებობს)
|
|
165
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
166
|
+
module.exports = GeorgianHyphenator;
|
|
167
|
+
}
|
|
Binary file
|
|
Binary file
|
package/dist/index.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Georgian Language Hyphenation Library
|
|
3
|
-
* ქართული ენის დამარცვლის ბიბლიოთეკა
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export class GeorgianHyphenator {
|
|
7
|
-
/**
|
|
8
|
-
* Create a Georgian hyphenator
|
|
9
|
-
* @param hyphenChar - Character to use for hyphenation points (default: U+00AD soft hyphen)
|
|
10
|
-
*/
|
|
11
|
-
constructor(hyphenChar?: string);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Hyphenate a Georgian word
|
|
15
|
-
* @param word - Georgian word to hyphenate
|
|
16
|
-
* @returns Word with hyphenation points inserted
|
|
17
|
-
*/
|
|
18
|
-
hyphenate(word: string): string;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Get syllables for a Georgian word
|
|
22
|
-
* @param word - Georgian word
|
|
23
|
-
* @returns Array of syllables
|
|
24
|
-
*/
|
|
25
|
-
getSyllables(word: string): string[];
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Hyphenate entire text
|
|
29
|
-
* @param text - Georgian text
|
|
30
|
-
* @returns Hyphenated text
|
|
31
|
-
*/
|
|
32
|
-
hyphenateText(text: string): string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Convert word to TeX pattern format
|
|
37
|
-
* @param word - Georgian word
|
|
38
|
-
* @returns TeX pattern
|
|
39
|
-
*/
|
|
40
|
-
export function toTeXPattern(word: string): string;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Convert word to Hunspell format
|
|
44
|
-
* @param word - Georgian word
|
|
45
|
-
* @returns Hunspell format
|
|
46
|
-
*/
|
|
47
|
-
export function toHunspellFormat(word: string): string;
|
package/dist/index.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Georgian Language Hyphenation Library (JavaScript)
|
|
3
|
-
* ქართული ენის დამარცვლის ბიბლიოთეკა
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* const hyphenator = new GeorgianHyphenator();
|
|
7
|
-
* const result = hyphenator.hyphenate("საქართველო");
|
|
8
|
-
* // Result: "სა\u00ADქარ\u00ADთვე\u00ADლო"
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
class GeorgianHyphenator {
|
|
12
|
-
/**
|
|
13
|
-
* Initialize Georgian Hyphenator
|
|
14
|
-
* @param {string} hyphenChar - Character to use for hyphenation (default: soft hyphen U+00AD)
|
|
15
|
-
*/
|
|
16
|
-
constructor(hyphenChar = '\u00AD') {
|
|
17
|
-
this.hyphenChar = hyphenChar;
|
|
18
|
-
this.C = '[ბგდვზთკლმნპჟრსტფქღყშჩცძწჭხჯჰ]'; // Consonants
|
|
19
|
-
this.V = '[აეიოუ]'; // Vowels
|
|
20
|
-
this.char = '[ა-ჰ]'; // All Georgian letters
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Count vowels in a word
|
|
25
|
-
* @param {string} word - Georgian word
|
|
26
|
-
* @returns {number} Number of vowels
|
|
27
|
-
*/
|
|
28
|
-
countVowels(word) {
|
|
29
|
-
const vowels = 'აეიოუ';
|
|
30
|
-
let count = 0;
|
|
31
|
-
for (let v of vowels) {
|
|
32
|
-
count += (word.match(new RegExp(v, 'g')) || []).length;
|
|
33
|
-
}
|
|
34
|
-
return count;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Apply hyphenation rules with specified boundary markers
|
|
39
|
-
* @private
|
|
40
|
-
*/
|
|
41
|
-
_applyRules(w, softhpn, startchar, endchar) {
|
|
42
|
-
const C = this.C;
|
|
43
|
-
const V = this.V;
|
|
44
|
-
const char = this.char;
|
|
45
|
-
|
|
46
|
-
let t = w;
|
|
47
|
-
|
|
48
|
-
// Rule 1: V+C+C++V → VC|CV
|
|
49
|
-
t = t.replace(new RegExp(`(${V})(${C})(${C}+)(${V})`, 'gu'),
|
|
50
|
-
`$1$2${softhpn}$3$4`);
|
|
51
|
-
|
|
52
|
-
// Rule 2: V+C+V+C+V → VCV|CV
|
|
53
|
-
t = t.replace(new RegExp(`(${V})(${C})(${V})(${C})(${V})`, 'gu'),
|
|
54
|
-
`$1$2$3${softhpn}$4$5`);
|
|
55
|
-
|
|
56
|
-
// Rule 3: C+V+C+V → CV|CV
|
|
57
|
-
t = t.replace(new RegExp(`(${C})(${V})(${C})(${V})`, 'gu'),
|
|
58
|
-
`$1$2${softhpn}$3$4`);
|
|
59
|
-
|
|
60
|
-
// Rule 4: V+V+V → VV|V
|
|
61
|
-
t = t.replace(new RegExp(`(${V})(${V})(${V})`, 'gu'),
|
|
62
|
-
`$1$2${softhpn}$3`);
|
|
63
|
-
|
|
64
|
-
// Rule 5: Word start - ^VCVCV
|
|
65
|
-
t = t.replace(new RegExp(`${startchar}(${V})(${C})(${V})(${C})(${V})`, 'gu'),
|
|
66
|
-
`$1$2$3${softhpn}$4$5`);
|
|
67
|
-
|
|
68
|
-
// Rule 6: Word start - ^VCVCchar
|
|
69
|
-
t = t.replace(new RegExp(`${startchar}(${V})(${C})(${V})(${C})(${char})`, 'gu'),
|
|
70
|
-
`$1$2$3${softhpn}$4$5`);
|
|
71
|
-
|
|
72
|
-
// Rule 7: Word start - ^C++CVCV
|
|
73
|
-
t = t.replace(new RegExp(`${startchar}(${C}+)(${V})(${C})(${V})`, 'gu'),
|
|
74
|
-
`$1$2${softhpn}$3$4`);
|
|
75
|
-
|
|
76
|
-
// Rule 8: Word start - ^C++VVchar
|
|
77
|
-
t = t.replace(new RegExp(`${startchar}(${C}+)(${V})(${V})(${char})`, 'gu'),
|
|
78
|
-
`$1$2${softhpn}$3$4`);
|
|
79
|
-
|
|
80
|
-
// Rule 9: Word end - charVVC++$
|
|
81
|
-
t = t.replace(new RegExp(`(${char})(${V})(${V})(${C}+)${endchar}`, 'gu'),
|
|
82
|
-
`$1$2${softhpn}$3$4`);
|
|
83
|
-
|
|
84
|
-
// Rule 10: Word end - charVCV$
|
|
85
|
-
t = t.replace(new RegExp(`(${char})(${V})(${C})(${V})${endchar}`, 'gu'),
|
|
86
|
-
`$1$2${softhpn}$3$4`);
|
|
87
|
-
|
|
88
|
-
// Rule 11: Word end - VCC++VC++$
|
|
89
|
-
t = t.replace(new RegExp(`(${V})(${C})(${C}+)(${V})(${C}+)${endchar}`, 'gu'),
|
|
90
|
-
`$1$2${softhpn}$3$4$5`);
|
|
91
|
-
|
|
92
|
-
// Rule 12: Word end - charVCVC++$
|
|
93
|
-
t = t.replace(new RegExp(`(${char})(${V})(${C})(${V}+)(${C}+)${endchar}`, 'gu'),
|
|
94
|
-
`$1$2${softhpn}$3$4$5`);
|
|
95
|
-
|
|
96
|
-
return t;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Hyphenate a single Georgian word
|
|
101
|
-
* @param {string} word - Georgian word to hyphenate
|
|
102
|
-
* @returns {string} Word with hyphenation points
|
|
103
|
-
*/
|
|
104
|
-
hyphenate(word) {
|
|
105
|
-
// Don't hyphenate words with 0-1 vowels
|
|
106
|
-
if (this.countVowels(word) <= 1) {
|
|
107
|
-
return word;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const softhpn = this.hyphenChar;
|
|
111
|
-
|
|
112
|
-
// Apply hyphenation rules with different boundary markers
|
|
113
|
-
let result = this._applyRules(word, softhpn, '^', '$');
|
|
114
|
-
result = this._applyRules(result, softhpn, '^', this._escapeRegex(softhpn));
|
|
115
|
-
result = this._applyRules(result, this._escapeRegex(softhpn), '$');
|
|
116
|
-
result = this._applyRules(result, this._escapeRegex(softhpn), this._escapeRegex(softhpn));
|
|
117
|
-
|
|
118
|
-
// Remove duplicate hyphens
|
|
119
|
-
const escapedHyphen = this._escapeRegex(softhpn);
|
|
120
|
-
result = result.replace(new RegExp(`${escapedHyphen}+`, 'gu'), softhpn);
|
|
121
|
-
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get array of syllables for a word
|
|
127
|
-
* @param {string} word - Georgian word
|
|
128
|
-
* @returns {string[]} Array of syllables
|
|
129
|
-
*/
|
|
130
|
-
getSyllables(word) {
|
|
131
|
-
const hyphenated = this.hyphenate(word);
|
|
132
|
-
return hyphenated.split(this.hyphenChar);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Hyphenate entire text
|
|
137
|
-
* @param {string} text - Georgian text
|
|
138
|
-
* @returns {string} Hyphenated text
|
|
139
|
-
*/
|
|
140
|
-
hyphenateText(text) {
|
|
141
|
-
const words = text.split(' ');
|
|
142
|
-
const hyphenatedWords = words.map(w => this.hyphenate(w));
|
|
143
|
-
return hyphenatedWords.join(' ');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Escape special regex characters
|
|
148
|
-
* @private
|
|
149
|
-
*/
|
|
150
|
-
_escapeRegex(str) {
|
|
151
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Convert word to TeX pattern format
|
|
157
|
-
* @param {string} word - Georgian word
|
|
158
|
-
* @returns {string} TeX pattern
|
|
159
|
-
*/
|
|
160
|
-
function toTeXPattern(word) {
|
|
161
|
-
const hyphenator = new GeorgianHyphenator();
|
|
162
|
-
const syllables = hyphenator.getSyllables(word);
|
|
163
|
-
if (syllables.length <= 1) {
|
|
164
|
-
return `.${word}`;
|
|
165
|
-
}
|
|
166
|
-
return '.' + syllables.join('1');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Convert word to Hunspell format
|
|
171
|
-
* @param {string} word - Georgian word
|
|
172
|
-
* @returns {string} Hunspell format
|
|
173
|
-
*/
|
|
174
|
-
function toHunspellFormat(word) {
|
|
175
|
-
const hyphenator = new GeorgianHyphenator();
|
|
176
|
-
const syllables = hyphenator.getSyllables(word);
|
|
177
|
-
return syllables.join('=');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Export for use in Node.js or browser
|
|
181
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
182
|
-
module.exports = {
|
|
183
|
-
GeorgianHyphenator,
|
|
184
|
-
toTeXPattern,
|
|
185
|
-
toHunspellFormat
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Demo usage
|
|
190
|
-
if (typeof window !== 'undefined') {
|
|
191
|
-
window.GeorgianHyphenator = GeorgianHyphenator;
|
|
192
|
-
window.toTeXPattern = toTeXPattern;
|
|
193
|
-
window.toHunspellFormat = toHunspellFormat;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Example usage:
|
|
197
|
-
// const hyphenator = new GeorgianHyphenator('-'); // visible hyphens
|
|
198
|
-
// console.log(hyphenator.hyphenate("საქართველო")); // "სა-ქარ-თვე-ლო"
|
|
199
|
-
// console.log(hyphenator.getSyllables("საქართველო")); // ["სა", "ქარ", "თვე", "ლო"]
|