如何在Java或Groovy中获取许多语言的数字的序数后缀

我正在构建一个多语言的grails网站,我需要获得英语,法语,西class牙语,德语和意大利语等多种语言序号后缀

我相信这个问题对于多语言网站所有者来说非常普遍。 我发现这篇文章提供了一个解决方案,但它只是英文版。

例如:

/** *@value number *@locale Current locale *@returns ordinal suffix for the given number **/ public static String getOrdinalFor(int value, Locale locale) 

将给出以下结果:

  assert getOrdinalFor(1, Locale.ENGLISH) == "st" assert getOrdinalFor(1, Locale.FRENCH) == "er" assert getOrdinalFor(2, Locale.ENGLISH) == "nd" assert getOrdinalFor(3, Locale.ENGLISH) == "rd" assert getOrdinalFor(4, Locale.ENGLISH) == "th" assert getOrdinalFor(4, Locale.FRENCH) == "ème" 

你知道一个可以帮助这个的库(Java或Groovy)吗? 或者您知道实现它的算法吗?

我认为在许多语言中这种方法是不可能的,因为它们根本没有可用由一些字母作为扩展的数字组成的序数概念。 对于“1st”即德语,你只能写“1”。 或“erster”/“erste”/“erstes”取决于你编号的属。

除非您可以对每种语言应用规则,否则通常会尝试回避复杂的语言问题。 您不仅要考虑数字及其序数,还要考虑它出现的背景,甚至句子中的位置如何影响翻译。

而不是尝试写“第一名” ,这样的资源更容易翻译:

 #easyToTranslate_en.properties label.position=Position: {0,number,integer} 

根据您尝试做的事情,您可以使用以下解决方案妥协:

 #compromise_en.properties label.position.first=1st place label.position.second=2nd place label.position.third=3rd place label.position.default=Position: {0,number,integer} 

这将需要读取资源的代码执行案例测试以选择要加载的资源。

 int index = 2; ChoiceFormat choiceFormat = new ChoiceFormat("1#st | 2#nd | 3#rd | 20 

输出=='第二'但我正在尝试编写一个规则,确保数字21-> 23,31-> 33等也能正常工作。 有人知道如何使用传递给ChoiceFormat的模式吗?

我不知道任何库,但最好的算法可能是在Map>获取所有可能的数字/语言环境/序数。

 private static Map> ordinals = new HashMap>(); static { Map ordinal1 = new HashMap(); ordinal1.put(Locale.ENGLISH, "st"); ordinal1.put(Locale.FRENCH, "er"); ordinals.put(1, ordinal1); Map ordinal2 = new HashMap(); ordinal2.put(Locale.ENGLISH, "nd"); ordinals.put(2, ordinal2); Map ordinal3 = new HashMap(); ordinal3.put(Locale.ENGLISH, "rd"); ordinals.put(3, ordinal3); Map ordinal4 = new HashMap(); ordinal4.put(Locale.ENGLISH, "th"); ordinal4.put(Locale.FRENCH, "ème"); ordinals.put(4, ordinal4); } 

然后getOrdinalFor()基本上看起来像(明显的运行时error handling):

 public static String getOrdinalFor(int value, Locale locale) { return ordinals.get(value).get(locale); } 

对于地图未涵盖的其他数字,您可以考虑倒数,直到在地图中找到匹配为止(因此请求例如5或更高的序数将返回4的序数(倒计时的第一个下一个匹配) ):

 public static String getOrdinalFor(int value, Locale locale) { Map ordinal = null; for (int i = value; i > 0 && (ordinal == null || !ordinal.containsKey(locale)); i--) { ordinal = ordinals.get(i); } return ordinal != null ? ordinal.get(locale) : null; // Or other default? }