All files / app/i18n casing.ts

90% Statements 9/10
75% Branches 3/4
100% Functions 1/1
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  41x               334x 334x 334x 17x 17x   334x 334x 334x    
// Creating Intl.Segmenter every time is slow, so cache one per locale.
const segmenterCache = new Map<string, Intl.Segmenter>();
 
/**
 * Uppercases the first grapheme cluster of a string, leaving the rest untouched.
 * Non-capitalizable first clusters (digits, CJK, etc.) are returned unchanged.
 * Only for strings that stand alone (their own "sentence") — never for text
 * interpolated into a larger translated string.
 */
export function capitalizeFirstLetter(value: string, locale: string): string {
  let segmenter = segmenterCache.get(locale);
  if (!segmenter) {
    segmenter = new Intl.Segmenter(locale, { granularity: "grapheme" });
    segmenterCache.set(locale, segmenter);
  }
  const first = segmenter.segment(value)[Symbol.iterator]().next().value?.segment;
  Iif (!first) return value;
  return first.toLocaleUpperCase(locale) + value.slice(first.length);
}