WKWebView のnavigationDelegateのメソッド経由で得られるエラーがローカライズされない

# 概要

`WKWebView` を使って Web ページを読み込む処理を実装したところ、端末がオフライン状態で通信失敗する等のエラー時に、 `WKWebView` の `navigationDelegate` のメソッド経由で得られるエラーがローカライズされない問題に遭遇しました。

ローカライズされないというのは、より具体的にいうと、アプリを実行している端末の言語設定に関わらず、 `Error` オブジェクトの `localizedDescription` 等のローカライズ可能な文字列が常に英語になっているということです。

Xcodeプロジェクトの設定をいろいろと試したり、インターネット上での検索をしたりしているうちに、この問題が iOS 側の問題である可能性が高いことがわかりました。

# 確認環境

## ビルド環境
* macOS 10.15.5
* Xcode 11.5 (11E608c)
* Deployment Target: iOS 13.0

## 実行環境
* 機種・OS
  * iPhone 11 Pro Max (iOS 13.5.1)
* 言語と地域の設定
  * 使用する言語の優先順序: 日本語、English(英語)
  * 地域: 日本

# 確認方法

## Xcodeプロジェクトの多言語対応

実際に `WKWebView` のエラーを確認をする前に、Xcode プロジェクトの多言語対応をします。今回は、アプリを英語と日本語に対応させます。

下の画像のようにして、Xcode プロジェクトについての設定画面で `Info` ペインの中の `Localizations` セクションの `+` ボタンから `Japanese (ja)` を選択することにより、日本語対応を追加します。これにより、デフォルトで対応していた英語に加えて、日本語にも対応するようになります。

![project_info_localizations.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200832/edda9af4-5333-1571-020f-4fb8280e8c94.png)

## `WKWebView` で Web ページを読み込んだ時のエラー内容を確認する

`WKWebView` を使って Web ページを読み込むための実装例を以下に示します。コードの中では読み込み対象の URL を `https://www.example.com` としていますが、この部分は実際に読み込みたいページの URL に置き換えてください。
 
```swift:SampleViewController.swift
import UIKit
import WebKit

class SampleViewController: UIViewController {
    
    @IBOutlet private weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.navigationDelegate = self

        let url = URL(string: "https://www.example.com")!
        let request = URLRequest(url: url)
        webView.load(request)
    }
}

extension SampleViewController: WKNavigationDelegate {
    
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        
    }
    
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        print(error)
    }
    
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print(error)
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    }
}
```

アプリを実行する端末がオフライン状態のときに、この `SampleViewController` に遷移させてみると、 `webView(_:didFailProvisionalNavigation:withError:)` が呼び出されます。このメソッドの引数に渡される `Error` オブジェクトは次のようになっていました。

```sh:WKWebViewの通信エラー
Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSErrorFailingURLKey=https://www.example.com/, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <747BB86D-7AFF-478E-B62E-E0496E9CBE3A>.<2>, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=The Internet connection appears to be offline., _WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x600001993540>, networkTaskDescription=LocalDataTask <747BB86D-7AFF-478E-B62E-E0496E9CBE3A>.<2>, _kCFStreamErrorDomainKey=1, NSErrorFailingURLStringKey=https://www.example.com/, NSUnderlyingError=0x6000017b7e70 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}}
```

アプリが日本語に対応していて、端末の言語設定で日本語が優先されているのにもかかわらず、 `NSLocalizedDescription` の値が `The Internet connection appears to be offline.` となっています。

## 比較: `URLSession` の通信エラーを確認する

`WKWebView` の通信エラー内の情報はローカライズされませんが、他のエラーについてはどうでしょうか。比較として、 `URLSession` の通信エラーについても確認してみます。

アプリを実行する端末がオフライン状態のときに次の処理を実行して、出力されるエラー情報を確認します。

```swift:URLSessionの通信エラーを確認
let session = URLSession(configuration: .default)
let url = URL(string: "https://www.example.com")!
let task = session.dataTask(with: url) { _, _, error in
    if let error = error {
        print(error)
    }
}
task.resume()
```
`dataTask(with:completionHandler:)` の `completionHandler` に渡される `Error` オブジェクトは次のようになっていました。

```sh:URLSessionの通信エラー
Error Domain=NSURLErrorDomain Code=-1009 "インターネット接続がオフラインのようです。" UserInfo={NSUnderlyingError=0x600003d97390 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=https://www.example.com/, NSErrorFailingURLKey=https://www.example.com/, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=インターネット接続がオフラインのようです。}
```

`URLSession` のエラーでは、`NSLocalizedDescription` の値が `インターネット接続がオフラインのようです。` となっていて、日本語にローカライズされていることがわかります。

# iOS 側の問題である可能性

インターネット上で関連情報がないか検索していたところ、次のバグレポートを発見しました。

[rdar://22818481: Localized Error Messages missing in WKWebView](https://openradar.appspot.com/22818481)

多言語対応しているアプリにおいて `webView(_:didFailProvisionalNavigation:withError:)` から得られるエラーの `localizedDescription` がローカライズされない（常に英語となる）という、まさに今回問題としている現象が指摘されています。また、このバグレポートのページによると、iOS 8.x, 9, 10においてこの問題が発生していることが報告されています。

もしこれが本当に iOS 側の問題だったのだとすると、現時点での最新バージョンである iOS 13.5.1 においてもまだ解決されていないのかもしれません。しかし、この現象について言及している他のページが見つからなかったので、果たして本当に iOS 側の問題なのか確信を持てずにいます。

今後 iOS のアップデートがあったときには、このエラーのローカライズについての変更があるのかに注目しようと思います。