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);
});