优麒麟技术论坛

 找回密码

【麒麟在线讲堂】浅谈 KF5 国际化 [复制链接]


引言

基于增加与软件产品交互的良好性,以及更便于软件产品的使用及推广,国际化成为了满足以上条件的基本要素之一。今日,笔者角度,以己拙见,简要介绍一下KF5框架下国际化 KI18n的实现。


KF5为 KDE Framework 5 的简体缩写,是开源桌面KDE发行的第五版框架,其中KI18n作为其国际化模块封装其中。i18n为英文 internationalization 取首位字母i与n,以18代替中间被省略的18个字符,用以代表国际化的意思,与之类似的,l10n代表localization,即本地化的含义。而 KI18n 国际话的实现其实就是依托于Linux 系统下基于GUN gettext的本地化实现。

本文以cmake 软件工程为例,浅谈下如何在自己的软件产品中使用KI18n 国际化,以及如何使用Linux本地化替代KI18n国际化的实现方法。

本地化介绍

本地化通常为将翻译文件(.po)文件编译为供软件程序加载的二进制文件(.mo),实现根据本地语言自动调用翻译的二进制文件,进而翻译软件中文字。

Linux下,GUN利用gettext命令生成翻译文件的模板(.pot)文件,可通过复制模板或msginit命令等方法生成翻译文件,其中msginit命令会对模板通用部分进行补充后在本地生成翻译文件。自动填充内容对比下图:

图:本地化模板文件(图左) 对比 本地化翻译文件(图右)

我们可以看到,翻译(.po)文件是msgid 与msgstr 一一对应的,其中msgid为翻译的标识文本,msgstr为翻译后的文本,软件产品中通过对标识文本的读取,根据语言码、国家码及编码获取对应翻译文件中的msgstr,进而实现本地化语言的展示输出。


但是,由于翻译文件属于源文本文件,软件产品如何实现对翻译文件的读取呢?当然不可能利用文本IO方法读取了,所以最后,利用msgfmt命令将翻译(.po)文件编译为二进制(.mo)文件,供软件产品调用,软件产品根据本地语言码,国家码及编码调用对应的二进制文件,实现本地化语言翻译的实现。

KI18n的使用
软件产品若希望使用KI18n国际化框架,需要在cmake列表中添加find_package(KF5I18n NO_MODULE)找到KI18n包,并利用语句target_link_libraries(yourAPP KF5::I18n)将KI18n动态库引入到自己的软件工程中。若使用qt工程研发,在工程.pro文件中需要添加 QT += KI18n。

在编码中,需要在程序中需要被翻译前的位置,利用如下语句引入自己的翻译文件:KLocalizedString::setApplicationDomain("yourPO");


其具体使用方法可参考用户手册,地址为:https://api.kde.org/frameworks/k ... uide.html#link_prog

其中头文件<KLocalizedString>包含具体翻译实现方法 inline QString i18n(const char *text) 等等,其深层次都是对KF5中KI18n等翻译函数的封装,由此,在生成对应翻译模板(.pot)文件时,关键key的选择可包含如下信息:i18n,i18nc, i18np, i18ncp, tr2i18n, I18N_NOOP,I18N_NOOP2, aliasLocale, ki18n, ki18nc, ki18np, ki18ncp等。

生成翻译模板文件(.pot)可参考如下脚本:


  1. #!/bin/sh
  2. BASEDIR="yourPath"  # root of translatable sourcesPROJECT="yourName"  # project nameWDIR=`pwd`      # working dir
  3. echo "Preparing rc files"cd ${BASEDIR}# we use simple sorting to make sure the lines do not jump around too much from system to systemfind . -name '*.rc' -o -name '*.ui' -o -name '*.kcfg' | sort > ${WDIR}/rcfiles.listxargs --arg-file=${WDIR}/rcfiles.list extractrc > ${WDIR}/rc.cpp# additional string for KAboutDataecho 'i18nc("NAME OF TRANSLATORS","Your names");' >> ${WDIR}/rc.cppecho 'i18nc("EMAIL OF TRANSLATORS","Your emails");' >> ${WDIR}/rc.cppcd ${WDIR}echo "Done preparing rc files"
  4. echo "Extracting messages"cd ${BASEDIR}# see above on sortingfind . -name '*.cpp' -o -name '*.h' -o -name '*.c' | sort > ${WDIR}/infiles.listecho "rc.cpp" >> ${WDIR}/infiles.listcd ${WDIR}xgettext --from-code=UTF-8 -C -kde -ci18n -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 -ktr2i18n:1 \    -kI18N_NOOP:1 -kI18N_NOOP2:1c,2 -kaliasLocale -kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \    --files-from=infiles.list -D ${BASEDIR} -D ${WDIR} -o ${PROJECT}.pot || { echo "error while calling xgettext. aborting."; exit 1; }echo "Done extracting messages"
  5. echo "Merging translations"catalogs=`find . -name '*.po'`for cat in $catalogs; do  echo $cat  msgmerge -o $cat.new $cat ${PROJECT}.pot  mv $cat.new $catdoneecho "Done merging translations"
  6. echo "Cleaning up"cd ${WDIR}rm rcfiles.listrm infiles.listrm rc.cppecho "Done"
复制代码

KI18n的替换方案

由前文可知,KI18n的实现是基于Linux GUN的本地化,由此,我们是否完全可以用Linux GUN的本地化方法来替代KI18n的实现?让我们开始做一下实验。

首先,我们需要引入Linux GUN本地化的头文件<libintl>,主要使用 extern char *gettext (const char *__msgid) __THROW __attribute_format_arg__ (1);函数,来实现对二进制翻译文件内容的读取。

其次,我们需要指定去哪里寻找编译后的翻译文件,即域(domain),需要用到 extern char *bindtextdomain (const char *__domainname, const char *__dirname) __THROW;

函数来对域与域所在路径进行绑定,其中__domainname指的为翻译的二进制文件(.mo)的名称,即域,__dirname为翻译的二进制文件(.mo)所有在路径,即install的路径。

最后,需要在调用gettext前之前,对翻译域(domain)的确认,此时要用到 extern char *textdomain (const char *__domainname) __THROW; 函数,__domainname指的为翻译的二进制文件(.mo)的名称,即域,如果__domainname传入为NULL,该函数会返回当前默认的域的名称,如果传入参数为””(即空字符串),则表示重置域为messages。

接下来,就是见证奇迹的时刻,请您自己动手,举一反三,实现自己软件产品的国际化吧。




发表于 2021-2-3 09:57:33
回复

使用道具 举报

小黑屋|手机版|Archiver|Ubuntu Kylin    

GMT+8, 2021-3-6 03:19 , Processed in 0.019914 second(s), 19 queries .

Copyright ©2013-2021 Ubuntu Kylin. All Rights Reserved .

ICP No. 15002470-2 Tianjin

快速回复 返回顶部 返回列表