From 18b87b0965d22c0655b26b75a9fe32b468414bc1 Mon Sep 17 00:00:00 2001 From: Doug Felt Date: Thu, 14 Jan 2010 02:23:46 +0000 Subject: [PATCH] ICU-7342 add LocaleDisplayNames and rudimentary test. Fix Locale.getVariant problem and add test. X-SVN-Rev: 27258 --- icu4c/source/common/locid.cpp | 14 +- icu4c/source/common/uloc.c | 10 +- icu4c/source/common/ulocimp.h | 16 +- icu4c/source/common/unicode/locid.h | 14 +- icu4c/source/i18n/Makefile.in | 4 +- icu4c/source/i18n/i18n.vcproj | 44 ++ icu4c/source/i18n/locdspnm.cpp | 504 +++++++++++++++++++++ icu4c/source/i18n/unicode/locdspnm.h | 203 +++++++++ icu4c/source/test/intltest/Makefile.in | 4 +- icu4c/source/test/intltest/intltest.vcproj | 8 + icu4c/source/test/intltest/itformat.cpp | 4 +- icu4c/source/test/intltest/locnmtst.cpp | 102 +++++ icu4c/source/test/intltest/locnmtst.h | 28 ++ icu4c/source/test/intltest/loctest.cpp | 9 + icu4c/source/test/intltest/loctest.h | 2 + 15 files changed, 949 insertions(+), 17 deletions(-) create mode 100644 icu4c/source/i18n/locdspnm.cpp create mode 100644 icu4c/source/i18n/unicode/locdspnm.h create mode 100644 icu4c/source/test/intltest/locnmtst.cpp create mode 100644 icu4c/source/test/intltest/locnmtst.h diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp index b30c26961e..0ed81c2904 100644 --- a/icu4c/source/common/locid.cpp +++ b/icu4c/source/common/locid.cpp @@ -63,6 +63,7 @@ typedef enum ELocalePos { eUS, eCANADA, eCANADA_FRENCH, + eROOT, //eDEFAULT, @@ -498,7 +499,7 @@ Locale &Locale::operator=(const Locale &other) uprv_strcpy(script, other.script); uprv_strcpy(country, other.country); - /* The variantBegin is an offset into fullName, just copy it */ + /* The variantBegin is an offset, just copy it */ variantBegin = other.variantBegin; fIsBogus = other.fIsBogus; return *this; @@ -654,6 +655,10 @@ Locale::setToBogus() { uprv_free(fullName); fullName = fullNameBuffer; } + if(baseName && baseName != baseNameBuffer) { + uprv_free(baseName); + baseName = NULL; + } *fullNameBuffer = 0; *language = 0; *script = 0; @@ -1001,6 +1006,12 @@ void Locale::setFromPOSIXID(const char *posixID) init(posixID, TRUE); } +const Locale & U_EXPORT2 +Locale::getRoot(void) +{ + return getLocale(eROOT); +} + const Locale & U_EXPORT2 Locale::getEnglish(void) { @@ -1157,6 +1168,7 @@ Locale::getLocaleCache(void) if (tLocaleCache == NULL) { return NULL; } + tLocaleCache[eROOT] = Locale(""); tLocaleCache[eENGLISH] = Locale("en"); tLocaleCache[eFRENCH] = Locale("fr"); tLocaleCache[eGERMAN] = Locale("de"); diff --git a/icu4c/source/common/uloc.c b/icu4c/source/common/uloc.c index d525e0aad5..638b3074e8 100644 --- a/icu4c/source/common/uloc.c +++ b/icu4c/source/common/uloc.c @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 1997-2009, International Business Machines +* Copyright (C) 1997-2010, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * @@ -2116,8 +2116,8 @@ uloc_setDefault(const char* newDefaultLocale, * default locale because that would result in a mix of languages that is * unpredictable to the programmer and most likely useless. */ -static const UChar * -_res_getTableStringWithFallback(const char *path, const char *locale, +U_CAPI const UChar * U_EXPORT2 +uloc_getTableStringWithFallback(const char *path, const char *locale, const char *tableKey, const char *subTableKey, const char *itemKey, int32_t *pLength, @@ -2256,7 +2256,7 @@ _getStringOrCopyKey(const char *path, const char *locale, *pErrorCode = U_MISSING_RESOURCE_ERROR; } else { /* second-level item, use special fallback */ - s=_res_getTableStringWithFallback(path, locale, + s=uloc_getTableStringWithFallback(path, locale, tableKey, subTableKey, itemKey, @@ -2953,7 +2953,7 @@ _uloc_getOrientationHelper(const char* localeId, if (!U_FAILURE(*status)) { const UChar* const value = - _res_getTableStringWithFallback( + uloc_getTableStringWithFallback( NULL, localeBuffer, "layout", diff --git a/icu4c/source/common/ulocimp.h b/icu4c/source/common/ulocimp.h index a0ea6aa5fc..c397121194 100644 --- a/icu4c/source/common/ulocimp.h +++ b/icu4c/source/common/ulocimp.h @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 2004, International Business Machines +* Copyright (C) 2004-2010, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -21,4 +21,18 @@ U_CAPI UEnumeration* U_EXPORT2 uloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCode* status); +/** + * Look up a resource bundle table item with fallback on the table level. + * This is accessible so it can be called by C++ code. + */ +U_CAPI const UChar * U_EXPORT2 +uloc_getTableStringWithFallback( + const char *path, + const char *locale, + const char *tableKey, + const char *subTableKey, + const char *itemKey, + int32_t *pLength, + UErrorCode *pErrorCode); + #endif diff --git a/icu4c/source/common/unicode/locid.h b/icu4c/source/common/unicode/locid.h index 55656bfb2c..c7ddc936f9 100644 --- a/icu4c/source/common/unicode/locid.h +++ b/icu4c/source/common/unicode/locid.h @@ -180,6 +180,8 @@ U_NAMESPACE_BEGIN class U_COMMON_API Locale : public UObject { public: + /** Useful constant for the Root locale. @draft ICU 4.4 */ + static const Locale &U_EXPORT2 getRoot(void); /** Useful constant for this language. @stable ICU 2.0 */ static const Locale &U_EXPORT2 getEnglish(void); /** Useful constant for this language. @stable ICU 2.0 */ @@ -425,8 +427,9 @@ public: /** * Gets the list of keywords for the specified locale. * - * @return pointer to StringEnumeration class. Client must dispose of it by calling delete. - * @param status Returns any error information while performing this operation. + * @param status the status code + * @return pointer to StringEnumeration class, or NULL if there are no keywords. + * Client must dispose of it by calling delete. * @stable ICU 2.8 */ StringEnumeration * createKeywords(UErrorCode &status) const; @@ -435,10 +438,10 @@ public: * Get the value for a keyword. * * @param keywordName name of the keyword for which we want the value. Case insensitive. - * @param status Returns any error information while performing this operation. * @param buffer The buffer to receive the keyword value. * @param bufferCapacity The capacity of receiving buffer - * @return the length of keyword value + * @param status Returns any error information while performing this operation. + * @return the length of the keyword value * * @stable ICU 2.8 */ @@ -758,7 +761,8 @@ Locale::getScript() const inline const char * Locale::getVariant() const { - return &fullName[variantBegin]; + getBaseName(); // lazy init + return &baseName[variantBegin]; } inline const char * diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in index 4d0bc711f5..0e883416c5 100644 --- a/icu4c/source/i18n/Makefile.in +++ b/icu4c/source/i18n/Makefile.in @@ -1,6 +1,6 @@ #****************************************************************************** # -# Copyright (C) 1998-2009, International Business Machines +# Copyright (C) 1998-2010, International Business Machines # Corporation and others. All Rights Reserved. # #****************************************************************************** @@ -83,7 +83,7 @@ wintzimpl.o windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o v zonemeta.o zstrfmt.o plurrule.o plurfmt.o dtitvfmt.o dtitvinf.o \ tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o currpinf.o \ uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o \ -ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o +ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o ## Header files to install HEADERS = $(srcdir)/unicode/*.h diff --git a/icu4c/source/i18n/i18n.vcproj b/icu4c/source/i18n/i18n.vcproj index c5d221c846..7b579ef2fe 100644 --- a/icu4c/source/i18n/i18n.vcproj +++ b/icu4c/source/i18n/i18n.vcproj @@ -1918,6 +1918,50 @@ RelativePath=".\japancal.h" > + + + + + + + + + + + + + + + + diff --git a/icu4c/source/i18n/locdspnm.cpp b/icu4c/source/i18n/locdspnm.cpp new file mode 100644 index 0000000000..c2e44debb9 --- /dev/null +++ b/icu4c/source/i18n/locdspnm.cpp @@ -0,0 +1,504 @@ +/* +******************************************************************************* +* Copyright (C) 2010, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +*/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/locdspnm.h" + +#include "unicode/msgfmt.h" + +#include "cmemory.h" +#include "cstring.h" +#include "ulocimp.h" +#include "ureslocs.h" + +/** + * Concatenate a number of null-terminated strings to buffer, leaving a + * null-terminated string. The last argument should be the null pointer. + * Return the length of the string in the buffer, not counting the trailing + * null. Return -1 if there is an error (buffer is null, or buflen < 1). + */ +static int32_t ncat(char *buffer, uint32_t buflen, ...) { + va_list args; + char *str; + char *p = buffer; + const char* e = buffer + buflen - 1; + + if (buffer == NULL || buflen < 1) { + return -1; + } + + va_start(args, buflen); + while (str = va_arg(args, char *)) { + char c; + while (p != e && (c = *str++)) { + *p++ = c; + } + } + *p = 0; + va_end(args); + + return p - buffer; +} + +U_NAMESPACE_BEGIN + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Access resource data for locale components. +// Wrap code in uloc.c for now. +class ICUDataTable { + const char* path; + Locale locale; + +public: + ICUDataTable(const char* path, const Locale& locale); + ~ICUDataTable(); + + const Locale& getLocale(); + + UnicodeString& get(const char* tableKey, const char* itemKey, + UnicodeString& result) const; + UnicodeString& get(const char* tableKey, const char* subTableKey, const char* itemKey, + UnicodeString& result) const; + + UnicodeString& getNoFallback(const char* tableKey, const char* itemKey, + UnicodeString &result) const; + UnicodeString& getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey, + UnicodeString &result) const; +}; + +inline UnicodeString & +ICUDataTable::get(const char* tableKey, const char* itemKey, UnicodeString& result) const { + return get(tableKey, NULL, itemKey, result); +} + +inline UnicodeString & +ICUDataTable::getNoFallback(const char* tableKey, const char* itemKey, UnicodeString& result) const { + return getNoFallback(tableKey, NULL, itemKey, result); +} + +ICUDataTable::ICUDataTable(const char* path, const Locale& locale) + : path(NULL), locale(Locale::getRoot()) +{ + if (path) { + int32_t len = uprv_strlen(path); + this->path = (const char*) uprv_malloc(len + 1); + if (this->path) { + uprv_strcpy((char *)this->path, path); + this->locale = locale; + } + } +} + +ICUDataTable::~ICUDataTable() { + if (path) { + uprv_free((void*) path); + path = NULL; + } +} + +const Locale& +ICUDataTable::getLocale() { + return locale; +} + +UnicodeString & +ICUDataTable::get(const char* tableKey, const char* subTableKey, const char* itemKey, + UnicodeString &result) const { + UErrorCode status = U_ZERO_ERROR; + int32_t len = 0; + + const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(), + tableKey, subTableKey, itemKey, + &len, &status); + if (U_SUCCESS(status)) { + return result.setTo(s, len); + } + return result.setTo(UnicodeString(itemKey, -1, US_INV)); +} + +UnicodeString & +ICUDataTable::getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey, + UnicodeString& result) const { + UErrorCode status = U_ZERO_ERROR; + int32_t len = 0; + + const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(), + tableKey, subTableKey, itemKey, + &len, &status); + if (U_SUCCESS(status)) { + return result.setTo(s, len); + } + + result.setToBogus(); + return result; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class DefaultLocaleDisplayNames : public LocaleDisplayNames { + UDialectHandling dialectHandling; + +public: + // constructor + DefaultLocaleDisplayNames(UDialectHandling dialectHandling); + + virtual ~DefaultLocaleDisplayNames(); + + virtual const Locale& getLocale() const; + virtual UDialectHandling getDialectHandling() const; + virtual UnicodeString& localeDisplayName(const Locale& locale, + UnicodeString& result) const; + virtual UnicodeString& localeDisplayName(const char* localeId, + UnicodeString& result) const; + virtual UnicodeString& languageDisplayName(const char* lang, + UnicodeString& result) const; + virtual UnicodeString& scriptDisplayName(const char* script, + UnicodeString& result) const; + virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode, + UnicodeString& result) const; + virtual UnicodeString& regionDisplayName(const char* region, + UnicodeString& result) const; + virtual UnicodeString& variantDisplayName(const char* variant, + UnicodeString& result) const; + virtual UnicodeString& keyDisplayName(const char* key, + UnicodeString& result) const; + virtual UnicodeString& keyValueDisplayName(const char* key, + const char* value, + UnicodeString& result) const; +}; + +DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling) + : dialectHandling(dialectHandling) { +} + +DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() { +} + +const Locale& +DefaultLocaleDisplayNames::getLocale() const { + return Locale::getRoot(); +} + +UDialectHandling +DefaultLocaleDisplayNames::getDialectHandling() const { + return dialectHandling; +} + +UnicodeString& +DefaultLocaleDisplayNames::localeDisplayName(const Locale& locale, + UnicodeString& result) const { + return result.remove(); +} + +UnicodeString& +DefaultLocaleDisplayNames::localeDisplayName(const char* localeId, + UnicodeString& result) const { + return result.remove(); +} + +UnicodeString& +DefaultLocaleDisplayNames::languageDisplayName(const char* lang, + UnicodeString& result) const { + return result = UnicodeString(lang, -1, US_INV); +} + +UnicodeString& +DefaultLocaleDisplayNames::scriptDisplayName(const char* script, + UnicodeString& result) const { + return result = UnicodeString(script, -1, US_INV); +} + +UnicodeString& +DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode, + UnicodeString& result) const { + const char* name = uscript_getName(scriptCode); + if (name) { + return result = UnicodeString(name, -1, US_INV); + } + return result.remove(); +} + +UnicodeString& +DefaultLocaleDisplayNames::regionDisplayName(const char* region, + UnicodeString& result) const { + return result = UnicodeString(region, -1, US_INV); +} + +UnicodeString& +DefaultLocaleDisplayNames::variantDisplayName(const char* variant, + UnicodeString& result) const { + return result = UnicodeString(variant, -1, US_INV); +} + +UnicodeString& +DefaultLocaleDisplayNames::keyDisplayName(const char* key, + UnicodeString& result) const { + return result = UnicodeString(key, -1, US_INV); +} + +UnicodeString& +DefaultLocaleDisplayNames::keyValueDisplayName(const char* key, + const char* value, + UnicodeString& result) const { + return result = UnicodeString(value, -1, US_INV); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class LocaleDisplayNamesImpl : public LocaleDisplayNames { + Locale locale; + UDialectHandling dialectHandling; + ICUDataTable langData; + ICUDataTable regionData; + UnicodeString sep; + MessageFormat *format; + +public: + // constructor + LocaleDisplayNamesImpl(const Locale& locale, UDialectHandling dialectHandling); + virtual ~LocaleDisplayNamesImpl(); + + virtual const Locale& getLocale() const; + virtual UDialectHandling getDialectHandling() const; + + virtual UnicodeString& localeDisplayName(const Locale& locale, + UnicodeString& result) const; + virtual UnicodeString& localeDisplayName(const char* localeId, + UnicodeString& result) const; + virtual UnicodeString& languageDisplayName(const char* lang, + UnicodeString& result) const; + virtual UnicodeString& scriptDisplayName(const char* script, + UnicodeString& result) const; + virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode, + UnicodeString& result) const; + virtual UnicodeString& regionDisplayName(const char* region, + UnicodeString& result) const; + virtual UnicodeString& variantDisplayName(const char* variant, + UnicodeString& result) const; + virtual UnicodeString& keyDisplayName(const char* key, + UnicodeString& result) const; + virtual UnicodeString& keyValueDisplayName(const char* key, + const char* value, + UnicodeString& result) const; +private: + UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const; +}; + +LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale, + UDialectHandling dialectHandling) + : dialectHandling(dialectHandling) + , langData(U_ICUDATA_LANG, locale) + , regionData(U_ICUDATA_REGION, locale) +{ + LocaleDisplayNamesImpl *nonConstThis = (LocaleDisplayNamesImpl *)this; + nonConstThis->locale = langData.getLocale() == Locale::getRoot() + ? regionData.getLocale() + : langData.getLocale(); + + langData.getNoFallback("localeDisplayPattern", "separator", sep); + if (sep.isBogus()) { + sep = UnicodeString(", ", -1, US_INV); + } + + UnicodeString pattern; + langData.getNoFallback("localeDisplayPattern", "pattern", pattern); + if (pattern.isBogus()) { + pattern = UnicodeString("{0} ({1})", -1, US_INV); + } + UErrorCode status = U_ZERO_ERROR; + format = new MessageFormat(pattern, status); +} + +LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() { +} + +const Locale& +LocaleDisplayNamesImpl::getLocale() const { + return locale; +} + +UDialectHandling +LocaleDisplayNamesImpl::getDialectHandling() const { + return dialectHandling; +} + +UnicodeString& +LocaleDisplayNamesImpl::localeDisplayName(const Locale& locale, + UnicodeString& result) const { + UnicodeString resultName; + + const char* lang = locale.getLanguage(); + const char* script = locale.getScript(); + const char* country = locale.getCountry(); + const char* variant = locale.getVariant(); + + UBool hasLang = uprv_strlen(lang) > 0; + UBool hasScript = uprv_strlen(script) > 0; + UBool hasCountry = uprv_strlen(country) > 0; + UBool hasVariant = uprv_strlen(variant) > 0; + + if (hasLang) { + if (dialectHandling == ULDN_DIALECT_NAMES) { + char buffer[ULOC_FULLNAME_CAPACITY]; + do { // loop construct is so we can break early out of search + if (hasScript && hasCountry) { + ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0); + langData.getNoFallback("Languages", buffer, resultName); + if (!resultName.isBogus()) { + hasScript = FALSE; + hasCountry = FALSE; + break; + } + } + if (hasScript) { + ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0); + langData.getNoFallback("Languages", buffer, resultName); + if (!resultName.isBogus()) { + hasScript = FALSE; + break; + } + } + if (hasCountry) { + ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0); + langData.getNoFallback("Languages", buffer, resultName); + if (!resultName.isBogus()) { + hasCountry = FALSE; + break; + } + } + } while (FALSE); + } + + if (resultName.isBogus() || resultName.isEmpty()) { + langData.get("Languages", lang, resultName); + } + } + + if (TRUE) { /* not language only */ + UnicodeString resultRemainder; + UnicodeString temp; + StringEnumeration *e = NULL; + UErrorCode status = U_ZERO_ERROR; + + if (hasScript) { + resultRemainder.append(scriptDisplayName(script, temp)); + } + if (hasCountry) { + appendWithSep(resultRemainder, regionDisplayName(country, temp)); + } + if (hasVariant) { + appendWithSep(resultRemainder, variantDisplayName(variant, temp)); + } + + e = locale.createKeywords(status); + if (e && U_SUCCESS(status)) { + UnicodeString temp2; + char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; // sigh, no ULOC_VALUE_CAPACITY + const char* key; + while (key = e->next((int32_t *)0, status)) { + locale.getKeywordValue(key, value, ULOC_KEYWORD_AND_VALUES_CAPACITY, status); + appendWithSep(resultRemainder, keyDisplayName(key, temp)) + .append("=") + .append(keyValueDisplayName(key, value, temp2)); + } + delete e; + } + + if (!resultRemainder.isEmpty()) { + if (!resultName.isEmpty()) { + Formattable data[] = { + resultName, + resultRemainder + }; + FieldPosition fpos; + status = U_ZERO_ERROR; + format->format(data, 2, result, fpos, status); + return result; + } + + return result = resultRemainder; + } + } + + return result = resultName; +} + +UnicodeString& +LocaleDisplayNamesImpl::appendWithSep(UnicodeString& buffer, const UnicodeString& src) const { + if (!buffer.isEmpty()) { + buffer.append(sep); + } + buffer.append(src); + return buffer; +} + +UnicodeString& +LocaleDisplayNamesImpl::localeDisplayName(const char* localeId, + UnicodeString& result) const { + return localeDisplayName(Locale(localeId), result); +} + +UnicodeString& +LocaleDisplayNamesImpl::languageDisplayName(const char* lang, + UnicodeString& result) const { + return langData.get("Languages", lang, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::scriptDisplayName(const char* script, + UnicodeString& result) const { + return langData.get("Scripts", script, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode, + UnicodeString& result) const { + const char* name = uscript_getName(scriptCode); + return langData.get("Scripts", name, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::regionDisplayName(const char* region, + UnicodeString& result) const { + return regionData.get("Countries", region, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::variantDisplayName(const char* variant, + UnicodeString& result) const { + return langData.get("Variants", variant, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::keyDisplayName(const char* key, + UnicodeString& result) const { + return langData.get("Keys", key, result); +} + +UnicodeString& +LocaleDisplayNamesImpl::keyValueDisplayName(const char* key, + const char* value, + UnicodeString& result) const { + return langData.get("Types", key, value, result); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +LocaleDisplayNames* +LocaleDisplayNames::createInstance(const Locale& locale, + UDialectHandling dialectHandling) { + return new LocaleDisplayNamesImpl(locale, dialectHandling); +} + +U_NAMESPACE_END + +#endif diff --git a/icu4c/source/i18n/unicode/locdspnm.h b/icu4c/source/i18n/unicode/locdspnm.h new file mode 100644 index 0000000000..402cc0ccf8 --- /dev/null +++ b/icu4c/source/i18n/unicode/locdspnm.h @@ -0,0 +1,203 @@ +/* +****************************************************************************** +* Copyright (C) 2010, International Business Machines Corporation and * +* others. All Rights Reserved. * +****************************************************************************** +*/ + +#ifndef LOCDSPNM_H +#define LOCDSPNM_H + +#include "unicode/utypes.h" + +/** + * \file + * \brief C++ API: Provides display names of Locale and its components. + */ + + +/** + * Enum used in LocaleDisplayNames::createInstance. + * @draft ICU 4.4 + */ +typedef enum { + /** + * Use standard names when generating a locale name, + * e.g. en_GB displays as 'English (United Kingdom)'. + * @draft ICU 4.4 + */ + ULDN_STANDARD_NAMES = 0, + /** + * Use dialect names, when generating a locale name, + * e.g. en_GB displays as 'British English'. + * @draft ICU 4.4 + */ + ULDN_DIALECT_NAMES +} UDialectHandling; + + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/locid.h" +#include "unicode/uscript.h" + +U_NAMESPACE_BEGIN + +/** + * Returns display names of Locales and components of Locales. For + * more information on language, script, region, variant, key, and + * values, see Locale. + * @draft ICU 4.4 + */ +class U_I18N_API LocaleDisplayNames : public UMemory { +public: + /** + * Destructor. + * @draft ICU 4.4 + */ + virtual ~LocaleDisplayNames(); + + /** + * Convenience overload of {@link #createInstance(locale, + * UDialectHandling)} that specifies STANDARD dialect handling. + * @param locale the display locale + * @return a LocaleDisplayNames instance + * @draft ICU 4.4 + */ + static LocaleDisplayNames* U_EXPORT2 createInstance(const Locale& locale); + + /** + * Returns an instance of LocaleDisplayNames that returns names + * formatted for the provided locale, using the provided + * dialectHandling. + * + * @param locale the display locale + * @param dialectHandling how to select names for locales + * @return a LocaleDisplayNames instance + * @draft ICU 4.4 + */ + static LocaleDisplayNames* U_EXPORT2 createInstance(const Locale& locale, + UDialectHandling dialectHandling); + + // getters for state + /** + * Returns the locale used to determine the display names. This is + * not necessarily the same locale passed to {@link #getInstance}. + * @return the display locale + * @draft ICU 4.4 + */ + virtual const Locale& getLocale() const = 0; + + /** + * Returns the dialect handling used in the display names. + * @return the dialect handling enum + * @draft ICU 4.4 + */ + virtual UDialectHandling getDialectHandling() const = 0; + + // names for entire locales + /** + * Returns the display name of the provided locale. + * @param locale the locale whose display name to return + * @param result receives the locale's display name + * @return the display name of the provided locale + * @draft ICU 4.4 + */ + virtual UnicodeString& localeDisplayName(const Locale& locale, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided locale id. + * @param localeId the id of the locale whose display name to return + * @param result receives the locale's display name + * @return the display name of the provided locale + * @draft ICU 4.4 + */ + virtual UnicodeString& localeDisplayName(const char* localeId, + UnicodeString& result) const = 0; + + // names for components of a locale id + /** + * Returns the display name of the provided language code. + * @param lang the language code + * @param result receives the language code's display name + * @return the display name of the provided language code + * @draft ICU 4.4 + */ + virtual UnicodeString& languageDisplayName(const char* lang, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided script code. + * @param script the script code + * @param result receives the script code's display name + * @return the display name of the provided script code + * @draft ICU 4.4 + */ + virtual UnicodeString& scriptDisplayName(const char* script, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided script code. + * @param scriptCode the script code number + * @param result receives the script code's display name + * @return the display name of the provided script code + * @draft ICU 4.4 + */ + virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided region code. + * @param region the region code + * @param result receives the region code's display name + * @return the display name of the provided region code + * @draft ICU 4.4 + */ + virtual UnicodeString& regionDisplayName(const char* region, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided variant. + * @param variant the variant string + * @param result receives the variant's display name + * @return the display name of the provided variant + * @draft ICU 4.4 + */ + virtual UnicodeString& variantDisplayName(const char* variant, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided locale key. + * @param key the locale key name + * @param result receives the locale key's display name + * @return the display name of the provided locale key + * @draft ICU 4.4 + */ + virtual UnicodeString& keyDisplayName(const char* key, + UnicodeString& result) const = 0; + + /** + * Returns the display name of the provided value (used with the provided key). + * @param key the locale key name + * @param value the locale key's value + * @param result receives the value's display name + * @return the display name of the provided value + * @draft ICU 4.4 + */ + virtual UnicodeString& keyValueDisplayName(const char* key, const char* value, + UnicodeString& result) const = 0; +}; + +inline LocaleDisplayNames::~LocaleDisplayNames() { +} + +inline LocaleDisplayNames* LocaleDisplayNames::createInstance(const Locale& locale) { + return LocaleDisplayNames::createInstance(locale, ULDN_STANDARD_NAMES); +} + +U_NAMESPACE_END + +#endif + +#endif diff --git a/icu4c/source/test/intltest/Makefile.in b/icu4c/source/test/intltest/Makefile.in index 6d10d43bb2..6ac9a8412f 100644 --- a/icu4c/source/test/intltest/Makefile.in +++ b/icu4c/source/test/intltest/Makefile.in @@ -1,6 +1,6 @@ #****************************************************************************** # -# Copyright (C) 1999-2009, International Business Machines +# Copyright (C) 1999-2010, International Business Machines # Corporation and others. All Rights Reserved. # #****************************************************************************** @@ -57,7 +57,7 @@ itrbnf.o itrbnfrt.o itrbnfp.o ucaconf.o icusvtst.o \ uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o incaltst.o \ calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \ windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o ssearch.o dtifmtts.o \ -tufmtts.o itspoof.o simplethread.o bidiconf.o +tufmtts.o itspoof.o simplethread.o bidiconf.o locnmtst.o DEPS = $(OBJECTS:.o=.d) diff --git a/icu4c/source/test/intltest/intltest.vcproj b/icu4c/source/test/intltest/intltest.vcproj index ce9723d2ff..4865b44817 100644 --- a/icu4c/source/test/intltest/intltest.vcproj +++ b/icu4c/source/test/intltest/intltest.vcproj @@ -947,6 +947,14 @@ RelativePath=".\itrbnfrt.h" > + + + + diff --git a/icu4c/source/test/intltest/itformat.cpp b/icu4c/source/test/intltest/itformat.cpp index 7a7d7564c0..45676ef048 100644 --- a/icu4c/source/test/intltest/itformat.cpp +++ b/icu4c/source/test/intltest/itformat.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2009, International Business Machines + * Copyright (c) 1997-2010, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************/ @@ -52,6 +52,7 @@ #include "plurfmts.h" // PluralFormatTest #include "dtifmtts.h" // DateIntervalFormatTest #include "tufmtts.h" // TimeUnitTest +#include "locnmtst.h" // LocaleDisplayNamesTest #define TESTCLASS(id, TestClass) \ case id: \ @@ -123,6 +124,7 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam TESTCLASS(36,PluralFormatTest); TESTCLASS(37,DateIntervalFormatTest); TESTCLASS(38,TimeUnitTest); + TESTCLASS(39,LocaleDisplayNamesTest); default: name = ""; break; //needed to end loop } diff --git a/icu4c/source/test/intltest/locnmtst.cpp b/icu4c/source/test/intltest/locnmtst.cpp new file mode 100644 index 0000000000..98ef62cd31 --- /dev/null +++ b/icu4c/source/test/intltest/locnmtst.cpp @@ -0,0 +1,102 @@ +/********************************************************************* + * COPYRIGHT: + * Copyright (c) 2010, International Business Machines Corporation and + * others. All Rights Reserved. + *********************************************************************/ + +#include "locnmtst.h" + +/* + Usage: + test_assert( Test (should be TRUE) ) + + Example: + test_assert(i==3); + + the macro is ugly but makes the tests pretty. +*/ + +#define test_assert(test) \ + { \ + if(!(test)) \ + errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \ + else \ + logln("PASS: asserted " #test); \ + } + +/* + Usage: + test_assert_print( Test (should be TRUE), printable ) + + Example: + test_assert(i==3, toString(i)); + + the macro is ugly but makes the tests pretty. +*/ + +#define test_assert_print(test,print) \ + { \ + if(!(test)) \ + errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \ + else \ + logln("PASS: asserted " #test "-> " + UnicodeString(print)); \ + } + +#define test_assert_equal(target,value) \ + { \ + if (UnicodeString(target)!=(value)) { \ + logln("unexpected value '" + (value) + "'"); \ + errln("FAIL: " #target " == " #value " was not true. In " __FILE__ " on line %d", __LINE__); \ + } else { \ + logln("PASS: asserted " #target " == " #value); \ + } \ + } + +#define test_dumpLocale(l) { logln(#l " = " + UnicodeString(l.getName(), "")); } + +LocaleDisplayNamesTest::LocaleDisplayNamesTest() { +} + +LocaleDisplayNamesTest::~LocaleDisplayNamesTest() { +} + +void LocaleDisplayNamesTest::runIndexedTest(int32_t index, UBool exec, const char* &name, + char* /*par*/) { + switch (index) { +#if !UCONFIG_NO_FORMATTING + TESTCASE(0, TestCreate); + TESTCASE(1, TestCreateDialect); + TESTCASE(2, TestWithKeywordsAndEverything); +#endif + default: + name = ""; + break; + } +} + +void LocaleDisplayNamesTest::TestCreate() { + UnicodeString temp; + LocaleDisplayNames *ldn = LocaleDisplayNames::createInstance(Locale::getGermany()); + ldn->localeDisplayName("de_DE", temp); + delete ldn; + test_assert_equal("Deutsch (Deutschland)", temp); +} + +void LocaleDisplayNamesTest::TestCreateDialect() { + UnicodeString temp; + LocaleDisplayNames *ldn = LocaleDisplayNames::createInstance(Locale::getUS(), ULDN_DIALECT_NAMES); + ldn->localeDisplayName("en_GB", temp); + delete ldn; + test_assert_equal("British English", temp); +} + +void LocaleDisplayNamesTest::TestWithKeywordsAndEverything() { + UnicodeString temp; + LocaleDisplayNames *ldn = LocaleDisplayNames::createInstance(Locale::getUS()); + const char *locname = "en_Hant_US_VALLEY@calendar=gregorian;collation=phonebook"; + const char *target = "English (Traditional Han, United States, VALLEY, " + "calendar=Gregorian Calendar, collation=Phonebook Sort Order)"; + ldn->localeDisplayName(locname, temp); + delete ldn; + test_assert_equal(target, temp); +} diff --git a/icu4c/source/test/intltest/locnmtst.h b/icu4c/source/test/intltest/locnmtst.h new file mode 100644 index 0000000000..b3b90699f2 --- /dev/null +++ b/icu4c/source/test/intltest/locnmtst.h @@ -0,0 +1,28 @@ +/******************************************************************** + * COPYRIGHT: + * Copyright (c) 2010, International Business Machines Corporation and + * others. All Rights Reserved. + ********************************************************************/ + +#include "intltest.h" +#include "unicode/locdspnm.h" + +/** + * Tests for the LocaleDisplayNames class + **/ +class LocaleDisplayNamesTest: public IntlTest { +public: + LocaleDisplayNamesTest(); + virtual ~LocaleDisplayNamesTest(); + + void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL); + +#if !UCONFIG_NO_FORMATTING + /** + * Test methods to set and get data fields + **/ + void TestCreate(void); + void TestCreateDialect(void); + void TestWithKeywordsAndEverything(void); +#endif +}; diff --git a/icu4c/source/test/intltest/loctest.cpp b/icu4c/source/test/intltest/loctest.cpp index 52fca11dd9..4b5249bda9 100644 --- a/icu4c/source/test/intltest/loctest.cpp +++ b/icu4c/source/test/intltest/loctest.cpp @@ -220,6 +220,7 @@ void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, c TESTCASE(29, TestVariantWithOutCountry); TESTCASE(30, TestCanonicalization); TESTCASE(31, TestCurrencyByDate); + TESTCASE(32, TestGetVariantWithKeywords); // keep the last index in sync with the condition in default: @@ -2492,3 +2493,11 @@ void LocaleTest::TestCurrencyByDate(void) status = U_ZERO_ERROR; // reset #endif } + +void LocaleTest::TestGetVariantWithKeywords(void) +{ + Locale l("en_US_VALLEY@foo"); + const char *variant = l.getVariant(); + logln(variant); + test_assert(strcmp("VALLEY", variant) == 0); +} diff --git a/icu4c/source/test/intltest/loctest.h b/icu4c/source/test/intltest/loctest.h index da5a7469f2..a9172b9207 100644 --- a/icu4c/source/test/intltest/loctest.h +++ b/icu4c/source/test/intltest/loctest.h @@ -100,6 +100,8 @@ public: void TestCurrencyByDate(void); + void TestGetVariantWithKeywords(void); + private: void _checklocs(const char* label, const char* req,