【问题标题】:How to make localized duration string?如何制作本地化的持续时间字符串?
【发布时间】:2012-11-04 13:38:29
【问题描述】:

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

  • 还剩 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 上运行。我宁愿不使用依赖于平台的函数,尽管了解它们会很好。

【问题讨论】:

    标签: c++ time wxwidgets duration


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      我建议将你的函数一分为二。

      第一部分将以 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 令牌。

      【讨论】:

      • 嗯,wxTimeSpan 很有用,但它不会解决最困难的部分:将其移植到具有不同时间结构的不同语言
      • 没有具体的例子很难解释。请提供两种不同“时间结构”的示例
      • 例如英语中的“1 minute, 2 minutes, ...”,但在俄语中“minute”一词的形式更多:“1 минута, 2 минуты, ..., 5 минут"
      【解决方案3】:

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

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

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

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-01
          • 2011-02-21
          • 1970-01-01
          相关资源
          最近更新 更多