如何使用C++的特性 与直接使用 C 语言的 gettext() 相比,更干净地使用 i18n 库

发布于 2024-07-23 10:34:58 字数 734 浏览 2 评论 0原文

我想要一种易于使用的方式来编写代码,例如:

#include <iostream>
int main (){
    std::cout << "hello, world!\n";
}

但支持 i18n。 以下是使用 gettext() 的示例:

#include <libintl.h>
#include <iostream>
int main (){
    std::cout << gettext("hello, world!\n");
}

然后可以由 xgettext 处理它以生成可以使用的消息目录文件 由译者创造各种版本。 这些额外的文件可以在目标上处理 系统允许用户以首选语言进行交互。

我想编写这样的代码:

#include <i18n-iostream>
int main (){
    i18n::cout << "hello, world!\n";
}

在构建时,引用的字符串将由像 xgettext 这样的程序检查以生成 基本消息目录文件。 带有参数 i18n::cout<< 运算符将采用字符串 文字作为从消息目录中查找要使用的运行时文本的键。

它存在于某处吗?

I would like to have an easy to use way to write code like:

#include <iostream>
int main (){
    std::cout << "hello, world!\n";
}

but that supports i18n. Here is an example using gettext():

#include <libintl.h>
#include <iostream>
int main (){
    std::cout << gettext("hello, world!\n");
}

This can then be processed by xgettext to produce a message catalog file that can be used
by translators to create various versions. These extra files can be handled on target
systems to allow the user to interact in a preferred language.

I would like to write the code something like this instead:

#include <i18n-iostream>
int main (){
    i18n::cout << "hello, world!\n";
}

At build time the quoted strings would be examined by a program like xgettext to produce the
base message catalog file. << operator with argument i18n::cout would take a string
literal as the key to lookup the run-time text to use from a message catalog.

Does it exist somewhere?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

南汐寒笙箫 2024-07-30 10:34:59

在构建时,引用的字符串将由 xgettext 等程序检查,以生成基本消息目录文件。 << 带有参数 i18n::cout 的运算符将采用字符串文字作为从消息目录中查找要使用的运行时文本的键。

您尝试像单个实例一样转换字符串,但它不是/

重点,您不想要这样的东西。 想一想:

if(n=1)
    i18n::cout << "I need one apple"
else
    i18n::cout << "I need " << n << " apples" ;

那么为什么这行不通,因为“n=1”或“n!=1”仅适用于英语,许多其他语言都有不止一种复数形式,而且它需要翻译“我需要 X 苹果”作为单个实例。

我建议你就去学习处理gettext,它相当简单而且功能强大,很多人都想过。

另一点,你通常不调用 gettext 但这

#include <libintl.h>
#include <iostream>
#define _(x) gettext(x)

int main (){
    std::cout << _("hello, world!\n");
}

使代码更加简洁,而且使用“_”作为 gettext 别名是一个相当“标准”的功能。

在尝试制作“更好”的 API 之前,只需学习如何使用它即可。 顺便提一下,gettext API 对于许多语言来说都是事实上的标准,而不仅仅是 C。

At build time the quoted strings would be examined by a program like xgettext to produce the base message catalog file. << operator with argument i18n::cout would take a string literal as the key to lookup the run-time text to use from a message catalog.

You try to convert a string like a single instance, but it isn't/

The point, you don't want something like this. Think of:

if(n=1)
    i18n::cout << "I need one apple"
else
    i18n::cout << "I need " << n << " apples" ;

So why this is would not work, because "n=1" or "n!=1" works only for English, many other languages have more then one plural form, also it requires translation of "I need X apples" as signle instance.

I suggest you just to learn to deal with gettext, it is quite simple and powerful, many people had thought about it.

Another point, you are usually do not call gettext but

#include <libintl.h>
#include <iostream>
#define _(x) gettext(x)

int main (){
    std::cout << _("hello, world!\n");
}

This makes the code much cleaner, also it is quite a "standard" feature to use "_" as gettext alias.

Just learn how to use it, before you try to make "nicer" API. Just to mention, gettext API is quite de-facto standard for many languages, not only C.

可爱暴击 2024-07-30 10:34:59

简短的回答是“否”:)

说实话,您对国际化的哪些方面感兴趣? ICU 提供了几乎所有功能,但感觉不像标准 C++。 还有其他范围较小的库提供了一些 i18n 功能,即用于处理 UTF-8 编码字符串的 UTF-CPP。

