QT 多语言 字库 编码 文字方向相关问题

QT是支持多语言的,能够支持不同语言的动态切换,不同语言对应的编码格式转换,不同语言字体使用不同字库进行显示。


编码

QT对于字符串的处理使用了基本类型QString,它将所有传递给它的字符串或者字符使用UTF16格式存储起来。 那么问题来了,对于中文"你好"的编码格式可能是GBK或者UTF8或者UTF16等,对于英文则默认使用UTF8(ASCII兼容)。 因此需要将这些字符进行编码格式化转换。 格式转换大概会出现在下面几个地方:

1、代码编写时

     QString message="你好".

    在不同的编辑器中输入"你好",对应的编码可能不一样。使用QtCreator可以设置编辑器默认使用的编码格式,我喜欢使用UTF8格式(在项目的属性设置对话框中)。

    代码中"你好"这时候实际上和"hello"没什么区别了,只是一个数组对应{0x11,0x12,0x13...}; 

2、char*和QString之间转换  QByteArray和QString之间转换

     上面代码中,对QString进行赋值会调用到QString::operator(const QString&)函数,中间会将char[]转换成QString,调用QString(const char*)。 在这里它需要将char*中的字符串的编码格式进行转换了。现在问题来了,QString不知道char* 中字符串的编码格式。(编码格式那么多,不可能挨个去试)。 这时候使用

    QTextCodec::setCodecForCStrings(QTextCodec::setCodecForCStrings("UTF-8"));

    它就告诉我们怎么在QString和char*之间如何进行编码转换。

    对于QByteArray和QString之间的转换也是一样的。    

3、tr宏

    对于多语言来说,需要使用到tr,这个函数的定义:   

    QString QObject::tr ( const char * sourceText, const char * disambiguation = 0, int n = -1 )

    从定义上可以看出输入的是char*,输出的却是QString,这其中肯定涉及到编码格式转换的问题。不过QT使用了另外一个函数对这个行为进行控制:
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); 
   下面可以看到,它实际上控制当翻译不成功时,如何将char*转换为QString。

4、业务流程需要编码转换    

    现在"你好"以及以UTF16的编码格式存储在message中了,若是需要将这个字符串写入一个记事本文件中并且希望用户打开文件后看到的不是乱码? 

    在这里,我们输出的字符串可能是中文,且国内大部分操作系统中编辑器默认使用的编码格式是GBK,所以:

    QTextCodec::codecForName("GBK")->fromUnicode(message)

   上面代码返回的就是"你好"的GBK编码数据,将它写入文件后,字符才能正常显示。

    当然,若是使用"BIG5“编码格式的编辑器的话,那么上面的代码就需要改为:

    QTextCodec::codecForName("GBK")->fromUnicode(message)



翻译

对于需要进行翻译的文字,需要使用tr("")进行包裹,例如QString c = tr("汉字"),在不同的语言设置中,返回不同的字符。这个函数的源码:

    static inline QString tr(const char *s, const char *c = 0) \
        { return staticMetaObject.tr(s, c); } \
    static inline QString trUtf8(const char *s, const char *c = 0) \
        { return staticMetaObject.trUtf8(s, c); } \
    static inline QString tr(const char *s, const char *c, int n) \
        { return staticMetaObject.tr(s, c, n); } \
    static inline QString trUtf8(const char *s, const char *c, int n) \
        { return staticMetaObject.trUtf8(s, c, n); }
QString QMetaObject::tr(const char *s, const char *c) const
{
    return QCoreApplication::translate(d.stringdata, s, c, <span style="color:#ff0000;">QCoreApplication::CodecForTr</span>);
}

QString QCoreApplication::translate(const char *context, const char *sourceText,
                                    const char *disambiguation, Encoding encoding)
{
    return translate(context, sourceText, disambiguation, encoding, -1);
}
QString QCoreApplication::translate(const char *context, const char *sourceText,
                                    const char *disambiguation, Encoding encoding, int n)
{
    QString result;

    if (!sourceText)
        return result;

    if (self && !self->d_func()->translators.isEmpty()) {
        QList<QTranslator*>::ConstIterator it;
        QTranslator *translationFile;
        for (it = self->d_func()->translators.constBegin(); it != self->d_func()->translators.constEnd(); ++it) {
            translationFile = *it;
            result = <span style="color:#ff0000;">translationFile->translate(context, sourceText, disambiguation, n);</span>
            if (!result.isEmpty())
                break;
        }
    }

    if (result.isEmpty()) {
#ifdef QT_NO_TEXTCODEC
        Q_UNUSED(encoding)
#else
        if (encoding == UnicodeUTF8)
            result = QString::fromUtf8(sourceText);
        else if (QTextCodec::codecForTr() != 0)
            result = QTextCodec::codecForTr()->toUnicode(sourceText);
        else
#endif
            result = QString::fromLatin1(sourceText);
    }

    replacePercentN(&result, n);
    return result;
}

