484c465ddf
X-SVN-Rev: 32247
330 lines
14 KiB
C++
330 lines
14 KiB
C++
/*
|
|
*******************************************************************************
|
|
*
|
|
* Copyright (C) 2012, International Business Machines
|
|
* Corporation and others. All Rights Reserved.
|
|
*
|
|
*******************************************************************************
|
|
* file name: listformatter.cpp
|
|
* encoding: US-ASCII
|
|
* tab size: 8 (not used)
|
|
* indentation:4
|
|
*
|
|
* created on: 2012aug27
|
|
* created by: Umesh P. Nair
|
|
*/
|
|
|
|
#include "unicode/listformatter.h"
|
|
#include "mutex.h"
|
|
#include "hash.h"
|
|
#include "cstring.h"
|
|
#include "ulocimp.h"
|
|
#include "charstr.h"
|
|
#include "ucln_cmn.h"
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
struct ListFormatData : public UMemory {
|
|
UnicodeString twoPattern;
|
|
UnicodeString startPattern;
|
|
UnicodeString middlePattern;
|
|
UnicodeString endPattern;
|
|
};
|
|
|
|
static Hashtable* listPatternHash = NULL;
|
|
static UMTX listFormatterMutex = NULL;
|
|
static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d }; // "{0}"
|
|
static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d }; // "{0}"
|
|
|
|
U_CDECL_BEGIN
|
|
static UBool U_CALLCONV uprv_listformatter_cleanup() {
|
|
delete listPatternHash;
|
|
listPatternHash = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
static void U_CALLCONV
|
|
uprv_deleteListFormatData(void *obj) {
|
|
delete static_cast<ListFormatData *>(obj);
|
|
}
|
|
|
|
U_CDECL_END
|
|
|
|
void ListFormatter::initializeHash(UErrorCode& errorCode) {
|
|
if (U_FAILURE(errorCode)) {
|
|
return;
|
|
}
|
|
|
|
listPatternHash = new Hashtable();
|
|
if (listPatternHash == NULL) {
|
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
|
|
listPatternHash->setValueDeleter(uprv_deleteListFormatData);
|
|
ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup);
|
|
|
|
addDataToHash("af", "{0} en {1}", "{0}, {1}", "{0}, {1}", "{0} en {1}", errorCode);
|
|
addDataToHash("am", "{0} \\u12a5\\u1293 {1}", "{0}, {1}", "{0}, {1}", "{0}, \\u12a5\\u1293 {1}", errorCode);
|
|
addDataToHash("ar", "{0} \\u0648 {1}", "{0}\\u060c {1}", "{0}\\u060c {1}", "{0}\\u060c \\u0648 {1}", errorCode);
|
|
addDataToHash("bg", "{0} \\u0438 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0438 {1}", errorCode);
|
|
addDataToHash("bn", "{0} \\u098f\\u09ac\\u0982 {1}", "{0}, {1}", "{0}, {1}", "{0}, \\u098f\\u09ac\\u0982 {1}", errorCode);
|
|
addDataToHash("bs", "{0} i {1}", "{0}, {1}", "{0}, {1}", "{0} i {1}", errorCode);
|
|
addDataToHash("ca", "{0} i {1}", "{0}, {1}", "{0}, {1}", "{0} i {1}", errorCode);
|
|
addDataToHash("cs", "{0} a {1}", "{0}, {1}", "{0}, {1}", "{0} a {1}", errorCode);
|
|
addDataToHash("da", "{0} og {1}", "{0}, {1}", "{0}, {1}", "{0} og {1}", errorCode);
|
|
addDataToHash("de", "{0} und {1}", "{0}, {1}", "{0}, {1}", "{0} und {1}", errorCode);
|
|
addDataToHash("ee", "{0} kple {1}", "{0}, {1}", "{0}, {1}", "{0}, kple {1}", errorCode);
|
|
addDataToHash("el", "{0} \\u03ba\\u03b1\\u03b9 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u03ba\\u03b1\\u03b9 {1}", errorCode);
|
|
addDataToHash("en", "{0} and {1}", "{0}, {1}", "{0}, {1}", "{0}, and {1}", errorCode);
|
|
addDataToHash("es", "{0} y {1}", "{0}, {1}", "{0}, {1}", "{0} y {1}", errorCode);
|
|
addDataToHash("et", "{0} ja {1}", "{0}, {1}", "{0}, {1}", "{0} ja {1}", errorCode);
|
|
addDataToHash("eu", "{0} eta {1}", "{0}, {1}", "{0}, {1}", "{0} eta {1}", errorCode);
|
|
addDataToHash("fa", "{0} \\u0648 {1}", "{0}\\u060c\\u200f {1}", "{0}\\u060c\\u200f {1}", "{0}\\u060c \\u0648 {1}", errorCode);
|
|
addDataToHash("fi", "{0} ja {1}", "{0}, {1}", "{0}, {1}", "{0} ja {1}", errorCode);
|
|
addDataToHash("fil", "{0} at {1}", "{0}, {1}", "{0}, {1}", "{0} at {1}", errorCode);
|
|
addDataToHash("fo", "{0} og {1}", "{0}, {1}", "{0}, {1}", "{0} og {1}", errorCode);
|
|
addDataToHash("fr", "{0} et {1}", "{0}, {1}", "{0}, {1}", "{0} et {1}", errorCode);
|
|
addDataToHash("fur", "{0} e {1}", "{0}, {1}", "{0}, {1}", "{0} e {1}", errorCode);
|
|
addDataToHash("gd", "{0} agus {1}", "{0}, {1}", "{0}, {1}", "{0}, agus {1}", errorCode);
|
|
addDataToHash("gl", "{0} e {1}", "{0}, {1}", "{0}, {1}", "{0} e {1}", errorCode);
|
|
addDataToHash("gsw", "{0} und {1}", "{0}, {1}", "{0}, {1}", "{0} und {1}", errorCode);
|
|
addDataToHash("gu", "{0} \\u0a85\\u0aa8\\u0ac7 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0a85\\u0aa8\\u0ac7 {1}", errorCode);
|
|
addDataToHash("he", "{0} \\u05d5-{1}", "{0}, {1}", "{0}, {1}", "{0} \\u05d5-{1}", errorCode);
|
|
addDataToHash("hi", "{0} \\u0914\\u0930 {1}", "{0}, {1}", "{0}, {1}", "{0}, \\u0914\\u0930 {1}", errorCode);
|
|
addDataToHash("hr", "{0} i {1}", "{0}, {1}", "{0}, {1}", "{0} i {1}", errorCode);
|
|
addDataToHash("hu", "{0} \\u00e9s {1}", "{0}, {1}", "{0}, {1}", "{0} \\u00e9s {1}", errorCode);
|
|
addDataToHash("id", "{0} dan {1}", "{0}, {1}", "{0}, {1}", "{0}, dan {1}", errorCode);
|
|
addDataToHash("is", "{0} og {1}", "{0}, {1}", "{0}, {1}", "{0} og {1}", errorCode);
|
|
addDataToHash("it", "{0} e {1}", "{0}, {1}", "{0}, {1}", "{0}, e {1}", errorCode);
|
|
addDataToHash("ja", "{0}\\u3001{1}", "{0}\\u3001{1}", "{0}\\u3001{1}", "{0}\\u3001{1}", errorCode);
|
|
addDataToHash("ka", "{0} \\u10d3\\u10d0 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u10d3\\u10d0 {1}", errorCode);
|
|
addDataToHash("kea", "{0} y {1}", "{0}, {1}", "{0}, {1}", "{0} y {1}", errorCode);
|
|
addDataToHash("kl", "{0} aamma {1}", "{0} aamma {1}", "{0}, {1}", "{0}, {1}", errorCode);
|
|
addDataToHash("kn", "{0} \\u0cae\\u0ca4\\u0ccd\\u0ca4\\u0cc1 {1}", "{0}, {1}", "{0}, {1}",
|
|
"{0}, \\u0cae\\u0ca4\\u0ccd\\u0ca4\\u0cc1 {1}", errorCode);
|
|
addDataToHash("ko", "{0} \\ubc0f {1}", "{0}, {1}", "{0}, {1}", "{0} \\ubc0f {1}", errorCode);
|
|
addDataToHash("ksh", "{0} un {1}", "{0}, {1}", "{0}, {1}", "{0} un {1}", errorCode);
|
|
addDataToHash("lt", "{0} ir {1}", "{0}, {1}", "{0}, {1}", "{0} ir {1}", errorCode);
|
|
addDataToHash("lv", "{0} un {1}", "{0}, {1}", "{0}, {1}", "{0} un {1}", errorCode);
|
|
addDataToHash("ml", "{0} \\u0d15\\u0d42\\u0d1f\\u0d3e\\u0d24\\u0d46 {1}", "{0}, {1}", "{0}, {1}",
|
|
"{0}, {1} \\u0d0e\\u0d28\\u0d4d\\u0d28\\u0d3f\\u0d35", errorCode);
|
|
addDataToHash("mr", "{0} \\u0906\\u0923\\u093f {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0906\\u0923\\u093f {1}", errorCode);
|
|
addDataToHash("ms", "{0} dan {1}", "{0}, {1}", "{0}, {1}", "{0}, dan {1}", errorCode);
|
|
addDataToHash("nb", "{0} og {1}", "{0}, {1}", "{0}, {1}", "{0} og {1}", errorCode);
|
|
addDataToHash("nl", "{0} en {1}", "{0}, {1}", "{0}, {1}", "{0} en {1}", errorCode);
|
|
addDataToHash("nn", "{0} og {1}", "{0}, {1}", "{0}, {1}", "{0} og {1}", errorCode);
|
|
addDataToHash("pl", "{0} i {1}", "{0}; {1}", "{0}; {1}", "{0} i {1}", errorCode);
|
|
addDataToHash("pt", "{0} e {1}", "{0}, {1}", "{0}, {1}", "{0} e {1}", errorCode);
|
|
addDataToHash("ro", "{0} \\u015fi {1}", "{0}, {1}", "{0}, {1}", "{0} \\u015fi {1}", errorCode);
|
|
addDataToHash("", "{0}, {1}", "{0}, {1}", "{0}, {1}", "{0}, {1}", errorCode); // root
|
|
addDataToHash("ru", "{0} \\u0438 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0438 {1}", errorCode);
|
|
addDataToHash("se", "{0} ja {1}", "{0}, {1}", "{0}, {1}", "{0} ja {1}", errorCode);
|
|
addDataToHash("sk", "{0} a {1}", "{0}, {1}", "{0}, {1}", "{0} a {1}", errorCode);
|
|
addDataToHash("sl", "{0} in {1}", "{0}, {1}", "{0}, {1}", "{0} in {1}", errorCode);
|
|
addDataToHash("sr", "{0} \\u0438 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0438 {1}", errorCode);
|
|
addDataToHash("sr_Cyrl", "{0} \\u0438 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0438 {1}", errorCode);
|
|
addDataToHash("sr_Latn", "{0} i {1}", "{0}, {1}", "{0}, {1}", "{0} i {1}", errorCode);
|
|
addDataToHash("sv", "{0} och {1}", "{0}, {1}", "{0}, {1}", "{0} och {1}", errorCode);
|
|
addDataToHash("sw", "{0} na {1}", "{0}, {1}", "{0}, {1}", "{0}, na {1}", errorCode);
|
|
addDataToHash("ta", "{0} \\u0bae\\u0bb1\\u0bcd\\u0bb1\\u0bc1\\u0bae\\u0bcd {1}", "{0}, {1}", "{0}, {1}",
|
|
"{0} \\u0bae\\u0bb1\\u0bcd\\u0bb1\\u0bc1\\u0bae\\u0bcd {1}", errorCode);
|
|
addDataToHash("te", "{0} \\u0c2e\\u0c30\\u0c3f\\u0c2f\\u0c41 {1}", "{0}, {1}", "{0}, {1}",
|
|
"{0} \\u0c2e\\u0c30\\u0c3f\\u0c2f\\u0c41 {1}", errorCode);
|
|
addDataToHash("th", "{0}\\u0e41\\u0e25\\u0e30{1}", "{0} {1}", "{0} {1}", "{0} \\u0e41\\u0e25\\u0e30{1}", errorCode);
|
|
addDataToHash("tr", "{0} ve {1}", "{0}, {1}", "{0}, {1}", "{0} ve {1}", errorCode);
|
|
addDataToHash("uk", "{0} \\u0442\\u0430 {1}", "{0}, {1}", "{0}, {1}", "{0} \\u0442\\u0430 {1}", errorCode);
|
|
addDataToHash("ur", "{0} \\u0627\\u0648\\u0631 {1}", "{0}\\u060c {1}", "{0}\\u060c {1}",
|
|
"{0}\\u060c \\u0627\\u0648\\u0631 {1}", errorCode);
|
|
addDataToHash("vi", "{0} v\\u00e0 {1}", "{0}, {1}", "{0}, {1}", "{0} v\\u00e0 {1}", errorCode);
|
|
addDataToHash("wae", "{0} und {1}", "{0}, {1}", "{0}, {1}", "{0} und {1}", errorCode);
|
|
addDataToHash("zh", "{0}\\u548c{1}", "{0}\\u3001{1}", "{0}\\u3001{1}", "{0}\\u548c{1}", errorCode);
|
|
addDataToHash("zu", "I-{0} ne-{1}", "{0}, {1}", "{0}, {1}", "{0}, no-{1}", errorCode);
|
|
}
|
|
|
|
void ListFormatter::addDataToHash(
|
|
const char* locale,
|
|
const char* two,
|
|
const char* start,
|
|
const char* middle,
|
|
const char* end,
|
|
UErrorCode& errorCode) {
|
|
if (U_FAILURE(errorCode)) {
|
|
return;
|
|
}
|
|
UnicodeString key(locale, -1, US_INV);
|
|
ListFormatData* value = new ListFormatData();
|
|
if (value == NULL) {
|
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
value->twoPattern = UnicodeString(two, -1, US_INV).unescape();
|
|
value->startPattern = UnicodeString(start, -1, US_INV).unescape();
|
|
value->middlePattern = UnicodeString(middle, -1, US_INV).unescape();
|
|
value->endPattern = UnicodeString(end, -1, US_INV).unescape();
|
|
listPatternHash->put(key, value, errorCode);
|
|
}
|
|
|
|
const ListFormatData* ListFormatter::getListFormatData(
|
|
const Locale& locale, UErrorCode& errorCode) {
|
|
{
|
|
Mutex m(&listFormatterMutex);
|
|
if (listPatternHash == NULL) {
|
|
initializeHash(errorCode);
|
|
if (U_FAILURE(errorCode)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
UnicodeString key(locale.getName(), -1, US_INV);
|
|
return static_cast<const ListFormatData*>(listPatternHash->get(key));
|
|
}
|
|
|
|
ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
|
|
Locale locale; // The default locale.
|
|
return createInstance(locale, errorCode);
|
|
}
|
|
|
|
ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
|
|
Locale tempLocale = locale;
|
|
for (;;) {
|
|
const ListFormatData* listFormatData = getListFormatData(tempLocale, errorCode);
|
|
if (U_FAILURE(errorCode)) {
|
|
return NULL;
|
|
}
|
|
if (listFormatData != NULL) {
|
|
ListFormatter* p = new ListFormatter(tempLocale, listFormatData);
|
|
if (p == NULL) {
|
|
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
|
return NULL;
|
|
}
|
|
return p;
|
|
}
|
|
errorCode = U_ZERO_ERROR;
|
|
Locale correctLocale;
|
|
getFallbackLocale(tempLocale, correctLocale, errorCode);
|
|
if (U_FAILURE(errorCode)) {
|
|
return NULL;
|
|
}
|
|
if (correctLocale.isBogus()) {
|
|
return createInstance(Locale::getRoot(), errorCode);
|
|
}
|
|
tempLocale = correctLocale;
|
|
}
|
|
}
|
|
|
|
ListFormatter::ListFormatter(const Locale& listFormatterLocale, const ListFormatData* listFormatterData)
|
|
: locale(listFormatterLocale), data(listFormatterData) {
|
|
}
|
|
|
|
ListFormatter::~ListFormatter() {}
|
|
|
|
void ListFormatter::getFallbackLocale(const Locale& in, Locale& out, UErrorCode& errorCode) {
|
|
if (uprv_strcmp(in.getName(), "zh_TW") == 0) {
|
|
out = Locale::getTraditionalChinese();
|
|
} else {
|
|
const char* localeString = in.getName();
|
|
const char* extStart = locale_getKeywordsStart(localeString);
|
|
if (extStart == NULL) {
|
|
extStart = uprv_strchr(localeString, 0);
|
|
}
|
|
const char* last = extStart;
|
|
|
|
// TODO: Check whether uloc_getParent() will work here.
|
|
while (last > localeString && *(last - 1) != '_') {
|
|
--last;
|
|
}
|
|
|
|
// Truncate empty segment.
|
|
while (last > localeString) {
|
|
if (*(last-1) != '_') {
|
|
break;
|
|
}
|
|
--last;
|
|
}
|
|
|
|
size_t localePortionLen = last - localeString;
|
|
CharString fullLocale;
|
|
fullLocale.append(localeString, localePortionLen, errorCode).append(extStart, errorCode);
|
|
|
|
if (U_FAILURE(errorCode)) {
|
|
return;
|
|
}
|
|
out = Locale(fullLocale.data());
|
|
}
|
|
}
|
|
|
|
UnicodeString& ListFormatter::format(const UnicodeString items[], int32_t nItems,
|
|
UnicodeString& appendTo, UErrorCode& errorCode) const {
|
|
if (U_FAILURE(errorCode)) {
|
|
return appendTo;
|
|
}
|
|
|
|
if (nItems > 0) {
|
|
UnicodeString newString = items[0];
|
|
if (nItems == 2) {
|
|
addNewString(data->twoPattern, newString, items[1], errorCode);
|
|
} else if (nItems > 2) {
|
|
addNewString(data->startPattern, newString, items[1], errorCode);
|
|
int i;
|
|
for (i = 2; i < nItems - 1; ++i) {
|
|
addNewString(data->middlePattern, newString, items[i], errorCode);
|
|
}
|
|
addNewString(data->endPattern, newString, items[nItems - 1], errorCode);
|
|
}
|
|
if (U_SUCCESS(errorCode)) {
|
|
appendTo += newString;
|
|
}
|
|
}
|
|
return appendTo;
|
|
}
|
|
|
|
/**
|
|
* Joins originalString and nextString using the pattern pat and puts the result in
|
|
* originalString.
|
|
*/
|
|
void ListFormatter::addNewString(const UnicodeString& pat, UnicodeString& originalString,
|
|
const UnicodeString& nextString, UErrorCode& errorCode) const {
|
|
if (U_FAILURE(errorCode)) {
|
|
return;
|
|
}
|
|
|
|
int32_t p0Offset = pat.indexOf(FIRST_PARAMETER, 3, 0);
|
|
if (p0Offset < 0) {
|
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
|
return;
|
|
}
|
|
int32_t p1Offset = pat.indexOf(SECOND_PARAMETER, 3, 0);
|
|
if (p1Offset < 0) {
|
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
|
return;
|
|
}
|
|
|
|
int32_t i, j;
|
|
|
|
const UnicodeString* firstString;
|
|
const UnicodeString* secondString;
|
|
if (p0Offset < p1Offset) {
|
|
i = p0Offset;
|
|
j = p1Offset;
|
|
firstString = &originalString;
|
|
secondString = &nextString;
|
|
} else {
|
|
i = p1Offset;
|
|
j = p0Offset;
|
|
firstString = &nextString;
|
|
secondString = &originalString;
|
|
}
|
|
|
|
UnicodeString result = UnicodeString(pat, 0, i) + *firstString;
|
|
result += UnicodeString(pat, i+3, j-i-3);
|
|
result += *secondString;
|
|
result += UnicodeString(pat, j+3);
|
|
originalString = result;
|
|
}
|
|
|
|
UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(ListFormatter)
|
|
|
|
U_NAMESPACE_END
|