The short answer is "No" :)

Seriously, which aspects of internationalization are you interested in? ICU provides pretty much everything but does not feel like standard C++. There are other libraries smaller in scope that provide some i18n functionalities, i.e. UTF-CPP for handling UTF-8 encoded strings.

太傻旳人生 2024-07-30 10:34:59

就我个人而言,我会选择这个答案,但可能可以使用当文本写入流时,使用 Streambuf 魔法来执行此操作。 如果您确实对此感兴趣,请查看 标准 C++ IOStreams 和Langer 和 Kreft 的 Locales,它是 iostreams 的圣经。

下面假设写入缓冲区的所有内容都将被翻译,并且每个整行都可以被完全翻译:

std::string xgettext (std::string const & s)
{
  return s;
}

以下 transbuf 类覆盖“溢出”函数并
每次看到换行符时都会翻译缓冲区。

class transbuf : public std::streambuf {
public:
  transbuf (std::streambuf * realsb) : std::streambuf (), m_realsb (realsb)
    , m_buf () {}

  ~transbuf () {
    // ... flush  m_buf if necessary
  }

  virtual std::streambuf::int_type overflow (std::streambuf::int_type c) {
    m_buf.push_back (c);
    if (c == '\n') {
      // We have a complete line, translate it and write it to our stream:
      std::string transtext = xgettext (m_buf);
      for (std::string::const_iterator i = transtext.begin ()
        ; i != transtext.end ()
        ; ++i) {
        m_realsb->sputc (*i);
        // ... check that overflow returned the correct value...
      }
      m_buf = "";
    }
    return c;
  }    

  std::streambuf * get () { return m_realsb; }

  // data
private:
  std::streambuf * m_realsb;
  std::string m_buf;
};

以下是如何使用它的示例:

int main ()
{
  transbuf * buf = new transbuf (std::cout.rdbuf ());
  std::ostream trans (buf);

  trans << "Hello";  // Added to m_buf
  trans << " World"; // Added to m_buf
  trans << "\n";     // Causes m_buf to be written

  trans << "Added to buffer\neach new line causes\n"
           "the string to be translated\nand written" << std::endl;

  delete buf;
}    

Personally I would go with this answer, but it might be possible to use a bit of streambuf magic to do this as the text is written to the stream. If you're really interested in doing this though, please take a look at Standard C++ IOStreams and Locales by Langer and Kreft, it's the bible of iostreams.

The following assumes that everything written to the buffer is to be translated, and that each full line can be translated completely:

std::string xgettext (std::string const & s)
{
  return s;
}

The following transbuf class overrides the "overflow" function and
translates the buffer every time it sees a newline.

class transbuf : public std::streambuf {
public:
  transbuf (std::streambuf * realsb) : std::streambuf (), m_realsb (realsb)
    , m_buf () {}

  ~transbuf () {
    // ... flush  m_buf if necessary
  }

  virtual std::streambuf::int_type overflow (std::streambuf::int_type c) {
    m_buf.push_back (c);
    if (c == '\n') {
      // We have a complete line, translate it and write it to our stream:
      std::string transtext = xgettext (m_buf);
      for (std::string::const_iterator i = transtext.begin ()
        ; i != transtext.end ()
        ; ++i) {
        m_realsb->sputc (*i);
        // ... check that overflow returned the correct value...
      }
      m_buf = "";
    }
    return c;
  }    

  std::streambuf * get () { return m_realsb; }

  // data
private:
  std::streambuf * m_realsb;
  std::string m_buf;
};

And here's an example of how that might be used:

int main ()
{
  transbuf * buf = new transbuf (std::cout.rdbuf ());
  std::ostream trans (buf);

  trans << "Hello";  // Added to m_buf
  trans << " World"; // Added to m_buf
  trans << "\n";     // Causes m_buf to be written

  trans << "Added to buffer\neach new line causes\n"
           "the string to be translated\nand written" << std::endl;

  delete buf;
}    
明媚殇 2024-07-30 10:34:59

您的意思是您只想要另一个 API? 你可以写一个小的包装器,应该不会太难,它会让你有可能使用你能想到的最好的 API :)

You mean you just want another API? You could write a small wrapper, shouldn't be too hard and it would give you the possibility to use the best API you can think of :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文