diff --git a/internal/string.go b/internal/string.go index e5ba00f..2116b03 100644 --- a/internal/string.go +++ b/internal/string.go @@ -61,5 +61,5 @@ func CharAt(s string, i int) byte { // to its title case. func ToTitle(m string) string { r, size := utf8.DecodeRuneInString(m) - return string(unicode.ToTitle(r)) + m[size:] + return string(unicode.ToTitle(r)) + strings.ToLower(m[size:]) } diff --git a/strcase/sentence.go b/strcase/sentence.go index a252030..a49ea35 100644 --- a/strcase/sentence.go +++ b/strcase/sentence.go @@ -45,8 +45,6 @@ func NewSentenceConverter(opts ...CaseOptFunc) *SentenceConverter { func (sc *SentenceConverter) Convert(s string) string { var made []string - s = strings.ToLower(s) - ps := `[\p{N}\p{L}*]+[^\s]*` if len(sc.vocab) > 0 { ps = fmt.Sprintf(`\b(?:%s)\b|%s`, strings.Join(sc.vocab, "|"), ps) @@ -54,6 +52,10 @@ func (sc *SentenceConverter) Convert(s string) string { re := regexp2.MustCompileStd(`(?i)` + ps) tokens := re.FindAllString(s, -1) + // NOTE: We have to do this *after* tokenizing the string in order to + // respect the case of would-be exceptions. + s = strings.ToLower(s) + for i, token := range tokens { prev := "" if i-1 >= 0 { diff --git a/strcase/sentence_test.go b/strcase/sentence_test.go index 461dd66..791f5ed 100644 --- a/strcase/sentence_test.go +++ b/strcase/sentence_test.go @@ -19,6 +19,7 @@ var vocabCases = []testCase{ {"Getting started with vale server", "Getting started with Vale Server"}, {"Issue triage", "Issue triage"}, {"macOS 15: What's new", "macOS 15: What's new"}, + {"Configuration", "Configuration"}, } func TestSentence(t *testing.T) { @@ -36,6 +37,7 @@ func TestVocab(t *testing.T) { "Vale Server", "I", "macOS", + "[Cc]onfig", })) for _, test := range vocabCases {