From c7f16d3236940bc3276f87bd6767d0f43bdee840 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Mon, 19 Oct 2026 15:56:05 +0200 Subject: [PATCH] :bug: Keep accented letters in organization avatar initials (#12328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get-initials used an ASCII-only [a-zA-Z] match, so names like Ábaco and Órbita skipped the leading accented letter. Match Unicode letters with \p{L} (CLJS RegExp + u/g flags) so org default avatars match the expected first letter. Closes #12324. AI-assisted-by: Cursor --- common/src/app/common/data.cljc | 12 ++++++++++-- common/test/common_tests/data_test.cljc | 13 ++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 8a1efbe5d3..9a4aaa3020 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -1202,12 +1202,20 @@ (str/replace (str s) #"([*_~`\[\]()>#+=\-|{}.!@\\])" (fn [[_ c]] (str "\\" c))) "")) +;; \p{L} (Unicode letter) works in Java regex natively, but in JavaScript it +;; requires the "u" flag which ClojureScript regex literals don't support. +;; Do not use the "g" flag: a shared global RegExp mutates lastIndex and +;; corrupts later get-initials calls (org avatar lists in the team switcher). +(def ^:private letter-re + #?(:clj #"\p{L}" + :cljs (js/RegExp. "\\p{L}" "u"))) + (defn get-initials "Returns up to two uppercase initials extracted from a string. - Non-letter prefixes in each token are ignored." + Non-letter prefixes in each token are ignored (Unicode letters)." [name] (->> (str/split (str/trim (or name "")) #"\s+") - (keep #(first (re-seq #"[a-zA-Z]" %))) + (keep #(re-find letter-re %)) (take 2) (map str/upper) (apply str))) diff --git a/common/test/common_tests/data_test.cljc b/common/test/common_tests/data_test.cljc index 353435bab8..fa56367800 100644 --- a/common/test/common_tests/data_test.cljc +++ b/common/test/common_tests/data_test.cljc @@ -34,7 +34,18 @@ (t/is (= "AB" (d/get-initials "123 Alpha ## beta"))) (t/is (= "PD" (d/get-initials " penpot design tool "))) (t/is (= "" (d/get-initials nil))) - (t/is (= "" (d/get-initials "!!! ???")))) + (t/is (= "" (d/get-initials "!!! ???"))) + ;; Accented / Unicode letters (org default avatars) + (t/is (= "Á" (d/get-initials "Ábaco"))) + (t/is (= "Ó" (d/get-initials "Órbita"))) + (t/is (= "ÁN" (d/get-initials "Álvaro Núñez"))) + ;; Sequential calls must stay stable (CLJS global RegExp lastIndex) + (t/is (= ["Á" "BB" "JG" "L" "Á"] + (mapv d/get-initials ["Ábaco" + "Black Bird" + "Jean Grey Academy" + "Library" + "Ábaco"])))) (t/deftest normalize-string-test ;; nil input returns empty string