Mojave – Apply Tags to a file?

Hi: Started playing with Mojave. Is there an Applescript way to color “tag” a file (Red, Green, Blue, etc.)? The Finder’s dictionary has “Label Index” but I can’t figure out what number corresponds to what combination of colors. In Sierra, I have a keyboard shortcut in Sierra to bring up the Tags dialog, but that method doesn’t work in Mojave either.

Any insight appreciated, thanks!

This will let you modify tags:

use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"

on returnTagsFor:posixPath -- get the tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags = missing value then return {} -- because when there are none, it returns missing value
	return theTags as list
end returnTagsFor:

on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

on addTags:tagList forPath:posixPath -- add to existing tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	-- get existing tags
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags ≠ missing value then -- add new tags
		set tagList to (theTags as list) & tagList
		set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
	end if
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:

set theFile to POSIX path of (choose file)

its returnTagsFor:theFile

Just to provide an alternative method that might be more palatable:

--FINDER TAGS:
property unset : 0
property orange : 1
property red : 2
property yellow : 3
property blue : 4
property purple : 5
property green : 6
property grey : 7

tell application "Finder"
		repeat with f in selection as alias list
				set label index of file f to red
		end repeat
end tell

which will take the selected files in Finder and tag them red. The benefit of Shane’s method is you can apply multiple tags to a file; here, you can only assign one tag at a time, and assigned a tag overwrites the existing tags (and, by “tags”, I mean “label colours”).

Your code is only assigning a tag indirectly. It’s actually (re-)assigning the Finder label (kMDItemFSLabel), which these days is arguably only there for backwards compatibility; the system adds a (roughly) matching tag at the same time.

Have you pulled that script out of your archives? Because I don’t think those colors match what you actually see these days (the names of which are localized, I believe).

@Shane

The indexes used in CK’s proposal are right - at least for 10.13.6.

The name of labels are really localized but here it’s not a problem.
You may use property DonaldTrump : 2, the instruction set label index of file f to DonaldTrump will apply a red label.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 14 mai 2019 12:12:38

Yes, I mis-spoke – it’s just the order they appear in the UI that’s changed.

Thanks, Shane, that seems to work great, in both Sierra 10.12.6 and Mojave 10.14.4! Below is my script based on your code, which allows me to select a combination of files and folders and tag them all with the selected tags.

Interestingly, I did find a way to use keyboard shortcuts to invoke the Tag box (weirdly, you go to Finder/Preferences/Tags, delete all custom tags, and then specify your keyboard shortcut), which has the benefit of allowing you to choose the order of the tags. See https://apple.stackexchange.com/questions/339126/is-there-a-way-to-set-a-finder-shortcut-for-tags-in-macos-10-14-mojave/339177.

Also thanks to CK and Yvan!


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"

tell application "Finder"
	set theItems to the selection
end tell

