-
Notifications
You must be signed in to change notification settings - Fork 0
/
Translit.tsx
116 lines (103 loc) · 2.83 KB
/
Translit.tsx
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
const transliterationMap: { [key: string]: string } = {
a: "а",
b: "б",
v: "в",
w: "в",
g: "г",
d: "д",
e: "е",
ыo: "ё", // yo
йo: "ё", // jo
зh: "ж", // zh
z: "з",
i: "и",
j: "й",
k: "к",
l: "л",
m: "м",
n: "н",
o: "о",
p: "п",
r: "р",
s: "с",
t: "т",
u: "у",
f: "ф",
h: "х",
c: "ц",
тz: "ц", // tz
цh: "ч", // ch
сh: "ш", // sh
шh: "щ", // ssh
'"': "ъ",
y: "ы",
"'": "ь",
ä: "э",
ыu: "ю", // yu
йu: "ю", // ju
ыa: "я", // ya
йa: "я", // ja
};
const isUpperCase = (s: string): boolean => {
// there are different cases for s and it is currently in upper case
return s.toUpperCase() !== s.toLowerCase() && s === s.toUpperCase();
};
const getTranslitRange = (
length: number,
cursorPos?: number,
): [number, number] => {
if (typeof cursorPos !== "undefined") {
// start up to two chars left of the cursor
let start =
cursorPos - 2 >= 0
? cursorPos - 2
: cursorPos - 1 >= 0
? cursorPos - 1
: 0;
// end up to one char right of the cursor
let end = cursorPos + 1 > length ? length : cursorPos + 1;
return [start, end];
} else {
// transliterate whole input if no cursorPos is passed
return [0, length];
}
};
// transliterates the input string
// optionally only transliterates a substring of `input` when `cursorPos`
// is specified
export function transliterate(input: string, cursorPos?: number): string {
let transliteratedText = "";
// get the limits of the substring that is to be transliterated
let range = getTranslitRange(input.length, cursorPos);
// parts of the intput string that will remain unchanged
let prefix = input.substring(0, range[0]);
let suffix = input.substring(range[1], input.length);
for (let i = range[0]; i < range[1]; i++) {
// save case information here instead of having a
// transliteration map of twice the size or doing
// arithmetic unicode shenanigans
const upperCase = isUpperCase(input[i]);
const currentChar = input[i].toLowerCase();
const nextChar = input[i + 1]?.toLowerCase();
const combination = currentChar + nextChar;
let replacement;
// first check if current and next char can be replaced
if (combination in transliterationMap) {
replacement = transliterationMap[combination];
// increment index because we replace two characters
i++;
// then check if current char can be replaced
} else if (currentChar in transliterationMap) {
replacement = transliterationMap[currentChar];
// or leave char unchanged
} else {
replacement = input[i];
}
// restore upper case
if (upperCase) {
replacement = replacement.toUpperCase();
}
transliteratedText += replacement;
}
return prefix + transliteratedText + suffix;
}