$ gdb ./inkscape GNU gdb (Debian 7.11.1-2) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./inkscape...done. (gdb) (gdb) (gdb) r Starting program: /home/walkingice/code/inkscape/inkscape-0.91/src/inkscape [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7fffe6a94700 (LWP 6493)] [New Thread 0x7fffe6293700 (LWP 6495)] [New Thread 0x7fffe5a92700 (LWP 6496)] [New Thread 0x7fffe2ff2700 (LWP 6497)] [New Thread 0x7fffe27f1700 (LWP 6498)]
Thread 1 "inkscape" received signal SIGSEGV, Segmentation fault. 0x00007fffeee51410 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) bt #0 0x00007fffeee51410 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007fffeef00045 in __vasprintf_chk () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007ffff0003ce9 in g_vasprintf () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #3 0x00007fffeffde67d in g_strdup_vprintf () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #4 0x00007fffeffde739 in g_strdup_printf () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #5 0x0000555555a463fd in Inkscape::SelectionDescriber::_updateMessageFromSelection (this=0x55555d63eec0, selection=0x5555577cee00) at selection-describer.cpp:217 #6 0x0000555555a46fde in sigc::bound_mem_functor1<void, Inkscape::SelectionDescriber, Inkscape::Selection*>::operator() (this=0x555559712c38, _A_a1=@0x7fffffffc548: 0x5555577cee00) at /usr/include/sigc++-2.0/sigc++/functors/mem_fun.h:2064
(gdb) set listsize 15 (gdb) list 210 int objcount = g_slist_length((GSList *)items); 211 char *terms = collect_terms ((GSList *)items); 212 int n_terms = count_terms((GSList *)items); 213 214 char* foo = ngettext("<b>%i</b> objects selected of type %s", 215 "<b>%i</b> objects selected of types %s", n_terms); 216 gchar *objects_str = g_strdup_printf(foo, 217 objcount, terms); 218 219 g_free(terms); 220 221 // indicate all, some, or none filtered 222 gchar *filt_str = NULL; 223 int n_filt = count_filtered((GSList *)items); //all filtered 224 if (n_filt) { (gdb) p foo $1 = 0x7ffff7f60ad1 "已選擇類型 %s 的 <b>%i</b> 個物件" (gdb) ptype objcount type = int (gdb) ptype terms type = char *
原來如此,ngettext 拿到的 string 是 %s 在前 %i 在後,可是 format 的時候是先給 int 再給 char*,當然就爆炸了。那麼其他語言會有這個問題嗎?
PO file
fr.po
1 2 3 4
msgid "<b>%i</b> objects selected of type %s" msgid_plural "<b>%i</b> objects selected of types %s" msgstr[0] "<b>%i</b> objets de type %s sélectionnés" msgstr[1] "<b>%i</b> objets de types %s sélectionnés"
zh_CN.po
1 2 3 4
msgid "<b>%i</b> objects selected of type %s" msgid_plural "<b>%i</b> objects selected of types %s" msgstr[0] "<b>%i</b>个对象选择" msgstr[1] "<b>%i</b>个对象选择"
zh_TW.po
1 2 3 4
msgid "<b>%i</b> objects selected of type %s" msgid_plural "<b>%i</b> objects selected of types %s" msgstr[0] "已選擇類型 %s 的 <b>%i</b> 個物件" msgstr[1] "已選擇類型 %s 的 <b>%i</b> 個物件"
Patch
嗯,只有繁體中文是這樣,其實上個簡單的 patch 就行了更新:這樣的 patch 是不對的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 1cb96fe..ab719a0 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -212,8 +212,8 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select int n_terms = count_terms((GSList *)items); gchar *objects_str = g_strdup_printf(ngettext( - "<b>%i</b> objects selected of type %s", - "<b>%i</b> objects selected of types %s", n_terms), + "<b>%1$i</b> objects selected of type %2$s", + "<b>%1$i</b> objects selected of types %2$s", n_terms), objcount, terms); g_free(terms); -- 2.8.1
In the “C” locale, or if none of the used catalogs contain a translation for msgid, the ngettext functions return msgid if n == 1, or msgid_plural if n != 1.
如果沒有找到合適的翻譯,那麼就拿 msgid 的字串當成單數型來用,msgid_plural 的字串當成複數型來用,要用哪一個由 n 來決定。
看到這邊就知道上面的 patch 錯了,因為它把整個 id(key) 變成了另外一個值,這會使得其他所有的 po 檔都失效,永遠找不到對應的翻譯。由於有 fallback 的關係而不會爆炸,但這樣的行為就不對了。
於是比較合理的作法,就是改 po 檔,從翻譯裡面指定 formatting 的時候參數的位置要擺到哪,這樣就不會出錯了。
額外一提的是,inkscape 跑起來的時候讀的 po 檔是 /usr/share/locale/zh_TW/LC_MESSAGES/inkscape.mo,我一開始不知道,想說怎麼改 po 檔的內容,make 完之後都沒變呢?後來才注意到即使是我自己編的 inkscape 還是跑去讀系統的 mo 檔。而且我找不到方法用 make 編出 mo 檔(除了整個 deb 重編以外 =.=)。不過我很偷懶地直接把 zh_TW.gmo 給硬塞進系統的位置,也算是另一個 workaround 吧 :P