diff --git a/dist/catalan2ipa.js b/dist/catalan2ipa.js index b0656d4..aade867 100644 --- a/dist/catalan2ipa.js +++ b/dist/catalan2ipa.js @@ -1,5 +1,5 @@ /*! - * catalan2ipa v1.0.0 (July 19th 2019) + * catalan2ipa v1.0.1 (June 17th 2021) * Converts Catalan words to IPA (international phonetic alphabet) notation, with variants for Cental Catalan (Català oriental central), Valencian (Valencià) and Balearic (Balear). * * https://github.com/Connum/catalan2ipa#readme @@ -85,15 +85,41 @@ accents.ca = function (syllablesIn) { } // v > b - current.onset = current.onset.replace(/v/g, 'b'); - current.coda = current.coda.replace(/nb/g, 'mb'); + if (/v/.test(current.onset)) { + current.onset = current.onset.replace(/v/g, 'b'); - if (i > 0 && /^b/.test(current.onset)) { - previous.coda = previous.coda.replace(/n$/, 'm'); + if (i > 0 && !/[pbtdkɡmɱnɲŋ]$/.test(previous.coda) && (previous.stressed === false || current.stressed === false)) { + current.onset = current.onset.replace(/^b/, 'β'); + } else if (i > 0 && /^b/.test(current.onset)) { + previous.coda = previous.coda.replace(/[ɱn]$/, 'm'); + } + + current.coda = current.coda.replace(/[ɱn]b/, 'mb'); } // allophones of r - current.coda = current.coda.replace(/ɾ/g, 'r'); // Remove j before palatal obstruents + current.coda = current.coda.replace(/ɾ/g, 'r'); // no spirants after r/z + + if (i > 0 && /[rz]$/.test(previous.coda)) { + current.onset = current.onset.replace(/^[β]/, 'b').replace(/^[ð]/, 'd').replace(/^[ɣ]/, 'g'); + } // Poststressed gemination bl, gl + + + if (i > 0 && (current.onset === 'βɫ' || current.onset === 'ɣɫ') && previous.coda === '' && previous.stressed) { + current.onset = current.onset.replace(/[β]/, 'b').replace(/[ɣ]/, 'g'); + previous.coda = current.onset.substr(0, 1); + } // tl > ll + + + if (i > 0 && current.onset === 'ɫ') { + previous.coda = previous.coda.replace('d', 'ɫ'); + } // Velarization -gn-, -cn- + + + if (i > 0 && current.onset === 'n') { + previous.coda = previous.coda.replace('ɡ', 'ŋ'); + } // Remove j before palatal obstruents + current.coda = current.coda.replace(/j([ʃʒ])/g, '$1'); current.coda = current.coda.replace(/j(t͡ʃ)/g, '$1'); @@ -226,11 +252,15 @@ exports.splitSyllables = splitSyllables; exports.toIPA = toIPA; exports["default"] = exports.wordFixes = void 0; -function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } -function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } -function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } @@ -430,6 +460,7 @@ function postprocessGeneral(syllablesIn) { m: true, n: true, ɲ: true, + ɫ: true, l: true, ʎ: true, r: true, @@ -452,13 +483,19 @@ function postprocessGeneral(syllablesIn) { f: 'v', p: 'b', t: 'd', - s: 'z' + s: 'z', + ʃ: 'ʒ' }; var devoicing = { b: 'p', d: 't', ɡ: 'k' }; + var lenition = { + b: 'β', + d: 'ð', + ɡ: 'ɣ' + }; for (var i = 0; i < syllables.length; i++) { var current = syllables[i]; @@ -549,6 +586,10 @@ function postprocessGeneral(syllablesIn) { previous.coda = 'ɡ'; current.onset = 'z'; } + + if (i > 0 && /^[bdɡ]/.test(current.onset) && !/^d͡/.test(current.onset) && !/[pbtdkɡmɱnɲŋ]$/.test(previous.coda) && !(/[ɫlʎ]/.test(previous.coda) && current.onset === 'd') && (previous.stressed === false || current.stressed === false)) { + current.onset = current.onset.replace(/b/, lenition.b).replace(/d/, lenition.d).replace(/ɡ/, lenition.ɡ); + } } // Final devoicing @@ -1043,11 +1084,15 @@ var _helpers = require("./helpers"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } -function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } -function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } -function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } +function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } diff --git a/dist/catalan2ipa.min.js b/dist/catalan2ipa.min.js index aba71de..2e297ef 100644 --- a/dist/catalan2ipa.min.js +++ b/dist/catalan2ipa.min.js @@ -1,5 +1,5 @@ /*! - * catalan2ipa v1.0.0 (July 19th 2019) + * catalan2ipa v1.0.1 (June 17th 2021) * Converts Catalan words to IPA (international phonetic alphabet) notation, with variants for Cental Catalan (Català oriental central), Valencian (Valencià) and Balearic (Balear). * * https://github.com/Connum/catalan2ipa#readme @@ -29,13 +29,13 @@ * along with this program. If not, see . */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.catalan2ipa = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;ie.stress&&"ee"===c?n=!1:("oe"===s||"ɔe"===s)&&(n=!1),n&&(a.vowel=a.vowel.replace(/[ae]/g,"ə"))}return e}function r(e){for(var r=[],t=e;""!==t;){var o,s=void 0,c=a(t.match(/^([^aeiouàèéêíòóôúïü]*)(.*?)$/),3);o=c[1];var n=a((t=c[2]).match(/^([aeiouàèéêíòóôúïü]*)(.*?)$/),3);if(s=n[1],t=n[2],""===s)r[r.length-1].coda+=o;else{var l=o,i=s.charAt(0);(/[gq]$/.test(l)&&("ü"===i||"u"===i&&"u"!==s)||(""===l||"h"===l)&&0===r.length&&"i"===i&&"i"!==s)&&(l+=s.charAt(0),s=s.substr(1));var p=m(s);p[0].onset=l+p[0].onset,p.forEach(function(e){r.push(e)})}}for(var d=1;de.length)&&(r=e.length);for(var t=0,o=Array(r);te.stress&&"ee"===n?c=!1:("oe"===s||"ɔe"===s)&&(c=!1),c&&(t.vowel=t.vowel.replace(/[ae]/g,"ə"))}return e}function t(e){for(var r=[],t=e;""!==t;){var s,n=void 0,c=a(t.match(/^([^aeiouàèéêíòóôúïü]*)(.*?)$/),3);s=c[1];var l=a((t=c[2]).match(/^([aeiouàèéêíòóôúïü]*)(.*?)$/),3);if(n=l[1],t=l[2],""===n)r[r.length-1].coda+=s;else{var i=s,p=n.charAt(0);(/[gq]$/.test(i)&&("ü"===p||"u"===p&&"u"!==n)||(""===i||"h"===i)&&0===r.length&&"i"===p&&"i"!==n)&&(i+=n.charAt(0),n=n.substr(1));var d=o(n);d[0].onset=i+d[0].onset,d.forEach(function(e){r.push(e)})}}for(var u=1;ur.length)&&(e=r.length);for(var t=0,o=Array(e);t { } // v > b - current.onset = current.onset.replace(/v/g, 'b'); - current.coda = current.coda.replace(/nb/g, 'mb'); - if (i > 0 && /^b/.test(current.onset)) { - previous.coda = previous.coda.replace(/n$/, 'm'); + if (/v/.test(current.onset)) { + current.onset = current.onset.replace(/v/g, 'b'); + if (i > 0 && !/[pbtdkɡmɱnɲŋ]$/.test(previous.coda) && (previous.stressed === false || current.stressed === false)) { + current.onset = current.onset.replace(/^b/, 'β'); + } else if (i > 0 && /^b/.test(current.onset)) { + previous.coda = previous.coda.replace(/[ɱn]$/, 'm'); + } + current.coda = current.coda.replace(/[ɱn]b/, 'mb'); } // allophones of r current.coda = current.coda.replace(/ɾ/g, 'r'); + // no spirants after r/z + if (i > 0 && /[rz]$/.test(previous.coda)) { + current.onset = current.onset + .replace(/^[β]/, 'b') + .replace(/^[ð]/, 'd') + .replace(/^[ɣ]/, 'g'); + } + + // Poststressed gemination bl, gl + if (i > 0 && (current.onset === 'βɫ' || current.onset === 'ɣɫ') && previous.coda === '' && previous.stressed) { + current.onset = current.onset + .replace(/[β]/, 'b') + .replace(/[ɣ]/, 'g'); + previous.coda = current.onset.substr(0, 1); + } + + // tl > ll + if (i > 0 && current.onset === 'ɫ') { + previous.coda = previous.coda.replace('d', 'ɫ'); + } + + // Velarization -gn-, -cn- + if (i > 0 && current.onset === 'n') { + previous.coda = previous.coda.replace('ɡ', 'ŋ'); + } + // Remove j before palatal obstruents current.coda = current.coda.replace(/j([ʃʒ])/g, '$1'); current.coda = current.coda.replace(/j(t͡ʃ)/g, '$1'); diff --git a/src/helpers.js b/src/helpers.js index 83b2a29..57466c0 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -222,6 +222,7 @@ function postprocessGeneral(syllablesIn) { m: true, n: true, ɲ: true, + ɫ: true, l: true, ʎ: true, r: true, @@ -234,10 +235,16 @@ function postprocessGeneral(syllablesIn) { p: true, t: true, k: true, f: true, s: true, ʃ: true, '': true }; const voicing = { - k: 'ɡ', f: 'v', p: 'b', t: 'd', s: 'z' + k: 'ɡ', f: 'v', p: 'b', t: 'd', s: 'z', ʃ: 'ʒ' }; const devoicing = { b: 'p', d: 't', ɡ: 'k' }; + const lenition = { + b: 'β', + d: 'ð', + ɡ: 'ɣ' + }; + for (let i = 0; i < syllables.length; i++) { const current = syllables[i]; const previous = syllables[i - 1]; @@ -329,6 +336,10 @@ function postprocessGeneral(syllablesIn) { previous.coda = 'ɡ'; current.onset = 'z'; } + + if (i > 0 && /^[bdɡ]/.test(current.onset) && !/^d͡/.test(current.onset) && !/[pbtdkɡmɱnɲŋ]$/.test(previous.coda) && !(/[ɫlʎ]/.test(previous.coda) && current.onset === 'd') && (previous.stressed === false || current.stressed === false)) { + current.onset = current.onset.replace(/b/, lenition.b).replace(/d/, lenition.d).replace(/ɡ/, lenition.ɡ); + } } // Final devoicing diff --git a/test/index.js b/test/index.js index 3263ddb..ac46cab 100644 --- a/test/index.js +++ b/test/index.js @@ -60,9 +60,9 @@ describe('Additional test cases', () => { it('should transliterate "investigació"', () => { const expectedVal = { - ca: '/im.bəs.ti.ɡə.siˈo/', - 'ca-valencia': '/im.ves.ti.ɡa.siˈo/', - 'ca-XB': '/im.vəs.ti.ɡə.siˈo/' + ca: '/im.bəs.ti.ɣə.siˈo/', + 'ca-valencia': '/im.ves.ti.ɣa.siˈo/', + 'ca-XB': '/im.vəs.ti.ɣə.siˈo/' }; assert.deepEqual(catalan2ipa('investigació'), expectedVal); }); @@ -78,18 +78,18 @@ describe('Additional test cases', () => { it('should transliterate "Bellreguard"', () => { const expectedVal = { - ca: '/bəʎ.ɾəˈɡwart/', - 'ca-valencia': '/beʎ.ɾeˈɡwaɾt/', - 'ca-XB': '/bəʎ.ɾəˈɡwaɾt/' + ca: '/bəʎ.ɾəˈɣwart/', + 'ca-valencia': '/beʎ.ɾeˈɣwaɾt/', + 'ca-XB': '/bəʎ.ɾəˈɣwaɾt/' }; assert.deepEqual(catalan2ipa('Bellreguard'), expectedVal); }); it('should transliterate "col·laborar"', () => { const expectedVal = { - ca: '/kul.lə.buˈɾa/', - 'ca-valencia': '/kol.la.boˈɾaɾ/', - 'ca-XB': '/kol.lə.boˈɾa/' + ca: '/kul.lə.βuˈɾa/', + 'ca-valencia': '/kol.la.βoˈɾaɾ/', + 'ca-XB': '/kol.lə.βoˈɾa/' }; assert.deepEqual(catalan2ipa('col·laborar'), expectedVal); });