バンドルIDで指定したアプリケーションのResourcesフォルダ中の、指定ロケールのstringsファイルをすべて読み込んでkeyを取り出すAppleScriptです。
アプリケーション内の指定のローカライズしたメッセージ(テキスト)の内容を取り出すことはできますが、そのためにはキーを知っておく必要があります。そのキーを取り出してローカライズされた文字列を取り出すため、キーを調査してみました。
これをそのまま何かのツールなりScriptに使うというものではなく、いわゆる「下調べ」のためのScriptの部品です。
ほぼ、ありもののルーチンを再利用しただけのプログラムでできていますが、ありものはありもので、数千本のAppleScriptのストックからそれを探し出してくるのも一苦労です。
アプリケーションバンドル内のResourcesフォルダ以下の(各lprojフォルダ以下の)stringsファイルの中身はまんま(シリアライズした)NSDictionaryなので、そのままDictionaryに読み込んでallkey()などのメソッドを実行できます。昔のstringsファイルはテキストファイルだったような気がしますが、テキストファイルだとparseしないといけないんで、ビルド時にparseしておいてDictionaryの状態でファイルに書いておくのは正しいと思います。
Xcode 8あたりから、アプリケーションのローカライズのルールが変更になったようで、基本となる言語環境がBase.lprojになり、英語はen.lprojといった1ローカライズ言語という位置付けに変更になりました。
NSLocalizedStringFromTableInBundleを使ってアクセスしようかとも思ったのですが、こちらはまだ目的を達成できていません。
▲Xcode 11上で実験的に作成したAppleScriptアプリケーションのバンドル構造(左)。ローカライズしていない状態だとEnglishではなくBase.lprojが作成される。右はKeynote.app/Contents/Resources/ja.lprojフォルダの内容。stringsファイルが大量に存在している
AppleScript名:指定アプリケーションの指定言語のstringsファイルの内容をすべて取り出す.scptd |
— – Created by: Takaaki Naganoya – Created on: 2019/09/21 — – Copyright © 2019 Piyomaru Software, All Rights Reserved — use AppleScript version "2.5" use scripting additions use framework "Foundation" property |NSURL| : a reference to current application’s |NSURL| property NSArray : a reference to current application’s NSArray property NSBundle : a reference to current application’s NSBundle property NSPredicate : a reference to current application’s NSPredicate property NSDictionary : a reference to current application’s NSDictionary property NSWorkspace : a reference to current application’s NSWorkspace property NSFileManager : a reference to current application’s NSFileManager property NSMutableDictionary : a reference to current application’s NSMutableDictionary property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles property NSDirectoryEnumerationSkipsPackageDescendants : a reference to current application’s NSDirectoryEnumerationSkipsPackageDescendants set targID to "com.apple.iWork.Keynote" set bRes to getLocalizationsFromBundleID(targID) of me –> {"de", "he", "en_AU", "ar", "el", "ja", "en", "uk", "es_419", "zh_CN", "es", "da", "it", "sk", "pt_PT", "ms", "sv", "cs", "ko", "Base", "no", "hu", "zh_HK", "tr", "pl", "zh_TW", "en_GB", "vi", "ru", "fr_CA", "fr", "fi", "id", "nl", "th", "pt", "ro", "hr", "hi", "ca"} set curLang to first item of (choose from list bRes) set aPath to retPathFromBundleID(targID) of me set aPath to aPath & "/Contents/Resources/" & curLang & ".lproj" set sList to getFilepathListByUTI(aPath, "com.apple.xcode.strings-text", "POSIX") of me set aMDict to NSMutableDictionary’s new() repeat with i in sList set j to contents of i set aDict to (NSDictionary’s alloc()’s initWithContentsOfFile:j) (aMDict’s addEntriesFromDictionary:aDict) end repeat return aMDict’s allKeys() as list –> {"Interactive Bubble Chart", "Rehearse Slideshow", "PMT_ARGUMENT_1", "ACCRINTM_ARGUMENT_4_MODE_0", "Truck_378",….} on getLocalizationsFromBundleID(aBundleID) set aRes to retPathFromBundleID(aBundleID) of me if aRes = false then error "Wrong Bundle ID." return getSpecifiedAppFilesLocalizationListWithDuplication(aRes) of me end getLocalizationsFromBundleID –指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を許容 on getSpecifiedAppFilesLocalizationListWithDuplication(appPOSIXpath) set aURL to (|NSURL|’s fileURLWithPath:appPOSIXpath) set aBundle to NSBundle’s bundleWithURL:aURL set locList to aBundle’s localizations() return locList as list end getSpecifiedAppFilesLocalizationListWithDuplication on retPathFromBundleID(aBundleID) set aURL to NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID if aURL = missing value then return false –Error return aURL’s |path|() as string end retPathFromBundleID on getFilepathListByUTI(aFolPOSIX, aUTI as string, aFileType as string) script spdFile property urlList : {} end script if aFileType is not in {"file", "POSIX"} then return {} set aFM to NSFileManager’s defaultManager() set aFolExt to (aFM’s fileExistsAtPath:aFolPOSIX isDirectory:true) as boolean if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す set aURL to |NSURL|’s fileURLWithPath:aFolPOSIX set theOptions to ((NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((NSDirectoryEnumerationSkipsHiddenFiles) as integer) set urlArray to (aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value)) if urlArray = missing value then return {} set (urlList of spdFile) to urlArray as list set newList to {} repeat with i in (urlList of spdFile) set j to POSIX path of i set tmpUTI to my retUTIfromPath(j) set utiRes to my filterUTIList({tmpUTI}, aUTI) if utiRes is not equal to {} then if aFileType = "POSIX" then set the end of newList to j else if aFileType = "file" then set the end of newList to POSIX file j end if end if end repeat return newList end getFilepathListByUTI –指定のPOSIX pathのファイルのUTIを求める on retUTIfromPath(aPOSIXPath) set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value) if theResult = true then return theValue as string else return theResult end if end retUTIfromPath –UTIリストが指定UTIに含まれているかどうか演算を行う on filterUTIList(aUTIList, aUTIstr) set anArray to NSArray’s arrayWithArray:aUTIList set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr) set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list return bRes end filterUTIList |