OS X 10.8 から,Mac には標準でウィズダム英和/和英辞典が内蔵されています。標準の 辞書.app や,command+control+D で検索できます。
Swift で書いている OS X 用アプリの中からウィズダム英和辞典で検索したいと思い,その方法を検討しました。
Dictionary Services を使えば,辞書の検索自体は可能です。
ただし,特定の辞書を指定して検索するのは,Objective-C でも Private API を使わなければできないようで,現在のところ直接的な方法は公式には用意されていないようです。
そこで,次のような方法を使うことにしました。
- 現在の検索辞書の設定を保存する。
- 検索辞書の設定を書き換え,ウィズダム英和辞典だけを検索辞書に指定する。
-
DCSCopyTextDefinition
を使って辞書を検索して意味を取得する。 - 検索辞書の設定を復元する。
このように,ユーザの検索辞書設定を一時的に変更して辞書検索を行い,すぐに元に戻すことで,特定の辞書を指定して検索を行うことが可能となります。
DictionaryServiceManager.swift
import Foundation
class DictionaryServiceManager {
private let AppleGlobalDomainName = "Apple Global Domain"
private let DictionaryServicesKey = "com.apple.DictionaryServices"
private let ActiveDictionariesKey = "DCSActiveDictionaries"
private var globalDomain: [String:Any]? { UserDefaults.standard.persistentDomain(forName: AppleGlobalDomainName) }
private var dictionaryPreferences: [String:AnyObject]? { self.globalDomain?[DictionaryServicesKey] as! [String:AnyObject]? }
private var currentDictionaryList: [String]? { self.dictionaryPreferences?[ActiveDictionariesKey] as! [String]? }
private func setUserDictPreferences(_ activeDictionaries: [String]) {
if var currentPref = self.dictionaryPreferences {
currentPref[ActiveDictionariesKey] = activeDictionaries as AnyObject
if var gDomain = self.globalDomain {
gDomain[DictionaryServicesKey] = currentPref
UserDefaults.standard.setPersistentDomain(gDomain, forName: AppleGlobalDomainName)
}
}
}
func lookUp(_ word: String, inDictionary dictionaryPath: String) -> String? {
let currentPrefs = self.currentDictionaryList
self.setUserDictPreferences([dictionaryPath])
let range = CFRangeMake(0, word.utf16.count)
let result = DCSCopyTextDefinition(nil, word as CFString, range)?.takeRetainedValue() as String?
if let currentPrefs = currentPrefs {
self.setUserDictPreferences(currentPrefs)
}
return result
}
}
これを使えば,たとえば次のようにしてウィズダム英和辞典を検索できます。
DictionaryServiceManager-Test.swift
let wisdomPath: String
if #available(macOS 13, *) {
wisdomPath = "/System/Library/AssetsV2/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/c47eada3a1cc3269ef6d8120a6cc20c7dcf70355.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else if #available(macOS 12, *) {
wisdomPath = "/System/Library/AssetsV2/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/b3bf6ae48c39f29f7ca1b7410a60eece625c5fc3.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else if #available(macOS 11, *) {
wisdomPath = "/System/Library/AssetsV2/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/eda7c0d385d0ccb68e97b60251d63e9e2633b466.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else if #available(macOS 10.15, *) {
wisdomPath = "/System/Library/AssetsV2/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/7725cba5b321a8308a603a40ac808699175c4aae.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else if #available(macOS 10.14, *) {
wisdomPath = "/System/Library/Assets/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/c15aa908a684112f63017e47bb6b289e99977135.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else if #available(macOS 10.13, *) {
wisdomPath = "/System/Library/Assets/com_apple_MobileAsset_DictionaryServices_dictionaryOSX/65c5f4f22827dba6b0a6bc85755863317890953b.asset/AssetData/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
} else {
wisdomPath = "/Library/Dictionaries/Sanseido The WISDOM English-Japanese Japanese-English Dictionary.dictionary"
}
// "swift" の意味を取得
let word = "swift"
if let content = DictionaryServiceManager().lookUp(word, inDictionary: wisdomPath) {
print(content)
} else {
print("NOT FOUND")
}