Standalone function:
function toProperCase(s){ return s.replace(/([^\s:\-])([^\s:\-]*)/g,function($0,$1,$2){ return $1.toUpperCase()+$2.toLowerCase(); }); }
Or for extending String.prototype:
String.prototype.toProperCase=function() { return this.replace(/([^\s:\-])([^\s:\-]*)/g,function($0,$1,$2){ return $1.toUpperCase()+$2.toLowerCase(); }); } "çoban ırmak becomes çOban ıRmak intead of Çoban Irmak Hello-wOrld".toProperCase();
Update:
The following code uses custom functions to translate locale-specific characters (partially verified). The code adds functions to String.prototype : toLocaleProperCase2 , toLocaleLowerCase2 and toLocaleUpperCase2 .
(function(){ // locale specific chars // IMPORTANT: name of locale must be always in lower case (for "tr-TR" locale - "tr-tr") !!! var localeInfos={ "tr-tr": { lower: { i:"İ", ı:"I", ş:"Ş", ğ:"Ğ", ü:"Ü", ç:"Ç", ö:"Ö" }, upper: { İ:"i", I:"ı", Ş:"ş", Ğ:"ğ", Ü:"ü", Ç:"ç", Ö:"ö" } } }, localeInfo; // helper vars var mask="\\s:\\-", // add additional delimeters chars to the mask if needed rg=new RegExp("([^"+mask+"])([^"+mask+"]*)","g"); var fnToLocaleLower=function(s){ return localeInfo.upper[s]; }, fnToLocaleUpper=function(s){ return localeInfo.lower[s]; }, fnToProper=function($0,$1,$2){ if(localeInfo){ if(localeInfo.lower.hasOwnProperty($1))$1=localeInfo.lower[$1]; $2=$2.replace(localeInfo.upperSearchRegExp,fnToLocaleLower); } return $1.toUpperCase()+$2.toLowerCase(); }; // helper calculations var localeInfosKeys=Object.keys(localeInfos); for(var i=0;localeInfo=localeInfos[localeInfosKeys[i]];i++){ localeInfo.lowerSearchRegExp=new RegExp("["+Object.keys(localeInfo.lower).join("")+"]","g"); localeInfo.upperSearchRegExp=new RegExp("["+Object.keys(localeInfo.upper).join("")+"]","g"); } // extending String.prototype String.prototype.toLocaleProperCase2=function toLocaleProperCase2(locale){ localeInfo=localeInfos[arguments.length?locale.toLowerCase():null]; return this.replace(rg,fnToProper); }; String.prototype.toLocaleLowerCase2=function toLocaleLowerCase2(locale){ return ((localeInfo=localeInfos[arguments.length?locale.toLowerCase():null]) ? this.replace(localeInfo.upperSearchRegExp,fnToLocaleLower): this).toLowerCase(); }; String.prototype.toLocaleUpperCase2=function toLocaleUpperCase2(locale){ return ((localeInfo=localeInfos[arguments.length?locale.toLowerCase():null]) ? this.replace(localeInfo.lowerSearchRegExp,fnToLocaleUpper) : this).toUpperCase(); }; })();
// testing var sss="çoban ırmak ibecıoimes çOban ıRmak intead of Çoban IrImaİk Hello-wOrld"; console.log("Origin: ", sss); console.log("Proper TR: ", sss.toLocaleProperCase2("tr-TR")); console.log("Proper: ", sss.toLocaleProperCase2()); console.log("Lower TR: ", sss.toLocaleLowerCase2("tr-TR")); console.log("Lower: ", sss.toLocaleLowerCase2()); console.log("Upper TR: ", sss.toLocaleUpperCase2("tr-TR")); console.log("Upper: ", sss.toLocaleUpperCase2()); // Origin: çoban ırmak ibecıoimes çOban ıRmak intead of Çoban IrImaİk Hello-wOrld // Proper TR: Çoban Irmak İbecıoimes Çoban Irmak İntead Of Çoban Irımaik Hello-World // Proper: Çoban Irmak Ibecıoimes Çoban Irmak Intead Of Çoban Irimaik Hello-World // Lower TR: çoban ırmak ibecıoimes çoban ırmak intead of çoban ırımaik hello-world // Lower: çoban ırmak ibecıoimes çoban ırmak intead of çoban irimaik hello-world // Upper TR: ÇOBAN IRMAK İBECIOİMES ÇOBAN IRMAK İNTEAD OF ÇOBAN IRIMAİK HELLO-WORLD // Upper: ÇOBAN IRMAK IBECIOIMES ÇOBAN IRMAK INTEAD OF ÇOBAN IRIMAİK HELLO-WORLD