2015-03-23 16:20:37 here_c_my 阅读数 4320
  • hibernate4从入门到大神(备java基础,mysql,javaee...

    Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,Hibernate分页技术,Hibernate性能优化技术。

    18636 人正在学习 去看看 任亮

含义:

PO 是 Portable Object (可移植对象)的缩写形式;MO 是 Machine Object (机器对象) 的缩写形式。

PO 文件是面向翻译人员的、提取于源代码的一种资源文件。当软件升级的时候,通过使用 gettext 软件包处理 PO 文件,可以在一定程度上使翻译成果得以继承,减轻翻译人员的负担。

MO 文件是面向计算机的、由 PO 文件通过 gettext 软件包编译而成的二进制文件。程序通过读取 MO 文件使自身的界面转换成用户使用的语言。

文件相互转换:

po->mo   msgfmt  *.po -o *.mo

mo->po msgunfmt *.mo -o *.po

2014-11-21 19:07:56 yygydjkthh 阅读数 4007
  • hibernate4从入门到大神(备java基础,mysql,javaee...

    Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,Hibernate分页技术,Hibernate性能优化技术。

    18636 人正在学习 去看看 任亮

/*********************************************************************
 * Author  : Samson
 * Date    : 11/21/2014
 * Test platform:
 *              3.13.0-24-generic
 *              GNU bash, 4.3.11(1)-release 
 * *******************************************************************/

在GNU Linux系统中,很多软件都是支持多种国家的语言的,而这些语言一般都是通过一个*.po的文件而区别开来不同的国家的语言的,有的可能会编译成二进制文件*.mo,而编译成二进制文件的命令为msgfmt。

有的时候存在这样的场景,为了修改语言翻译的问题,想直接修改语言文件,那么就要使用将编译好的二进制的*.mo文件转换成*.po文件,那么使用命令msgunfmt命令即可完成这个需求,以下的例子中test.po表示一个语言文件的ascii码的文件,test.mo表示编译后的二进制语言文件:
    
例子:
反编译mo二进制文件成ascii po文件
    msgunfmt test.mo -o test.po
编码ascii po文件为二进制mo文件
    msgfmt -o test.mo test.po
2016-12-04 21:08:11 men_wen 阅读数 12197
  • hibernate4从入门到大神(备java基础,mysql,javaee...

    Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,Hibernate分页技术,Hibernate性能优化技术。

    18636 人正在学习 去看看 任亮

Linux网络编程—I/O复用模型之epoll

1. epoll模型简介

epoll是Linux多路服用IO接口select/poll的加强版,e对应的英文单词就是enhancement,中文翻译为增强,加强,提高,充实的意思。所以epoll模型会显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。

  • epoll把用户关心的文件描述符上的时间放在内核的一个事件表中,无需像select和poll那样每次调用都重复传入文件描述符集。
  • epoll在获取事件的时候,无需遍历整个被监听的文件描述符集合,而是遍历那些被内核IO事件异步唤醒而加入ready队列的描述符集合。

所以,epoll是Linux大规模高并发网络程序的首选模型。

2.epoll模型的API

epoll使用一组函数来完成任务

2.1 函数epoll_create

创建一个epoll句柄,句柄的英文是handle,相通的意思是把手,把柄。

#include <sys/epoll.h>

int epoll_create(int size);
//返回值:若成功,返回一个非负的文件描述符,若出错,返回-1。
  • 该函数返回一个文件描述符,用来唯一标示内核中这个事件表,sizeof参数提示内核要监听的文件描述符个数,这与内存大小有关。
  • 返回的文件描述符将是其他所有epoll系统调用的第一个参数,以指定要访问的内核时间表,所以用该返回的文件描述符相当与其他epoll调用的把手、把柄一样。

查看进程能够打开的最大数目的文件描述符

➜  ~ cat /proc/sys/fs/file-max
1215126
//该值与内存大小有关

修改最大文件描述符限制

➜  ~ sudo vim /etc/security/limits.conf
//重启生效

2.2 函数epoll_ctl

该函数用来操作epoll的内核事件表

#include <sys/epoll.h>

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//返回值:若成功,返回0,若出错返回-1。
  • epfd就是函数epoll_create创建的句柄。
  • op是指定操作类型,有一下三种
    • EPOLL_CTL_ADD,向epfd注册fd的上的event
    • EPOLL_CTL_MOD,修改fd已注册的event
    • EPOLL_CTL_DEL,从epfd上删除fd的event
      1. fd是操作的文件描述符
      2. event指定内核要监听事件,它是struct epoll_event结构类型的指针。epoll_event定义如下:
struct epoll_event {
    uint32_t     events;      /* Epoll events */
    epoll_data_t data;        /* User data variable */
};
  • events成员描述事件类型,将以下宏定义通过位或方式组合

    • EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
    • POLLOUT:表示对应的文件描述符可以写
    • EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)
    • EPOLLERR:表示对应的文件描述符发生错误
    • EPOLLHUP:表示对应的文件描述符被挂断;
    • EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的
    • EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
  • data用于存储用户数据,是epoll_data_t结构类型,该结构定义如下:

typedef union epoll_data {
    void        *ptr;
    int          fd;
    uint32_t     u32;
    uint64_t     u64;
} epoll_data_t;
  • epoll_data_t是一个联合体,fd指定事件所从属的目标文件描述符。ptr可以用来指定fd相关的用户数据,但两者不能同时使用。

2.3 函数epoll_wait

函数epoll_wait用来等待所监听文件描述符上有事件发生

#include <sys/epoll.h>

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
//返回值:若成功,返回就绪的文件描述符个数,若出错,返回-1,时间超时返回0
  • epfd就是函数epoll_create创建的句柄
  • timeout是超时事件,-1为阻塞,0为立即返回,非阻塞,大于0是指定的微妙
  • events是一个 传入传出参数,它是epoll_event结构的指针,用来从内核得到事件的集合
  • maxevents告知内核events的大小,但不能大于epoll_create()时创建的size

3. LT和ET模式

  • LT(Level Triggered,电平触发):LT模式是epoll默认的工作模式,也是select和poll的工作模式,在LT模式下,epoll相当于一个效率较高的poll。
    • 采用LT模式的文件描述符,当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理此事件,当下一次调用epoll_wait是,epoll_wait还会将此事件通告应用程序。
  • ET(Edge Triggered,边沿触发):当调用epoll_ctl,向参数event注册EPOLLET事件时,epoll将以ET模式来操作该文件描述符,ET模式是epoll的高效工作模式.
    • 对于采用ET模式的文件描述符,当epoll_wait检测到其上有事件发生并将此通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait调用将不在向应用程序通知这一事件。ET模式降低了同意epoll事件被触发的次数,效率比LT模式高。

4. LT和ET的服务端和客户端代码

4.1 服务器端

#include <sys/epoll.h>
#include <fcntl.h>
#include "wrap.h"

#define MAX_EVENT_NUM           1024
#define BUFFER_SIZE             10
#define true                    1
#define false                   0

int setnonblocking(int fd)
{
        int old_opt = fcntl(fd, F_GETFD);
        int new_opt = old_opt | O_NONBLOCK;
        fcntl(fd, F_SETFD, new_opt);

        return old_opt;
}//将文件描述符设置为非阻塞的

void addfd(int epollfd, int fd, int enable_et)
{
        struct epoll_event event;
        event.data.fd = fd;
        event.events = EPOLLIN;
        if(enable_et){
                event.events |= EPOLLET;
        }
        epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
//      setnonblocking(fd);
}//将文件描述符fd的EPOLLIN注册到epollfd指示的epoll内核事件表中,enable_et表示是否对fd启用ET模式

void lt(struct epoll_event *events, int num, int epollfd, int listenfd)
{
        char buf[BUFFER_SIZE];
        for(int i = 0; i < num; i++){
                int sockfd = events[i].data.fd;
                if(sockfd == listenfd){
                        struct sockaddr_in clientaddr;
                        socklen_t clilen = sizeof(clientaddr);
                        int connfd = Accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);
                        addfd(epollfd, connfd, false);//对connfd使用默认的lt模式
                }else if(events[i].events & EPOLLIN){//只要socket读缓存中还有未读的数据,这段代码就会触发
                        printf("event trigger once\n");
                        memset(buf, '\0', BUFFER_SIZE);
                        int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
                        if(ret <= 0){
                                Close(sockfd);
                                continue;
                        }
                        printf("get %d bytes of content:%s\n", ret, buf);
                }else{
                        printf("something else happened\n");
                }
        }
}

void et(struct epoll_event *event, int num, int epollfd, int listenfd)
{
        char buf[BUFFER_SIZE];
        for(int i = 0; i < num; i++){
                int sockfd = event[i].data.fd;
                if(sockfd == listenfd){
                        struct sockaddr_in clientaddr;
                        int clilen = sizeof(clientaddr);
                        int connfd = Accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);
                        addfd(epollfd, connfd, true);//多connfd开启ET模式
                }else if(event[i].events & EPOLLIN){
                        printf("event trigger once\n");
                        while(1){//这段代码不会重复触发,所以要循环读取数据
                                memset(buf, '\0', BUFFER_SIZE);
                                int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
                                if(ret < 0){
                                        if((errno == EAGAIN) || (errno == EWOULDBLOCK)){
                                                printf("read later\n");
                                                break;
                                        }
                                        Close(sockfd);
                                        break;
                                }else if(ret == 0){
                                        Close(sockfd);
                                }else{
                                        printf("get %d bytes of content:%s\n", ret, buf);
                                }
                        }
                }else{

                        printf("something else happened \n");
                }
        }
}

