Thursday, February 21, 2019

#1 2008-03-31 09:44:43 am

ChristInBen
Member
Registered: 2008-03-27
Posts: 66

Using dictionaries (key/value pairs) in Applescript....

Hi guys,

I've been creating an application using Applescript that uninstalls a software off a Mac. It's supposed to be multi-platform (Panther, Tiger, and Leopard), and I have finished it. The only problem is that I have to make it more efficient, so I thought of using the dictionaries to reduce my localization part of the code (as my code is very lengthy due to this). Currently, this is how I handle localization:

Applescript:

on displayEnglish()
   display dialog "This will uninstall your Software. Do you want to continue?" buttons {"Yes", "No"} default button "Yes" with icon caution
   if button returned of result is "No" then error number -128
end displayEnglish

on displayFrench()
   display dialog "This is French!" buttons {"Yes", "No"} default button "Yes" with icon caution
   if button returned of result is "No" then error number -128
end displayFrench

So I thought of using dictionaries to minimize this code to something like:

set key "en" to value "This is English",
set key "fr" to value "This is French".

And so on. Then I would have to probably loop through it and query through my if statements, so if the current language is "en" then display the value for that key which is" Uninstall software....".

Can you guys help me achieve this?

Thanks so much and God Bless you all! smile

Ben.

Offline

 

#2 2008-03-31 10:28:21 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11550
Website

Re: Using dictionaries (key/value pairs) in Applescript....

Hi,

there is a quite easy way to localize AppleScripts without AppleScript Studio.
The only requirement is, that the script must be saved as bundle

• Open the bundle with the contextual menu > Show Package Contents
• Open the folder Contents > Resources
• Create a folder English.lproj in the folder Resources and further localized folders, in the following example I'll describe an additional folder German.lproj
• Open TextEdit (or another text editor) and create a plain text file with the contents

[code]"CONTINUE"  =  "This will uninstall your Software. Do you want to continue?";
"YES" = "Yes";
"NO" = "No";[/code]
Notes: The syntax "Label" = "the text";  is important
The preferred text encoding is UTF-8

• save the file as Localizable.strings in yourApp/Contents/Resources/English.lproj
• create a second plain text file with the contents

[code]"CONTINUE"  =  "Das script wird Ihre Software entfernen. Wollen Sie fortfahren?";
"YES" = "Ja";
"NO" = "Nein";[/code]
• save the file as Localizable.strings in yourApp/Contents/Resources/German.lproj

Use this kind of AppleScript code. The literal string after localized string represents the label in the localizable.strings file.
If there is an equivalent .lproj folder with a Localizable.strings file in it, the script will always display the messages in the current system language

Applescript:


displayLocalized()

on displayLocalized()
display dialog (localized string "CONTINUE") buttons {localized string "YES", localized string "NO"} default button 1 with icon caution
if button returned of result is (localized string "NO") then error number -128
end displayLocalized

Last edited by StefanK (2008-03-31 10:30:03 am)


regards

Stefan

Offline

 

#3 2008-03-31 12:11:23 pm

Bruce Phillips
Administrator
Registered: 2004-07-16
Posts: 2649

Re: Using dictionaries (key/value pairs) in Applescript....

If you'd like an example, my Screenshot Settings app has a French localization. Also, note that localized string is only available on Tiger or later.

See also: localized string

Offline

 

#4 2008-03-31 07:58:45 pm

ChristInBen
Member
Registered: 2008-03-27
Posts: 66

Re: Using dictionaries (key/value pairs) in Applescript....

So guys, this method provided by Stefan doesn't work on Panther? It only works on Tiger and Leopard?

Offline

 

#5 2008-04-01 07:31:39 am

ChristInBen
Member
Registered: 2008-03-27
Posts: 66

Re: Using dictionaries (key/value pairs) in Applescript....

Is there a universal method between Panther, Tiger, and Leopard, or should I use dictionaries?

Offline

 

#6 2008-04-01 08:45:39 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11550
Website

Re: Using dictionaries (key/value pairs) in Applescript....