注意上面调用translate时会传入QCoreApplication::CodecForTr,它实际上控制着翻译不成功时如何将char*转为QString。

从上面可以看到,最终调用的是QTranslator::translate,它实际上调用的函数是:

QString QTranslatorPrivate::do_translate(const char *context, const char *sourceText,
                                         const char *comment, int n) const
{
    if (context == 0)
        context = "";
    if (sourceText == 0)
        sourceText = "";
    if (comment == 0)
        comment = "";

    if (!offsetLength)
        return QString();

    /*
        Check if the context belongs to this QTranslator. If many
        translators are installed, this step is necessary.
    */
    if (contextLength) {
        quint16 hTableSize = read16(contextArray);
        uint g = elfHash(context) % hTableSize;
        const uchar *c = contextArray + 2 + (g << 1);
        quint16 off = read16(c);
        c += 2;
        if (off == 0)
            return QString();
        c = contextArray + (2 + (hTableSize << 1) + (off << 1));

        for (;;) {
            quint8 len = read8(c++);
            if (len == 0)
                return QString();
            if (match(c, context, len))
                break;
            c += len;
        }
    }

    size_t numItems = offsetLength / (2 * sizeof(quint32));
    if (!numItems)
        return QString();

    int numerus = 0;
    if (n >= 0)
        numerus = numerusHelper(n, numerusRulesArray, numerusRulesLength);

    for (;;) {
        quint32 h = elfHash(QByteArray(sourceText) + comment);

        const uchar *start = offsetArray;
        const uchar *end = start + ((numItems-1) << 3);
        while (start <= end) {
            const uchar *middle = start + (((end - start) >> 4) << 3);
            uint hash = read32(middle);
            if (h == hash) {
                start = middle;
                break;
            } else if (hash < h) {
                start = middle + 8;
            } else {
                end = middle - 8;
            }
        }

        if (start <= end) {
            // go back on equal key
            while (start != offsetArray && read32(start) == read32(start-8))
                start -= 8;

            while (start < offsetArray + offsetLength) {
                quint32 rh = read32(start);
                start += 4;
                if (rh != h)
                    break;
                quint32 ro = read32(start);
                start += 4;
                QString tn = getMessage(messageArray + ro, messageArray + messageLength, context,
                                        sourceText, comment, numerus);
                if (!tn.isNull())
                    return tn;
            }
        }
        if (!comment[0])
            break;
        comment = "";
    }
    return QString();
}

do_translate将从offsetArray指向的中查找对应的翻译字符串,中间涉及的存储结构以及如何查找和Hash表相关。

使用时步骤:

1、将所有需要翻译的字符使用tr("")包裹起来

2、在项目文件中定义TRANSLATIONS,指定翻译文件生成路径

3、使用lupdate生成ts文件

4、使用Linguist对ts文件进行翻译

5、使用lrelease将ts文件转换为qm文件

6、将qm文件部署到设备上

7、代码中添加对qm文件的加载,根据不同的业务加载不同的文件:

                translatorpass = new QTranslator();
                //removeTranslator(translatorpass); 如果之前添加过,需要先删除
               translatorpass->load("en.ts","/usr/local/translation");

字库

除了编码和翻译问题,还需要解决字库部署问题。例如,在支持中文的基础上,需要添加对阿拉伯语的支持,除了涉及翻译和编码外,还需要部署支持阿拉伯的字库文件。
不然当切换到阿拉伯下,整个界面对于阿拉伯语的显示就有问题。

对于中文,我们可以使用文泉译这种开源字库(wqy-zenhei.ttf), 对于阿拉伯语则找到了名为DroidSansArabic.ttf的字库。将这两个字库放入QT安装路径下的font文件夹下,QT就能找到他们。

当然,也可以使用其他方式进行部署,例如指定fontdir的路径,然后在fontdir中定义字库名字。

业务逻辑实现时,需要动态切换字库,则需要调用

void QApplication::setFont(const QFont &font, const char *className)

它会指定整个应用的默认字库

对于整个系统支持的字库文件可以使用下面程序进行查询:

QFontDatabase database;
QStringList families=database.families();


文字输入/显示方向

上面提到的阿拉伯语在显示文字是从右往左,这个实现比较简单。

程序中声明

QApplication::tr("QT_LAYOUT_DIRECTION");

