Stylized alphanumeric text in vanilla AppleScript dialog windows

A desire for stylized text (bold, italic, etc) in vanilla AppleScript dialog windows has been expressed in various posts over the years. (For example, here, here, and here.) Cocoa windows and NSAttributedString objects offer a solution, but this is not a trivial undertaking. Provided that one’s need is confined to alphabetic (and, for some styles, numeric) text only, a simple vanilla AppleScript solution is readily available through the Mathematical Alphanumeric Symbols block of the Unicode character set, whose characters are inherently stylized. The handler below, stylizedText:usingStyle:, takes as input a text string and a style. It replaces the input string’s alphabetic (and, for some styles, numeric) characters with their stylized counterparts from the Mathematical Alphanumeric Symbols block (and for a few letters in the “double struck” style, the Letterlike Symbols block) by means of the shell command tr, and returns the resulting stylized string.

on stylizedText:theString usingStyle:theStyle
	-- Stylizes a text string indirectly by replacing alphanumeric characters with their stylized counterparts from the Mathematical Alphanumeric Symbols block of the Unicode character set

	-- INPUT:
	-- theString = the text string to be stylized
	-- theStyle = one of the following text strings specifying the desired style: "bold", "bold italic", "sans serif", "sans serif bold", "sans serif italic", "sans serif bold italic", "script bold", "double struck", "monospace"

	-- RETURN VALUE:
	-- the stylized text string

	-- Note: Stylized numeric characters (digits 0-9) are not available for the following styles: "bold italic", "sans serif italic", "sans serif bold italic", "script bold"
	-- Note: Double-struck capital letters C, H, N, P, Q, R, and Z are located in the Letterlike Symbols block, not the Mathematical Alphanumeric Symbols block, of the Unicode character set

	if theString = "" then return ""
	set {searchTermWithoutDigits, searchTermWithDigits} to {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}
	tell theStyle
		ignoring white space
			if it = "bold" then
				set {searchTerm, replacementTerm} to {searchTermWithDigits, character id {119808, 119809, 119810, 119811, 119812, 119813, 119814, 119815, 119816, 119817, 119818, 119819, 119820, 119821, 119822, 119823, 119824, 119825, 119826, 119827, 119828, 119829, 119830, 119831, 119832, 119833, 119834, 119835, 119836, 119837, 119838, 119839, 119840, 119841, 119842, 119843, 119844, 119845, 119846, 119847, 119848, 119849, 119850, 119851, 119852, 119853, 119854, 119855, 119856, 119857, 119858, 119859, 120782, 120783, 120784, 120785, 120786, 120787, 120788, 120789, 120790, 120791}}
			else if it = "bolditalic" then
				set {searchTerm, replacementTerm} to {searchTermWithoutDigits, character id {119912, 119913, 119914, 119915, 119916, 119917, 119918, 119919, 119920, 119921, 119922, 119923, 119924, 119925, 119926, 119927, 119928, 119929, 119930, 119931, 119932, 119933, 119934, 119935, 119936, 119937, 119938, 119939, 119940, 119941, 119942, 119943, 119944, 119945, 119946, 119947, 119948, 119949, 119950, 119951, 119952, 119953, 119954, 119955, 119956, 119957, 119958, 119959, 119960, 119961, 119962, 119963}}
			else if it = "sansserif" then
				set {searchTerm, replacementTerm} to {searchTermWithDigits, character id {120224, 120225, 120226, 120227, 120228, 120229, 120230, 120231, 120232, 120233, 120234, 120235, 120236, 120237, 120238, 120239, 120240, 120241, 120242, 120243, 120244, 120245, 120246, 120247, 120248, 120249, 120250, 120251, 120252, 120253, 120254, 120255, 120256, 120257, 120258, 120259, 120260, 120261, 120262, 120263, 120264, 120265, 120266, 120267, 120268, 120269, 120270, 120271, 120272, 120273, 120274, 120275, 120802, 120803, 120804, 120805, 120806, 120807, 120808, 120809, 120810, 120811}}
			else if it = "sansserifbold" then
				set {searchTerm, replacementTerm} to {searchTermWithDigits, character id {120276, 120277, 120278, 120279, 120280, 120281, 120282, 120283, 120284, 120285, 120286, 120287, 120288, 120289, 120290, 120291, 120292, 120293, 120294, 120295, 120296, 120297, 120298, 120299, 120300, 120301, 120302, 120303, 120304, 120305, 120306, 120307, 120308, 120309, 120310, 120311, 120312, 120313, 120314, 120315, 120316, 120317, 120318, 120319, 120320, 120321, 120322, 120323, 120324, 120325, 120326, 120327, 120812, 120813, 120814, 120815, 120816, 120817, 120818, 120819, 120820, 120821}}
			else if it = "sansserifitalic" then
				set {searchTerm, replacementTerm} to {searchTermWithoutDigits, character id {120328, 120329, 120330, 120331, 120332, 120333, 120334, 120335, 120336, 120337, 120338, 120339, 120340, 120341, 120342, 120343, 120344, 120345, 120346, 120347, 120348, 120349, 120350, 120351, 120352, 120353, 120354, 120355, 120356, 120357, 120358, 120359, 120360, 120361, 120362, 120363, 120364, 120365, 120366, 120367, 120368, 120369, 120370, 120371, 120372, 120373, 120374, 120375, 120376, 120377, 120378, 120379}}
			else if it = "sansserifbolditalic" then
				set {searchTerm, replacementTerm} to {searchTermWithoutDigits, character id {120380, 120381, 120382, 120383, 120384, 120385, 120386, 120387, 120388, 120389, 120390, 120391, 120392, 120393, 120394, 120395, 120396, 120397, 120398, 120399, 120400, 120401, 120402, 120403, 120404, 120405, 120406, 120407, 120408, 120409, 120410, 120411, 120412, 120413, 120414, 120415, 120416, 120417, 120418, 120419, 120420, 120421, 120422, 120423, 120424, 120425, 120426, 120427, 120428, 120429, 120430, 120431}}
			else if it = "scriptbold" then
				set {searchTerm, replacementTerm} to {searchTermWithoutDigits, character id {120016, 120017, 120018, 120019, 120020, 120021, 120022, 120023, 120024, 120025, 120026, 120027, 120028, 120029, 120030, 120031, 120032, 120033, 120034, 120035, 120036, 120037, 120038, 120039, 120040, 120041, 120042, 120043, 120044, 120045, 120046, 120047, 120048, 120049, 120050, 120051, 120052, 120053, 120054, 120055, 120056, 120057, 120058, 120059, 120060, 120061, 120062, 120063, 120064, 120065, 120066, 120067}}
			else if it = "doublestruck" then
				set {searchTerm, replacementTerm} to {searchTermWithDigits, character id {120120, 120121, 8450, 120123, 120124, 120125, 120126, 8461, 120128, 120129, 120130, 120131, 120132, 8469, 120134, 8473, 8474, 8477, 120138, 120139, 120140, 120141, 120142, 120143, 120144, 8484, 120146, 120147, 120148, 120149, 120150, 120151, 120152, 120153, 120154, 120155, 120156, 120157, 120158, 120159, 120160, 120161, 120162, 120163, 120164, 120165, 120166, 120167, 120168, 120169, 120170, 120171, 120792, 120793, 120794, 120795, 120796, 120797, 120798, 120799, 120800, 120801}}
			else if it = "monospace" then
				set {searchTerm, replacementTerm} to {searchTermWithDigits, character id {120432, 120433, 120434, 120435, 120436, 120437, 120438, 120439, 120440, 120441, 120442, 120443, 120444, 120445, 120446, 120447, 120448, 120449, 120450, 120451, 120452, 120453, 120454, 120455, 120456, 120457, 120458, 120459, 120460, 120461, 120462, 120463, 120464, 120465, 120466, 120467, 120468, 120469, 120470, 120471, 120472, 120473, 120474, 120475, 120476, 120477, 120478, 120479, 120480, 120481, 120482, 120483, 120822, 120823, 120824, 120825, 120826, 120827, 120828, 120829, 120830, 120831}}
			end if
		end ignoring
	end tell
	set stylizedString to (do shell script ("LANG='en_US.UTF-8' tr " & searchTerm's quoted form & " " & replacementTerm's quoted form & " <<<" & theString's quoted form) without altering line endings) -- "LANG='en_US.UTF-8'" assures proper handling of multibyte characters by the "tr" command; 'en_US.UTF-8' (American English locale) may be replaced by any Unicode-aware locale
	tell stylizedString to if (its length > theString's length) and ((it ends with return) or (it ends with linefeed)) then set stylizedString to text 1 thru -2 -- "text 1 thru -2" removes the spurious trailing line ending character added to the string by the "do shell script" command when the "without altering line endings" option is used
	return stylizedString
end stylizedText:usingStyle:

The following examples demonstrate use of the handler, displaying text in the various styles in display dialog windows:

set {okButton, cancelButton} to {"·······························OK·······························", "·························Cancel·························"} -- buttons widened to prevent text wrapping
set unstylizedText to "Unstylized: The numbers zero through nine are 0123456789."

set stylizedText to (my stylizedText:"Bold: The numbers zero through nine are 0123456789." usingStyle:"bold")
display dialog (unstylizedText & return & return & stylizedText & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Bold Italic: The numbers zero through nine are 0123456789." usingStyle:"bold italic")
display dialog (unstylizedText & return & return & stylizedText & return & return & "(Stylized digits 0-9 are not available for this style.)" & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Sans Serif: The numbers zero through nine are 0123456789." usingStyle:"sans serif")
display dialog (unstylizedText & return & return & stylizedText & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Sans Serif Bold: The numbers zero through nine are 0123456789." usingStyle:"sans serif bold")
display dialog (unstylizedText & return & return & stylizedText & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Sans Serif Italic: The numbers zero through nine are 0123456789." usingStyle:"sans serif italic")
display dialog (unstylizedText & return & return & stylizedText & return & return & "(Stylized digits 0-9 are not available for this style.)" & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Sans Serif Bold Italic: The numbers zero through nine are 0123456789." usingStyle:"sans serif bold italic")
display dialog (unstylizedText & return & return & stylizedText & return & return & "(Stylized digits 0-9 are not available for this style.)" & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Script Bold: The numbers zero through nine are 0123456789." usingStyle:"script bold")
display dialog (unstylizedText & return & return & stylizedText & return & return & "(Stylized digits 0-9 are not available for this style.)" & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Double Struck: The numbers zero through nine are 0123456789." usingStyle:"double struck")
display dialog (unstylizedText & return & return & stylizedText & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

set stylizedText to (my stylizedText:"Monospace: The numbers zero through nine are 0123456789." usingStyle:"monospace")
display dialog (unstylizedText & return & return & stylizedText & return) buttons {cancelButton, okButton} default button okButton cancel button cancelButton

(Note: Window buttons are widened in the above examples to prevent text wrapping. Space characters are normally used to accomplish this, but for some reason the webpage editor is stripping extra spaces, so middle dot characters are used instead.)

Edit note: Corrections were made to the “double struck” style shortly after the initial post was submitted.

Works well on Catalina. Nice!

Thank you, kerflooey.

Incidentally, the only reason the stylized characters were presented as numerical Unicode code points in the code above is that the webpage editor didn’t display the stylized characters properly. You can replace the code points with the actual characters in your code simply by (1) executing each character id {…} expression as a command in Script Editor or Script Debugger, then replacing the character id {…} expression with the resulting stylized “ABCD…” string by copying and pasting.