ChristInBen wrote:

Is there a universal method between Panther, Tiger, and Leopard?


Alternatively use different scripts for the message handlers containing the localized parts, which will be loaded as script (object) depending on the language.
This example works in Panther, Tiger and Leopard, the localized scripts are located in the bundle /Contents/Resources/Scripts/

Applescript:


set SystemLanguage to word 1 of (do shell script "defaults read -g AppleLanguages")
--> returns en for english, de for german, fr for french etc.
set localizedFolder to ((path to me as string) & "Contents:Resources:Scripts:")
try
   set localizedScript to load script alias (localizedFolder & "localized_" & SystemLanguages & ".scpt")
on error
   set localizedScript to load script alias (localizedFolder & "localized_en.scpt")
end try
tell localizedScript to displayMessage()

• create a script for each language named localized_[lang].scpt ([lang] represents the two character language abbreviation)
for example, if no localized script will be found, the main script uses always the english version.

script myApp.app/Contents/Resources/Scripts/localized_en.scpt

Applescript:


on displayMessage()
display dialog "This will uninstall your Software. Do you want to continue?" buttons {"Yes", "No"} default button 1 with icon caution
if button returned of result is "No" then error number -128
end displayMessage

script myApp.app/Contents/Resources/Scripts/localized_de.scpt

Applescript:


on displayMessage()
display dialog "Das script wird Ihre Software entfernen. Wollen Sie fortfahren?" buttons {"Ja, "Nein"} default button 1 with icon caution
if button returned of result is "
Nein" then error number -128
end displayMessage


regards

Stefan

Offline

 

#7 2008-04-01 08:58:26 am

ChristInBen
Member
Registered: 2008-03-27
Posts: 66

Re: Using dictionaries (key/value pairs) in Applescript....

Cool, I'll definitely try that. Also, I use this Bash command:

Applescript:

set SystemLanguage to do shell script "defaults read .GlobalPreferences AppleLanguages | tr -d [:space:] | cut -c2-3"

As I couldn't truncate the first word, however, word1 does that for me instead of this line correct?

Offline

 

#8 2008-04-01 09:04:59 am

StefanK
Member
From:: St. Gallen, Switzerland
Registered: 2006-10-21
Posts: 11550
Website

Re: Using dictionaries (key/value pairs) in Applescript....

ChristInBen wrote:

As I couldn't truncate the first word, however, word1 does that for me instead of this line correct?


I've tested my version successfully on all of the three system versions, but the tr / cut version should also work


regards

Stefan

Offline

 

#9 2008-04-01 02:00:59 pm

ChristInBen
Member
Registered: 2008-03-27
Posts: 66

Re: Using dictionaries (key/value pairs) in Applescript....

Hey thanks again you guys are helping a lot....but I just did a code review and the lead wants dictionaries (key/ value pairs) used for localization. So I have to do this....whats the syntax for using dictionaries on Applescript....back to my original question and also, how can I use it for my localization stuff. Sorry for the long list of questions, but I have to meet a deadline in two days! sad

Thanks and God Bless.

Ben.

Offline

 

#10 2011-05-26 10:30:54 am

tempel
Member
From:: Germany
Registered: 2010-11-19
Posts: 68
Website

Re: Using dictionaries (key/value pairs) in Applescript....

I need a solution for what the subject asks for - i.e. I do not need to do localization, I really need key-value pairs in AppleScript.

I am scanning a large set of data and need to find matching names in it. Imagine I want to scan a large folder with subfolders and want to find all files of the same name, appearing in different folders.

So I need to use a dictionary-like variable in which I can put the found items with their names. I also need to see if the item's name is already in there, and react on that.

I know that there's a "contains" verb, but that's not enough for me. I need something like "index of", or "item with name".

Basically, I imagine writing this:

Applescript:


set mySet to {}
repeat with theItem ...
set itsName to name of theItem
set itemFromSet to (index of itsName in mySet's keys)
if itemFromSet is nil then
-- not in the set yet -> store this item now
set mySet to mySet & { key: itsName, value: theItem }
else
-- found a match
end
end

I understand that I could write my own "findItemInList" function performing a loop over all items in the set - but that would be quite slow and getting quadradically worse the more items I have. Not good. I need hash-like lookup function. I'm surprised I can't find any postings on this. My AppleScript book also doesn't discuss this. And I thought such lookup functions would be quite popular.

Offline

 

#11 2011-05-26 12:31:19 pm

Adam Bell
Administrator
From:: Nova Scotia, Canada
Registered: 2005-10-04
Posts: 4665

Re: Using dictionaries (key/value pairs) in Applescript....

There are some very fast sort algorithms (mostly by Nigel Garvey under Code Exchange). My usual approach to your problem is to get the list of entire contents, sort them, and then run through the list looking for duplicates which will be adjacent.


iMac running OS X 10.13.1

Offline

 

#12 2011-05-26 07:40:31 pm

regulus6633
Member
From:: Taulov, Denmark
Registered: 2006-11-02
Posts: 1695
Website

Re: Using dictionaries (key/value pairs) in Applescript....

All you would need to do is keep track of the names you have added in a separate list. Then you check against that list before adding the item to your list...

Applescript:

set mySet to {}
set namesList to {}

repeat with theItem in theItems
   tell application "Finder" to set itsName to name of theItem
   
   if itsName is not in namesList then
       set end of namesList to itsName
       set mySet to mySet & {key:itsName, value:theItem}
   else
       -- found a match
   end if
end repeat

Offline

 

#13 2015-03-16 01:14:42 pm

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Using dictionaries (key/value pairs) in Applescript....

Hello.

The use of localized string, doesn't work well in Mavericks, not for me anyway, so I have tried to make a general handler for returning the correct localized string.

In order to return the correct localized string, I have to get at the correct Lproj bundle, that contains the localized string for either my language or AppleLocale.

Algorithm:
   
    see if the first of languages is in one of the *big* languages[1], if it is, then return correct bundle name.
   
    Else see if the appleLocale, is among the *very detailed bundles*

    check and see if the language, has a related, *normal region specific bundle*
   
    if all else fails, use English.lproj as fall back.

[1] Big Languages:

Dutch.lproj, English.lproj, French.lproj, German.lproj, Italian.lproj, Japanese.lproj, Spanish.lproj
The "big languages " are collected up  front.

[2] Very detailed bundles:
pt_PT.lproj, zh_CN.lproj zh_TW.lproj

[3]*normal region specific bundle*:
ar.lproj, ca.lproj, cs.lproj, da.lproj, el.lproj, fi.lproj, and so on . . .


Documentation:

This handler is for returning a localized string, on some machine from some app, according to the current users language and locale settings.


How to preparate input for  this handler:

You have to open the resources folder of the app that you inted to retrieve the localized string from, and other than assure that you have got the correct "key" for your localized string, you have to make a list with any spelled out language names, and a related list with the language codes, this page may help when contstructing the lists: iso-639-2 list.


Here comes the handler with a demonstration:  Figure out the local string for screenshots of ScreenCapture app.

Applescript:

set hfsAppName to "Macintosh HD:System:Library:CoreServices:SystemUIServer.app:"
# I have figured out the big languages list, by peeking into the SystemUIServer apps Resources folder . . .
set langList to {"nl", "en", "fr", "de", "it", "jp", "es"}
set lProjList to {"Dutch.lproj", "English.lproj", "French.lproj", "German.lproj", "Italian.lproj", "Japanese.lproj", "Spanish.lproj"}
set rscPath to POSIX path of ((hfsAppName & "Contents:Resources") as alias)

set correctLProj to getTheLProjBundle(rscPath, langList, lProjList)

set correctResource to path to resource "no.lproj" in bundle file hfsAppName

set locString to localized string of "%@ %@ at %@" from table "ScreenCapture" in bundle correctResource

log locString
--> "%@ %@ kl. %@"

on getTheLProjBundle(pxPathToResourcesFolder, langList, lProjList)
   # [url]http://macscripter.net/viewtopic.php?pid=179383#p179383[/url]
   set sysLang to word 1 of (do shell script "defaults read -g AppleLanguages")
   # StefanK
   if (count langList) ≠ (count lProjList) then error "getTheLProjBundle: langList is not as long as lProjList"
   set pass to 1
   repeat
       
       if pass = 1 then
           -- check if the first language is amongst the "big" languages.
           if sysLang is in langList then
               repeat with i from 1 to (count langList)
                   if sysLang is item i of langList then return item i of lProjList
               end repeat
           else
               set pass to 2
           end if
       else if pass = 2 then
           -- check if the current AppleLocales are among the very detailed localization bundles.
           try
               set curLocale to do shell script "/usr/bin/defaults read -g AppleLocale"
           on error
               set pass to 3
           end try
           if pass = 2 then -- still
               try
                   tell application id "MACS"
                       set locBundleName to name of first folder of folder (POSIX file pxPathToResourcesFolder as text) whose name begins with curLocale
                   end tell
                   return locBundleName
               on error
                   set pass to 3
               end try
           end if
       else if pass = 3 then
           -- check and see if the language, has a related, *normal region specific bundle*
           try
               set region to (do shell script "/usr/bin/grep \"" & sysLang & "_*\" /usr/share/locale/locale.alias |/usr/bin/head -1 |/usr/bin/sed -En 's/([[:alpha:]]+[[:blank:]]+)([^_]+)_([^.]+)(.*)/\\3/p' |/usr/bin/tr 'A-Z' 'a-z'")
           on error
               set pass to 4
           end try
           if pass = 3 then -- still . . .
               try
                   tell application id "MACS"
                       set locBundleName to name of first folder of folder (POSIX file pxPathToResourcesFolder as text) whose name begins with region
                   end tell
                   return locBundleName
               on error
                   set pass to 4
               end try
           end if
       else if pass = 4 then
           -- fall back
           -- Thanks to Shane Stanley
           tell application id "MACS"
               set rcsFol to folder (POSIX file pxPathToResourcesFolder as text)
               if exists folder "English.lproj" of rcsFol then
                   return "English.lproj"
               else if exists folder "en.lproj" of rcsFol then
                   return "en.lproj"
               else
                   error "getTheLProjBundle: No english localization bundle in this App!!"
               end if
           end tell
       end if
   end repeat
end getTheLProjBundle

Last edited by McUsrII (2015-03-17 08:14:23 am)

Offline

 

#14 2015-03-16 06:41:49 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 5569

Re: Using dictionaries (key/value pairs) in Applescript....

McUsrII wrote:

[1] Big Languages:

Dutch.lproj, English.lproj, French.lproj, German.lproj, Italian.lproj, Japanese.lproj, Spanish.lproj


You should be aware that Apple recommends using the ISO identifiers instead these days -- en.lproj, fr.lproj, &c. That's what you will see in newer apps.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#15 2015-03-17 05:15:38 am

McUsrII
Member
Registered: 2012-11-21
Posts: 3046
Website

Re: Using dictionaries (key/value pairs) in Applescript....

Shane Stanley wrote:
McUsrII wrote:

[1] Big Languages:

Dutch.lproj, English.lproj, French.lproj, German.lproj, Italian.lproj, Japanese.lproj, Spanish.lproj


You should be aware that Apple recommends using the ISO identifiers instead these days -- en.lproj, fr.lproj, &c. That's what you will see in newer apps.


Yes, I should have communicated better that in order to use this handle, you have to use what is in the apps resorce folder as a vantage point when assembling the "Big Languages" list.

This is something of the past, since Apple nowadays recommends en.lproj over English.lproj, in the case of SystemUIServer, I guess they can't change it, or in any app for that matter for backwards compatibility.

Again, this handler deals with what is there, not what should be there. smile

Edit

Thank you Shane for pointing out the bug in my code, I have changed the fallback now, to en.lproj, if there isn't any English.lproj there.

Last edited by McUsrII (2015-03-17 06:26:41 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)