int start_ser(char *ipaddr, char *port)
{
        int sock = Socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in serveraddr;
        bzero(&serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(atoi(port));
        inet_pton(AF_INET, ipaddr, &serveraddr.sin_addr);

        Bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

        Listen(sock, 128);

        return sock;
}

int main(int argc, char *argv[])
{
        int listenfd = start_ser(argv[1], argv[2]);

        struct epoll_event events[MAX_EVENT_NUM];
        int epollfd = epoll_create(5);
        if(epollfd < 0){
                perr_exit("epoll_create err");
        }
        addfd(epollfd, listenfd, true);
        while(1){
                int ret = epoll_wait(epollfd, events, MAX_EVENT_NUM, -1);
                if(ret < 0){
                        printf("epoll failure\n");
                        break;
                }

                lt(events, ret, epollfd, listenfd);//lt模式
                //et(events, ret, epollfd, listenfd);//et模式
        }
        Close(listenfd);
        return 0;
}
//warp.h文件是将socket,bind,listen等函数封装为第一个字母大写的头文件

4.2 客户端

#include "wrap.h"                                                            

int main(int argc, char *argv[])
{
        int connfd;
        struct sockaddr_in serveraddr;
        char buf[1024];

        connfd = Socket(AF_INET, SOCK_STREAM, 0);

        bzero(&serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_port = htons(atoi(argv[2]));
        inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);

        Connect(connfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

        while(fgets(buf, 1024, stdin) != NULL){
                Write(connfd, buf, strlen(buf));
        }

        Close(connfd);
        return 0;
}

4.3 两种模式结果对比

ET模式

LT模式
当发送超过缓冲区大小的数据量,LT会多次调用epoll_wait函数接受数据,则打印了多次“event level once”,而ET则是循环读取数据知道读完,打印了一次“event trigger once”。

2008-12-14 11:04:11 kissinger_1984 阅读数 38
  • hibernate4从入门到大神(备java基础,mysql,javaee...

    Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,Hibernate分页技术,Hibernate性能优化技术。

    18636 人正在学习 去看看 任亮

很久之前看的东西,当时激动的就翻译了一下,其实也是翻译的七零八落,有些东西觉得太白就没有翻译,或者有的觉得复杂,也没翻译。既然翻译过了,那就po上来吧

 

About Wine
Wine是一个转换层(或者说是一个程序加载器),它可以在Linux上或其他符合POSIX标准的系统上运行Windows的程序。在Wine中运行的Windows程序就像本地程序一样,不会有如模拟器一般存在的内存使用或性能方面的问题,同时它的样子以及使用感觉看起来也如同你桌面的其他程序。
Wine项目开始于1993年,那时是为了支持在Linux上运行Windows3.1的程序。Bob Amstadt是最初的协调者,但是后来很快将此职责就转交给Alexandre Julliard,他一直工作到现在。随着时间的推移,逐渐增加了对其他类Unix系统的支持,Win32应用程序流行起来时,也增加了对Win32的支持。
Wine现在仍在开发中,它还没有完全普遍适用。但是,许多人发现利用它可以运行许多Windows应用程序,并且,这个数目还在增长中。详情请参阅应用程序数据库,那里有关于几百个windows程序成功和失败的报告,同时也有一个bug跟踪数据库,列出了已知的问题,在status页面可以看到wine项目目前开发进度的总体概况。
在Wine的论坛可以看到大批的wine开发者.....

Wine`s History
Wine的足迹可以追溯到1993年,那时,在几个组织的努力下,使得运行Windows程序看起来非常有吸引力。微软成功的运作,使他的Windows程序运行在广大个人电脑的桌面。IBM本来希望他的OS/2系统能够赶上微软的Windows,但是即使是IBM,他们也承认,支持Windows程序是非常必要的,并把他们已经把这个特性植入了他们的产品中。随着人们渐渐发现在PC上是可能运行一个多用户多任务的操作系统的,诞生于80年代的自由软件运动也迅速的发展壮大起来。
Sun公司在1992年9月获得叫做Praxsys的技术,这导致了一个叫做Wabi产品的开发。Sun公司在1993年的Solaris开发者大会上展示了这个软件。它可以让solaris x86用户以及solaris 2.2 for sparc用户直接运行windows应用程序。那时,虽然也有其他产品允许Windows程序来运行,但是他们要求机器级别的模拟并且安装DOS和Windows。Wabi是独一无二的,他将Windows的窗口调用直接转化为X窗口的调用。通过模拟X86的其余代码,在RISC工作站上有可能更快的运行Windows程序!Wabi还有更多高级特性,包括处理Truetype字体的bitstream字体处理技术。
新兴的LInux操作系统的用户1993年6月开始讨论一个类似的方法。那时,移植Wabi到linux的可能性几乎为零。大家建立了一个mail list来促进这种讨论。名字“Wine”很快被采用了。一些最初的开发者包括了:第一代Linux kernel hacker:Eric Youngdale and David Metcalfe,还有Alexandre Julliard,他现在领导着Wine,以及久负GNOME盛名的Miguel de Icaza。Bob Amstadt则带领着开发。
最初的工作包括:让程序加载器可以运行Windows的16bit的Binaries。这项工作主要是由Bob带领。Alexandre's 加入后,他更致力于把Peter MacDonald 用 Tcl/Tk写的窗口函数合并进来。进度很快,头六个月的时间,已经可以运行纸牌游戏了。1993年11月,Wine被移植到另一个架构上-John Brezak的补丁工作使得Wine可以运行在NetBSD上。Bob估计,以现在的开发速度,团队大概6个月到一年就可以发布产品了。具有讽刺意味的是,下面十年里,Wine始终处于6个月到一年就可以release的状态。


XXXXXXXXXXXXXXXXXXXXXXX未翻译

Why Wine is so important

在那些人气旺盛的论坛里面,许多人一直认为Wine是“Linux最后需要的东西”,或者认为那根本不重要。下面我们将列出一些应该足够可以彻底击败上述以及其他言论的理由。
5个关键点:
1.供应多样化
2.大量有共同需求的人群存在是对社会的一个威胁
3.任何Windows的替代品必须跨越运行Windows应用程序
4.桌面上关于Linux的:先有鸡还是先有蛋的故事
5.Wine的好处

供应多样化
人们一致认为,保持你的供应多样化是风险管理中非常重要的一方面。
然后,美国司法部却刚刚发现微软的Windows已经运行在超过95%的个人电脑上。即使把Apple公司的Mac OS算在内,微软的Windows仍然占据了超过80%的电脑,并且,不仅在美国,在其他的国家的大多数电脑上,也可能存在同样的情况。政府,企业,以及全世界的个人用户最终都依赖于一个单独的供应商:微软。
问题不在于微软是否有邪恶的意图,或者它是否将要倒闭了,而在于它的计划是否符合你的。一个企业应该愿意仅仅使用简单的客户端来简化管理,并且节省花在每一个客户端Windows上的钱。但是,微软是否愿意让他们的愿望成真,并且削减市场份额?假如微软以签订协议付定金的方式推广他们的软件,我们是否还有的选择?假如微软对迎合你的想法不感兴趣,那么,你就没有别的目标可以投奔了。

大量同性质的产品存在是对社会的一个威胁

另一方面是:如此众多的同类人群的存在是对社会是危险的。1845年,爱尔兰人未被收割的土豆被一种真菌毁坏的时候,他们艰难的了解到这个道理。“土豆饥荒”,饿死了超过100万人(大概占人口的10%)。在一个有着共同需求的人群中,所有的个体都有着相同的弱点,只要找到其中一个弱点,你就可以消灭这整个人群,既然这样,我们,一个社会,是否吸取了这个教训?
就像上面所说的。微软的Windows在个人电脑上占有压倒性的比例。如果把不同版本的Windows考虑进去,主要是Windows9x和WindowsNT家族,这就代表着大量共同需求的人群。大多数的政府,企业,以及家庭用户,都依赖于它。
这个人群的组成,就像其他复杂的系统一样,除了那些缺点以外,都没有什么好神秘的。2001年夏天爆发的红色代码病毒提醒了我们。红色代码病毒做了任何现存病毒对一个共需人群可能做的事情:仅仅第一天,它感染了超过359000台电脑。幸运的是,它只感染了Windows家庭中一个不那么普遍的成员,造成的损失也不是那么大;它不会随机的破坏文件或者格式化你的硬盘分区。
将会有更为凶猛的病毒,这只是一个时间问题。减少这种损失的唯一办法就是操作系统的多样化。这个问题非常严肃,以至于许多安全专家称我们信赖的微软Windows为:对国家安全的威胁。
因为我们有不同的WIN32的API可以选择,并且运行在完全不同的多种操作系统上,Wine不会有那些瑕疵,因此,可以提供我们需要的多样性。

任何Windows的替代品必须可以运行Windows应用程序

Windows应用程序的依赖关系并不像windows系统那样严重。那些打包的成品,应用程序,游戏,室内应用程序,垂直市场的应用程序,就是阻止用户,企业,政府,转向另一个操作系统的主要原因。即使大多数用户90%的需求都被照顾到了(Office套件,电子邮件客户端,浏览器,媒体播放器),他们仍有10%的需求,而且是潜在的非常重要的需求,只是还没有碰到而已。不幸的是,这剩下的10%的需求也已经扩张为大范围的应用程序。数千种程序,从游戏到法国农场定制的会计软件,在到意大利百科全书,德国税收软件,儿童教育软件,银行软件,室内软件,等等,这些年都在快速发展。就是因为这些软件的唾手可得,使得Windows才那么有吸引力,并且垄断力越来越强。如果一个平台不能运行绝大多数那些软件,并且让个人用户,公司,政府节省他们在软件上的投资,那么这个平台绝不会成为主流。

桌面上linux先有鸡还是先有蛋的故事

这就给我们带来了一个问题,那就是,桌面linux,先有鸡还是先有蛋的问题。如果Linux不能提供上述那些软件,那它在桌面上的市场份额就会停滞不前。但是市场份额不上升,就没有厂家愿意为linux开发软件。怎么才能打破这个恶性循环?
Wine再一次给我们提供了答案。通过让用户重新利用他们投入了时间和金钱的Windows应用程序,Wine,戏剧化的降低了用户转向linux的门槛。这样,linux在桌面上的起飞也具有了可能性,同时也将增加它的市场份额。然后,那些公司也有可能为linux开发应用程序了,也就会有只针对linux市场的产品了。
如果Wine仅仅运行如纸牌之类的软件,这套说辞很容易就失去信服力。然而现在,它可以运行Mircosoft Office,多媒体程序如Quicktime何Windows medea player,甚至像Max Payne 或者 模拟人生这样的游戏.
只要一些时间,其他那些复杂的程序也可以良好的运行,每一次成功的运行,都会给这张应用程序表单增加一条记录,其他的应用程序也会从这些工作中受益,并且变的可用
看看我们的应用程序数据库吧,来了解现在到底有多少程序可以在Wine下运行。

从Wine中受益

最后一点,但绝不是最不重要的一点,Wine现在可以提供的益处超越了Windows:
 Wine的出现使得我们在使用Windows应用程序的时候,还可以拥有Unix的优点(稳定性,灵活性,远程管理)
下面没有翻译

2011-04-09 11:47:00 renjiedona 阅读数 257
  • hibernate4从入门到大神(备java基础,mysql,javaee...

    Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,Hibernate分页技术,Hibernate性能优化技术。

    18636 人正在学习 去看看 任亮

linux系统下,以c语言程序为例来实现程序的国际化,即让程序根据Linux系统不同的语言环境的不同来显示出对应该语言的文字,即先让c程序支持国际化然后再进行本地化翻译。

Linux上实现这个过程需要用到xgettextmsgfmt这两个工具:

Xgettext 是国际化的工具,用来提取程序中的字符串,生成*.po或是*.pot的文件,

msgfmt 是本地化的工具,用来编译翻译后的.po文件为.mo文件,这样系统在启动时候会扫描系统环境提取对应名字的.mo文件中的字符串替代原来的英文,实现本地化。在加载不同的言语环境变量(LANG)时,可以出翻译相应的语言。

 

1、  实际操作:

1)  在有需要进行翻译的文件中加入头文件:

#include <glib/gi18n.h>

2)  并添加如下定义:

#define PACKAGE "name"          //name为相应翻译包name.mo的名称

#define LOCALEDIR "/usr/share/locale/" //此行不变

3)  在要翻译的位置之前添加此内容:

setlocale (LC_ALL, "");

   bindtextdomain (PACKAGE, LOCALEDIR);

   textdomain (PACKAGE);

4)  对要进行翻译的内容加上:_()

例如要将button = gtk_button_new_with_label ("Hello World!");中的Hello World! 翻译为:你好,世界!则改为:button = gtk_button_new_with_label (_("Hello World!"));

5)命令行输入:xgettext –k_ name.c -o name.pot

xgettext –k--keyword =_ name.c -o name.pot

生成name.pot 文件

6)  改变当前shell的语言环境为要翻译的语言环境:export LANG=target

并命令行输入:msginit -l target -i name.pot

生成target.po

并对其进行翻译。

生成的.po文件内容如下:

# Chinese translations for PACKAGE package

# PACKAGE 软件包的简体中文翻译.

# Copyright (C) 2011 THE PACKAGE'S COPYRIGHT HOLDER

# This file is distributed under the same license as the PACKAGE package.

#  <rj@server>, 2011.

#

msgid ""

msgstr ""

"Project-Id-Version: PACKAGE VERSION/n"

"Report-Msgid-Bugs-To: /n"

"POT-Creation-Date: 2011-04-02 16:21+0800/n"

"PO-Revision-Date: 2011-04-02 16:21+0800/n"

"Last-Translator: JieRen <renjiedona@hotmail.com>/n"

"Language-Team: Chinese (simplified)/n"

"MIME-Version: 1.0/n"

"Content-Type: text/plain; charset=UTF-8/n"

"Content-Transfer-Encoding: 8bit/n"

"Language: zh_CN/n"

 

#: hello.c:67

#: hello.c:76

#: hello.c:126

msgid "Hello World!"

msgstr "你好世界!"//此处为要翻译的内容,在此翻译后保存即可。

 

 

7)命令行:msgfmt target.po -o target.mo

生成最终要的翻译包,再复制到usr/share/locale/**/LC_MESSAGES/

**为对应的语言,如简体中文为:zh_CN

8)  完成本地化工作。

9)  6条以后的内容可以用工具(poedit)等完成。

10)  相关头文件:

#include <glib/gi18n.h>//包含了locale 所需的(#include <libintl.h>#include <locale.h>

 

 

 

 

2、  

 

 

 

 

3、  相关头文件:

#include <glib/gi18n.h>//包含了locale 所需的(#include <libintl.h>#include <locale.h> 及_()的定义)

 

 

//与文件读写相关的头文件

#include<stdlib.h>

#include<stdio.h>

#include<string.h>

4、生成各文件用途:

         .pot  该文件是从代码中生成的原始翻译文件,它是生成所有其它 .po 文件的源文件。

         .po   .po 文件生成,该文件是翻译人员进行翻译的文档,即直接在该文件中翻译,保存。

         .mo 该文件是最后要得到的翻译文件。里面包含要翻译的内容和相关语言参数。

5、  步骤(以hello.c翻译中文为例)

创建pot文件,potPortable Object Template的首字母缩写,与po对应的是momoMachine Object的首字母缩写。前者意指原始的字符串文件,一般用于给翻译人员去修改的,后者则是与机器相关的,一般是供程序读取。可以手工创建pot文件,也可以通过xgettext从代码中抽取字符串来产生。这里是用xgettext来产生的:

xgettext –k_ hello.c -o hello.pot

*注意:-k_ 是查找关键字:“_

根据pot产生不同语言的po文件,这里我们先产生一个简体中文的po文件:

export LANG=zh_CN.UTF-8

msginit -l zh_CN.UTF-8 -i hello.pot

生成文件名会自动和语言一致:zh_CN.po

翻译zh_CN.po里对应的字符串为中文:

msgid "Hello, World!/n"

msgstr "你好,世界!/n"

保存

根据po文件生成mo文件。

msgfmt zh_CN.po -o zh_CN.mo

安装mo文件到系统中:

cp -f zh_CN.mo /usr/share/locale/zh_CN/LC_MESSAGES/foonly.mo

*注:可以自定义路径,但该目录最后几个路径是固定的即.mo文件应该放在该目录之下:/zh_CN/LC_MESSAGES/

在程序中定义LOCALEDIR的路径就是以上路径“/zh_CN/”的上一个目录。

设置环境变量:export LANG=……

通过不同环境变量,显示不同语言。

详细请参考《语言国际化.pdf

建立多语言翻译时,要建立对应语言的文件目录:例如台语:/zh_TW/LC_MESSAGES/

 

 

 

 

 

参考资料:

http://www.gnu.org/software/gettext/manual/gettext.html#Top

http://l10n.gnome.org/languages/

http://www.ibm.com/developerworks/cn/opensource/os-unicode/

 

没有更多推荐了,返回首页