ipa-hangul 1.2.3 → 1.3.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/dist/index.d.mts CHANGED
@@ -12,6 +12,13 @@
12
12
  */
13
13
  interface IpaToHangulOptions {
14
14
  markStress?: 'markdown' | 'html';
15
+ /**
16
+ * When true, trailing consonants move to next syllable if it starts with a vowel.
17
+ * This produces more natural Korean loan word pronunciation.
18
+ * e.g., "tɪti" → "티티" instead of "팉이"
19
+ * @default true
20
+ */
21
+ preferOnset?: boolean;
15
22
  }
16
23
  /**
17
24
  * Convert IPA notation to Korean Hangul pronunciation
package/dist/index.d.ts CHANGED
@@ -12,6 +12,13 @@
12
12
  */
13
13
  interface IpaToHangulOptions {
14
14
  markStress?: 'markdown' | 'html';
15
+ /**
16
+ * When true, trailing consonants move to next syllable if it starts with a vowel.
17
+ * This produces more natural Korean loan word pronunciation.
18
+ * e.g., "tɪti" → "티티" instead of "팉이"
19
+ * @default true
20
+ */
21
+ preferOnset?: boolean;
15
22
  }
16
23
  /**
17
24
  * Convert IPA notation to Korean Hangul pronunciation
package/dist/index.js CHANGED
@@ -262,7 +262,7 @@ function preprocessIPA(ipa) {
262
262
  function hasIPAVowel(text) {
263
263
  return /[iɪeɛæɑɒɔʌəɜɝʊuoa]/.test(text);
264
264
  }
265
- function getTrailingConsonants(text) {
265
+ function getTrailingConsonants(text, preferOnset = false) {
266
266
  let i = text.length;
267
267
  while (i > 0) {
268
268
  if (i >= 2) {
@@ -284,6 +284,25 @@ function getTrailingConsonants(text) {
284
284
  if (!allTrailing) {
285
285
  return { before: text, trailing: "" };
286
286
  }
287
+ if (preferOnset) {
288
+ if (allTrailing.length >= 2) {
289
+ const lastTwo = allTrailing.substring(allTrailing.length - 2);
290
+ if (CONSONANT_TO_CHOSEONG[lastTwo] || CONSONANT_TO_JAMO[lastTwo]) {
291
+ return {
292
+ before: beforeConsonants + allTrailing.substring(0, allTrailing.length - 2),
293
+ trailing: lastTwo
294
+ };
295
+ }
296
+ }
297
+ const lastOne = allTrailing[allTrailing.length - 1];
298
+ if (CONSONANT_TO_CHOSEONG[lastOne] || CONSONANT_TO_JAMO[lastOne]) {
299
+ return {
300
+ before: beforeConsonants + allTrailing.substring(0, allTrailing.length - 1),
301
+ trailing: lastOne
302
+ };
303
+ }
304
+ return { before: text, trailing: "" };
305
+ }
287
306
  let keepUntil = 0;
288
307
  if (allTrailing.length >= 2) {
289
308
  const twoChar = allTrailing.substring(0, 2);
@@ -305,7 +324,7 @@ function getTrailingConsonants(text) {
305
324
  function startsWithVowel(text) {
306
325
  return matchVowel(text, 0) !== null;
307
326
  }
308
- function parseSyllables(text) {
327
+ function parseSyllables(text, preferOnset = true) {
309
328
  const syllables = [];
310
329
  const parts = text.split(".");
311
330
  for (const part of parts) {
@@ -332,7 +351,7 @@ function parseSyllables(text) {
332
351
  const curr = merged[i];
333
352
  const next = merged[i + 1];
334
353
  if (startsWithVowel(next.text)) {
335
- const { before, trailing } = getTrailingConsonants(curr.text);
354
+ const { before, trailing } = getTrailingConsonants(curr.text, preferOnset);
336
355
  if (trailing && before) {
337
356
  curr.text = before;
338
357
  next.text = trailing + next.text;
@@ -512,9 +531,10 @@ function applyStressMarker(hangul, stress, format) {
512
531
  }
513
532
  function ipaToHangul(ipa, options) {
514
533
  if (!ipa) return "";
534
+ const preferOnset = options?.preferOnset !== false;
515
535
  const cleaned = preprocessIPA(ipa);
516
536
  if (!cleaned) return "";
517
- const syllables = parseSyllables(cleaned);
537
+ const syllables = parseSyllables(cleaned, preferOnset);
518
538
  const results = [];
519
539
  for (const syllable of syllables) {
520
540
  const segments = splitByLongVowel(syllable.text);
package/dist/index.mjs CHANGED
@@ -238,7 +238,7 @@ function preprocessIPA(ipa) {
238
238
  function hasIPAVowel(text) {
239
239
  return /[iɪeɛæɑɒɔʌəɜɝʊuoa]/.test(text);
240
240
  }
241
- function getTrailingConsonants(text) {
241
+ function getTrailingConsonants(text, preferOnset = false) {
242
242
  let i = text.length;
243
243
  while (i > 0) {
244
244
  if (i >= 2) {
@@ -260,6 +260,25 @@ function getTrailingConsonants(text) {
260
260
  if (!allTrailing) {
261
261
  return { before: text, trailing: "" };
262
262
  }
263
+ if (preferOnset) {
264
+ if (allTrailing.length >= 2) {
265
+ const lastTwo = allTrailing.substring(allTrailing.length - 2);
266
+ if (CONSONANT_TO_CHOSEONG[lastTwo] || CONSONANT_TO_JAMO[lastTwo]) {
267
+ return {
268
+ before: beforeConsonants + allTrailing.substring(0, allTrailing.length - 2),
269
+ trailing: lastTwo
270
+ };
271
+ }
272
+ }
273
+ const lastOne = allTrailing[allTrailing.length - 1];
274
+ if (CONSONANT_TO_CHOSEONG[lastOne] || CONSONANT_TO_JAMO[lastOne]) {
275
+ return {
276
+ before: beforeConsonants + allTrailing.substring(0, allTrailing.length - 1),
277
+ trailing: lastOne
278
+ };
279
+ }
280
+ return { before: text, trailing: "" };
281
+ }
263
282
  let keepUntil = 0;
264
283
  if (allTrailing.length >= 2) {
265
284
  const twoChar = allTrailing.substring(0, 2);
@@ -281,7 +300,7 @@ function getTrailingConsonants(text) {
281
300
  function startsWithVowel(text) {
282
301
  return matchVowel(text, 0) !== null;
283
302
  }
284
- function parseSyllables(text) {
303
+ function parseSyllables(text, preferOnset = true) {
285
304
  const syllables = [];
286
305
  const parts = text.split(".");
287
306
  for (const part of parts) {
@@ -308,7 +327,7 @@ function parseSyllables(text) {
308
327
  const curr = merged[i];
309
328
  const next = merged[i + 1];
310
329
  if (startsWithVowel(next.text)) {
311
- const { before, trailing } = getTrailingConsonants(curr.text);
330
+ const { before, trailing } = getTrailingConsonants(curr.text, preferOnset);
312
331
  if (trailing && before) {
313
332
  curr.text = before;
314
333
  next.text = trailing + next.text;
@@ -488,9 +507,10 @@ function applyStressMarker(hangul, stress, format) {
488
507
  }
489
508
  function ipaToHangul(ipa, options) {
490
509
  if (!ipa) return "";
510
+ const preferOnset = options?.preferOnset !== false;
491
511
  const cleaned = preprocessIPA(ipa);
492
512
  if (!cleaned) return "";
493
- const syllables = parseSyllables(cleaned);
513
+ const syllables = parseSyllables(cleaned, preferOnset);
494
514
  const results = [];
495
515
  for (const syllable of syllables) {
496
516
  const segments = splitByLongVowel(syllable.text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ipa-hangul",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "Convert IPA (International Phonetic Alphabet) pronunciation to Korean Hangul",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",