set tagList to choose from list {"Red", "Orange", "Yellow", "Green", "Blue", "Gray", "Purple"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

repeat with thisItem in theItems
	set theFile to POSIX path of (thisItem as alias)
	
	(its setTags:tagList forPath:theFile)
end repeat

on returnTagsFor:posixPath -- get the tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags = missing value then return {} -- because when there are none, it returns missing value
	return theTags as list
end returnTagsFor:

on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

on addTags:tagList forPath:posixPath -- add to existing tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	-- get existing tags
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags ≠ missing value then -- add new tags
		set tagList to (theTags as list) & tagList
		set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
	end if
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:


As I am curious, I tried the given script using a list of localized color names.

It’s easy to get these names:

set theNames to {}
repeat with i from 0 to 7
	set theKey to ("TG_COLOR_" & i)
	tell application "Finder" to set theName to localized string theKey
	set end of theNames to {theKey, theName}
end repeat
theNames
--> {{"TG_COLOR_0", "Aucune couleur"}, {"TG_COLOR_1", "Gris"}, {"TG_COLOR_2", "Vert"}, {"TG_COLOR_3", "Violet"}, {"TG_COLOR_4", "Bleu"}, {"TG_COLOR_5", "Jaune"}, {"TG_COLOR_6", "Rouge"}, {"TG_COLOR_7", "Orange"}}

I edited the choose from list instruction as :

set tagList to choose from list {"Rouge", "Orange", "Jaune", "Vert", "Bleu", "Gris", "Violet"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

Good point, we may use the English names or the localized ones, the behavior will be the same.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 14 mai 2019 18:35:11

Hey Yvan,

I could not find any reference to TG_COLOR_x in the applescript books I have.
So if I do:

tell application "Finder"
	localized string "TG_COLOR_3"
end tell

I get: Purple

But if I do:

tell application "Finder"
	localized string "TA_COLOR_3" -- >> TA_COLOR_3
end tell

I get: TA_COLOR_3

Where did you get the info on TG_COLOR_x ?

The keys used to localize strings aren’t defined in the sdefs.

We may just get them in the resources files available in application’s bundles.

TG_COLOR_x where x is a digit from 0 to 7 is a key in the localizable.strings files used by the system to localize some strings. It’s the one reachable by default but there are numerous other ones.

For French resources they are in the folder:

"/System/Library/CoreServices/Finder.app/Contents/Resources/French.lproj/"

The complete list is :

AboutWindow.strings
AirDropCollectionView.strings
AirDropDiscoverableModePopoverView.strings
AirDropIconView.strings
AirDropInfoView.strings
AirDropLegacyModePopoverView.strings
AirDropNotAvailableView.strings
ArrangeByMenu.strings
BannerView.strings
BulkRenameWindow.strings
ClipWindow.strings
ColumnCellView.strings
ColumnPreview.strings
ColumnView.strings
DecryptionPasswordSheet.strings
FFKBrowserWindow.strings
FFKMenuBar.strings
GotoWindow.strings
GroupNameField.strings
ICloudNoDocumentsView.strings
iCloudQuotaBanner.strings
ICloudSetupView.strings
ICloudUpgradeView.strings
IconCollectionGroupHeaderView.strings
InfoPlist.strings
ListView.strings
Localizable.strings
NavChooseApp.strings
PreferencesWindow.strings
ProgressErrorView.strings
ProgressStatusView.strings
ProgressStatusView2Line.strings
SearchCriteriaSheet.strings
SearchForSlice.strings
SearchScopeSlice.strings
ServicesMenu.strings
SidebarView.strings
SimpleGrouping.strings
SlicesAttributeNameOverrides.strings
SlicesStrings.strings
StatusBar.strings
TagColumnTableView.strings
TagsPrefCellView.strings
Toolbar.strings
ViewOptionsWindow.strings

Infos about these resources are given in Standard Additions’s dictionary:

localized string v : Return the localized string for the specified key
localized string text : the key
[from table text] : the name of the strings file excluding the “.strings” suffix (default is “Localizable”)
[in bundle file] : an alias or file reference to the bundle containing the strings file (default is the current application/script bundle)
→ text : the localized string

Example with the results returned under a system running in French.
CAUTION: The keys aren’t guaranteed to survive a major version change.

(*
Simple case, the string to localize is defined in the table Localizable.strings.
There is no need to describe explicitely the table and the source bundle.
*)

tell application "Finder" to set toRemoveFromiCloudDrive_loc to localized string "A31"
--> "Pour supprimer des éléments d’iCloud Drive, déplacez-les dans votre dossier Bureau ou Documents sur ce Mac."

(*
If the string is defined in an other file we must pass the table's name (without the suffix .strings) and the bundle stroring it
*)
set FinderBundle to path to application "Finder"
--> alias "SSD 500:System:Library:CoreServices:Finder.app:"
set IconSize_loc to localized string "383.title" from table "ViewOptionsWindow" in bundle FinderBundle
--> "Taille des icônes :"

set |Finder/Reveal_loc| to localized string "Finder/Reveal" from table "ServicesMenu" in bundle FinderBundle
--> "Finder/Afficher dans le Finder"

set LastOpen_loc to localized string "116.title" from table "ArrangeByMenu" in bundle FinderBundle
--> "Date de dernière ouverture"

# Other one for the fun

set Volume_loc to localized string "tCs-xJ-UEw.title" from table "ArrangeByMenu" in bundle FinderBundle
--> "Volume"

# It seems that there is no global control upon these tables so several keys may describe the same string.
set showLibrary_loc1 to localized string "Ukt-Pm-iTw.title" from table "ViewOptionsWindow" in bundle FinderBundle
--> "Afficher le dossier Bibliothèque"
set showLibrary_loc2 to localized string "noX-Qe-gkU.title" from table "ViewOptionsWindow" in bundle FinderBundle
--> "Afficher le dossier Bibliothèque"
set showLibrary_loc3 to localized string "sld-Oo-X54.title" from table "ViewOptionsWindow" in bundle FinderBundle
--> "Afficher le dossier Bibliothèque"

I’ve use localized string for years and met changes only two or three times.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mercredi 15 mai 2019 12:08:55

2 Likes

Thanks !

I’m back about localized string because I forgot an important feature.
Sometimes, the English.lproj doesn’t contain every tables available for other countries.
You will see some examples below.
You will discover a case where I am unable to find the correct English spelling.

(*
Simple case, the string to localize is defined in the table Localizable.strings.
There is no need to describe explicitely the table and the source bundle.
*)

tell application "Finder" to set toRemoveFromiCloudDrive_loc to localized string "A31"
--> "Pour supprimer des éléments d’iCloud Drive, déplacez-les dans votre dossier Bureau ou Documents sur ce Mac."

(*
If the string is defined in an other file we must pass the table's name (without the suffix .strings) and the bundle stroring it
*)
set FinderBundle to path to application "Finder"
--> alias "SSD 500:System:Library:CoreServices:Finder.app:"

set theKey to "383.title"
set IconSize_loc to localized string theKey from table "ViewOptionsWindow" in bundle FinderBundle
if IconSize_loc = theKey then # The system run in English for which there is no table "ViewOptionsWindow"
	set IconSize_loc to "Icon size:"
end if
log IconSize_loc --> "Taille des icônes :"

set |Finder/Reveal_loc| to localized string "Finder/Reveal" from table "ServicesMenu" in bundle FinderBundle
--> "Finder/Afficher dans le Finder"

set theKey to "116.title"
set LastOpen_loc to localized string theKey from table "ArrangeByMenu" in bundle FinderBundle
if LastOpen_loc = theKey then # The system run in English for which there is no table "ArrangeByMenu"
	set LastOpen_loc to "Date Last Opened"
end if
log LastOpen_loc --> "Date de dernière ouverture"

# Other one for the fun
set theKey to "tCs-xJ-UEw.title"
set Volume_loc to localized string theKey from table "ArrangeByMenu" in bundle FinderBundle
if Volume_loc = theKey then # The system run in English for which there is no table "ArrangeByMenu"
	set Volume_loc to "Volume"
	(*
In fact I don't know which is the exact spelling.
in Russian it's "по тому" which according to Google means "on that"
in Spanish it's "Volumen" which according to Google means "Volume"
in Japanese it's "ボリューム"  which according to Google means "Volume"
And I never saw this string in the View menu which contain the ArrangeBy menu
*)
end if
log Volume_loc --> "Volume"

# It seems that there is no global control upon these tables so several keys may describe the same string.
set theKey to "Ukt-Pm-iTw.title"
set showLibrary_loc1 to localized string theKey from table "ViewOptionsWindow" in bundle FinderBundle
if showLibrary_loc1 = theKey then # The system run in English for which there is no table "ViewOptionsWindow"
	set showLibrary_loc1 to "Show Library Folder"
end if
log showLibrary_loc1 -->"Afficher le dossier Bibliothèque"

set theKey to "noX-Qe-gkU.title"
set showLibrary_loc2 to localized string theKey from table "ViewOptionsWindow" in bundle FinderBundle
if showLibrary_loc2 = theKey then # The system run in English for which there is no table "ViewOptionsWindow"
	set showLibrary_loc2 to "Show Library Folder"
end if
log showLibrary_loc2 -->"Afficher le dossier Bibliothèque"

set theKey to "sld-Oo-X54.title"
set showLibrary_loc3 to localized string theKey from table "ViewOptionsWindow" in bundle FinderBundle
if showLibrary_loc3 = theKey then # The system run in English for which there is no table "ViewOptionsWindow"
	set showLibrary_loc3 to "Show Library Folder"
end if
log showLibrary_loc3 -->"Afficher le dossier Bibliothèque"

Happily, such annoying cases are rare.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 16 mai 2019 12:38:15

Just be aware that when you see a key in a form like “sld-Oo-X54.title”, it means it has been automatically generated by Xcode when the app’s code was compiled. This means it’s pretty much guaranteed to change in future.

Thanks Shane.
What you wrote may explain why several keys may be used to describe the same string.
As I am curious, I ran my sample script upon Finder 10.12.6 and - I am lucky - the “easy to remember keys” available in Finder 10.13.6 were already available in the old version.

In practice it’s not really important. I never had to use such keys. I use localized string when I have to write GUI scripting code where the name of UI elements are always localized.
The fact that some tables are unavailable in English.lprog is more annoying.
I’m wondering were are the English strings defined in such cases.

I’m really puzzled by the key “tCs-xJ-UEw.title” in the table ArrangeByMenu.strings.
Most of the time the local string means volume but sometimes it’s really different.
For instance, the danish key is Enhed which is supposed to mean Unit.

And of course I’m always unable to find where is this string really used.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 17 mai 2019 12:08:03

How would the modified script of Shane Stanley look like (kerflooey) if you dont want to choose a label, but have it set to a specific label?

Hi. The script I use is below, which I use in Catalina. If you choose labels, they are applied. If you don’t choose a label, all current labels are removed. Not sure about your question, though. You want to not choose a label, but apply a specific label?


use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"

tell application "Finder"
	set theItems to the selection
end tell

set tagList to choose from list {"Red", "Orange", "Yellow", "Green", "Blue", "Gray", "Purple"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

repeat with thisItem in theItems
	set theFile to POSIX path of (thisItem as alias)
	
	(its setTags:tagList forPath:theFile)
end repeat

on returnTagsFor:posixPath -- get the tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags = missing value then return {} -- because when there are none, it returns missing value
	return theTags as list
end returnTagsFor:

on setTags:tagList forPath:posixPath -- set the tags, replacing any existing
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end setTags:forPath:

on addTags:tagList forPath:posixPath -- add to existing tags
	set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
	-- get existing tags
	set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
	if theTags ≠ missing value then -- add new tags
		set tagList to (theTags as list) & tagList
		set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
	end if
	aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forPath:



Hi, yes Kerflooey. I tried the script and it works fine. :slight_smile:

I would like to have it set to a fixed chosen label. That way I can make an automator “quick action”.

The goal is to right click a folder in finder that is red, go into services and pick the script that changes it to green.

When I try to do it only using automator I get green label in addition to the red.
So this AppleScript would be the solution I need.

If I understand correctly, you want to select a file (or files) and apply a fixed-text tag to it. A quick and dirty approach is to remove or comment out the “set tagList to…” line near the beginning and replace it with a line to just set the tag to whatever you want. For example:


--set tagList to choose from list {"Red", "Orange", "Yellow", "Green", "Blue", "Gray", "Purple"} with title "Tag Selected Items" with prompt "Choose colors:" OK button name "Apply" cancel button name "Cancel" with multiple selections allowed and empty selection allowed

set tagList to {"Red"} 

-- or, to remove a tag: 
--set tagList to {""}




kerflooey, you are the MAN! :cool:

Very grateful for that help! It worked flawlessly.

Thanks dude!

kerflooey, you are the MAN! cool

Ha, no. That would be Shane! :slight_smile: Glad it worked for you.