然后在ts文件中将它翻译成"RTL",即可。

因为在文字显示过程中,有这样一句代码:

static bool qt_detectRTLLanguage()
{
    return force_reverse ^
        (QApplication::tr("QT_LAYOUT_DIRECTION",
                         "Translate this string to the string 'LTR' in left-to-right"
                         " languages or to 'RTL' in right-to-left languages (such as Hebrew"
                         " and Arabic) to get proper widget layout.") == QLatin1String("RTL"));
}




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
v1.11 (08/14/2012) 1. 增加注册年限选择。 v1.10 (06/26/2012) 1. 精简字库检索表。 2. 增加 GBK 字库输出。 3. 增加一种点阵数据存储格式(只存有效像素数据--not fixed, 不支持MBCS编码格式的中日韩), 对泰文,缅甸文等特殊语种显示非常便捷。 v1.09 (06/15/2012) 1. 增加输出 C 语言(数组) 字体格式。 V1.08 (05/17/2012) 1. 增加了两个版本(免费和试用版) 免费版 只对 16点阵有效。 试用版 对所有点阵有效,但是会缺部分字符。 2. 增加热键功能。 3. 修改了多国语言生成.h文件时,start 与 end 不匹配的bug。 4. 完善文档《GuiTool 使用说明》, 增加更多图解说明。 文档下载地址: http://ishare.iask.sina.com.cn/f/24472766.html v1.07 (05/02/2012) 1. 修改注册方式(改为文件)。 2. 增加bdf格式编码过滤功能,主要是为了支持 MTK 手机点阵字库。 3. 增加xp控件属性。 4. 增加扫描模式图解。 5. 修改了 bdf 2 bin 的一个bug。(选择输出位图时,会输出n个位图文件) 6. 修改了 BDF 文件中当字符显示宽度为0,存位图(所有字符存一张图片)失败的错误。 v1.06 (04/10/2012) 1. 增加系统字体支持,操作更简便,快捷。 枚举所有已安装系统字体,直接选择即可。 v1.05 (03/24/2012) Fontmaker(点阵字库) 1. 修正了字符对齐问题。 2. 增加了单个字符或多个字符输出成位图文件设定。 3. 完善了阿拉伯文字库(unicode 字库有效)。 4. 增加自定义字符功能(unicode 字库有效)。 Multi-language(多国语言) 1. 增加输出编码格式 (mbcs, utf16-lb, utf8)设置 2. 增加数组格式输出。 Image Manager(图像管理) 1. 该页为新增功能,支持图片图像的数据转换。主要应用在做产品logo图片方面。 V1.04 (07/16/2011) 1. 增加了一个字符串mbcs2unicode(内码转统一码)的功能。 (支持转:U16-LE, U16-BE, UTF8) V1.03 (07/05/2011) 1. 修改了 Example 中点阵字库解析源码,更加便于移植。(基本做到只需修改font_file.c 即可) 2. 修改了内码(MBCS)字库点阵信息读取的一个错误。 3. 增加了多语言支持(简中,英文),还有待完善。。。 V1.02 (07/01/2011) 1. FontMaker V2.03 a. 增加字符宽高比调节(HorR & VerR) b. 增加对*.ttc 字库的支持。 c. 增加bdf(*.bdf)文件格式转Simple Unicode编码格式的bin文件。 V1.01 (06/29/2011) 1. FontMaker V2.02 a. 增加了 Simple Unicode功能。(适合小字库) b. 增加了 “扫描方向及反显”设置。 2. Multi-Language V1.01 a. 修改了除 office 2000 外,其它不能支持的问题。 V1.00: (2007-2011) 1. 继承 FontMaker V2.01 的所有功能。 2. 增加了一个 Multi-Languge V1.00 的打包转换功能。 FontMaker 基本功能: 1.支持所有 windows 字符集:CP932(日文Shift-JIS)CP936(简体中文GBK)CP949(韩文)CP950(繁体中文 Big5),CP874(泰文),CP1250(中欧)CP1251(西里尔文),CP1252(西欧--"拉丁文I"),CP1253(希腊文), CP1254(土耳其文),CP1255(希伯来文),CP1256(阿拉伯文),CP1257(波罗的海文),CP1258(越南) 2.支持非等宽字库。 3.支持BIN,TXT,BMP,BDF 文件输出。 4.支持unicode字库输出,即可以做到在一个窗口中同时显示多国语言文字) 5.支持单个字符编辑,预览(所见即所得)。 6.支持字库文件和输出路径记忆功能. 7. 支持从bdf格式转换自定义字库(bin文件)格式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值