marathi-transliterate 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marathi-transliterate",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Zero-dependency, offline-first Marathi / Devanagari phonetic transliteration library. Converts English typing to Marathi (e.g. sakhar -> साखर) seamlessly in plain JS, Node.js, and frontend frameworks.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/dictionary.js CHANGED
@@ -1029,5 +1029,336 @@ export const MARATHI_DICTIONARY = {
1029
1029
  "bana": "बाण",
1030
1030
  "dane": "दाणे",
1031
1031
  "dana": "दाणा",
1032
- };
1033
1032
 
1033
+ // --- Modern English Loanwords with Chandra ॉ / ॅ & Kirana Problem Words ---
1034
+ "polish": "पॉलिश",
1035
+ "polysh": "पॉलिश",
1036
+ "pawlish": "पॉलिश",
1037
+ "shoepolish": "शू पॉलिश",
1038
+ "cherrypolish": "चेरी पॉलिश",
1039
+ "cherryblossom": "चेरी ब्लॉसम",
1040
+ "nailpolish": "नेल पॉलिश",
1041
+ "furniturepolish": "फर्निचर पॉलिश",
1042
+
1043
+ "coil": "कॉईल",
1044
+ "koyalcoil": "कॉईल",
1045
+ "machharcoil": "मच्छर कॉईल",
1046
+ "machhardani": "मच्छरदाणी",
1047
+ "goodnightcoil": "गुडनाईट कॉईल",
1048
+ "alloutcoil": "ऑलआऊट कॉईल",
1049
+ "morteincoil": "मॉर्टिन कॉईल",
1050
+ "kasavchhap": "कासव छाप",
1051
+ "kasavchhapcoil": "कासव छाप कॉईल",
1052
+ "maxocoil": "मॅक्सो कॉईल",
1053
+
1054
+ "rajhans": "राजहंस",
1055
+ "rajhansh": "राजहंस",
1056
+ "rajhansdudh": "राजहंस दूध",
1057
+ "rajhanstup": "राजहंस तूप",
1058
+ "rajhansmilk": "राजहंस दूध",
1059
+ "rajhanspashukhadya": "राजहंस पशुखाद्य",
1060
+
1061
+ "sunth": "सुंठ",
1062
+ "soonth": "सुंठ",
1063
+ "suntha": "सुंठ",
1064
+ "sunthavda": "सुंठवडा",
1065
+ "sunthpowder": "सुंठ पावडर",
1066
+ "sunthpud": "सुंठ पूड",
1067
+
1068
+ "coffee": "कॉफी",
1069
+ "coldcoffee": "कोल्ड कॉफी",
1070
+ "sauce": "सॉस",
1071
+ "sos": "सॉस",
1072
+ "redchillisauce": "रेड चिली सॉस",
1073
+ "greenchillisauce": "ग्रीन चिली सॉस",
1074
+ "soyasauce": "सोया सॉस",
1075
+ "schezwansauce": "शेजवान सॉस",
1076
+ "stock": "स्टॉक",
1077
+ "bottle": "बॉटल",
1078
+ "ball": "बॉल",
1079
+ "towel": "टॉवेल",
1080
+ "torch": "टॉर्च",
1081
+ "top": "टॉप",
1082
+ "drop": "ड्रॉप",
1083
+ "drops": "ड्रॉप्स",
1084
+ "doctor": "डॉक्टर",
1085
+ "dr": "डॉक्टर",
1086
+ "chocolate": "चॉकलेट",
1087
+ "toffee": "टॉफी",
1088
+ "popcorn": "पॉपकॉर्न",
1089
+ "cornflour": "कॉर्नफ्लोर",
1090
+ "cornflakes": "कॉर्नफ्लेक्स",
1091
+ "cotton": "कॉटन",
1092
+ "mop": "मॉप",
1093
+ "lock": "लॉक",
1094
+ "office": "ऑफिस",
1095
+ "shop": "शॉप",
1096
+ "mall": "मॉल",
1097
+ "hall": "हॉल",
1098
+ "call": "कॉल",
1099
+ "toll": "टोल",
1100
+ "horlicks": "हॉर्लिक्स",
1101
+ "bournvita": "बॉर्नव्हिटा",
1102
+ "complan": "कॉम्प्लॅन",
1103
+ "boost": "बूस्ट",
1104
+ "dettol": "डेटॉल",
1105
+ "allout": "ऑलआऊट",
1106
+ "mortein": "मॉर्टिन",
1107
+ "baygon": "बायगॉन",
1108
+ "odonil": "ओडोनिल",
1109
+ "lizol": "लायझोल",
1110
+ "harpic": "हार्पिक",
1111
+ "pril": "प्रिल",
1112
+ "exo": "एक्सो",
1113
+ "exobar": "एक्सो बार",
1114
+ "vanish": "व्हॅनिश",
1115
+ "hit": "हिट",
1116
+ "hitspray": "हिट स्प्रे",
1117
+ "goodnight": "गुडनाईट",
1118
+ "goodknight": "गुडनाईट",
1119
+ "colgate": "कोलगेट",
1120
+ "closeup": "क्लोज अप",
1121
+ "closup": "क्लोज अप",
1122
+ "pepsodent": "पेप्सोडेंट",
1123
+ "sensodyne": "सेन्सोडाइन",
1124
+ "battery": "बॅटरी",
1125
+ "packet": "पॅकेट",
1126
+ "snack": "स्नॅक्स",
1127
+ "snacks": "स्नॅक्स",
1128
+ "wafers": "वेफर्स",
1129
+ "shampoo": "शॅम्पू",
1130
+ "conditioner": "कंडिशनर",
1131
+ "talcumpowder": "टॅल्कम पावडर",
1132
+ "oil": "ऑईल",
1133
+ "coconutoil": "खोबरेल तेल",
1134
+ "hairoil": "केसांचे तेल",
1135
+
1136
+ // --- Regional Brands & FMCG Products ---
1137
+ "amul": "अमुल",
1138
+ "amuldudh": "अमुल दूध",
1139
+ "amulghee": "अमुल तूप",
1140
+ "amulbutter": "अमुल बटर",
1141
+ "amulpaneer": "अमुल पनीर",
1142
+ "amulcheese": "अमुल चीज",
1143
+ "gokul": "गोकुळ",
1144
+ "gokuldudh": "गोकुळ दूध",
1145
+ "warana": "वारणा",
1146
+ "katdaremasale": "काटदरे मसाले",
1147
+ "katdaregodamasala": "काटदरे गोडा मसाला",
1148
+ "kpramasale": "के-प्र मसाले",
1149
+ "bedekarachaar": "बेडेकर लोणचे",
1150
+ "bakarwadi": "बाकरवडी",
1151
+ "patanjali": "पतंजली",
1152
+ "patanjalighee": "पतंजली तूप",
1153
+ "patanjalihoney": "पतंजली मध",
1154
+ "dantkanti": "दंतकांती",
1155
+ "fortune": "फॉर्च्युन",
1156
+ "gemini": "जेमिनी",
1157
+ "geminioil": "जेमिनी तेल",
1158
+ "dhara": "धारा",
1159
+ "saffola": "सॅफोला",
1160
+ "quaker": "क्वेकर",
1161
+ "quakeroats": "क्वेकर ओट्स",
1162
+ "kissan": "किसान",
1163
+ "kissanjam": "किसान जॅम",
1164
+ "dabur": "दाबर",
1165
+ "daburhoney": "दाबर मध",
1166
+ "chyawanprash": "च्यवनप्राश",
1167
+ "hajmola": "हजमोला",
1168
+ "zandu": "झांडू",
1169
+ "zandubalm": "झांडू बाम",
1170
+ "tigerbalm": "टायगर बाम",
1171
+ "amrutanjan": "अमृतांजन",
1172
+ "moov": "मूव्ह",
1173
+ "volini": "व्होलिनी",
1174
+ "iodex": "आयोडॅक्स",
1175
+ "vicks": "व्हिक्स",
1176
+ "bourbon": "बर्बन",
1177
+ "hideandseek": "हाईड अँड सीक",
1178
+ "krackjack": "क्रॅकजॅक",
1179
+ "monaco": "मोनेको",
1180
+ "goodday": "गुड डे",
1181
+ "mariegold": "मेरी गोल्ड",
1182
+ "parleg": "पारले-जी",
1183
+ "oreo": "ओरियो",
1184
+ "darkfantasy": "डार्क फँटसी",
1185
+ "maggi": "मॅगी",
1186
+ "maggie": "मॅगी",
1187
+ "yippee": "यिप्पी",
1188
+ "chings": "चिंग्स",
1189
+ "tatasalt": "टाटा मीठ",
1190
+ "tatatea": "टाटा चहा",
1191
+ "tatapremium": "टाटा प्रीमियम",
1192
+ "redlabel": "रेड लेबल",
1193
+ "taazatea": "ताझा चहा",
1194
+ "waghbakritea": "वाघ बकरी चहा",
1195
+ "societytea": "सोसायटी चहा",
1196
+ "dhoop": "धूप",
1197
+ "dhoopbatti": "धूपबत्ती",
1198
+ "kapoor": "कापूर",
1199
+ "bhimsenikapoor": "भीमसेनी कापूर",
1200
+ "fulvaat": "फुलवात",
1201
+ "telvaat": "तेलवात",
1202
+ "haladikunku": "हळदीकुंकू",
1203
+ "gulal": "गुलाल",
1204
+ "bukka": "बुक्का",
1205
+ "rangoli": "रांगोळी",
1206
+ "velchipowder": "वेलची पूड",
1207
+ "jaiphal": "जायफळ",
1208
+ "javantri": "जायपत्री",
1209
+ "dalchini": "दालचिनी",
1210
+ "lavang": "लवंग",
1211
+ "kalimiri": "काळी मिरी",
1212
+ "shahjeere": "शहाजिरे",
1213
+ "badihop": "बडीशेप",
1214
+ "badishep": "बडीशेप",
1215
+ "ovaladana": "ओवा",
1216
+ "singhadatta": "शिंगाडा पीठ",
1217
+ "rajgiraladdu": "राजगिरा लाडू",
1218
+ "rajgiraatta": "राजगिरा पीठ",
1219
+ "manuka": "मनुका",
1220
+ "bedana": "बेदाणे",
1221
+ "charoli": "चारोळी",
1222
+ "khaskhas": "खसखस",
1223
+
1224
+
1225
+ // --- Extended English Loanwords with ॲ / ऑ & Ayurvedic/Herbals from Internet ---
1226
+ "apple": "ॲपल",
1227
+ "applecidervinegar": "ॲपल सायडर व्हिनेगर",
1228
+ "vinegar": "व्हिनेगर",
1229
+ "oats": "ओट्स",
1230
+ "oliveoil": "ऑलिव्ह ऑईल",
1231
+ "action": "ॲक्शन",
1232
+ "active": "ॲक्टिव्ह",
1233
+ "app": "ॲप",
1234
+ "advance": "ॲडव्हान्स",
1235
+ "address": "ॲड्रेस",
1236
+ "acid": "ॲसिड",
1237
+ "bat": "बॅट",
1238
+ "cat": "कॅट",
1239
+ "map": "मॅप",
1240
+ "hat": "हॅट",
1241
+ "bag": "बॅग",
1242
+ "bank": "बँक",
1243
+ "tanker": "टँकर",
1244
+ "gas": "गॅस",
1245
+ "fan": "फॅन",
1246
+ "lighter": "लायटर",
1247
+ "gaslighter": "गॅस लायटर",
1248
+ "foilpaper": "फॉईल पेपर",
1249
+ "tissue": "टिशू",
1250
+ "tissuepaper": "टिशू पेपर",
1251
+ "napkin": "नॅपकिन",
1252
+ "plasticbag": "प्लास्टिक पिशवी",
1253
+ "carrybag": "कॅरीबॅग",
1254
+ "order": "ऑर्डर",
1255
+ "orange": "ऑरेंज",
1256
+ "all": "ऑल",
1257
+ "already": "ऑलरेडी",
1258
+ "august": "ऑगस्ट",
1259
+ "auto": "ऑटो",
1260
+ "option": "ऑप्शन",
1261
+ "toilet": "टॉयलेट",
1262
+ "foil": "फॉईल",
1263
+ "boil": "बॉईल",
1264
+ "soil": "सॉईल",
1265
+ "dog": "डॉग",
1266
+ "cock": "कॉक",
1267
+ "brush": "ब्रश",
1268
+ "toothpaste": "टूथपेस्ट",
1269
+ "toothbrush": "टूथब्रश",
1270
+ "detergent": "डिटर्जंट",
1271
+ "washingpowder": "वॉशिंग पावडर",
1272
+ "phenyl": "फिनाईल",
1273
+
1274
+ // Ayurvedic, Medicinal & Special Grains
1275
+ "saindhav": "सैंधव मीठ",
1276
+ "sendhanamak": "सैंधव मीठ",
1277
+ "kalameeth": "काळे मीठ",
1278
+ "gavrantup": "गावरान तूप",
1279
+ "sajuktup": "साजूक तूप",
1280
+ "tilachetel": "तिळाचे तेल",
1281
+ "kulith": "कुळीथ",
1282
+ "kulithdal": "कुळीथ डाळ",
1283
+ "salichatandul": "साळीचा तांदूळ",
1284
+ "brownrice": "ब्राऊन राईस",
1285
+ "nachanipith": "नाचणी पीठ",
1286
+ "jawas": "जवस",
1287
+ "alshi": "अळशी",
1288
+ "triphala": "त्रिफळा चूर्ण",
1289
+ "ashwagandha": "अश्वगंधा पावडर",
1290
+ "bramhi": "ब्राह्मी",
1291
+ "shankhpushpi": "शंखपुष्पी",
1292
+ "jyeshthamadh": "ज्येष्ठमध",
1293
+ "jethimadh": "ज्येष्ठमध",
1294
+ "giloy": "गुळवेल",
1295
+ "gulvel": "गुळवेल",
1296
+ "tulsi": "तुळस",
1297
+ "tulsipane": "तुळशीची पाने",
1298
+ "arjunsaal": "अर्जुनसाल",
1299
+ "shatavari": "शतावरी",
1300
+ "hirda": "हिरडा",
1301
+ "behada": "बेहडा",
1302
+ "dink": "डिंक",
1303
+ "khanyachadink": "खाण्याचा डिंक",
1304
+ "bavchi": "बावची",
1305
+ "nagarmotha": "नागरमोथा",
1306
+ "pippali": "पिंपळी",
1307
+
1308
+ // Kranti (Famous Maharashtrian edible oil brand & name)
1309
+ "kranti": "क्रांती",
1310
+ "cranti": "क्रांती",
1311
+ "kraanti": "क्रांती",
1312
+ "krantee": "क्रांती",
1313
+ "krantioil": "क्रांती तेल",
1314
+ "krantitel": "क्रांती तेल",
1315
+ "krantisunfloweroil": "क्रांती सूर्यफूल तेल",
1316
+ "krantisoyabeanoil": "क्रांती सोयाबीन तेल",
1317
+ "krantigroundnutoil": "क्रांती शेंगदाणा तेल",
1318
+
1319
+ // Electricals, Lighting & General Store terms (Watt, Bulb, LED, etc.)
1320
+ "watt": "वॉट",
1321
+ "watts": "वॉट",
1322
+ "wat": "वाट",
1323
+ "waat": "वाट",
1324
+ "vat": "वात",
1325
+ "bulb": "बल्ब",
1326
+ "bulbs": "बल्ब",
1327
+ "balb": "बल्ब",
1328
+ "led": "एलईडी",
1329
+ "cfl": "सीएफएल",
1330
+ "switch": "स्विच",
1331
+ "switches": "स्विचेस",
1332
+ "socket": "सॉकेट",
1333
+ "wire": "वायर",
1334
+ "wires": "वायर",
1335
+ "plug": "प्लग",
1336
+ "holder": "होल्डर",
1337
+ "tester": "टेस्टर",
1338
+ "tubelight": "ट्युबलाईट",
1339
+ "tube": "ट्यूब",
1340
+ "cell": "सेल",
1341
+ "adaptor": "अ‍ॅडॉप्टर",
1342
+ "adapter": "अ‍ॅडॉप्टर",
1343
+ "cable": "केबल",
1344
+ "fuse": "फ्युज",
1345
+ "mcb": "एमसीबी",
1346
+ "choke": "चोक",
1347
+ "starter": "स्टार्टर",
1348
+ "tape": "टेप",
1349
+ "insulationtape": "इन्स्युलेशन टेप",
1350
+ "regulator": "रेग्युलेटर",
1351
+ "board": "बोर्ड",
1352
+ "extensionboard": "एक्स्टेंशन बोर्ड",
1353
+
1354
+ // Common Marathi vocabulary & items
1355
+ "shanti": "शांती",
1356
+ "shaanti": "शांती",
1357
+ "shantee": "शांती",
1358
+ "kanti": "कांती",
1359
+ "vati": "वाटी",
1360
+ "vatya": "वाट्या",
1361
+ "watti": "वाटी",
1362
+ "wattya": "वाट्या"
1363
+
1364
+ };
package/src/dom.js CHANGED
@@ -218,7 +218,7 @@ export function attachDevanagari(target, options = {}) {
218
218
  selectCandidate(selectedIndex, e.key === 'Enter' ? '' : ' ');
219
219
  return;
220
220
  }
