All files / lib/rrm language.ts

100% Statements 19/19
100% Branches 12/12
100% Functions 2/2
100% Lines 14/14

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 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85                1x                     1x                                               1x                           16x 16x 12x   9x 9x 9x 138x 138x   5x                           8x 5x    
import { tokenise } from "./text";
 
export type RrmLocale = "en" | "te" | "te-Latn";
 
/**
 * Telugu Unicode block. Any character here means the person is typing in
 * script, which is unambiguous — no scoring needed.
 */
const TELUGU_SCRIPT = /[ఀ-౿]/;
 
/**
 * Romanised-Telugu markers.
 *
 * Deliberately common, short, high-frequency words rather than a dictionary:
 * the goal is to notice "this person is writing Telugu in Latin letters", not
 * to translate. Two matches are required because several of these are also
 * English or Hindi words in other contexts ("sare", "undi"), and misdetecting
 * an English speaker into Telugu replies is worse than missing the switch.
 */
const TE_LATN_MARKERS = [
	"kada",
	"cheppandi",
	"enti",
	"ela",
	"vaddu",
	"kaavali",
	"meeru",
	"naaku",
	"cheyandi",
	"undi",
	"ledu",
	"unnaru",
	"pampandi",
	"telusu",
	"sare",
	"chestunnaru",
	"ippudu",
	"parledu",
	"chala",
	"emi",
] as const;
 
/** Minimum marker hits before we call a message romanised Telugu. */
export const TE_LATN_THRESHOLD = 2;
 
/**
 * Detects the locale of an inbound message.
 *
 * Matters more than it looks: getting a Telugu reply and answering in English
 * is worse than never offering Telugu at all, and this is the only signal we
 * get — the prospect never picks a language from a menu.
 *
 * Note that outbound templates being approved in Telugu SCRIPT does not mean
 * inbound will be. Many Hyderabad agents read script comfortably but type
 * romanised, so `te-Latn` has to be detectable even in a script-first campaign.
 */
export function detectLocale(text: string | null | undefined): RrmLocale {
	const raw = (text ?? "").trim();
	if (!raw) return "en";
	if (TELUGU_SCRIPT.test(raw)) return "te";
 
	const tokens = new Set(tokenise(raw));
	let hits = 0;
	for (const marker of TE_LATN_MARKERS) {
		if (tokens.has(marker)) hits += 1;
		if (hits >= TE_LATN_THRESHOLD) return "te-Latn";
	}
	return "en";
}
 
/**
 * Whether a newly detected locale should overwrite what is stored.
 *
 * A locale the person stated themselves always wins; a detection only
 * overwrites the default. Without this, one English word in an otherwise
 * Telugu conversation would flip them back and forth mid-thread.
 */
export function shouldUpdateLocale(
	storedSource: "default" | "detected" | "stated" | null | undefined,
	incomingSource: "detected" | "stated",
): boolean {
	if (incomingSource === "stated") return true;
	return storedSource !== "stated";
}