pyunislavic 0.1.0__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.
- pyunislavic-0.1.0/.gitignore +25 -0
- pyunislavic-0.1.0/LICENSE +22 -0
- pyunislavic-0.1.0/PKG-INFO +446 -0
- pyunislavic-0.1.0/README.md +429 -0
- pyunislavic-0.1.0/pyproject.toml +40 -0
- pyunislavic-0.1.0/src/pyunislavic/__init__.py +11 -0
- pyunislavic-0.1.0/src/pyunislavic/py.typed +0 -0
- pyunislavic-0.1.0/src/pyunislavic/transliterate.py +376 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Python bytecode
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
|
|
8
|
+
# Build artifacts
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
|
|
13
|
+
# Test and coverage artifacts
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.coverage
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# Virtual environments
|
|
19
|
+
.venv/
|
|
20
|
+
venv/
|
|
21
|
+
env/
|
|
22
|
+
|
|
23
|
+
# IDE settings
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zijie ZHANG
|
|
4
|
+
Copyright (c) 2021 Medžuslovjansky (Меджусловјанскы)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyunislavic
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python implementation for transliterating and normalizing text from many Slavic languages and Interslavic into unified writing systems.
|
|
5
|
+
Author: Zijie ZHANG
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: cyrillic,cyrillization,interslavic,latin,normalization,orthography,romanization,slavic,transliteration
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# PyUniSlavic
|
|
19
|
+
|
|
20
|
+
A Python implementation for transliterating and normalizing text from many
|
|
21
|
+
Slavic languages and Interslavic into unified writing systems.
|
|
22
|
+
|
|
23
|
+
PyUniSlavic converts text written with a broad range of Latin and Cyrillic
|
|
24
|
+
letters used across Slavic orthographies into a selected common Latin,
|
|
25
|
+
ASCII-oriented, or Cyrillic representation. It preserves the source words,
|
|
26
|
+
grammar, and meaning: it is a writing-system converter, not a machine
|
|
27
|
+
translator.
|
|
28
|
+
|
|
29
|
+
The package is an independent, focused Python port of part of the
|
|
30
|
+
transliteration logic in
|
|
31
|
+
[`@interslavic/utils`](https://github.com/medzuslovjansky/js-utils). The
|
|
32
|
+
upstream algorithm was created for Interslavic transliteration. PyUniSlavic
|
|
33
|
+
also uses its permissive input normalization as a practical common writing
|
|
34
|
+
layer for text in multiple Slavic languages.
|
|
35
|
+
|
|
36
|
+
This broader use follows from the design of
|
|
37
|
+
[Interslavic orthography](https://interslavic.fun/learn/orthography/) itself.
|
|
38
|
+
Its standard Latin and Cyrillic alphabets are cross-Slavic compromises rather
|
|
39
|
+
than adaptations of any one national orthography, and they were designed to be
|
|
40
|
+
intuitively understandable and easy to transliterate between. Its optional
|
|
41
|
+
etymological letters represent shared historical phonemes whose developments
|
|
42
|
+
in modern Slavic languages are largely predictable. The official orthography
|
|
43
|
+
guide therefore explicitly identifies transcription from any Slavic language
|
|
44
|
+
into Interslavic orthography as one possible use of this etymological layer.
|
|
45
|
+
It illustrates the principle with `pęť`: one shared etymological form that
|
|
46
|
+
relates several divergent national spellings of the same inherited word.
|
|
47
|
+
|
|
48
|
+
The
|
|
49
|
+
[upstream implementation](https://github.com/medzuslovjansky/js-utils/blob/main/src/transliterate/transliterate.ts)
|
|
50
|
+
turns that cross-Slavic design into a reusable pipeline: its loose preprocessor
|
|
51
|
+
maps many Latin and Cyrillic letter variants, historical characters, and
|
|
52
|
+
alternative spellings into a common internal representation; the flavor stage
|
|
53
|
+
then preserves or merges selected distinctions before the result is rendered
|
|
54
|
+
in the requested output orthography. PyUniSlavic reuses this orthographic
|
|
55
|
+
pipeline without changing the source vocabulary or grammar. In this way, a
|
|
56
|
+
mechanism created for Interslavic transliteration can also provide practical
|
|
57
|
+
cross-Slavic script unification and same-script normalization. This remains
|
|
58
|
+
orthographic normalization rather than translation, and it does not claim
|
|
59
|
+
exact language-specific phonological conversion for every Slavic language.
|
|
60
|
+
|
|
61
|
+
PyUniSlavic is not an official Interslavic implementation and is not affiliated
|
|
62
|
+
with or endorsed by the Interslavic project.
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
- Transliterates between common Latin and Cyrillic representations.
|
|
67
|
+
- Normalizes Latin text to a shared Latin orthography.
|
|
68
|
+
- Normalizes Cyrillic text to a shared Cyrillic orthography.
|
|
69
|
+
- Accepts many modern, historical, and alternative Latin and Cyrillic letters
|
|
70
|
+
recognized by the upstream loose-input normalizer.
|
|
71
|
+
- Provides etymological, standard, and simplified output profiles.
|
|
72
|
+
- Preserves punctuation, numbers, spacing, and basic capitalization patterns.
|
|
73
|
+
- Uses only the Python standard library.
|
|
74
|
+
- Does not translate, lemmatize, or alter the grammar of the source language.
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install pyunislavic
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Quick start
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from pyunislavic import transliterate
|
|
86
|
+
|
|
87
|
+
result = transliterate(
|
|
88
|
+
"Меджусловјанскы језык",
|
|
89
|
+
type=1,
|
|
90
|
+
flav=2,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
print(result)
|
|
94
|
+
# Medžuslovjansky jezyk
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The public function is:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
transliterate(i_source: str, type: int, flav: int = 2) -> str
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Supported output types
|
|
104
|
+
|
|
105
|
+
| `type` | Name | Output |
|
|
106
|
+
| ---: | --- | --- |
|
|
107
|
+
| `1` | Latin | Common Latin orthography with diacritics |
|
|
108
|
+
| `2` | ASCII-oriented | Digraph-based Latin output such as `sz`, `cz`, and `zs` |
|
|
109
|
+
| `5` | Standard Cyrillic | Common Cyrillic orthography using letters such as `ј`, `љ`, and `њ` |
|
|
110
|
+
|
|
111
|
+
`type=2` follows the behavior and naming of the upstream `ASCII` mode. With
|
|
112
|
+
`flav=2`, some supported soft-consonant letters can remain non-ASCII, so this
|
|
113
|
+
mode should be understood as ASCII-oriented rather than an unconditional
|
|
114
|
+
7-bit ASCII guarantee.
|
|
115
|
+
|
|
116
|
+
## Supported flavor profiles
|
|
117
|
+
|
|
118
|
+
| `flav` | Name | Behavior |
|
|
119
|
+
| ---: | --- | --- |
|
|
120
|
+
| `2` | Etymological | Preserves the greatest number of distinctions supported by this port |
|
|
121
|
+
| `3` | Standard | Merges several historical vowels and soft-consonant distinctions |
|
|
122
|
+
| `4` | Slovianto | Applies additional simplification, including `ě → e` and `y → i` |
|
|
123
|
+
|
|
124
|
+
Every supported output type can be combined with every supported flavor, for a
|
|
125
|
+
total of nine combinations:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
type = 1, 2, or 5
|
|
129
|
+
flav = 2, 3, or 4
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Unsupported values raise `ValueError`.
|
|
133
|
+
|
|
134
|
+
Enums are also available:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from enum import IntEnum
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class TransliterationType(IntEnum):
|
|
141
|
+
LATIN = 1
|
|
142
|
+
ASCII = 2
|
|
143
|
+
STANDARD_CYRILLIC = 5
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class FlavorizationType(IntEnum):
|
|
147
|
+
ETYMOLOGICAL = 2
|
|
148
|
+
STANDARD = 3
|
|
149
|
+
SLOVIANTO = 4
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
They can be imported and passed directly to `transliterate`:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from pyunislavic import (
|
|
156
|
+
FlavorizationType,
|
|
157
|
+
TransliterationType,
|
|
158
|
+
transliterate,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
result = transliterate(
|
|
162
|
+
"Medžuslovjansky jezyk",
|
|
163
|
+
type=TransliterationType.STANDARD_CYRILLIC,
|
|
164
|
+
flav=FlavorizationType.STANDARD,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
print(result)
|
|
168
|
+
# Меджусловјанскы језык
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Same-script normalization
|
|
172
|
+
|
|
173
|
+
The source and output scripts do not have to be different. Latin input can be
|
|
174
|
+
normalized to the selected common Latin profile, and Cyrillic input can be
|
|
175
|
+
normalized to the selected common Cyrillic profile.
|
|
176
|
+
|
|
177
|
+
### Latin input
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
transliterate(
|
|
181
|
+
"Nawet przy założeniu",
|
|
182
|
+
type=1,
|
|
183
|
+
flav=2,
|
|
184
|
+
)
|
|
185
|
+
# 'Navet przy založeniu'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Cyrillic input
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
transliterate(
|
|
192
|
+
"Улаштовуватимуть водопровідний вузол",
|
|
193
|
+
type=5,
|
|
194
|
+
flav=2,
|
|
195
|
+
)
|
|
196
|
+
# 'Улаштовуватимуть водопровидниј вузол'
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
These examples retain Polish and Ukrainian vocabulary and grammar. Only their
|
|
200
|
+
orthographic representation is normalized.
|
|
201
|
+
|
|
202
|
+
## Extended real-language examples
|
|
203
|
+
|
|
204
|
+
The following examples were produced by the current implementation from text
|
|
205
|
+
in several Slavic languages. Language labels use ISO 639-3 codes. They show
|
|
206
|
+
orthographic conversion and normalization as implemented by the upstream-derived
|
|
207
|
+
pipeline; they are not translations or claims about official national spelling.
|
|
208
|
+
|
|
209
|
+
### Latin etymological output (`type=1`, `flav=2`)
|
|
210
|
+
|
|
211
|
+
#### Belarusian (`bel`)
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
INPUT
|
|
215
|
+
Той жа Юры Чыж рабіў свой бізнэс па «паняцьцях», дзякуючы блізкасьці да «цела» меў прывілеі, атрымліваў вольны доступ у прыбытковыя сфэры, куды пускалі толькі абраных, напрыклад, у гандаль нафтапрадуктамі.
|
|
216
|
+
|
|
217
|
+
OUTPUT
|
|
218
|
+
Toj ža Jury Čiž rabiv svoj biznes pa «panjacjcjah», dźakujuči blizkaści da «cela» mev pryvilei, atrymlivav voĺny dostup u prybytkovyja sfery, kudy puskali toĺki abranyh, napryklad, u gandaĺ naftapraduktami.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Russian (`rus`)
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
INPUT
|
|
225
|
+
В боях за Дубно 14 февраля 1944 года молодой фотокорреспондент находился в боевых порядках 29-го гвардейского кавалерийского полка, оказавшегося в эпицентре сражения за город.
|
|
226
|
+
|
|
227
|
+
OUTPUT
|
|
228
|
+
V bojah za Dubno 14 fevralja 1944 goda molodoj fotokorrespondent nahodilśa v boevyh poŕadkah 29-go gvardejskogo kavalerijskogo polka, okazavšegośa v epicentre sraženija za gorod.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### Ukrainian (`ukr`)
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
INPUT
|
|
235
|
+
"Улаштовуватимуть водопровідний вузол на водоводі діаметром 900 мм на розі вул. Зеленогірської та вул. Петра Радченка", — йдеться у повідомленні.
|
|
236
|
+
|
|
237
|
+
OUTPUT
|
|
238
|
+
"Ulaštovuvatimut́ vodoprovidnij vuzol na vodovodi diametrom 900 mm na rozi vul. Zelenogirśkoji ta vul. Petra Radčenka", — jdet́śa u povidomlenni.
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Rusyn (`rue`)
|
|
242
|
+
|
|
243
|
+
```text
|
|
244
|
+
INPUT
|
|
245
|
+
Ключі організовано за дихотомічною системою і представлено у вигляді основного ключа до родин і 10 ключів до родів і видів кожної родини (кротові, мідицеві, вовчкові, мишівкові, тушканові, сліпакові, мишачі, хом'якові, норицеві).
|
|
246
|
+
|
|
247
|
+
OUTPUT
|
|
248
|
+
Ključi organizovano za dihotomičnoju sistemoju i predstavleno u vigljadi osnovnogo ključa do rodin i 10 ključiv do rodiv i vidiv kožnoji rodini (krotovi, midicevi, vovčkovi, mišivkovi, tuškanovi, slipakovi, mišači, hom'jakovi, noricevi).
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### Serbian (`srp`)
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
INPUT
|
|
255
|
+
Бугари су имали 7.000 погинулих 6.000 заробљених војника и 130 топова а Грци су имали 8.700 погинулих.
|
|
256
|
+
|
|
257
|
+
OUTPUT
|
|
258
|
+
Bugari su imali 7.000 poginulih 6.000 zarobljenih vojnika i 130 topova a Grci su imali 8.700 poginulih.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Cyrillic etymological output (`type=5`, `flav=2`)
|
|
262
|
+
|
|
263
|
+
#### Slovak (`slk`)
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
INPUT
|
|
267
|
+
Pridať do obľúbenýchProdukt si uložíte medzi vami zvolené obľúbené položky a môžete si ho tak rýchlo nájsť Drevený vozík na kolieskach obsahuje 24 farebných drevených kociek v rôznych tvaroch.
|
|
268
|
+
|
|
269
|
+
OUTPUT
|
|
270
|
+
Придать до обльубеныхпродукт си уложите медзи вами зволене обльубене положкы а можете си хо так рыхло најсть Древены возик на колиесках обсахује 24 фаребных древеных коциек в розных тварох.
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Polish (`pol`)
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
INPUT
|
|
277
|
+
Pytałem o Olsztyn, a oni wypowiadali się o mieście w samych superlatywach, twierdząc m.in., że szczególnie latem jest tu pięknie.
|
|
278
|
+
|
|
279
|
+
OUTPUT
|
|
280
|
+
Пыталем о Олштын, а они выповиадали сиѧ о миесьцие в самых суперлатывах, твиердзѫц м.ин., же шчеголние латем јест ту пиѧкние.
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Czech (`ces`)
|
|
284
|
+
|
|
285
|
+
```text
|
|
286
|
+
INPUT
|
|
287
|
+
Trojice slonů afrických v Zoo Dvůr Králové nad Labem na Trutnovsku si dnes pochutnala na vánoční nadílce, v níž bylo i několik vánočních stromků.
|
|
288
|
+
|
|
289
|
+
OUTPUT
|
|
290
|
+
Тројице слону африцкых в Зоо Двур Кралове над Лабем на Трутновску си днес похутнала на ваночни надилце, в ниж было и нѣколик ваночних стромку.
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Latin standard output (`type=1`, `flav=3`)
|
|
294
|
+
|
|
295
|
+
#### Polish (`pol`)
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
INPUT
|
|
299
|
+
Pytałem o Olsztyn, a oni wypowiadali się o mieście w samych superlatywach, twierdząc m.in., że szczególnie latem jest tu pięknie.
|
|
300
|
+
|
|
301
|
+
OUTPUT
|
|
302
|
+
Pytalem o Olštyn, a oni vypoviadali sie o miescie v samyh superlatyvah, tvierdzuc m.in., že ščegolnie latem jest tu pieknie.
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### ASCII-oriented standard output (`type=2`, `flav=3`)
|
|
306
|
+
|
|
307
|
+
#### Czech (`ces`)
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
INPUT
|
|
311
|
+
Trojice slonů afrických v Zoo Dvůr Králové nad Labem na Trutnovsku si dnes pochutnala na vánoční nadílce, v níž bylo i několik vánočních stromků.
|
|
312
|
+
|
|
313
|
+
OUTPUT
|
|
314
|
+
Trojice slonu africkyh v Zoo Dvur Kralove nad Labem na Trutnovsku si dnes pohutnala na vanoczni nadilce, v nizs bylo i njekolik vanocznih stromku.
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Cyrillic standard output (`type=5`, `flav=3`)
|
|
318
|
+
|
|
319
|
+
#### Belarusian (`bel`)
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
INPUT
|
|
323
|
+
Той жа Юры Чыж рабіў свой бізнэс па «паняцьцях», дзякуючы блізкасьці да «цела» меў прывілеі, атрымліваў вольны доступ у прыбытковыя сфэры, куды пускалі толькі абраных, напрыклад, у гандаль нафтапрадуктамі.
|
|
324
|
+
|
|
325
|
+
OUTPUT
|
|
326
|
+
Тој жа Јуры Чиж рабив свој бизнес па «пањацјцјах», дзакујучи близкасци да «цела» мев прывилеи, атрымливав волны доступ у прыбытковыја сферы, куды пускали толки абраных, напрыклад, у гандал нафтапрадуктами.
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### Russian (`rus`)
|
|
330
|
+
|
|
331
|
+
```text
|
|
332
|
+
INPUT
|
|
333
|
+
В боях за Дубно 14 февраля 1944 года молодой фотокорреспондент находился в боевых порядках 29-го гвардейского кавалерийского полка, оказавшегося в эпицентре сражения за город.
|
|
334
|
+
|
|
335
|
+
OUTPUT
|
|
336
|
+
В бојах за Дубно 14 февраља 1944 года молодој фотокорреспондент находилса в боевых порадках 29-го гвардејского кавалеријского полка, оказавшегоса в епицентре сраженија за город.
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### Ukrainian (`ukr`)
|
|
340
|
+
|
|
341
|
+
```text
|
|
342
|
+
INPUT
|
|
343
|
+
"Улаштовуватимуть водопровідний вузол на водоводі діаметром 900 мм на розі вул. Зеленогірської та вул. Петра Радченка", — йдеться у повідомленні.
|
|
344
|
+
|
|
345
|
+
OUTPUT
|
|
346
|
+
"Улаштовуватимут водопровидниј вузол на водоводи диаметром 900 мм на рози вул. Зеленогирскоји та вул. Петра Радченка", — јдетса у повидомленни.
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Rusyn (`rue`)
|
|
350
|
+
|
|
351
|
+
```text
|
|
352
|
+
INPUT
|
|
353
|
+
Ключі організовано за дихотомічною системою і представлено у вигляді основного ключа до родин і 10 ключів до родів і видів кожної родини (кротові, мідицеві, вовчкові, мишівкові, тушканові, сліпакові, мишачі, хом'якові, норицеві).
|
|
354
|
+
|
|
355
|
+
OUTPUT
|
|
356
|
+
Кључи организовано за дихотомичноју системоју и представлено у вигљади основного кључа до родин и 10 кључив до родив и видив кожноји родини (кротови, мидицеви, вовчкови, мишивкови, тушканови, слипакови, мишачи, хом'јакови, норицеви).
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### Slovak (`slk`)
|
|
360
|
+
|
|
361
|
+
```text
|
|
362
|
+
INPUT
|
|
363
|
+
Pridať do obľúbenýchProdukt si uložíte medzi vami zvolené obľúbené položky a môžete si ho tak rýchlo nájsť Drevený vozík na kolieskach obsahuje 24 farebných drevených kociek v rôznych tvaroch.
|
|
364
|
+
|
|
365
|
+
OUTPUT
|
|
366
|
+
Придат до облубеныхпродукт си уложите медзи вами зволене облубене положкы а можете си хо так рыхло најст Древены возик на колиесках обсахује 24 фаребных древеных коциек в розных тварох.
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Choosing a flavor
|
|
370
|
+
|
|
371
|
+
Use `flav=2` when retaining soft consonants and etymological distinctions is
|
|
372
|
+
more important than minimizing the character inventory.
|
|
373
|
+
|
|
374
|
+
Use `flav=3` for a more neutral and compact common orthography. For example,
|
|
375
|
+
some soft-sign distinctions retained by `flav=2` are removed by `flav=3`.
|
|
376
|
+
|
|
377
|
+
Use `flav=4` when maximum simplification is preferred and the additional loss
|
|
378
|
+
of orthographic distinctions is acceptable.
|
|
379
|
+
|
|
380
|
+
## Input processing
|
|
381
|
+
|
|
382
|
+
This focused port always uses the upstream loose-input preprocessing path. It:
|
|
383
|
+
|
|
384
|
+
1. normalizes input to Unicode NFC;
|
|
385
|
+
2. processes continuous sequences of Unicode letters and combining marks;
|
|
386
|
+
3. converts recognized Latin and Cyrillic variants to an internal common form;
|
|
387
|
+
4. applies the selected flavor profile;
|
|
388
|
+
5. renders the selected output type; and
|
|
389
|
+
6. restores lowercase, title-style, or uppercase word casing.
|
|
390
|
+
|
|
391
|
+
Punctuation, whitespace, digits, and other non-letter characters are preserved.
|
|
392
|
+
|
|
393
|
+
## Scope and limitations
|
|
394
|
+
|
|
395
|
+
PyUniSlavic provides a common orthographic representation, not a normative
|
|
396
|
+
spelling standard for every living Slavic language.
|
|
397
|
+
|
|
398
|
+
The loose-input rules were designed primarily to accept varied Interslavic
|
|
399
|
+
input. Their broad character coverage is useful for other Slavic languages,
|
|
400
|
+
but the normalizer is not a complete language-specific phonological analyzer.
|
|
401
|
+
For example:
|
|
402
|
+
|
|
403
|
+
- Polish combinations such as `rz` or `dzi` are not always interpreted as a
|
|
404
|
+
single language-specific sound.
|
|
405
|
+
- Some Ukrainian distinctions, including certain uses of `і/и` and `г/ґ`, can
|
|
406
|
+
be merged by normalization.
|
|
407
|
+
- Etymological and standard profiles intentionally merge different sets of
|
|
408
|
+
letters, so conversion is not guaranteed to be reversible.
|
|
409
|
+
- Mixed or camel-case capitalization is reduced to lowercase, title-style, or
|
|
410
|
+
uppercase at the word level, matching the upstream behavior.
|
|
411
|
+
|
|
412
|
+
Applications that require exact source-language phonology should add a
|
|
413
|
+
language-specific input adapter before calling `transliterate`.
|
|
414
|
+
|
|
415
|
+
## Compatibility testing
|
|
416
|
+
|
|
417
|
+
The initial Python port was checked against the upstream TypeScript behavior
|
|
418
|
+
for all nine supported parameter combinations. The parity suite included 144
|
|
419
|
+
targeted cases and 4,500 deterministic randomized Unicode cases, with identical
|
|
420
|
+
outputs for the tested inputs.
|
|
421
|
+
|
|
422
|
+
## Upstream project and attribution
|
|
423
|
+
|
|
424
|
+
The core transliteration and loose-normalization rules are adapted from:
|
|
425
|
+
|
|
426
|
+
- [`medzuslovjansky/js-utils`](https://github.com/medzuslovjansky/js-utils)
|
|
427
|
+
- [`src/transliterate/transliterate.ts`](https://github.com/medzuslovjansky/js-utils/blob/main/src/transliterate/transliterate.ts)
|
|
428
|
+
- [Interslavic](https://interslavic.fun/)
|
|
429
|
+
|
|
430
|
+
The upstream project describes `@interslavic/utils` as a collection of
|
|
431
|
+
JavaScript utilities for the Interslavic language, including transliteration.
|
|
432
|
+
|
|
433
|
+
The upstream source is distributed under the MIT License:
|
|
434
|
+
|
|
435
|
+
> Copyright (c) 2021 Medžuslovjansky (Меджусловјанскы)
|
|
436
|
+
|
|
437
|
+
Any distribution of this derived port must include the upstream copyright and
|
|
438
|
+
MIT permission notice. See the
|
|
439
|
+
[`@interslavic/utils` license](https://github.com/medzuslovjansky/js-utils/blob/main/LICENSE)
|
|
440
|
+
for the complete text.
|
|
441
|
+
|
|
442
|
+
## Project status
|
|
443
|
+
|
|
444
|
+
PyUniSlavic currently implements only the nine combinations documented above.
|
|
445
|
+
Other upstream output modes and flavor profiles are intentionally outside the
|
|
446
|
+
scope of this focused port.
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# PyUniSlavic
|
|
2
|
+
|
|
3
|
+
A Python implementation for transliterating and normalizing text from many
|
|
4
|
+
Slavic languages and Interslavic into unified writing systems.
|
|
5
|
+
|
|
6
|
+
PyUniSlavic converts text written with a broad range of Latin and Cyrillic
|
|
7
|
+
letters used across Slavic orthographies into a selected common Latin,
|
|
8
|
+
ASCII-oriented, or Cyrillic representation. It preserves the source words,
|
|
9
|
+
grammar, and meaning: it is a writing-system converter, not a machine
|
|
10
|
+
translator.
|
|
11
|
+
|
|
12
|
+
The package is an independent, focused Python port of part of the
|
|
13
|
+
transliteration logic in
|
|
14
|
+
[`@interslavic/utils`](https://github.com/medzuslovjansky/js-utils). The
|
|
15
|
+
upstream algorithm was created for Interslavic transliteration. PyUniSlavic
|
|
16
|
+
also uses its permissive input normalization as a practical common writing
|
|
17
|
+
layer for text in multiple Slavic languages.
|
|
18
|
+
|
|
19
|
+
This broader use follows from the design of
|
|
20
|
+
[Interslavic orthography](https://interslavic.fun/learn/orthography/) itself.
|
|
21
|
+
Its standard Latin and Cyrillic alphabets are cross-Slavic compromises rather
|
|
22
|
+
than adaptations of any one national orthography, and they were designed to be
|
|
23
|
+
intuitively understandable and easy to transliterate between. Its optional
|
|
24
|
+
etymological letters represent shared historical phonemes whose developments
|
|
25
|
+
in modern Slavic languages are largely predictable. The official orthography
|
|
26
|
+
guide therefore explicitly identifies transcription from any Slavic language
|
|
27
|
+
into Interslavic orthography as one possible use of this etymological layer.
|
|
28
|
+
It illustrates the principle with `pęť`: one shared etymological form that
|
|
29
|
+
relates several divergent national spellings of the same inherited word.
|
|
30
|
+
|
|
31
|
+
The
|
|
32
|
+
[upstream implementation](https://github.com/medzuslovjansky/js-utils/blob/main/src/transliterate/transliterate.ts)
|
|
33
|
+
turns that cross-Slavic design into a reusable pipeline: its loose preprocessor
|
|
34
|
+
maps many Latin and Cyrillic letter variants, historical characters, and
|
|
35
|
+
alternative spellings into a common internal representation; the flavor stage
|
|
36
|
+
then preserves or merges selected distinctions before the result is rendered
|
|
37
|
+
in the requested output orthography. PyUniSlavic reuses this orthographic
|
|
38
|
+
pipeline without changing the source vocabulary or grammar. In this way, a
|
|
39
|
+
mechanism created for Interslavic transliteration can also provide practical
|
|
40
|
+
cross-Slavic script unification and same-script normalization. This remains
|
|
41
|
+
orthographic normalization rather than translation, and it does not claim
|
|
42
|
+
exact language-specific phonological conversion for every Slavic language.
|
|
43
|
+
|
|
44
|
+
PyUniSlavic is not an official Interslavic implementation and is not affiliated
|
|
45
|
+
with or endorsed by the Interslavic project.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- Transliterates between common Latin and Cyrillic representations.
|
|
50
|
+
- Normalizes Latin text to a shared Latin orthography.
|
|
51
|
+
- Normalizes Cyrillic text to a shared Cyrillic orthography.
|
|
52
|
+
- Accepts many modern, historical, and alternative Latin and Cyrillic letters
|
|
53
|
+
recognized by the upstream loose-input normalizer.
|
|
54
|
+
- Provides etymological, standard, and simplified output profiles.
|
|
55
|
+
- Preserves punctuation, numbers, spacing, and basic capitalization patterns.
|
|
56
|
+
- Uses only the Python standard library.
|
|
57
|
+
- Does not translate, lemmatize, or alter the grammar of the source language.
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install pyunislavic
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quick start
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from pyunislavic import transliterate
|
|
69
|
+
|
|
70
|
+
result = transliterate(
|
|
71
|
+
"Меджусловјанскы језык",
|
|
72
|
+
type=1,
|
|
73
|
+
flav=2,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
print(result)
|
|
77
|
+
# Medžuslovjansky jezyk
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The public function is:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
transliterate(i_source: str, type: int, flav: int = 2) -> str
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Supported output types
|
|
87
|
+
|
|
88
|
+
| `type` | Name | Output |
|
|
89
|
+
| ---: | --- | --- |
|
|
90
|
+
| `1` | Latin | Common Latin orthography with diacritics |
|
|
91
|
+
| `2` | ASCII-oriented | Digraph-based Latin output such as `sz`, `cz`, and `zs` |
|
|
92
|
+
| `5` | Standard Cyrillic | Common Cyrillic orthography using letters such as `ј`, `љ`, and `њ` |
|
|
93
|
+
|
|
94
|
+
`type=2` follows the behavior and naming of the upstream `ASCII` mode. With
|
|
95
|
+
`flav=2`, some supported soft-consonant letters can remain non-ASCII, so this
|
|
96
|
+
mode should be understood as ASCII-oriented rather than an unconditional
|
|
97
|
+
7-bit ASCII guarantee.
|
|
98
|
+
|
|
99
|
+
## Supported flavor profiles
|
|
100
|
+
|
|
101
|
+
| `flav` | Name | Behavior |
|
|
102
|
+
| ---: | --- | --- |
|
|
103
|
+
| `2` | Etymological | Preserves the greatest number of distinctions supported by this port |
|
|
104
|
+
| `3` | Standard | Merges several historical vowels and soft-consonant distinctions |
|
|
105
|
+
| `4` | Slovianto | Applies additional simplification, including `ě → e` and `y → i` |
|
|
106
|
+
|
|
107
|
+
Every supported output type can be combined with every supported flavor, for a
|
|
108
|
+
total of nine combinations:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
type = 1, 2, or 5
|
|
112
|
+
flav = 2, 3, or 4
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Unsupported values raise `ValueError`.
|
|
116
|
+
|
|
117
|
+
Enums are also available:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from enum import IntEnum
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TransliterationType(IntEnum):
|
|
124
|
+
LATIN = 1
|
|
125
|
+
ASCII = 2
|
|
126
|
+
STANDARD_CYRILLIC = 5
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class FlavorizationType(IntEnum):
|
|
130
|
+
ETYMOLOGICAL = 2
|
|
131
|
+
STANDARD = 3
|
|
132
|
+
SLOVIANTO = 4
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
They can be imported and passed directly to `transliterate`:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from pyunislavic import (
|
|
139
|
+
FlavorizationType,
|
|
140
|
+
TransliterationType,
|
|
141
|
+
transliterate,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
result = transliterate(
|
|
145
|
+
"Medžuslovjansky jezyk",
|
|
146
|
+
type=TransliterationType.STANDARD_CYRILLIC,
|
|
147
|
+
flav=FlavorizationType.STANDARD,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
print(result)
|
|
151
|
+
# Меджусловјанскы језык
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Same-script normalization
|
|
155
|
+
|
|
156
|
+
The source and output scripts do not have to be different. Latin input can be
|
|
157
|
+
normalized to the selected common Latin profile, and Cyrillic input can be
|
|
158
|
+
normalized to the selected common Cyrillic profile.
|
|
159
|
+
|
|
160
|
+
### Latin input
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
transliterate(
|
|
164
|
+
"Nawet przy założeniu",
|
|
165
|
+
type=1,
|
|
166
|
+
flav=2,
|
|
167
|
+
)
|
|
168
|
+
# 'Navet przy založeniu'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Cyrillic input
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
transliterate(
|
|
175
|
+
"Улаштовуватимуть водопровідний вузол",
|
|
176
|
+
type=5,
|
|
177
|
+
flav=2,
|
|
178
|
+
)
|
|
179
|
+
# 'Улаштовуватимуть водопровидниј вузол'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
These examples retain Polish and Ukrainian vocabulary and grammar. Only their
|
|
183
|
+
orthographic representation is normalized.
|
|
184
|
+
|
|
185
|
+
## Extended real-language examples
|
|
186
|
+
|
|
187
|
+
The following examples were produced by the current implementation from text
|
|
188
|
+
in several Slavic languages. Language labels use ISO 639-3 codes. They show
|
|
189
|
+
orthographic conversion and normalization as implemented by the upstream-derived
|
|
190
|
+
pipeline; they are not translations or claims about official national spelling.
|
|
191
|
+
|
|
192
|
+
### Latin etymological output (`type=1`, `flav=2`)
|
|
193
|
+
|
|
194
|
+
#### Belarusian (`bel`)
|
|
195
|
+
|
|
196
|
+
```text
|
|
197
|
+
INPUT
|
|
198
|
+
Той жа Юры Чыж рабіў свой бізнэс па «паняцьцях», дзякуючы блізкасьці да «цела» меў прывілеі, атрымліваў вольны доступ у прыбытковыя сфэры, куды пускалі толькі абраных, напрыклад, у гандаль нафтапрадуктамі.
|
|
199
|
+
|
|
200
|
+
OUTPUT
|
|
201
|
+
Toj ža Jury Čiž rabiv svoj biznes pa «panjacjcjah», dźakujuči blizkaści da «cela» mev pryvilei, atrymlivav voĺny dostup u prybytkovyja sfery, kudy puskali toĺki abranyh, napryklad, u gandaĺ naftapraduktami.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Russian (`rus`)
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
INPUT
|
|
208
|
+
В боях за Дубно 14 февраля 1944 года молодой фотокорреспондент находился в боевых порядках 29-го гвардейского кавалерийского полка, оказавшегося в эпицентре сражения за город.
|
|
209
|
+
|
|
210
|
+
OUTPUT
|
|
211
|
+
V bojah za Dubno 14 fevralja 1944 goda molodoj fotokorrespondent nahodilśa v boevyh poŕadkah 29-go gvardejskogo kavalerijskogo polka, okazavšegośa v epicentre sraženija za gorod.
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Ukrainian (`ukr`)
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
INPUT
|
|
218
|
+
"Улаштовуватимуть водопровідний вузол на водоводі діаметром 900 мм на розі вул. Зеленогірської та вул. Петра Радченка", — йдеться у повідомленні.
|
|
219
|
+
|
|
220
|
+
OUTPUT
|
|
221
|
+
"Ulaštovuvatimut́ vodoprovidnij vuzol na vodovodi diametrom 900 mm na rozi vul. Zelenogirśkoji ta vul. Petra Radčenka", — jdet́śa u povidomlenni.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### Rusyn (`rue`)
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
INPUT
|
|
228
|
+
Ключі організовано за дихотомічною системою і представлено у вигляді основного ключа до родин і 10 ключів до родів і видів кожної родини (кротові, мідицеві, вовчкові, мишівкові, тушканові, сліпакові, мишачі, хом'якові, норицеві).
|
|
229
|
+
|
|
230
|
+
OUTPUT
|
|
231
|
+
Ključi organizovano za dihotomičnoju sistemoju i predstavleno u vigljadi osnovnogo ključa do rodin i 10 ključiv do rodiv i vidiv kožnoji rodini (krotovi, midicevi, vovčkovi, mišivkovi, tuškanovi, slipakovi, mišači, hom'jakovi, noricevi).
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Serbian (`srp`)
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
INPUT
|
|
238
|
+
Бугари су имали 7.000 погинулих 6.000 заробљених војника и 130 топова а Грци су имали 8.700 погинулих.
|
|
239
|
+
|
|
240
|
+
OUTPUT
|
|
241
|
+
Bugari su imali 7.000 poginulih 6.000 zarobljenih vojnika i 130 topova a Grci su imali 8.700 poginulih.
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Cyrillic etymological output (`type=5`, `flav=2`)
|
|
245
|
+
|
|
246
|
+
#### Slovak (`slk`)
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
INPUT
|
|
250
|
+
Pridať do obľúbenýchProdukt si uložíte medzi vami zvolené obľúbené položky a môžete si ho tak rýchlo nájsť Drevený vozík na kolieskach obsahuje 24 farebných drevených kociek v rôznych tvaroch.
|
|
251
|
+
|
|
252
|
+
OUTPUT
|
|
253
|
+
Придать до обльубеныхпродукт си уложите медзи вами зволене обльубене положкы а можете си хо так рыхло најсть Древены возик на колиесках обсахује 24 фаребных древеных коциек в розных тварох.
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### Polish (`pol`)
|
|
257
|
+
|
|
258
|
+
```text
|
|
259
|
+
INPUT
|
|
260
|
+
Pytałem o Olsztyn, a oni wypowiadali się o mieście w samych superlatywach, twierdząc m.in., że szczególnie latem jest tu pięknie.
|
|
261
|
+
|
|
262
|
+
OUTPUT
|
|
263
|
+
Пыталем о Олштын, а они выповиадали сиѧ о миесьцие в самых суперлатывах, твиердзѫц м.ин., же шчеголние латем јест ту пиѧкние.
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Czech (`ces`)
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
INPUT
|
|
270
|
+
Trojice slonů afrických v Zoo Dvůr Králové nad Labem na Trutnovsku si dnes pochutnala na vánoční nadílce, v níž bylo i několik vánočních stromků.
|
|
271
|
+
|
|
272
|
+
OUTPUT
|
|
273
|
+
Тројице слону африцкых в Зоо Двур Кралове над Лабем на Трутновску си днес похутнала на ваночни надилце, в ниж было и нѣколик ваночних стромку.
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Latin standard output (`type=1`, `flav=3`)
|
|
277
|
+
|
|
278
|
+
#### Polish (`pol`)
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
INPUT
|
|
282
|
+
Pytałem o Olsztyn, a oni wypowiadali się o mieście w samych superlatywach, twierdząc m.in., że szczególnie latem jest tu pięknie.
|
|
283
|
+
|
|
284
|
+
OUTPUT
|
|
285
|
+
Pytalem o Olštyn, a oni vypoviadali sie o miescie v samyh superlatyvah, tvierdzuc m.in., že ščegolnie latem jest tu pieknie.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### ASCII-oriented standard output (`type=2`, `flav=3`)
|
|
289
|
+
|
|
290
|
+
#### Czech (`ces`)
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
INPUT
|
|
294
|
+
Trojice slonů afrických v Zoo Dvůr Králové nad Labem na Trutnovsku si dnes pochutnala na vánoční nadílce, v níž bylo i několik vánočních stromků.
|
|
295
|
+
|
|
296
|
+
OUTPUT
|
|
297
|
+
Trojice slonu africkyh v Zoo Dvur Kralove nad Labem na Trutnovsku si dnes pohutnala na vanoczni nadilce, v nizs bylo i njekolik vanocznih stromku.
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Cyrillic standard output (`type=5`, `flav=3`)
|
|
301
|
+
|
|
302
|
+
#### Belarusian (`bel`)
|
|
303
|
+
|
|
304
|
+
```text
|
|
305
|
+
INPUT
|
|
306
|
+
Той жа Юры Чыж рабіў свой бізнэс па «паняцьцях», дзякуючы блізкасьці да «цела» меў прывілеі, атрымліваў вольны доступ у прыбытковыя сфэры, куды пускалі толькі абраных, напрыклад, у гандаль нафтапрадуктамі.
|
|
307
|
+
|
|
308
|
+
OUTPUT
|
|
309
|
+
Тој жа Јуры Чиж рабив свој бизнес па «пањацјцјах», дзакујучи близкасци да «цела» мев прывилеи, атрымливав волны доступ у прыбытковыја сферы, куды пускали толки абраных, напрыклад, у гандал нафтапрадуктами.
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Russian (`rus`)
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
INPUT
|
|
316
|
+
В боях за Дубно 14 февраля 1944 года молодой фотокорреспондент находился в боевых порядках 29-го гвардейского кавалерийского полка, оказавшегося в эпицентре сражения за город.
|
|
317
|
+
|
|
318
|
+
OUTPUT
|
|
319
|
+
В бојах за Дубно 14 февраља 1944 года молодој фотокорреспондент находилса в боевых порадках 29-го гвардејского кавалеријского полка, оказавшегоса в епицентре сраженија за город.
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Ukrainian (`ukr`)
|
|
323
|
+
|
|
324
|
+
```text
|
|
325
|
+
INPUT
|
|
326
|
+
"Улаштовуватимуть водопровідний вузол на водоводі діаметром 900 мм на розі вул. Зеленогірської та вул. Петра Радченка", — йдеться у повідомленні.
|
|
327
|
+
|
|
328
|
+
OUTPUT
|
|
329
|
+
"Улаштовуватимут водопровидниј вузол на водоводи диаметром 900 мм на рози вул. Зеленогирскоји та вул. Петра Радченка", — јдетса у повидомленни.
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### Rusyn (`rue`)
|
|
333
|
+
|
|
334
|
+
```text
|
|
335
|
+
INPUT
|
|
336
|
+
Ключі організовано за дихотомічною системою і представлено у вигляді основного ключа до родин і 10 ключів до родів і видів кожної родини (кротові, мідицеві, вовчкові, мишівкові, тушканові, сліпакові, мишачі, хом'якові, норицеві).
|
|
337
|
+
|
|
338
|
+
OUTPUT
|
|
339
|
+
Кључи организовано за дихотомичноју системоју и представлено у вигљади основного кључа до родин и 10 кључив до родив и видив кожноји родини (кротови, мидицеви, вовчкови, мишивкови, тушканови, слипакови, мишачи, хом'јакови, норицеви).
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### Slovak (`slk`)
|
|
343
|
+
|
|
344
|
+
```text
|
|
345
|
+
INPUT
|
|
346
|
+
Pridať do obľúbenýchProdukt si uložíte medzi vami zvolené obľúbené položky a môžete si ho tak rýchlo nájsť Drevený vozík na kolieskach obsahuje 24 farebných drevených kociek v rôznych tvaroch.
|
|
347
|
+
|
|
348
|
+
OUTPUT
|
|
349
|
+
Придат до облубеныхпродукт си уложите медзи вами зволене облубене положкы а можете си хо так рыхло најст Древены возик на колиесках обсахује 24 фаребных древеных коциек в розных тварох.
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Choosing a flavor
|
|
353
|
+
|
|
354
|
+
Use `flav=2` when retaining soft consonants and etymological distinctions is
|
|
355
|
+
more important than minimizing the character inventory.
|
|
356
|
+
|
|
357
|
+
Use `flav=3` for a more neutral and compact common orthography. For example,
|
|
358
|
+
some soft-sign distinctions retained by `flav=2` are removed by `flav=3`.
|
|
359
|
+
|
|
360
|
+
Use `flav=4` when maximum simplification is preferred and the additional loss
|
|
361
|
+
of orthographic distinctions is acceptable.
|
|
362
|
+
|
|
363
|
+
## Input processing
|
|
364
|
+
|
|
365
|
+
This focused port always uses the upstream loose-input preprocessing path. It:
|
|
366
|
+
|
|
367
|
+
1. normalizes input to Unicode NFC;
|
|
368
|
+
2. processes continuous sequences of Unicode letters and combining marks;
|
|
369
|
+
3. converts recognized Latin and Cyrillic variants to an internal common form;
|
|
370
|
+
4. applies the selected flavor profile;
|
|
371
|
+
5. renders the selected output type; and
|
|
372
|
+
6. restores lowercase, title-style, or uppercase word casing.
|
|
373
|
+
|
|
374
|
+
Punctuation, whitespace, digits, and other non-letter characters are preserved.
|
|
375
|
+
|
|
376
|
+
## Scope and limitations
|
|
377
|
+
|
|
378
|
+
PyUniSlavic provides a common orthographic representation, not a normative
|
|
379
|
+
spelling standard for every living Slavic language.
|
|
380
|
+
|
|
381
|
+
The loose-input rules were designed primarily to accept varied Interslavic
|
|
382
|
+
input. Their broad character coverage is useful for other Slavic languages,
|
|
383
|
+
but the normalizer is not a complete language-specific phonological analyzer.
|
|
384
|
+
For example:
|
|
385
|
+
|
|
386
|
+
- Polish combinations such as `rz` or `dzi` are not always interpreted as a
|
|
387
|
+
single language-specific sound.
|
|
388
|
+
- Some Ukrainian distinctions, including certain uses of `і/и` and `г/ґ`, can
|
|
389
|
+
be merged by normalization.
|
|
390
|
+
- Etymological and standard profiles intentionally merge different sets of
|
|
391
|
+
letters, so conversion is not guaranteed to be reversible.
|
|
392
|
+
- Mixed or camel-case capitalization is reduced to lowercase, title-style, or
|
|
393
|
+
uppercase at the word level, matching the upstream behavior.
|
|
394
|
+
|
|
395
|
+
Applications that require exact source-language phonology should add a
|
|
396
|
+
language-specific input adapter before calling `transliterate`.
|
|
397
|
+
|
|
398
|
+
## Compatibility testing
|
|
399
|
+
|
|
400
|
+
The initial Python port was checked against the upstream TypeScript behavior
|
|
401
|
+
for all nine supported parameter combinations. The parity suite included 144
|
|
402
|
+
targeted cases and 4,500 deterministic randomized Unicode cases, with identical
|
|
403
|
+
outputs for the tested inputs.
|
|
404
|
+
|
|
405
|
+
## Upstream project and attribution
|
|
406
|
+
|
|
407
|
+
The core transliteration and loose-normalization rules are adapted from:
|
|
408
|
+
|
|
409
|
+
- [`medzuslovjansky/js-utils`](https://github.com/medzuslovjansky/js-utils)
|
|
410
|
+
- [`src/transliterate/transliterate.ts`](https://github.com/medzuslovjansky/js-utils/blob/main/src/transliterate/transliterate.ts)
|
|
411
|
+
- [Interslavic](https://interslavic.fun/)
|
|
412
|
+
|
|
413
|
+
The upstream project describes `@interslavic/utils` as a collection of
|
|
414
|
+
JavaScript utilities for the Interslavic language, including transliteration.
|
|
415
|
+
|
|
416
|
+
The upstream source is distributed under the MIT License:
|
|
417
|
+
|
|
418
|
+
> Copyright (c) 2021 Medžuslovjansky (Меджусловјанскы)
|
|
419
|
+
|
|
420
|
+
Any distribution of this derived port must include the upstream copyright and
|
|
421
|
+
MIT permission notice. See the
|
|
422
|
+
[`@interslavic/utils` license](https://github.com/medzuslovjansky/js-utils/blob/main/LICENSE)
|
|
423
|
+
for the complete text.
|
|
424
|
+
|
|
425
|
+
## Project status
|
|
426
|
+
|
|
427
|
+
PyUniSlavic currently implements only the nine combinations documented above.
|
|
428
|
+
Other upstream output modes and flavor profiles are intentionally outside the
|
|
429
|
+
scope of this focused port.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "pyunislavic"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
description = "A Python implementation for transliterating and normalizing text from many Slavic languages and Interslavic into unified writing systems."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
authors = [
|
|
15
|
+
{ name = "Zijie ZHANG" }
|
|
16
|
+
]
|
|
17
|
+
keywords = [
|
|
18
|
+
"slavic",
|
|
19
|
+
"interslavic",
|
|
20
|
+
"transliteration",
|
|
21
|
+
"cyrillic",
|
|
22
|
+
"latin",
|
|
23
|
+
"orthography",
|
|
24
|
+
"normalization",
|
|
25
|
+
"romanization",
|
|
26
|
+
"cyrillization",
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Development Status :: 3 - Alpha",
|
|
30
|
+
"Intended Audience :: Developers",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
"Programming Language :: Python :: 3",
|
|
33
|
+
"Typing :: Typed",
|
|
34
|
+
"Topic :: Text Processing :: Linguistic",
|
|
35
|
+
]
|
|
36
|
+
dependencies = []
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
packages = ["src/pyunislavic"]
|
|
File without changes
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
"""Faithful Python subset of ``transliterate.ts``.
|
|
2
|
+
|
|
3
|
+
Supported combinations:
|
|
4
|
+
|
|
5
|
+
* type=1 (Latin), flav=2/3/4
|
|
6
|
+
* type=2 (ASCII), flav=2/3/4
|
|
7
|
+
* type=5 (Standard Cyrillic), flav=2/3/4
|
|
8
|
+
|
|
9
|
+
Only the original loose-input preprocessing path is included.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from enum import IntEnum
|
|
15
|
+
import re
|
|
16
|
+
import unicodedata
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TransliterationType(IntEnum):
|
|
20
|
+
LATIN = 1
|
|
21
|
+
ASCII = 2
|
|
22
|
+
STANDARD_CYRILLIC = 5
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class FlavorizationType(IntEnum):
|
|
26
|
+
ETYMOLOGICAL = 2
|
|
27
|
+
STANDARD = 3
|
|
28
|
+
SLOVIANTO = 4
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_SUPPORTED_TYPES = frozenset(TransliterationType)
|
|
32
|
+
_SUPPORTED_FLAVORS = frozenset(FlavorizationType)
|
|
33
|
+
_VOWELS = frozenset("aeiouyąęųåėȯèòěê")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def transliterate(i_source: str, type: int, flav: int = 2) -> str:
|
|
37
|
+
"""Transliterate text using one of the nine supported combinations.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
i_source: Input text.
|
|
41
|
+
type: 1 for Latin, 2 for ASCII, or 5 for Standard Cyrillic.
|
|
42
|
+
flav: 2 for etymological, 3 for standard, or 4 for Slovianto.
|
|
43
|
+
|
|
44
|
+
The function always uses the loose preprocessing mode from the TypeScript
|
|
45
|
+
implementation. Non-letter characters are preserved unchanged.
|
|
46
|
+
"""
|
|
47
|
+
if not isinstance(i_source, str):
|
|
48
|
+
raise TypeError("i_source must be a string")
|
|
49
|
+
if type not in _SUPPORTED_TYPES:
|
|
50
|
+
raise ValueError("type must be one of: 1 (Latin), 2 (ASCII), 5 (Standard Cyrillic)")
|
|
51
|
+
if flav not in _SUPPORTED_FLAVORS:
|
|
52
|
+
raise ValueError("flav must be one of: 2 (Etymological), 3 (Standard), 4 (Slovianto)")
|
|
53
|
+
|
|
54
|
+
source = unicodedata.normalize("NFC", i_source)
|
|
55
|
+
result: list[str] = []
|
|
56
|
+
word: list[str] = []
|
|
57
|
+
|
|
58
|
+
def flush_word() -> None:
|
|
59
|
+
if not word:
|
|
60
|
+
return
|
|
61
|
+
original_word = "".join(word)
|
|
62
|
+
marked_original = f"%{original_word}%"
|
|
63
|
+
internal_word = _nmsify_loose(marked_original.lower())
|
|
64
|
+
result.append(
|
|
65
|
+
_transliterate_word(
|
|
66
|
+
internal_word,
|
|
67
|
+
marked_original,
|
|
68
|
+
int(type),
|
|
69
|
+
int(flav),
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
word.clear()
|
|
73
|
+
|
|
74
|
+
for char in source:
|
|
75
|
+
if unicodedata.category(char)[:1] in {"L", "M"}:
|
|
76
|
+
word.append(char)
|
|
77
|
+
else:
|
|
78
|
+
flush_word()
|
|
79
|
+
result.append(char)
|
|
80
|
+
flush_word()
|
|
81
|
+
|
|
82
|
+
return "".join(result)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _transliterate_word(
|
|
86
|
+
i_w: str,
|
|
87
|
+
original_word: str,
|
|
88
|
+
type: int,
|
|
89
|
+
flav: int,
|
|
90
|
+
) -> str:
|
|
91
|
+
# 'ŕ' remains between two consonants; otherwise it is represented by 'ř'.
|
|
92
|
+
i_w = i_w.replace("ŕ", "ř")
|
|
93
|
+
a_pos = i_w.find("ř")
|
|
94
|
+
if (
|
|
95
|
+
a_pos > 1
|
|
96
|
+
and i_w[a_pos - 1] != "%"
|
|
97
|
+
and i_w[a_pos - 1] not in _VOWELS
|
|
98
|
+
and i_w[a_pos + 1] not in _VOWELS
|
|
99
|
+
):
|
|
100
|
+
i_w = i_w[:a_pos] + "ŕ" + i_w[a_pos + 1 :]
|
|
101
|
+
|
|
102
|
+
# Protect rj/jr, then classify the first remaining consonantal 'r'.
|
|
103
|
+
i_w = i_w.replace("rj", "Rj")
|
|
104
|
+
i_w = i_w.replace("jr", "jR")
|
|
105
|
+
r_pos = i_w.find("r")
|
|
106
|
+
if (
|
|
107
|
+
r_pos > 1
|
|
108
|
+
and i_w[r_pos - 1] != "%"
|
|
109
|
+
and i_w[r_pos - 1] not in _VOWELS
|
|
110
|
+
and i_w[r_pos + 1] not in _VOWELS
|
|
111
|
+
):
|
|
112
|
+
i_w = i_w[:r_pos] + "ṙ" + i_w[r_pos + 1 :]
|
|
113
|
+
i_w = re.sub(r"([šžčc])ṙ", r"\g<1>ŕ", i_w)
|
|
114
|
+
i_w = i_w.replace("R", "r")
|
|
115
|
+
|
|
116
|
+
i_w = i_w.replace("x", "ks")
|
|
117
|
+
i_w = re.sub(r"([ńľřťďśź])j", r"\g<1>ıj", i_w)
|
|
118
|
+
i_w = re.sub(r"([dsz])j", r"\g<1>#j", i_w)
|
|
119
|
+
i_w = i_w.replace("%obj", "ob#j")
|
|
120
|
+
i_w = i_w.replace("%neobj", "neob#j")
|
|
121
|
+
i_w = i_w.replace("%vj", "v#j")
|
|
122
|
+
|
|
123
|
+
# Flavor 2 is the shared base for flavors 2, 3, and 4.
|
|
124
|
+
i_w = i_w.replace("ê", "ě")
|
|
125
|
+
i_w = i_w.replace("ŭ", "v")
|
|
126
|
+
i_w = re.sub(r"[ṱḓ]", "", i_w)
|
|
127
|
+
i_w = re.sub(r"[’`]", "#%", i_w)
|
|
128
|
+
i_w = re.sub(r"([čšžj])ě", r"\g<1>e", i_w)
|
|
129
|
+
|
|
130
|
+
# Flavors 3 and 4 share the standard simplifications.
|
|
131
|
+
if flav in (3, 4):
|
|
132
|
+
i_w = re.sub(r"[ęė]", "e", i_w)
|
|
133
|
+
i_w = i_w.replace("å", "a")
|
|
134
|
+
i_w = i_w.replace("ȯ", "o")
|
|
135
|
+
i_w = i_w.replace("ų", "u")
|
|
136
|
+
i_w = i_w.replace("ć", "č")
|
|
137
|
+
i_w = i_w.replace("đ", "dž")
|
|
138
|
+
i_w = i_w.replace("ř", "r")
|
|
139
|
+
i_w = i_w.replace("ľ", "l")
|
|
140
|
+
i_w = i_w.replace("ń", "n")
|
|
141
|
+
i_w = i_w.replace("ť", "t")
|
|
142
|
+
i_w = i_w.replace("ď", "d")
|
|
143
|
+
i_w = i_w.replace("ś", "s")
|
|
144
|
+
i_w = i_w.replace("ź", "z")
|
|
145
|
+
|
|
146
|
+
if flav == 4:
|
|
147
|
+
i_w = i_w.replace("ě", "e")
|
|
148
|
+
i_w = i_w.replace("y", "i")
|
|
149
|
+
|
|
150
|
+
if type == 1:
|
|
151
|
+
if flav == 2:
|
|
152
|
+
i_w = i_w.replace("ṙ", "r")
|
|
153
|
+
i_w = i_w.replace("ř", "ŕ")
|
|
154
|
+
i_w = i_w.replace("ľ", "ĺ")
|
|
155
|
+
i_w = i_w.replace("ť", "t́")
|
|
156
|
+
i_w = i_w.replace("ď", "d́")
|
|
157
|
+
i_w = re.sub(r"([čšžj])ŕ", r"\g<1>r", i_w)
|
|
158
|
+
elif flav in (3, 4):
|
|
159
|
+
i_w = re.sub(r"[ṙŕ]", "r", i_w)
|
|
160
|
+
i_w = i_w.replace("ȯ", "ă")
|
|
161
|
+
|
|
162
|
+
elif type == 2:
|
|
163
|
+
i_w = re.sub(r"[ṙŕ]", "r", i_w)
|
|
164
|
+
i_w = i_w.replace("š", "sz")
|
|
165
|
+
i_w = re.sub(r"[ćč]", "cz", i_w)
|
|
166
|
+
i_w = i_w.replace("ž", "zs")
|
|
167
|
+
i_w = i_w.replace("đ", "dzs")
|
|
168
|
+
i_w = i_w.replace("ě", "je")
|
|
169
|
+
i_w = i_w.replace("å", "a")
|
|
170
|
+
i_w = re.sub(r"[ęė]", "e", i_w)
|
|
171
|
+
i_w = i_w.replace("ȯ", "o")
|
|
172
|
+
i_w = i_w.replace("ų", "u")
|
|
173
|
+
|
|
174
|
+
elif type == 5:
|
|
175
|
+
i_w = i_w.replace("lj", "љ")
|
|
176
|
+
i_w = i_w.replace("nj", "њ")
|
|
177
|
+
i_w = i_w.replace("a", "а")
|
|
178
|
+
i_w = i_w.replace("å", "ӑ")
|
|
179
|
+
i_w = i_w.replace("b", "б")
|
|
180
|
+
i_w = i_w.replace("c", "ц")
|
|
181
|
+
i_w = i_w.replace("ć", "ћ")
|
|
182
|
+
i_w = i_w.replace("č", "ч")
|
|
183
|
+
i_w = re.sub(r"[dḓ]", "д", i_w)
|
|
184
|
+
i_w = i_w.replace("ď", "дь")
|
|
185
|
+
i_w = i_w.replace("đ", "ђ")
|
|
186
|
+
i_w = i_w.replace("e", "е")
|
|
187
|
+
i_w = i_w.replace("ę", "ѧ")
|
|
188
|
+
i_w = i_w.replace("ě", "є")
|
|
189
|
+
i_w = i_w.replace("f", "ф")
|
|
190
|
+
i_w = i_w.replace("g", "г")
|
|
191
|
+
i_w = i_w.replace("h", "х")
|
|
192
|
+
i_w = i_w.replace("i", "и")
|
|
193
|
+
i_w = i_w.replace("j", "ј")
|
|
194
|
+
i_w = i_w.replace("k", "к")
|
|
195
|
+
i_w = i_w.replace("l", "л")
|
|
196
|
+
i_w = i_w.replace("ľ", "ль")
|
|
197
|
+
i_w = i_w.replace("m", "м")
|
|
198
|
+
i_w = i_w.replace("n", "н")
|
|
199
|
+
i_w = i_w.replace("ń", "нь")
|
|
200
|
+
i_w = i_w.replace("o", "о")
|
|
201
|
+
i_w = i_w.replace("ȯ", "ъ")
|
|
202
|
+
i_w = i_w.replace("p", "п")
|
|
203
|
+
i_w = i_w.replace("r", "р")
|
|
204
|
+
i_w = i_w.replace("ř", "рь")
|
|
205
|
+
i_w = i_w.replace("s", "с")
|
|
206
|
+
i_w = i_w.replace("ś", "сь")
|
|
207
|
+
i_w = i_w.replace("š", "ш")
|
|
208
|
+
i_w = re.sub(r"[tṱ]", "т", i_w)
|
|
209
|
+
i_w = i_w.replace("ť", "ть")
|
|
210
|
+
i_w = i_w.replace("u", "у")
|
|
211
|
+
i_w = i_w.replace("ų", "ѫ")
|
|
212
|
+
i_w = i_w.replace("ŭ", "ў")
|
|
213
|
+
i_w = i_w.replace("v", "в")
|
|
214
|
+
i_w = i_w.replace("y", "ы")
|
|
215
|
+
i_w = i_w.replace("z", "з")
|
|
216
|
+
i_w = i_w.replace("ź", "зь")
|
|
217
|
+
i_w = i_w.replace("ž", "ж")
|
|
218
|
+
i_w = i_w.replace("’", "ъ")
|
|
219
|
+
i_w = i_w.replace("`", "’")
|
|
220
|
+
|
|
221
|
+
i_w = re.sub(r"[ṙŕ]", "р", i_w)
|
|
222
|
+
i_w = i_w.replace("ė", "е")
|
|
223
|
+
if flav == 2:
|
|
224
|
+
i_w = i_w.replace("є", "ѣ")
|
|
225
|
+
|
|
226
|
+
i_w = i_w.replace("jj", "j")
|
|
227
|
+
i_w = re.sub(r"[#ı%]", "", i_w)
|
|
228
|
+
original_word = original_word.replace("%", "")
|
|
229
|
+
|
|
230
|
+
i_w_first = i_w[:1]
|
|
231
|
+
i_w_rest = i_w[1:]
|
|
232
|
+
if original_word[0] == original_word[0].lower():
|
|
233
|
+
return i_w.lower()
|
|
234
|
+
if len(original_word) > 1 and original_word[1] == original_word[1].lower():
|
|
235
|
+
return i_w_first.upper() + i_w_rest.lower()
|
|
236
|
+
return i_w.upper()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _nmsify_loose(i_w: str) -> str:
|
|
240
|
+
# Iotated vowels and soft-sign sequences.
|
|
241
|
+
i_w = re.sub(r"[яꙗ]", "#a", i_w)
|
|
242
|
+
i_w = i_w.replace("ьа", "#a")
|
|
243
|
+
i_w = i_w.replace("ѥ", "#e")
|
|
244
|
+
i_w = i_w.replace("ье", "#e")
|
|
245
|
+
i_w = i_w.replace("ї", "#i")
|
|
246
|
+
i_w = i_w.replace("ьи", "#i")
|
|
247
|
+
i_w = i_w.replace("ё", "#o")
|
|
248
|
+
i_w = i_w.replace("ьо", "#o")
|
|
249
|
+
i_w = i_w.replace("ю", "#u")
|
|
250
|
+
i_w = i_w.replace("ьу", "#u")
|
|
251
|
+
i_w = i_w.replace("ѩ", "#ę")
|
|
252
|
+
i_w = i_w.replace("ьѧ", "#ę")
|
|
253
|
+
i_w = i_w.replace("ѭ", "#ų")
|
|
254
|
+
i_w = i_w.replace("ьѫ", "#ų")
|
|
255
|
+
i_w = i_w.replace("нь", "ń")
|
|
256
|
+
i_w = i_w.replace("н#", "nj")
|
|
257
|
+
i_w = i_w.replace("њ", "nj")
|
|
258
|
+
i_w = i_w.replace("ль", "ĺ")
|
|
259
|
+
i_w = i_w.replace("л#", "lj")
|
|
260
|
+
i_w = i_w.replace("љ", "lj")
|
|
261
|
+
i_w = i_w.replace("рь", "ŕ")
|
|
262
|
+
i_w = i_w.replace("р#", "ŕ")
|
|
263
|
+
i_w = i_w.replace("ть", "ť")
|
|
264
|
+
i_w = i_w.replace("т#", "ť")
|
|
265
|
+
i_w = i_w.replace("дь", "ď")
|
|
266
|
+
i_w = i_w.replace("д#", "ď")
|
|
267
|
+
i_w = i_w.replace("сь", "ś")
|
|
268
|
+
i_w = i_w.replace("с#", "ś")
|
|
269
|
+
i_w = i_w.replace("зь", "ź")
|
|
270
|
+
i_w = i_w.replace("з#", "ź")
|
|
271
|
+
i_w = i_w.replace("ь%", "%")
|
|
272
|
+
i_w = re.sub(r"[ђѓ]", "đ", i_w)
|
|
273
|
+
i_w = re.sub(r"[ћќ]", "ć", i_w)
|
|
274
|
+
i_w = i_w.replace("ѕ", "dz")
|
|
275
|
+
i_w = i_w.replace("џ", "dž")
|
|
276
|
+
|
|
277
|
+
# Cyrillic to the internal Latin representation.
|
|
278
|
+
i_w = i_w.replace("а", "a")
|
|
279
|
+
i_w = i_w.replace("б", "b")
|
|
280
|
+
i_w = i_w.replace("в", "v")
|
|
281
|
+
i_w = re.sub(r"[гґ]", "g", i_w)
|
|
282
|
+
i_w = i_w.replace("д", "d")
|
|
283
|
+
i_w = re.sub(r"[еэ]", "e", i_w)
|
|
284
|
+
i_w = re.sub(r"[єѣ]", "ě", i_w)
|
|
285
|
+
i_w = i_w.replace("ж", "ž")
|
|
286
|
+
i_w = re.sub(r"[зꙁꙀ]", "z", i_w)
|
|
287
|
+
i_w = re.sub(r"[иіѵѷ]", "i", i_w)
|
|
288
|
+
i_w = re.sub(r"[йјь#]", "j", i_w)
|
|
289
|
+
i_w = i_w.replace("к", "k")
|
|
290
|
+
i_w = i_w.replace("л", "l")
|
|
291
|
+
i_w = i_w.replace("м", "m")
|
|
292
|
+
i_w = i_w.replace("н", "n")
|
|
293
|
+
i_w = re.sub(r"[оѡ]", "o", i_w)
|
|
294
|
+
i_w = i_w.replace("п", "p")
|
|
295
|
+
i_w = i_w.replace("р", "r")
|
|
296
|
+
i_w = i_w.replace("с", "s")
|
|
297
|
+
i_w = re.sub(r"[тѳ]", "t", i_w)
|
|
298
|
+
i_w = re.sub(r"[уȣѹ]", "u", i_w)
|
|
299
|
+
i_w = i_w.replace("ф", "f")
|
|
300
|
+
i_w = i_w.replace("х", "h")
|
|
301
|
+
i_w = i_w.replace("ц", "c")
|
|
302
|
+
i_w = i_w.replace("ч", "č")
|
|
303
|
+
i_w = i_w.replace("ш", "š")
|
|
304
|
+
i_w = i_w.replace("щ", "šč")
|
|
305
|
+
i_w = re.sub(r"[ыꙑ]", "y", i_w)
|
|
306
|
+
i_w = i_w.replace("ъ", "ȯ")
|
|
307
|
+
i_w = i_w.replace("ў", "ŭ")
|
|
308
|
+
i_w = i_w.replace("ѧ", "ę")
|
|
309
|
+
i_w = i_w.replace("ѫ", "ų")
|
|
310
|
+
i_w = i_w.replace("ѱ", "ps")
|
|
311
|
+
i_w = i_w.replace("ѯ", "ks")
|
|
312
|
+
i_w = i_w.replace("ӑ", "å")
|
|
313
|
+
|
|
314
|
+
i_w = i_w.replace("⁙", ".")
|
|
315
|
+
|
|
316
|
+
# Boundaries that protect morphology from later j/s transformations.
|
|
317
|
+
i_w = i_w.replace("zsk", "z#sk")
|
|
318
|
+
i_w = i_w.replace("zst", "z#st")
|
|
319
|
+
i_w = i_w.replace("%izs", "%iz#s")
|
|
320
|
+
i_w = i_w.replace("%bezs", "%bez#s")
|
|
321
|
+
i_w = i_w.replace("%obezs", "%obez#s")
|
|
322
|
+
i_w = i_w.replace("%razs", "%raz#s")
|
|
323
|
+
i_w = i_w.replace("%råzs", "%råz#s")
|
|
324
|
+
i_w = i_w.replace("%szadu%", "%s#zadu%")
|
|
325
|
+
i_w = i_w.replace("%vozs", "%voz#s")
|
|
326
|
+
i_w = i_w.replace("%vȯzs", "%vȯz#s")
|
|
327
|
+
i_w = i_w.replace("konjug", "kon#jug")
|
|
328
|
+
i_w = i_w.replace("konjun", "kon#jun")
|
|
329
|
+
i_w = i_w.replace("injek", "in#jek")
|
|
330
|
+
|
|
331
|
+
i_w = re.sub(r"s[xz]", "š", i_w)
|
|
332
|
+
i_w = re.sub(r"c[xz]", "č", i_w)
|
|
333
|
+
i_w = re.sub(r"z[xs]", "ž", i_w)
|
|
334
|
+
i_w = i_w.replace("ż", "ž")
|
|
335
|
+
i_w = i_w.replace("ye", "ě")
|
|
336
|
+
|
|
337
|
+
i_w = i_w.replace("qu", "kv")
|
|
338
|
+
i_w = i_w.replace("ŀ", "ȯl")
|
|
339
|
+
i_w = re.sub(r"[ăq`]", "’", i_w)
|
|
340
|
+
i_w = i_w.replace("ch", "h")
|
|
341
|
+
i_w = i_w.replace("w", "v")
|
|
342
|
+
i_w = i_w.replace("x", "ks")
|
|
343
|
+
|
|
344
|
+
i_w = re.sub(r"[áàâā]", "a", i_w)
|
|
345
|
+
i_w = re.sub(r"[íìîīĭı]", "i", i_w)
|
|
346
|
+
i_w = re.sub(r"[úûůū]", "u", i_w)
|
|
347
|
+
i_w = re.sub(r"[ąǫũ]", "ų", i_w)
|
|
348
|
+
i_w = i_w.replace("ù", "ŭ")
|
|
349
|
+
i_w = re.sub(r"[éē]", "e", i_w)
|
|
350
|
+
i_w = re.sub(r"[ĕëè]", "ė", i_w)
|
|
351
|
+
i_w = re.sub(r"[œóô]", "o", i_w)
|
|
352
|
+
i_w = re.sub(r"[ŏöò]", "ȯ", i_w)
|
|
353
|
+
i_w = i_w.replace("ý", "y")
|
|
354
|
+
i_w = i_w.replace("ł", "l")
|
|
355
|
+
i_w = i_w.replace("ç", "c")
|
|
356
|
+
i_w = i_w.replace("ʒ", "z")
|
|
357
|
+
i_w = i_w.replace("ĵ", "j")
|
|
358
|
+
i_w = re.sub(r"[ĺļlj]", "ľ", i_w)
|
|
359
|
+
i_w = re.sub(r"[ňñņnj]", "ń", i_w)
|
|
360
|
+
i_w = i_w.replace("ř", "ŕ")
|
|
361
|
+
i_w = i_w.replace("t́", "ť")
|
|
362
|
+
i_w = i_w.replace("d́", "ď")
|
|
363
|
+
|
|
364
|
+
i_w = re.sub(r"([jćđšžč])y", r"\g<1>i", i_w)
|
|
365
|
+
return i_w.replace("jj", "j")
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
__all__ = [
|
|
369
|
+
"FlavorizationType",
|
|
370
|
+
"TransliterationType",
|
|
371
|
+
"transliterate",
|
|
372
|
+
]
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|