Edited at

Swiftでシステム内蔵辞書を検索する方法

More than 1 year has passed since last update.

OS X 10.8 から,Mac には標準でウィズダム英和/和英辞典が内蔵されています。標準の 辞書.app や,command+control+D で検索できます。

Swift で書いている OS X 用アプリの中からウィズダム英和辞典で検索したいと思い,その方法を検討しました。

Dictionary Services を使えば,辞書の検索自体は可能です。

ただし,特定の辞書を指定して検索するのは,Objective-C でも Private API を使わなければできないようで,現在のところ直接的な方法は公式には用意されていないようです。

そこで,次のような方法を使うことにしました。


  1. 現在の検索辞書の設定を保存する。

  2. 検索辞書の設定を書き換え,ウィズダム英和辞典だけを検索辞書に指定する。


  3. DCSCopyTextDefinition を使って辞書を検索して意味を取得する。

  4. 検索辞書の設定を復元する。

このように,ユーザの検索辞書設定を一時的に変更して辞書検索を行い,すぐに元に戻すことで,特定の辞書を指定して検索を行うことが可能となります。


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]? {
return UserDefaults.standard.persistentDomain(forName: AppleGlobalDomainName)
}

private var dictionaryPreferences: [String : AnyObject]? {
return self.globalDomain?[DictionaryServicesKey] as! [String : AnyObject]?
}

private var currentDictionaryList: [String]? {
return 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(OSX 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")
}