2011年6月6日月曜日

LocalizedStringファイルの生成を半自動化する。

開発の規模が大きくなってくると、LocalizedStringの数がハンパなく多くなってきますね。
プログラマが複数名いて、とにかく自由奔放にNSLocalizedString()マクロを書きまくっていると収集がつかなくなります。
ソースコード上ではNSLocalizedStringしてるんだけど、ローカライズのファイルにその文言がなかったりとか
微妙に文言が違うとかありがち。


そんなんで時間をかけているのも馬鹿馬鹿しいけれど、表示の文言も大切な仕様です。
表記違いもプログラムの深刻なバグも同じと考える人もいるかもしれません。


そこでこのうざい問題を秒殺する方法を考えましたw


まず、すべての文言をリスト化します。
僕はこの作業でExcelを使います。Mac使いだからってWindowを使っちゃいけないって法律はないし。
管理しやすいし、文字列変換のコードがくそ簡単に書ける。



まず、ソースコード上のNSLocalizedStringをテキストに吐き出します。
ターミナルを開いて、プロジェクトが置いてあるフォルダのClassへ移動。基本的なコマンドがわからん!って人は簡単なので勉強してください。

下のコマンドを実行

grep -i "NSLocalizedString" $(find . -name '*.m') | less >> result.txt

これやると、どのクラスファイルで何をローカライズしようとしてるかがテキストファイルになります。

続いてウインドウズへ。
VBEを開いて下のコードをコピペ。

sub getLocalize()
Const cnsTITLE = "テキストファイル読み込み処理"
Const cnsFILTER = "全てのファイル (*.*),*.*"
Dim xlAPP As Application ' Applicationオブジェクト
Dim intFF As Integer ' FreeFile値
Dim strFILENAME As String ' OPENするファイル名(フルパス)
Dim strREC As String ' 読み込んだレコード内容
Dim GYO As Long ' 収容するセルの行
Dim lngREC As Long ' レコード件数カウンタ
Dim allString As String
Dim allArray As Variant
Dim strbuf As String
Dim lineArray As Variant
Dim splitArray As Variant
Dim lineCount As Integer
Dim z As Integer
Dim y As Integer
Dim row As Integer

Rows("2:65536").ClearContents
' Applicationオブジェクト取得
Set xlAPP = Application

strFILENAME = xlAPP.GetOpenFilename(FileFilter:=cnsFILTER, _
Title:=cnsTITLE)

If StrConv(strFILENAME, vbUpperCase) = "FALSE" Then Exit Sub


intFF = FreeFile

Open strFILENAME For Input As #intFF
GYO = 1

Do Until EOF(intFF)
' レコード件数カウンタの加算
lngREC = lngREC + 1

' 改行までをレコードとして読み込む
Line Input #intFF, strREC
' 行を加算しA列にレコード内容を表示(先頭は2行目)
GYO = GYO + 1
allString = allString & strREC
Loop
' 指定ファイルをCLOSE
Close #intFF

allArray = Split(strREC, vbLf)

row = 2
For i = 2 To UBound(allArray)


lineArray = Split(allArray(i), "NSLocalizedString")

If UBound(lineArray) > 0 Then
Cells(row, 1).Value = lineArray(0)
End If

For lineCount = 1 To UBound(lineArray)
lineArray(lineCount) = "NSLocalizedString" & lineArray(lineCount)
z = InStr(1, lineArray(lineCount), "@")
y = InStr(1, lineArray(lineCount), "nil") - 3
strbuf = Left(lineArray(lineCount), y)
Cells(row, 2).Value = Replace(Replace(Replace(Replace(strbuf, "NSLocalizedString", ""), "(", ""), "@", ""), Chr(34), "")
row = row + 1
Next lineCount



Next i


end sub



こいつを実行するときれいに形を整えてエクセルに取り込んでくれます。これを元にエクセルで翻訳リストを作成。
吐き出しようには下のモジュールを使う。
普通のテキスト吐き出し(フリーファイルとかFileSystemObject)とかだとUnicodeを扱えないのでADOStreamを使う。

参照設定でADOにチェック。
こいつを実行すると、実行したエクセルファイルと同じ場所にLocalized.Stringを吐き出すってわけ。
このファイルをそのまま使うんじゃなくて、ここからコピペをする予定なのでBOMとかはとってないです。

Sub getLocal()

Dim i As Integer
Dim endline As Integer
Dim str As String
Dim path As String
Dim endC As Integer
Dim strUni As String
'オブジェクトを作成
Dim txt2 As Object


Dim xlAPP As Application

Dim fileName As String ' OPENするファイル名(フルパス)
Dim strREC As String ' 書き出すレコード内容


Dim str_buf As String

path = Application.ThisWorkbook.path
endline = Cells(65536, 1).End(xlUp).row
endC = Cells(1, 200).End(xlToLeft).Column



For C = 2 To endC
Set txt2 = CreateObject("ADODB.Stream")

'オブジェクトに保存するデータの種類を文字列型に指定する
'txt2.Type = adTypeText
txt2.Type = 2
'文字列型のオブジェクトの文字コードを指定する
txt2.Charset = "UTF-16"

'オブジェクトのインスタンスを作成
txt2.Open

'//翻訳を作る処理

strREC = ""
strUni = ""
fileName = path & "\" & Cells(1, C).Value & ".txt"

For i = 2 To endline



If Cells(i, 1).Value <> "" And Left(Cells(i, 1).Value, 1) <> "#" Then
str = Chr(34) & Cells(i, 1).Value & Chr(34) & "=" & Chr(34) & Cells(i, C).Value & Chr(34) & ";"

Else
str = "//" & Cells(i, 1).Value
End If
str = Replace(str, "\" & Chr(13), "\n")
str = Replace(str, Chr(10), "")








'1行ずつ書き込む
txt2.WriteText str, adWriteLine




Next i

'オブジェクトの内容をファイルに保存
txt2.SaveToFile (fileName), adSaveCreateOverWrite


'オブジェクトを閉じる
txt2.Close

'メモリからオブジェクトを削除する
Set txt2 = Nothing


Next C

MsgBox "ファイル出力が完了しました。"
End Sub



このファイルを上手に使えば、翻訳リストとソースコードと実際のLocalizedStringファイルをマッチングして、ローカライズ漏れを一網打尽にすることができます。