mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-12994 Have C++ ListFormatter use ures_getAllItemsWithFallback to load resources; add tests for C and J
X-SVN-Rev: 39926
This commit is contained in:
parent
77416a6e7c
commit
9711357617
6 changed files with 170 additions and 33 deletions
|
@ -25,6 +25,7 @@
|
|||
#include "charstr.h"
|
||||
#include "ucln_cmn.h"
|
||||
#include "uresimp.h"
|
||||
#include "resource.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -78,17 +79,6 @@ uprv_deleteListFormatInternal(void *obj) {
|
|||
|
||||
U_CDECL_END
|
||||
|
||||
static ListFormatInternal* loadListFormatInternal(
|
||||
const Locale& locale,
|
||||
const char* style,
|
||||
UErrorCode& errorCode);
|
||||
|
||||
static void getStringByKey(
|
||||
const UResourceBundle* rb,
|
||||
const char* key,
|
||||
UnicodeString& result,
|
||||
UErrorCode& errorCode);
|
||||
|
||||
ListFormatter::ListFormatter(const ListFormatter& other) :
|
||||
owned(other.owned), data(other.data) {
|
||||
if (other.owned != NULL) {
|
||||
|
@ -171,30 +161,100 @@ const ListFormatInternal* ListFormatter::getListFormatInternal(
|
|||
return result;
|
||||
}
|
||||
|
||||
static ListFormatInternal* loadListFormatInternal(
|
||||
static const UChar solidus = 0x2F;
|
||||
static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
|
||||
enum {
|
||||
kAliasPrefixLen = UPRV_LENGTHOF(aliasPrefix),
|
||||
kStyleLenMax = 24 // longest currently is 14
|
||||
};
|
||||
|
||||
struct ListFormatter::ListPatternsSink : public ResourceSink {
|
||||
UnicodeString two, start, middle, end;
|
||||
char aliasedStyle[kStyleLenMax+1] = {0};
|
||||
|
||||
ListPatternsSink() {}
|
||||
virtual ~ListPatternsSink();
|
||||
|
||||
void setAliasedStyle(UnicodeString alias) {
|
||||
int32_t startIndex = alias.indexOf(aliasPrefix, kAliasPrefixLen, 0);
|
||||
if (startIndex < 0) {
|
||||
return;
|
||||
}
|
||||
startIndex += kAliasPrefixLen;
|
||||
int32_t endIndex = alias.indexOf(solidus, startIndex);
|
||||
if (endIndex < 0) {
|
||||
endIndex = alias.length();
|
||||
}
|
||||
alias.extract(startIndex, endIndex-startIndex, aliasedStyle, kStyleLenMax+1, US_INV);
|
||||
aliasedStyle[kStyleLenMax] = 0;
|
||||
}
|
||||
|
||||
void handleValueForPattern(ResourceValue &value, UnicodeString &pattern, UErrorCode &errorCode) {
|
||||
if (pattern.isEmpty()) {
|
||||
if (value.getType() == URES_ALIAS) {
|
||||
if (aliasedStyle[0] == 0) {
|
||||
setAliasedStyle(value.getAliasUnicodeString(errorCode));
|
||||
}
|
||||
} else {
|
||||
pattern = value.getUnicodeString(errorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
|
||||
UErrorCode &errorCode) {
|
||||
aliasedStyle[0] = 0;
|
||||
if (value.getType() == URES_ALIAS) {
|
||||
setAliasedStyle(value.getAliasUnicodeString(errorCode));
|
||||
return;
|
||||
}
|
||||
ResourceTable listPatterns = value.getTable(errorCode);
|
||||
for (int i = 0; U_SUCCESS(errorCode) && listPatterns.getKeyAndValue(i, key, value); ++i) {
|
||||
if (uprv_strcmp(key, "2") == 0) {
|
||||
handleValueForPattern(value, two, errorCode);
|
||||
} else if (uprv_strcmp(key, "end") == 0) {
|
||||
handleValueForPattern(value, end, errorCode);
|
||||
} else if (uprv_strcmp(key, "middle") == 0) {
|
||||
handleValueForPattern(value, middle, errorCode);
|
||||
} else if (uprv_strcmp(key, "start") == 0) {
|
||||
handleValueForPattern(value, start, errorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Virtual destructors must be defined out of line.
|
||||
ListFormatter::ListPatternsSink::~ListPatternsSink() {}
|
||||
|
||||
ListFormatInternal* ListFormatter::loadListFormatInternal(
|
||||
const Locale& locale, const char * style, UErrorCode& errorCode) {
|
||||
UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
ures_close(rb);
|
||||
return NULL;
|
||||
}
|
||||
rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
|
||||
rb = ures_getByKeyWithFallback(rb, style, rb, &errorCode);
|
||||
|
||||
if (U_FAILURE(errorCode)) {
|
||||
ures_close(rb);
|
||||
return NULL;
|
||||
}
|
||||
UnicodeString two, start, middle, end;
|
||||
getStringByKey(rb, "2", two, errorCode);
|
||||
getStringByKey(rb, "start", start, errorCode);
|
||||
getStringByKey(rb, "middle", middle, errorCode);
|
||||
getStringByKey(rb, "end", end, errorCode);
|
||||
ListFormatter::ListPatternsSink sink;
|
||||
char currentStyle[kStyleLenMax+1];
|
||||
uprv_strncpy(currentStyle, style, kStyleLenMax);
|
||||
currentStyle[kStyleLenMax] = 0;
|
||||
|
||||
for (;;) {
|
||||
ures_getAllItemsWithFallback(rb, currentStyle, sink, errorCode);
|
||||
if (U_FAILURE(errorCode) || sink.aliasedStyle[0] == 0 || uprv_strcmp(currentStyle, sink.aliasedStyle) == 0) {
|
||||
break;
|
||||
}
|
||||
uprv_strcpy(currentStyle, sink.aliasedStyle);
|
||||
}
|
||||
ures_close(rb);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
}
|
||||
ListFormatInternal* result = new ListFormatInternal(two, start, middle, end, errorCode);
|
||||
if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
|
||||
errorCode = U_MISSING_RESOURCE_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, errorCode);
|
||||
if (result == NULL) {
|
||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
|
@ -206,15 +266,6 @@ static ListFormatInternal* loadListFormatInternal(
|
|||
return result;
|
||||
}
|
||||
|
||||
static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode) {
|
||||
int32_t len;
|
||||
const UChar* ustr = ures_getStringByKeyWithFallback(rb, key, &len, &errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return;
|
||||
}
|
||||
result.setTo(ustr, len);
|
||||
}
|
||||
|
||||
ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
|
||||
Locale locale; // The default locale.
|
||||
return createInstance(locale, errorCode);
|
||||
|
|
|
@ -157,6 +157,8 @@ class U_COMMON_API ListFormatter : public UObject{
|
|||
private:
|
||||
static void initializeHash(UErrorCode& errorCode);
|
||||
static const ListFormatInternal* getListFormatInternal(const Locale& locale, const char *style, UErrorCode& errorCode);
|
||||
struct ListPatternsSink;
|
||||
static ListFormatInternal* loadListFormatInternal(const Locale& locale, const char* style, UErrorCode& errorCode);
|
||||
|
||||
ListFormatter();
|
||||
|
||||
|
|
|
@ -147,6 +147,48 @@ void ListFormatterTest::TestEnglishUS() {
|
|||
CheckFourCases("en_US", one, two, three, four, results);
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
// has only partial data for the listPattern element (overriding
|
||||
// some of the parent data). #12994
|
||||
void ListFormatterTest::TestEnglishGB() {
|
||||
UnicodeString results[4] = {
|
||||
one,
|
||||
one + " and " + two,
|
||||
one + ", " + two + " and " + three,
|
||||
one + ", " + two + ", " + three + " and " + four
|
||||
};
|
||||
|
||||
CheckFourCases("en_GB", one, two, three, four, results);
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
// has only partial data for the listPattern element (overriding
|
||||
// some of the parent data). #12994
|
||||
void ListFormatterTest::TestNynorsk() {
|
||||
UnicodeString results[4] = {
|
||||
one,
|
||||
one + " og " + two,
|
||||
one + ", " + two + " og " + three,
|
||||
one + ", " + two + ", " + three + " og " + four
|
||||
};
|
||||
|
||||
CheckFourCases("nn", one, two, three, four, results);
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
// has only partial data for the listPattern element (overriding
|
||||
// some of the parent data). #12994
|
||||
void ListFormatterTest::TestChineseTradHK() {
|
||||
UnicodeString results[4] = {
|
||||
one,
|
||||
one + "\u53CA" + two,
|
||||
one + "\u3001" + two + "\u53CA" + three,
|
||||
one + "\u3001" + two + "\u3001" + three + "\u53CA" + four
|
||||
};
|
||||
|
||||
CheckFourCases("zh_Hant_HK", one, two, three, four, results);
|
||||
}
|
||||
|
||||
// Formatting in Russian.
|
||||
// "\\u0438" is used before the last element, and all elements up to (but not including) the penultimate are followed by a comma.
|
||||
void ListFormatterTest::TestRussian() {
|
||||
|
@ -229,6 +271,9 @@ void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
|
|||
case 6: name = "TestZulu"; if (exec) TestZulu(); break;
|
||||
case 7: name = "TestOutOfOrderPatterns"; if (exec) TestOutOfOrderPatterns(); break;
|
||||
case 8: name = "Test9946"; if (exec) Test9946(); break;
|
||||
case 9: name = "TestEnglishGB"; if (exec) TestEnglishGB(); break;
|
||||
case 10: name = "TestNynorsk"; if (exec) TestNynorsk(); break;
|
||||
case 11: name = "TestChineseTradHK"; if (exec) TestChineseTradHK(); break;
|
||||
|
||||
default: name = ""; break;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ class ListFormatterTest : public IntlTest {
|
|||
void TestBogus();
|
||||
void TestEnglish();
|
||||
void TestEnglishUS();
|
||||
void TestEnglishGB();
|
||||
void TestNynorsk();
|
||||
void TestChineseTradHK();
|
||||
void TestRussian();
|
||||
void TestMalayalam();
|
||||
void TestZulu();
|
||||
|
|
|
@ -1790,6 +1790,8 @@ void MeasureFormatTest::TestManyLocaleDurations() {
|
|||
helperTestManyLocaleDurations("de", UMEASFMT_WIDTH_NUMERIC, measures, UPRV_LENGTHOF(measures), "5:37");
|
||||
helperTestManyLocaleDurations("en", UMEASFMT_WIDTH_NARROW, measures, UPRV_LENGTHOF(measures), "5h 37m");
|
||||
helperTestManyLocaleDurations("en", UMEASFMT_WIDTH_NUMERIC, measures, UPRV_LENGTHOF(measures), "5:37");
|
||||
helperTestManyLocaleDurations("en_GB", UMEASFMT_WIDTH_NARROW, measures, UPRV_LENGTHOF(measures), "5h 37m");
|
||||
helperTestManyLocaleDurations("en_GB", UMEASFMT_WIDTH_NUMERIC, measures, UPRV_LENGTHOF(measures), "5:37");
|
||||
helperTestManyLocaleDurations("es", UMEASFMT_WIDTH_NARROW, measures, UPRV_LENGTHOF(measures), "5h 37min");
|
||||
helperTestManyLocaleDurations("es", UMEASFMT_WIDTH_NUMERIC, measures, UPRV_LENGTHOF(measures), "5:37");
|
||||
helperTestManyLocaleDurations("fi", UMEASFMT_WIDTH_NARROW, measures, UPRV_LENGTHOF(measures), "5t 37min");
|
||||
|
|
|
@ -53,6 +53,40 @@ public class ListFormatterTest extends TestFmwk {
|
|||
}
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
// has only partial data for the listPattern element (overriding
|
||||
// some of the parent data). #12994
|
||||
String[] EnglishGBTestData = {
|
||||
"",
|
||||
"A",
|
||||
"A and B",
|
||||
"A, B and C",
|
||||
"A, B, C and D",
|
||||
"A, B, C, D and E"
|
||||
};
|
||||
|
||||
@Test
|
||||
public void TestEnglishGB() {
|
||||
checkData(ListFormatter.getInstance(new ULocale("en_GB")), EnglishGBTestData);
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
// has only partial data for the listPattern element (overriding
|
||||
// some of the parent data). #12994
|
||||
String[] ChineseTradHKTestData = {
|
||||
"",
|
||||
"A",
|
||||
"A\u53CAB",
|
||||
"A\u3001B\u53CAC",
|
||||
"A\u3001B\u3001C\u53CAD",
|
||||
"A\u3001B\u3001C\u3001D\u53CAE"
|
||||
};
|
||||
|
||||
@Test
|
||||
public void TestChineseTradHK() {
|
||||
checkData(ListFormatter.getInstance(new ULocale("zh_Hant_HK")), ChineseTradHKTestData);
|
||||
}
|
||||
|
||||
String[] JapaneseTestData = {
|
||||
"",
|
||||
"A",
|
||||
|
|
Loading…
Add table
Reference in a new issue