横山です。この記事では、gettext(GNU gettext)を使って翻訳対象ファイルと翻訳ファイル(POファイル)をVimで編集するときの便利設定を紹介します。
gettextを使ったことがない方は、ククログの過去記事を読んでみると雰囲気がわかるかもしれません。
gettextによる翻訳は、まず翻訳対象のファイルからメッセージを抽出し、それぞれのメッセージに対応する翻訳をPOファイルに記述するという流れで行われます。翻訳対象のファイルとPOファイルの間を行き来することになるので、その手間を減らすのが今回の目標です。
バッファで開いておく、NERDTreeなどでブックマークしておくといった方法もあるのですが、POファイルの数が多いと探す時間がばかにならないので、翻訳対象ファイルに対応するPOファイルを自動で検出できると効率が上がります。*1
ここでは、vim-altrというプラグインを使ってみます。
vim-altrは、設定されたルールに従って、編集中のファイルに関連する別のファイルを開いてくれるプラグインです。 以下のように任意のキーバインドを設定して使います。
nmap <Leader>a <Plug>(altr-forward)
デフォルトでもルールが用意されているので、各言語の一般的なファイル構成であればこれだけでいい感じに動作してくれるようです。 が、gettextの対象ファイルの配置はプロジェクトによって異なるため、これだけだと動作しないので、vimrcに設定を追加していきます。
ここではGroongaプロジェクトを例に説明します。GroongaではSphinxと一緒にgettextを使用していて、ドキュメント構成は以下のようになっています。
上記の例の中では、更新頻度的に一番頻繁に行き来するのはdoc/source/news.rstとdoc/locale/ja/LC_MESSAGES/news.rstの間です。よって、まずはこの2ファイル用の設定を追加してみます。
.rst(reStructuredText形式)決め打ちでよいのであれば、以下の1行をvimrcなどに追加するだけです。
call altr#define('doc/source/%.rst', 'doc/locale/ja/LC_MESSAGES/%.po')
これで、doc/source/news.rstとdoc/locale/ja/LC_MESSAGES/news.rstの間を設定したキーバインド(<Leader>a
など)で行き来することができるようになります。
.rst以外にも対応させておきたい場合、以下のように設定します。
call altr#define('doc/source/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')
(2018/5/10追記: 初稿では2行目として call altr#define('doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/%.*')
を記載していたのですが、これがなくてもaltr-forwardだけで行き来できました。)
頻度は多くありませんが、doc/source/install/debian.rstとdoc/locale/ja/LC_MESSAGES/install.rstの間や、doc/source/install/centos.rstとdoc/locale/ja/LC_MESSAGES/install.rstの間もたまに行き来します。これらは、複数の翻訳対象ファイルに1つのPOファイルが対応しています。このような場合、POファイルから翻訳対象ファイルを検出することは難しいので、翻訳対象ファイルからPOファイルへの一方通行の設定を追加しておくのがおすすめです。具体的には以下のような設定を追加します。
call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')
この設定を追加することで、doc/source/install/debian.rstやdoc/source/install/centos.rstからdoc/locale/ja/LC_MESSAGES/install.rstを簡単に開くことができるようになります。
この場合、翻訳対象ファイルに戻るときは、vim-altrではなくC-^
(直前に開いていたバッファを開く)などを使うことになります。
細かいところですが、doc/source/%/%.*
をdoc/source/%/*.*
などとしてしまうと、doc/source/install/debian.rstとdoc/source/install/centos.rstがお互いに行き来する対象になってしまうので注意してください。
後から定義したルールが優先されるようなので、1対1と多対1の設定を両方追加する場合、以下のようにしておくと1対1のルールが優先されます(doc/locale/ja/LC_MESSAGES/news.poからaltr-forwardするときに、doc/source/news/ではなくdoc/source/news.rstが開かれるようになる)。
call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')
call altr#define('doc/source/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')
1対1の関係のファイル間の移動の設定が不要であれば、以下のように.poからaltr-forwardするときは明示的にディレクトリを開くようにしておくのも一案だと思います。
call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/%/')
または
call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/')
Vimでgettextの翻訳対象ファイルとPOファイルを紐付けて簡単に開けるようにする方法を紹介しました。 gettext以外にも応用できる方法だと思うので、ぜひ活用してみてください。
横山です。
社内から「Vimで単語をクォーテーション("..."など)で囲むのによい方法はないか」という質問をもらったので、調べたことをまとめました。
主に4つくらいのやり方がありそうだったので、順番に紹介します。
ciw
普通にi
でインサートモードに切り替えて入力する方法です。
ポイントは、単語単位で移動することと、ドットコマンドを活用することです。
b
で単語の先頭に移動"
を入力e
で単語の末尾に移動l
で右側に移動.
(ドット)を入力(直前の編集操作が繰り返されて、"
が入力される)以下は、phw/peekとwavexx/screenkey(どちらもAPTでインストール可能)を使って取得したGIFアニメです。
ciw
c
から始まるコマンドを使うことで、文字列を削除(カット)しつつインサートモードに切り替えることができます。
削除対象範囲は以下のように柔軟に指定できます(以下は一例です)。
cw
: カーソル位置から単語の末尾までcb
: カーソル位置から単語の先頭までciw
: カーソル位置の単語の先頭から末尾までc0
: カーソル位置から行頭までc$
: カーソル位置から行末までcG
: カーソル位置からファイル末尾まで削除した部分はレジスタに保持されているので、ペーストすることができます。よって、囲みたい文字を続けて入力した後で、その間にペーストするという方法が使えます。囲みたい文字は同じ文字であることが多いので、続けて入力できるとだいぶ楽になります。
ciw
でカーソル位置の単語の先頭から末尾までをカットしてインサートモードに切り替え"
を2つ(開始と終了)入力Esc
でノーマルモードに切り替えP
でカーソル位置の左側にカットした単語をペーストよく使う括弧の種類や対象範囲が決まっている場合、以下のようにマッピングすると便利です。
nnoremap <Leader>s" ciw""<Esc>P
nnoremap <Leader>s' ciw''<Esc>P
nnoremap <Leader>s` ciw``<Esc>P
nnoremap <Leader>s( ciw()<Esc>P
nnoremap <Leader>s{ ciw{}<Esc>P
nnoremap <Leader>s[ ciw[]<Esc>P
同じ文字で囲みたい単語が複数ある場合は、置換を使うと時間短縮になって、漏れも防げます。
置換には正規表現が使えますが、Vimの正規表現はエスケープ対象の文字が少し特殊なので注意が必要です。
例えば、+
や()
をメタ文字として扱うときはエスケープが必要です。
以下の例は、カーソルがある行の単語([0-9A-Za-z_]+
)をすべて"..."で囲みます。
例: :s/\(\w\+\)/"\1"/g
正規表現のオプションにc
を付けると、逐一置換するかどうかの確認をすることができます。ファイル全体を対象とする場合などは、意図しない置換を防げて安全かもしれません。
例: :%s/\(\w\+\)/"\1"/gc
また、いちいち入力するのは面倒なので、コマンド履歴を活用するのがおすすめです。
同じ置換を繰り返すのであれば、:
でコマンドモードに切り替えた後に<C-p>
で履歴をたどれます。
少し違うことをしたいときなどは、コマンドモードに切り替えた後に<C-f>
でコマンドウィンドウを開けば、履歴を修正してから実行することもできます。
以下の例は、対象を丸括弧*1内の文字列のみにしてから置換を実行しています。
例: :%s/(\(\w\+\))/("\1")/gc
プラグインを使って実現することもできます。有名なのはtpope/vim-surroundですが、後発のrhysd/vim-operator-surroundも、ドットコマンドで繰り返せるなどの利点があっておすすめです。
参考: 犬製 Vim プラグイン紹介3本立て - はやくプログラムになりたい
設定例:
<Leader>s
などにマッピング(sはsurroundのs)
map <Leader>s <Plug>(operator-surround-append)
<Leader>sw"
でカーソル位置から単語の末尾まで囲めるb<Leader>sw"
でカーソル位置の単語の先頭から末尾まで囲める<Leader>s$"
でカーソル位置から行末まで囲める(
などは自動で閉じる文字を判別してくれるClearCode.vimの一環として、Vimについて調べたことをまとめました。ClearCode.vimはGitterとGitHubでやっているので、質問などがある方は社内外を問わずお気軽にコメントください。リアルタイムで質問したい方は、毎週水曜日の18:30-19:00はほぼ確実に見ているので、この時間にGitterまでお越しください。(反応が遅れてもよければ、いつ書き込んでもらっても大丈夫です。)
*1 昔は、中括弧({})や大括弧([])と特に区別したいときは小括弧と言っていた記憶があるのですが、最近はそれぞれ丸括弧、波括弧、角括弧と言うらしいです。
横山です。去年の11月くらいから、社内でVimの勉強会を始めました。ほぼ週に一度のペースでやっていて、前回(3/14)は14回目の開催でした。 次回から形式を変えるつもりなので、この機会に経緯や方針などを簡単にまとめておきたいと思います。
始めたきっかけは、主にVimを使っている人が続けて2名(私を入れると3名)入社したことです。クリアコードはおすすめEmacs設定 - ククログ(2011-02-16)を公開しているように、主にEmacsを使っている人が多かったので、Vimの情報がまとまっていませんでした。これはいけないということで、この機会に社内のおすすめVim設定を作ろうというのが最初の目標でした。
その目標は既にclear-code/vim.dで達成しています。今は特に次の目標は定めず、日々の開発で不便だなと感じたことを調べて、Vimで解決できそうなら設定を追加する、という感じで進めています。まだ未熟なところはありますが、だいぶ育ってきたなという印象です。
これまでは社内で「オフラインの情報共有会」という形式でやっていたのですが、オフラインだと記録を残すのが大変だったり、情報共有会だと準備の時間が必要だったりして負担を感じていたので、次回からは「オンラインのもくもく会」(基本的に各自で作業しつつ、困ったら気軽に相談可)という形式でやってみることにしました。*1
で、オンラインでやるのであれば社内に閉じておく理由がないということで、次回からは社外の人の参加も歓迎します。 それに伴って、メモ(その回まとめ)置き場とチャットルームを、社内の情報共有に使っているRedmine・Zulipから、GitHub・Gitterへ移行しました。
開催時間も、今までは17:30-17:45でやっていたのですが、仕事を中断しづらい(ときがある)、15分だともくもく会としては短すぎるなどの理由から、18:30-19:00に変更します。この時間がちょうどよいかはまだわからないので、回を重ねながら調整する予定です。
まとめると、次回の開催概要は以下です。
上に書いた通り相談は歓迎なのですが、参加者のレベル感としては(clear-code/vim.dを見てもらえばなんとなくわかるかもしれませんが)、初級〜中級くらいを想定しています。ただ、会の中で答えられなくても、より詳しい人が集まる場所にエスカレーションすることは可能なので、どんなことでもお気軽にご相談ください。ご参加お待ちしています。
*1 ただ、オフラインでやるメリット(気軽に発言できる、など)もありそうなので、人が集まりそうだったらたまにはオフラインでやる予定です。また、オフラインでやる際はせっかくなので発表者も募りたいと思っています。興味がある方は下記のチャット等でお声掛けください。(社内外問わず。オフラインでも時間次第では社内に閉じておく必要はなさそうなので。ただ、社外の人が来る場合は開催時間を19:00以降にするかもしれません。場所はクリアコードの予定です。)