ローカライズの情報を集めていたらこんなツールを見つけた。
iLingual
http://homepage.mac.com/nsekine/SYW/SYWSoft/softOSX.html#iLingual
PISCES での紹介記事
http://pisces-319.seesaa.net/article/71705307.html
面白い。フリーウェアのローカライズは無料ということなので試してみよう。
2009年3月31日火曜日
ローカライズツール iLingual
2009年3月30日月曜日
β版リファクタリング - 座標変換メソッドを切り出す(2)
Windowキャプチャの動作がおかしい。調べると全ウィンドウの範囲を計算するメソッドが原因だった。
+ (NSRect)unionNSRectWithWindowList:(NSArray*)list
{
NSRect all_rect = NSZeroRect;
NSRect rect;
for(Window* window in list) {
rect = [window rect];
if (NSEqualRects(all_rect, NSZeroRect)) {
all_rect = rect;
} else {
all_rect = NSUnionRect(all_rect, rect);
}
}
all_rect.origin = [CoordinateConverter convertFromLocalToCGWindowPoint:all_rect.origin];
return all_rect;
}
前回 Windowクラスの座標系はすべてローカル座標系に変えてしまった。一方、このメソッドの結果は CGWindow系で使われている。
調査したところ、このメソッドは CGWindowでしか利用していなかったので今回は安易だがメソッド内で変換してしまう。
all_rect.origin = [CoordinateConverter
convertFromLocalToCGWindowPoint:all_rect.origin]; // 追加
return all_rect;
これでOK。
- - - -
マルチスクリーンに関連するバグフィックスはこれで(多分)全部片づいた。最初から異なる座標系を意識していればこんなに苦労しなかった。次?は是非最初から座標系の変換を実装に盛り込みたい。
2009年3月29日日曜日
β版リファクタリング - 座標変換メソッドを切り出す
座標変換のメソッドは各所で使う事になるので専用のクラスを用意してここにまとめることにする。
@interface CoordinateConverter : NSObject {
}
+ (NSPoint)convertFromLocalToCGWindowPoint:(NSPoint)from_p;
+ (NSPoint)convertFromCGWindowPointToLocal:(NSPoint)from_p;
@end
とりあえずインスタンスは必要なさそうなのでクラスメソッドとして定義した。
内容は以前定義したものと同じ。
これで座標変換メソッドが利用しやすくなった。これを Windowモデルで使い、内部管理の座標系を CGWindowからローカル座標系へ切り替える。
Windowモデル(クラス)は CGWindow系関数で取得したウィンドウの情報を保持するクラス。定義はこんな感じ。
@interface Window : NSObject {
int _order;
CGWindowID _window_id;
int _owner_pid;
NSString* _window_name;
NSString* _owner_name;
int _layer;
NSRect _rect;
NSImage* _image;
}
このイニシャライザ #initWithWindowDictionaryRef: の中で _rectへ格納する時に座標変換を行っておく。
- (id)initWithWindowDictionaryRef:(CFDictionaryRef)window
{
self = [super init];
if (self) {
CGRect cgrect;
CFNumberGetValue(CFDictionaryGetValue(window, kCGWindowNumber),
kCGWindowIDCFNumberType, &_window_id);
CFNumberGetValue(CFDictionaryGetValue(window, kCGWindowOwnerPID),
kCFNumberIntType, &_owner_pid);
CFNumberGetValue(CFDictionaryGetValue(window, kCGWindowLayer),
kCFNumberIntType, &_layer);
CGRectMakeWithDictionaryRepresentation(CFDictionaryGetValue(window, kCGWindowBounds), &cgrect);
_window_name = (NSString*)CFDictionaryGetValue(window, kCGWindowName);
_owner_name = (NSString*)CFDictionaryGetValue(window, kCGWindowOwnerName);
[_window_name retain];
[_owner_name retain];
_rect = NSRectFromCGRect(cgrect);
_rect.origin = [CoordinateConverter convertFromCGWindowPointToLocal:_rect.origin];
}
return self;
}
動作確認は明日マルチスクリーン環境で。
2009年3月28日土曜日
2009年3月27日金曜日
2009年3月26日木曜日
ローカライズ(その9)
今回マージ作業をやってみて、実際の運用では気を付ける点がいくつかあることがわかった。
(1) 前回ローカライズした時点のNibファイルをすべて取っておく
ibtool によるマージは旧バージョンと新バージョンの Nibの差分情報を使う。この為、前回ローカライズを行った時全言語の Nibファイルを取っておく必要がある。これを忘れるとマージができない。
(2) 英語Nibファイルに追加された文字列を用意する
英語Nibファイルに変更を入れた後、翻訳用に文字列(例:MainMenu.strings)を生成する。この中で追加があったものだけを抽出してから翻訳を行う。前回の検証ではこの差分抽出は手作業で行った。
ibtool のマージ(--localize-incrementalオプション)のルールは ADCのドキュメントに書かれている。これに目を通しておくと引数で渡すファイルの役割がよく理解できる。
Interface Builder User Guide > Localization
Performing Incremental Localization Updates
ルールは次の通り(英文内のFrenchは「日本語」と置きえた)。
1. 新英語NIBファイルをコピーして新日本語NIBファイルとする。
2. 新英語NIBファイルと、旧英語NIBファイルを比較する。
a) 新旧変更が無いものについては、旧日本語の文字列を、新NIBファイルへ適用する。
b) もし新英語NIBファイルに存在して、旧英語NIBファイルに存在しない場合は、何もしない。
(つまり、1.でコピーした時の英語の文字列が新日本語NIBに残る)
c) もし旧英語NIBファイルに存在して、新英語NIBファイルに存在しない場合は、何もしない。
(項目が削除された場合に起こる。この項目は新NIBには含まれないので問題ない)
3. 日本語文字列(*.strings)を新日本語NIBファイルへ適用する。
(ここで 2-b) の新規文字列を置換する)
図で書くとこんな感じ。
多少は手間がかかるが(特に追加文字列の抽出)、今後の運用・保守のメドが立ったのでこの方法を使っていくことにしよう。
- - - -
引越やら何やらで作業進まず。
3月中リリースはちょっと無理かもしれない。
(プログラムはほぼ出来ているのだが翻訳やホームページ作成が間に合わない。。)
2009年3月25日水曜日
ローカライズ(その8)
ibtool を使ってマージを試してみる。
※以下、拡張子が xib だが Nibファイルと統一して呼ぶ。またターミナルの操作はすべてXcodeプロジェクトのフォルダ内で行った。
1. まず修正を入れる前に最後のバージョンをコピーしておく。ここでは old フォルダへ English.lproj と Japanese.lproj をコピーする。
$ mkdir old
$ cp -pr English.lproj old
$ cp -pr Japanese.lproj old
$ ls old
English.lproj MainMenu.strings MainMenu.xib
$
2. コピーしたら Nibファイルに修正を加えてみる。ここでは Interface Builder で英語の Nibファイルにラベル "Hello !" を追加する。
3. 英語の Nibファイルから文字列を抽出する。
ibtool --generate-stringsfile Japanese.lproj/MainMenu.strings \
English.lproj/MainMenu.xib
ラベル "Hello !" が最後に追加されている。文字列を再生成したので前回翻訳した "Japan"は英語に戻っている。
4. このファイルを編集して "Hello !"の行だけ残すようにする。
5. 準備ができたのでマージしてみよう。ADCページの例を参考にして用意した下記のコマンドを実行する。
ibtool --previous-file old/English.lproj/MainMenu.xib \
--incremental-file old/Japanese.lproj/MainMenu.xib \
--strings-file Japanese.lproj/MainMenu.strings \
--write Japanese.lproj/MainMenu.xib \
--localize-incremental \
English.lproj/MainMenu.xib
6. 日本語の Nibファイルを Interface Builder で開いてみる。
おお、"Hello" が "こんにちは"に置き換わっている。ただラベルサイズが不足しているので途中で切れている。
7. 手動でサイズを拡張してやる。
8. 最後にXcodeでビルドして実行してみる。
出た。
2009年3月24日火曜日
ローカライズ(その7)
Interface Builder User Guide: Localization - Localizing Your Nib File’s Content にPerforming Incremental Localization UpdatesというローカライズされたNibのアップデート方法についての説明がある。
これによれば差分をマージしてNibをアップデートできるとのこと。
ibtool に --localize-incremental オプションを指定する。
- - - -
今日も時間切れ。明日は実際に試したい。
2009年3月23日月曜日
ローカライズ(その6)
HK さんよりInterfaceBuilderを使ったローカライズ方法について情報をもらったのでこれを試してみる(情報ありがとうございました)。
Interface Builder User Guide: Localization
検証用に簡単なプロジェクトを作成して試してみる。
まずは先日のおさらいから。
単純なウィンドウを一つ用意して、この英単語を日本語にローカライズする。
(1) Nib(xib)ファイルからローカライズ用文字列ファイルを生成する。
ibtool --generate-stringsfile English.lproj/MainMenu.strings \
English.lproj/MainMenu.xib
(2) English.lproj/MainMenu.strings をプロジェクトへ追加する
(3) ローカリゼーション(Japanese)を追加する
(4) Japanese.lproj/MainMenu.strings を修正(翻訳)する
(5) Nib(xib)ファイルを書き出す
ibtool --strings-file Japanese.lproj/MainMenu.strings \
--write Japanese.lproj/MainMenu.xib \
English.lproj/MainMenu.xib
(6) 日本語のNib(xib)ファイルをプロジェクトへ追加する
ここまでの結果プロジェクトの中身はこうなる。
(7) ビルド&実行。日本語が出た。
- - - -
今日は時間切れ。
明日は変更を入れてマージをやってみる。
2009年3月22日日曜日
β版バグ修正 - マルチスクリーン(ウィンドウ-2)
ウィンドウキャプチャ時のボタンの位置がおかしい。
これも座標系の不一致の問題。ボタン位置を指定している箇所に前回用意した #convertFromCGWindowPointToLocal: をかます。
- (void)adjustButtonBar
{
if ([_selected_window_list count]) {
Window* wn = [_selected_window_list objectAtIndex:0];
NSRect rect = [wn rect];
rect.origin = [self convertFromCGWindowPointToLocal:rect.origin];
[_button_bar setButtonBarWithFrame:rect];
[_button_bar2 setButtonBarWithFrame:rect];
[_button_bar startFlasher];
}
}
その他にもウィンドウキャプチャ時にウィンドウを選択しようとしてクリックしても反応が無い。これもマウスクリック時の座標系(ローカル座標系)と内部管理しているウィンドウの座標系(CGWindow座標系)の違いによる。前回作った #convertFromCGWindowPointToLocal: をヒット判定処理に加える。
// (1) search a window on mouse down (already selected)
for (Window* swn in _selected_window_list) {
rect = [swn rect];
rect.origin = [self convertFromCGWindowPointToLocal:rect.origin];
if (NSPointInRect(cp, rect)) {
hit_flag = YES;
selected_window = swn;
break;
}
}
これで直った。
- - - -
内部管理しているウィンドウの座標を使うたびにいちいち変換するのではなく、管理上の座標系自体を CGWindowをやめて ローカル座標系に直した方が良さそうだ(続く)。
2009年3月21日土曜日
β版バグ修正 - マルチスクリーン(ウィンドウ)
スクリーン配置によってウィンドウキャプチャも表示が変になっているのに気が付いた。
例えば上にサブ画面、下にメイン画面があった場合。
ウィンドウキャプチャを起動すると下の画面のウィンドウが選択状態になるのだが、上のサブ画面に選択ウィンドウの画像が表示されてしまう。
これは以前調査した通り座標系の問題。
β版バグ修正 - マルチスクリーン(その2)
http://xcatsan.blogspot.com/2009/03/blog-post_06.html
内部的にウィンドウを管理している座標系が CGWindowなのに対して、ウィンドウを描画する座標系がカスタムビューのローカル座標であるのが原因。CGWindow系からローカル座標系へ変換してやればいいだろう。
以前、ローカル座標系からCGWindow系へ変換するメソッド #convertFromLocalToCGWindowPoint: を用意した。ここでは下記の数式を使っていた。
・スクリーン座標系上での全画面範囲(左下)-(右上):(sx1, sy1)-(sx2, xy2)
・メイン画面のサイズ(幅・高さ):(sw, sh)
・ローカル座標系上でキャプチャした範囲選択の開始点(左上):(lx1, ly1)
・CGWindow関数へ渡す開始点(左上):(cx1,cy1)
cx1 = lx1 + sx1
cy1 = ly1 - (sy2 - sh)
この最後数式を入れ替えれば逆変換になる。
lx1 = cx1 - sx1
ly1 = cy1 + (sy2 - sh)
この変換を行うメソッド #convertFromCGWindowPointToLocal: を用意し、これを使うように修正してみた。
- (NSPoint)convertFromCGWindowPointToLocal:(NSPoint)from_p
{
CGFloat cx1, cy1, lx1, ly1, sx1, sy2;
NSRect frame = [[Screen defaultScreen] frame];
NSRect m_frame = [[NSScreen mainScreen] frame];
CGFloat sh = m_frame.size.height;
cx1 = from_p.x;
cy1 = from_p.y;
sx1 = frame.origin.x;
sy2 = frame.origin.y + frame.size.height;
lx1 = cx1 - sx1;
ly1 = cy1 + (sy2 - sh);
return NSMakePoint(lx1, ly1);
}
実行してみる。
今度は大丈夫だ。
ただボタンの位置がおかしい??
2009年3月20日金曜日
β版バグ修正 - マルチスクリーン(マウスカーソル)
2009年3月19日木曜日
ローカライズ(その5)
試しに nib に新しくメニューアイテムを追加してみる。
ibtool で English.proj/MainMenu.nib.strings を生成する。
すると新しい ObjectIDが発行され、最後に項目が追加されていた。
これを手作業で Japanese.proj/MainMenu.nib.strings へマージ&翻訳する作業が必要ということか。
逆に項目を削除したら Japanese.proj/MainMenu.nib.strings を削除しないといけない。
Nibファイルを修正する時は常にこの辺りを意識しないと駄目みたいだ。
- - -
ObjectIDとかのメタ情報を使えばマージを楽にするツールが作れそうだ。
と、考えるのは私1人じゃないはずなので、既にツールがありそうだが。
2009年3月18日水曜日
ローカライズ(その4)
ふと思ったのだが nibを変更したり項目を追加した場合の他言語のメンテナンスはどうやるんだろうか?
昨日の方法のおさらいをしてみる。
(1) 最初に ibtoolを使い MainMenu.nib から文字列だけを抜き出したファイル English.proj/MainMenu.nib.strings を生成した。
(2) 次にローカリゼーションを追加して Japanese.proj/MainMenu.nib.strings を作成し、これを日本語に書き換えた。
(3) 最後に Japanse.proj/MainMenu.nib.strings から Japanese.lproj/MainMenu.nib を作成した。
この状態で InterfaceBuidlerを使い English.proj/MainMenu.nibを変更したとする。
その場合 (1)までは良いが、その後はどうやって変更分を日本語へ反映させるのか?
もしかして手作業でマージのような処理が必要とか?
むむ?
2009年3月17日火曜日
ローカライズ(その3)
katokichi さんより nib(xib) についてローカライズの情報をもらった。
2008/11/6 iPhone SDK勉強会 まとめ
http://iphone-dev.jp/modules/pico/index.php?content_id=9
UIをローカライズする手順
http://d.hatena.ne.jp/uasi/20081115/1226676887
なるほど ibtool というツールを使うと文言の翻訳だけで対応できるらしい。
他にもいくつか解説ページがあった。
ibtoolによるnibファイルのローカライズ
http://www.fraction.jp/log/archives/2008/01/23/localize_nib_file_with_ibtool
試してみよう。
(1) ターミナルを開き、Xcodeのプロジェクトディレクトリへ移動する。
(2) ibtool を実行する。
ibtool --generate-stringsfile English.lproj/MainMenu.nib.strings English.lproj/MainMenu.nib
すると English.lproj フォルダ配下に MainMenu.nib.strings が生成される。
(3) Xcodeプロジェクトへ追加する。
コンテキストメニューで追加するか、ドラッグ&ドロップで生成されたファイル MainMenu.nib.string をプロジェクトへ追加する。
この時、エンコーディングを Unicode(UTF-16)にしておく。
そうでないとこんな感じで化け化けになる。
(4) このファイルにさらにローカライズを追加する。追加するのは "Japanese"。
"MainMenu.nib.string"の上でコンテキストメニューを表示し「情報を見る」でダイアログを開く。ここで画面下の「ローカリゼーションの追加」ボタンを押す。
ファイルの中身はこんな感じ。
(5) 少し書き換えてみる。
(6) nibを生成する前に MainMenu.nib にローカリゼーション"Japanese"を追加しておく。
(7) さて書き換えたファイルを元に nibファイルを生成する。
ibtool --write Japanese.lproj/MainMenu.nib -d Japanese.lproj/MainMenu.nib.strings English.lproj/MainMenu.nib
ターミナルで実行。
Japanese.lproj フォルダを見ると MainMenu.nibが生成されている。
(8) ビルドして実行する。
さてどうだろう。
おお出た。
- - - -
この辺りの一連の作業はビルドに組み込んで自動化できるらしい。後で試してみよう。
それにしても量が多い。。
2009年3月16日月曜日
ローカライズ(その2)
2009年3月15日日曜日
ローカライズ(その1)
2009年3月14日土曜日
範囲選択の範囲を微調整
前から気になっていたのだが範囲選択で1ドット単位の細かい範囲指定をやろうとすると少しくせがあって使いにくかった。
例えば次の1ドットの黒枠の画像を、黒枠を含めてピッタリとキャプチャしたいとする。
SimpleCapの範囲選択を起動しラバーバンドの線を黒枠上にぴったり重ねてキャプチャする。
すると左と下の黒枠はキャプチャに含まれるのだが、右と上の黒枠は含まれない。
右と上も含めるにはラバーバンドを右上に1ドットづつ大きめに指定する必要があった。
これでは感覚的ではないのでキャプチャ対象をラーババンドの線上を含む範囲とするように微調整した。
描画する時に右と上の線が1ドット程度内側に表示すれば良いので、描画枠の位置と範囲を調整してみた。
NSRect d_rect = _rect;
d_rect.origin.y += 0.1;
d_rect.size.height -= 0.2;
d_rect.origin.x += 0.1;
d_rect.size.width -= 0.2;
[path appendBezierPathWithRect:d_rect];
さて試してみる。黒枠上にラバーバンドを重ねてパチリ。
うまくいった。