2

我正在制作一个需要显示持续时间字符串的应用程序。几个例子:

  • 离休息还有 1 小时 2 分钟,
  • 离休息还有 2 分 8 秒

目前我有一个 C++ 函数,它在给定的秒/毫秒/分钟内给你一个字符串:

wxString getTimeStr(int value, 
                    ETimeUnit time_unit, // milliseconds or seconds or minutes or hours
                    wxString const & lang) // english or russian

它由许多条件组成,具体取决于语言、时间单位和现有值。现在我正在考虑将应用程序移植到其他语言,为每种新语言编写 c++ 代码会有点痛苦。有没有办法使用标准函数制作该字符串?

该应用程序是使用 wxWidgets 用 C++ 编写的,目前只能在 Windows 上运行。我宁愿不使用依赖于平台的函数,尽管了解它们会很好。

4

4 回答 4

1

我建议将您的功能一分为二。

第一部分将剩余时间作为 wxTimeSpan 返回。

第二部分将 wxTimeSpan '翻译'成所需的语言并返回一个字符串。这是您需要为每种语言更改的唯一部分。

为了便于解释,我们假设

  • 我们只关心小时和分钟
  • 克林贡人喜欢看小时/分钟
  • 火神喜欢看分钟:小时
  • 俄罗斯人对分钟这个词有多种形式

然后你的第二个函数会写成这样

// extract hours and residual minutes into CSV

wxString csv = theTimeSpan.Format("%H,%M);

// extract tokens for csv
wxString hours, mins
...

if( lang == "Klingon" ) {
  return hours + "/" + mins
} else if ( lang == "Vulcan" ) {
  return mins + ":" + hours 
} else if ( lang == "Russian" ) {
  wxString min_name;
  switch( mins.ToLong() ) {
    case 1: min_name = "---"; break;
    ...
  }
 return mins + " " + min_name;
}

不幸的是,您不能使用 Format 来获得任意的“时间结构”,因为在时间跨度中的小时数等存在本质上的歧义。它可以是总小时数(例如,对于 50 小时的时间跨度,这将是 50)或只是时间跨度的小时部分,在这种情况下为 2,因为 50 小时等于 2 天和 2 小时。

wxTimeSpan 以下列方式解决了这种歧义:如果确实存在在 H 之前指定的 D 格式,则它被解释为 2。否则,它是 50。这同样适用于所有其他格式说明符:如果它们遵循较大单位的说明符,只取其余部分,否则使用完整值。

因此,您必须使用 csv 令牌,如我的代码示例中所示。

于 2012-11-04T13:45:11.430 回答
1

如果不为不同的语言编写不同的代码,你将无法完美地做到这一点。例如,我敢打赌,您现有的代码不允许产生像“三点半前 5 分钟”这样的时间,但仍用于(口语)德语。即使不做这样的延伸,考虑一下英语“三点半”实际上被翻译成“半到四点”。

因此,如果使用官方时间还不够(如果是,请查看wxLocale::GetInfo(wxLOCALE_TIME_FMT)),您确实需要编写代码来专门处理至少一些语言。

于 2012-11-04T19:21:49.247 回答
0

有时,最好让程序更技术性,而不是更接近自然语言。我也发现自己处于这种情况(让它看起来很酷)。通常情况下,客户并不关心。信息有时比它的确切形式重要得多。

程序员有时应该选择权衡——一种与编程语言/框架无关的元解决方案。换句话说,你应该权衡解决方案的正确性和期望的正确性。

于 2012-12-12T08:52:23.817 回答
0

解决本地化问题的传统方法是构建地图label name -> label value并在值中使用占位符。

  1. 在代码中,您只引用标签名称,并为占位符提供值
  2. 要移植到另一种语言,您只需翻译地图

根据您需要的复杂程度,您可能有一个简单的占位符机制(snprintf-like),或者允许迷你语言在运行时根据简单参数(例如,区分单数和复数)构建值。

在这个例子中,它很简单:

using LabelsType = std::map<LabelName, std::string>;
using LangToLabelsType = std::map<Language, LabelsType>;

注意:我建议为语言使用枚举,而不是纯字符串。

如果您使用的是 Linux,我会推荐gettext,但我不确定它是否适用于 Windows。不过,您可以查看它并查看它是如何工作的,它可能会对您有所帮助。

于 2012-11-04T14:50:16.013 回答