【问题标题】:How to do an app with truly multilingual strings?如何用真正的多语言字符串做一个应用程序?
【发布时间】:2011-08-15 21:27:54
【问题描述】:

为不同语言制作字符串的最佳方法应该是什么?我有这个问题,我正在尝试显示诸如“月”、“月”、“年”、“年”之类的字符串。目前我正在研究我知道的 3 种语言:西班牙语、英语和波兰语。对于英语和西班牙语,这是直截了当的。但是例如,在波兰语中,“年”可以变成“lata”(在数字 2 - 4 之后)或“lat”(在数字 5 之后)。我正在考虑为此添加一个额外的字符串,并在其他语言中使其为空。然而,这让我想到了我不知道的其他语言,它们可能有更多的差异。如果我考虑将来添加更多语言,那么在这种情况下,哪种方法最好?

【问题讨论】:

  • 只是为了让您注意,我希望您正在使用清单字符串文件,您的问题是:您指的是在运行时选择您的语言的情况?如果是这样,我认为使用本地化的反射将帮助您,甚至无需询问您的用户......
  • 是的,我正在处理字符串文件。但是我不知道是否可以使用字符串文件以干净的方式实现我想要的。是的,它是关于在运行时显示某些消息,更具体地说是关于处理复数,在某些语言中可以有不止一种方式来编写它们。

标签: java android multilingual


【解决方案1】:

听起来你想要一个ChoiceFormat,或者至少通过MessageFormat 使用一个:

public static void main(String... args) {
    String[] formats = { 
        // NOTE - In a real app, you'd fetch the format strings from a language,
        // file, not hard-code them in your program. Obviously.
        "{0,number} {0,choice,0#years|1#year|1<years}", // english
        "{0,number} {0,choice,0#años|1#año|1<años}", // spanish
        "{0,number} {0,choice,1#[fewer than 2]|2#lata|4<lat}", // polish
        "{0,number} år", // swedish - singular and plural forms look the same!
    };
    int[] years = {0, 1, 2, 3, 4, 5, 6};
    for (int year : years) {
        for (String format : formats) {
            System.out.println(MessageFormat.format(format, year));
        }
        System.out.println();
    }
}

在您的程序中,您当然会从字符串文件中获取format 字符串。

【讨论】:

  • 感谢您的示例,起初我正在寻找一个更基于 android 的解决方案(例如,仅使用 xml 来获取字符串),所以说实话,我认为这是不可能的将 Android 字符串系统与 ChoiceFormat 集成,但您只是给了我一个关于如何混合两者的好主意。顺便说一句,这正是我想要的,复数在某些数字之后会发生变化。唯一需要注意的是,添加具有特殊复数变化的新语言需要修改源代码。
  • 这当然不是要走的路。将您的字符串放在 /res/string 的资源文件中。但是最好使用 ChoiceFormat 而不是复数,因为stackoverflow.com/questions/5651902/…
  • 为了记录,这里的代码示例只是为了展示如何使用ChoiceFormat。我不建议您对语言字符串进行硬编码。编辑代码以澄清。
【解决方案2】:

感谢我得到的答案,我正在编写 2 个基于 Android 的解决方案。我使用的第一个是复数形式。乍一看检查复数文档/示例,您可能会认为有一个数量 =“few”(用于 2-4 个复数),在 sources 处检查仅适用于语言环境“cs”。对于其他语言环境,只有“一个”和“其他”有效。 所以在你的 strings.xml 文件中:

<plurals name ="years">
    <item quantity="one">1 year</item>
    <item quantity="other"><xliff:g id="number">%d</xliff:g> years</item>
</plurals>

所以对于波兰语,我会:

<plurals name ="years">
    <item quantity="one">1 rok</item>
    <item quantity="other"><xliff:g id="number">%d</xliff:g> lat</item>
</plurals>

然后我会在我的代码上:

int n = getYears(...);
if (Locale.getDefault().getLanguage().equalsIgnoreCase("pl") && n >= 2 && n <= 4) {
   return getString(R.string.years_pl, n);
} else {
   return getResources().getQuantityString(R.plurals.years, n, n);
}

在波兰语语言环境的 strings.xml 文件中,我将添加缺少的字符串:

<string name="years_pl"><xliff:g id="number">%d</xliff:g> lata</string>

我的第二个解决方案有英语、西班牙语和其他没有太多复数变化的语言的复数元素。然后对于其他有这种变化的语言,我会使用 ChoiceFormat。所以在我的代码中:

...
private static final int LANG_PL = 0;
// add more languages here if needed
...
String formats[] = {
"{0,number} {0,choice,1#" + getString(R.string.year_1) + "|2#" + getString(R.string.years_2_4) +  "|4<" + getString(R.string.years_lots) +"}", // polish
// more to come
};
...
// Here I would add more for certain languages
    if (Locale.getDefault().getLanguage().equalsIgnoreCase("pl")) {
       return MessageFormat.format(formats[LANG_PL], n);
    } else {
       return getResources().getQuantityString(R.plurals.years, n, n);
    }

我不知道这些方法是否是最好的方法,但就目前而言,或者在 Google 做出更好的东西之前,这对我有用。

【讨论】:

  • 我真的不明白你为什么要麻烦混合复数和MessageFormat?如果我是你,我要么试着弄清楚如何只用复数正确地做到这一点,要么我会完全放弃复数,只为所有语言选择 MessageFormat - 说像 MessageFormat.format(getString(R.string.year_format), n) 这样的东西似乎比你现在拥有什么。
  • 是的,我认为你是对的,我将只使用 MessageFormat。我只是不想扔掉复数代码。我不能只使用复数形式(这将是最好的)。感谢您的帮助:)
  • 不要使用复数。他们被窃听了。 stackoverflow.com/questions/5651902/…
【解决方案3】:

有一个内置的“复数”支持,没有很好的文档记录。
提到here,你可以在Browser sources看到它。

【讨论】:

  • 谢谢,我想这就是我需要的!你知道使用 xliff 和不使用 xliff 的区别吗?在其中一个链接中,他们使用:%s thing 在另一个链接中,他们使用:%d 个匹配
  • 在尝试这个之后,它似乎不支持像 之类的东西(我需要这个,因为在波兰语中,从 2 到 4 的数量的复数与其他数量不同)。有什么方法可以实现吗?
  • 我自己没有用这个,你需要搜索Android源代码。
  • 正如我在之前的评论中已经说过的,不要使用复数,它们不支持“零”。
【解决方案4】:

请注意,我没有任何特定于 android 的经验...但我通常选择为我要支持的每种语言提供单独的视图文件,这允许比单独的语言更广泛的本地化,您现在也可以拥有如果您知道其他语言的文本可能需要稍微改变布局,例如更宽的按钮,甚至不同的图像。

【讨论】:

  • 使用 Android 可以做到这一点。您如何处理需要在运行时设置的字符串?
  • 我在运行时需要做的事情相当有限,但我通过一些我自己的类方法使用“普通”i18n 表,例如String::stringWithLocalizedString('Good {timeofday} {username}'),这样可以与格式化函数一起使用。
猜你喜欢
  • 2018-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多