はじめに
ダブルクォーテーションで囲まれた文字列が Swift・Storyboard ファイルのいたるところに散りばめられたアプリを一度は作ったことがあるのではないでしょうか?それがグローバル化が決まった大きなプロジェクトだったら…
方針
Swift・Storyboard ファイルから取り出す箇所の総数がわからなければ工数見積やチームでの役割分担も非常に困難です。そこで、おおよその修正対象箇所を Shell で探し出すことにします。
Shell
今回のサンプルコマンドは zsh で実行確認をしたものになります。実行結果はテキストファイルとして出力するようにしています。
※あくまでもサンプルということで参考程度に見ていただければと思います。
文字列探索
特徴はダブルクォーテーションで囲まれているということ。これを利用して探索します。
find . -type d -name Gens -prune -o -type d -name Debug -prune -o -type f -name "*.swift" -print | xargs grep -n "" -po '(?<=")[^",]+(?=")' | grep '"' | grep -v '\["' | grep -v '""' > ~/Downloads/memo.txt
-type d -name Gens -prune -o
で Gens
ディレクトリを検索対象から除外しています。 また、 -type f -name "*.swift"
で Swift ファイルを検索対象のファイルに指定しています。
grep -n "" -po '(?<=")[^",]+(?=")' | grep '"'
で文字列であるかの判定を行います。また、 grep -v '\["' | grep -v '""'
でAPI周りの記述と空文字部分を判定して排除しています。ココで注意なのが、 ["日本", "アメリカ", "中国"]
といった記述が排除されてしまうため、このような記述がある可能性がある場合は ``grep -v '["'` を除いて実行するようにしましょう。
日本語の文字列探索
先程よりも条件を多くしてみます。
find . -type d -name Gens -prune -o -type d -name Debug -prune -o -type f -name "*.swift" -print | xargs grep -n "" -po '(?<=")[^",]+(?=")' | grep '"' | grep -v '\["' | grep -v '""' | grep '[亜-熙ぁ-んァ-ヶ]' > ~/Downloads/memo.txt
追加されたのは grep '[亜-熙ぁ-んァ-ヶ]'
だけです。漢字・ひらがな・カタカナを判定しています。ココで注意なのが、日本語設定でも半角表記される「OK」などが排除されてしまうため、先程の探索方法と合わせて利用すると良いでしょう。また、API 周りは日本語というフィルタで排除されるので grep -v '\["'
は取り除いたほうがいいかもしれません。
Storyboard Version
上記の処理を応用すると簡単に実現できます。
find . -type d -name Gens -prune -o -type d -name Debug -prune -o -type f -name "*.storyboard" -print | xargs grep -n "" -po '(?<=")[^",]+(?=")' | grep '"' | grep -v '\["' | grep -v '""' | grep '[亜-熙ぁ-んァ-ヶ]' > ~/Downloads/memo-s.txt
変わったのは -type f -name "*.storyboard"
だけです。 Storyboard の場合は、IDなどもダブルクォーテーションで囲まれた文字列形式で記述されるため、精度はかなり落ちます。 grep '[亜-熙ぁ-んァ-ヶ]'
で日本語に絞り込まないと探索結果が膨大になるので、半角表記箇所については個別に対応する感じになります。
結果
以下のように対象のファイルパスと行数・文字列が列挙されたファイルが生成されます。これを参考に工数見積や役割分担を行いましょう。ただし、漏れている箇所があるかもしれないということを忘れないようにしましょう。
./Entity/Category.swift:8:private let akkeyTitle = "あっきーのQiita"
./Entity/Category.swift:9:private let akkeyLabTitle = "あっきーラボのQiita"
./Entity/Category.swift:10:private var akkeyLabMessage = "iOSエンジニアの研究所です"
./Classes/Storyboard/Popover.storyboard:29: <string key="content">写真を投稿しました!
./Classes/Storyboard/Popover.storyboard:76: <fragment content="枚">
./Classes/Storyboard/Popover.storyboard:94: <string key="content">登録はこちら