221
- if (e.key === ' ') {
221
+ if (e.key === ' ' || e.key === 'Spacebar' || e.code === 'Space') {
222
222
  e.preventDefault();
223
223
  selectCandidate(selectedIndex, ' ');
224
224
  return;
package/src/index.js CHANGED
@@ -220,10 +220,63 @@ export function getSuggestions(word, options = {}) {
220
220
  if (withAnusvar.endsWith("ि")) add(withAnusvar.slice(0, -1) + "ी");
221
221
  if (withAnusvar.endsWith("ी")) add(withAnusvar.slice(0, -1) + "ि");
222
222
  }
223
+
224
+ // 4l. Chandra "ॉ" (Candra O, \u0949) and "ो" (O, \u094B)
225
+ // Essential for English loanwords in grocery & everyday shop items
226
+ // e.g. watt -> वॉट / वॅट / वाट, polish -> पॉलिश, coil -> कॉईल, coffee -> कॉफी, doctor -> डॉक्टर, sauce -> सॉस, box -> बॉक्स, ball -> बॉल, stock -> स्टॉक
227
+ if (s.includes("ो")) {
228
+ add(s.replace(/ो/g, "ॉ"));
229
+ } else if (s.includes("ॉ")) {
230
+ add(s.replace(/ॉ/g, "ो"));
231
+ add(s.replace(/ॉ/g, "ॅ"));
232
+ add(s.replace(/ॉ/g, "ा"));
233
+ }
234
+ if (s.startsWith("ओ")) {
235
+ add("ऑ" + s.slice(1));
236
+ } else if (s.startsWith("ऑ")) {
237
+ add("ओ" + s.slice(1));
238
+ }
239
+
240
+ // 4m. Chandra "ॅ" (Candra E, \u0945) and "े" (E) / "ै" (AI)
241
+ // For English loanwords: battery -> बॅटरी, packet -> पॅकेट, snack -> स्नॅक्स, bat -> बॅट, match -> मॅच
242
+ if (s.includes("े")) {
243
+ add(s.replace(/े/g, "ॅ"));
244
+ } else if (s.includes("ॅ")) {
245
+ add(s.replace(/ॅ/g, "े"));
246
+ add(s.replace(/ॅ/g, "ॉ"));
247
+ }
248
+
249
+ // 4n. Smart Anusvara on "su" prefixes and "sunth"
250
+ // e.g. typing "sun" offers "सुं" (with anusvara) and "सुंठ"
251
+ if (clean.startsWith("sun")) {
252
+ add("सुं");
253
+ add("सुंठ");
254
+ }
255
+
256
+ // 4o. Smart "rajhans" and compound words
257
+ if (clean.startsWith("rajh")) {
258
+ add("राजहंस");
259
+ }
260
+
261
+ // 4p. Smart Kana + Anusvara (ां) expansion (मराठी शुद्धलेखन)
262
+ // e.g. "kranti" -> "क्रांती" / "क्रांति", "shanti" -> "शांती", "kanti" -> "कांती", "kanda" -> "कांदा", "gandhi" -> "गांधी"
263
+ if (s.includes("ं")) {
264
+ const withKanaAnusvar = s.replace(/([^ािीुूेैोौॉॅ्\s])ं/g, "$1ां");
265
+ if (withKanaAnusvar !== s) {
266
+ add(withKanaAnusvar);
267
+ if (withKanaAnusvar.endsWith("ि")) add(withKanaAnusvar.slice(0, -1) + "ी");
268
+ if (withKanaAnusvar.endsWith("ी")) add(withKanaAnusvar.slice(0, -1) + "ि");
269
+ }
270
+ }
271
+ }
272
+
273
+ // Background fetch to enrich cache if online (non-blocking)
274
+ if (typeof fetch !== "undefined" && !getCachedWord(clean)) {
275
+ fetchOnlineMarathi(clean).catch(() => {});
223
276
  }
224
277
 
225
- // 5. Prefix matches from dictionary (if clean.length >= 3)
226
- if (clean.length >= 3 && suggestions.length < max) {
278
+ // 5. Prefix matches from dictionary (if clean.length >= 2)
279
+ if (clean.length >= 2 && suggestions.length < max) {
227
280
  for (const [key, val] of Object.entries(MARATHI_DICTIONARY)) {
228
281
  if (key.startsWith(clean) && key !== clean) {
229
282
  add(val);
package/src/phonetics.js CHANGED
@@ -129,9 +129,37 @@ export function phoneticTransliterateWord(text) {
129
129
  continue;
130
130
  }
131
131
 
132
- // Check independent vowel at the beginning of a word or after non-alpha
132
+ // Check independent vowel at the beginning of a word, after non-alpha, or after another vowel
133
133
  let matchedVowel = false;
134
- if (i === 0 || !/[a-zA-Z]/.test(clean[i - 1])) {
134
+ const prevChar = i > 0 ? clean[i - 1] : "";
135
+ const isAfterVowel = prevChar && /[aeiou]/i.test(prevChar);
136
+
137
+ if (i === 0 || !/[a-zA-Z]/.test(prevChar) || isAfterVowel) {
138
+ if (isAfterVowel) {
139
+ const nextTwo = clean.substring(i, i + 2).toLowerCase();
140
+ if (nextTwo === "ee" || nextTwo === "ii") {
141
+ res += "ई";
142
+ i += 2;
143
+ matchedVowel = true;
144
+ } else if (nextTwo === "oo" || nextTwo === "uu") {
145
+ res += "ऊ";
146
+ i += 2;
147
+ matchedVowel = true;
148
+ } else if (clean[i].toLowerCase() === "i") {
149
+ res += "ई";
150
+ i += 1;
151
+ matchedVowel = true;
152
+ } else if (clean[i].toLowerCase() === "u") {
153
+ res += "ऊ";
154
+ i += 1;
155
+ matchedVowel = true;
156
+ } else if (clean[i].toLowerCase() === "a") {
157
+ i += 1;
158
+ matchedVowel = true;
159
+ }
160
+ }
161
+
162
+ if (!matchedVowel) {
135
163
  const initialNasal = clean.substring(i, i + 2).toLowerCase();
136
164
  if (initialNasal === 'am' || initialNasal === 'an') {
137
165
  const charAfter = clean[i + 2];
@@ -152,6 +180,7 @@ export function phoneticTransliterateWord(text) {
152
180
  break;
153
181
  }
154
182
  }
183
+ }
155
184
  if (matchedVowel) continue;
156
185
  }
157
186