diff --git a/src/common/intl.cpp b/src/common/intl.cpp index 3f46ff1bb6..9ae59c0bd8 100644 --- a/src/common/intl.cpp +++ b/src/common/intl.cpp @@ -1135,6 +1135,22 @@ wxString wxLocale::GetHeaderValue(const wxString& header, namespace { +bool IsAtTwoSingleQuotes(const wxString& fmt, wxString::const_iterator p) +{ + if ( p != fmt.end() && *p == '\'') + { + ++p; + if ( p != fmt.end() && *p == '\'') + { + return true; + } + } + + return false; +} + +} // anonymous namespace + // This function translates from Unicode date formats described at // // http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns @@ -1142,7 +1158,7 @@ namespace // to strftime()-like syntax. This translation is not lossless but we try to do // our best. -static wxString TranslateFromUnicodeFormat(const wxString& fmt) +wxString wxTranslateFromUnicodeFormat(const wxString& fmt) { wxString fmtWX; fmtWX.reserve(fmt.length()); @@ -1385,20 +1401,63 @@ static wxString TranslateFromUnicodeFormat(const wxString& fmt) if ( p == fmt.end() ) break; - // not a special character so must be just a separator, treat as is - if ( *p == wxT('%') ) + /* + Handle single quotes: + "Two single quotes represents [sic] a literal single quote, either + inside or outside single quotes. Text within single quotes is not + interpreted in any way (except for two adjacent single quotes)." + */ + + if ( IsAtTwoSingleQuotes(fmt, p) ) { - // this one needs to be escaped - fmtWX += wxT('%'); + fmtWX += '\''; + ++p; // the 2nd single quote is skipped by the for loop's increment + continue; } - fmtWX += *p; + bool isEndQuote = false; + if ( *p == '\'' ) + { + ++p; + while ( p != fmt.end() ) + { + if ( IsAtTwoSingleQuotes(fmt, p) ) + { + fmtWX += '\''; + p += 2; + continue; + } + + if ( *p == '\'' ) + { + isEndQuote = true; + break; + } + + fmtWX += *p; + ++p; + } + } + + if ( p == fmt.end() ) + break; + + if ( !isEndQuote ) + { + // not a special character so must be just a separator, treat as is + if ( *p == wxT('%') ) + { + // this one needs to be escaped + fmtWX += wxT('%'); + } + + fmtWX += *p; + } } return fmtWX; } -} // anonymous namespace #endif // __WINDOWS__ || __WXOSX__ @@ -1476,7 +1535,7 @@ GetInfoFromLCID(LCID lcid, if ( ::GetLocaleInfo(lcid, GetLCTYPEFormatFromLocalInfo(index), buf, WXSIZEOF(buf)) ) { - return TranslateFromUnicodeFormat(buf); + return wxTranslateFromUnicodeFormat(buf); } break; @@ -1630,7 +1689,7 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) wxCFRef dateFormatter( CFDateFormatterCreate (NULL, userLocaleRef, dateStyle, timeStyle)); wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter )); - wxString format = TranslateFromUnicodeFormat(cfs.AsString()); + wxString format = wxTranslateFromUnicodeFormat(cfs.AsString()); // we always want full years format.Replace("%y","%Y"); return format; diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 7005e81fbd..08ac272282 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -232,6 +232,7 @@ private: CPPUNIT_TEST( TestTimeArithmetics ); CPPUNIT_TEST( TestDSTBug ); CPPUNIT_TEST( TestDateOnly ); + CPPUNIT_TEST( TestTranslateFromUnicodeFormat ); CPPUNIT_TEST_SUITE_END(); void TestLeapYears(); @@ -252,6 +253,7 @@ private: void TestTimeArithmetics(); void TestDSTBug(); void TestDateOnly(); + void TestTranslateFromUnicodeFormat(); DECLARE_NO_COPY_CLASS(DateTimeTestCase) }; @@ -1447,4 +1449,37 @@ void DateTimeTestCase::TestDateOnly() CPPUNIT_ASSERT_EQUAL( wxDateTime::Today(), wxDateTime::Now().GetDateOnly() ); } +// Forward declaration +wxString wxTranslateFromUnicodeFormat(const wxString& fmt); + +void DateTimeTestCase::TestTranslateFromUnicodeFormat() +{ + // Test single quote handling... + + CPPUNIT_ASSERT_EQUAL("", wxTranslateFromUnicodeFormat("'")); + CPPUNIT_ASSERT_EQUAL("%H", wxTranslateFromUnicodeFormat("H'")); + CPPUNIT_ASSERT_EQUAL("H", wxTranslateFromUnicodeFormat("'H")); + + CPPUNIT_ASSERT_EQUAL("'", wxTranslateFromUnicodeFormat("''")); + CPPUNIT_ASSERT_EQUAL("%H'", wxTranslateFromUnicodeFormat("H''")); + CPPUNIT_ASSERT_EQUAL("H", wxTranslateFromUnicodeFormat("'H'")); + CPPUNIT_ASSERT_EQUAL("'%H", wxTranslateFromUnicodeFormat("''H")); + + CPPUNIT_ASSERT_EQUAL("'", wxTranslateFromUnicodeFormat("'''")); + CPPUNIT_ASSERT_EQUAL("%H'", wxTranslateFromUnicodeFormat("H'''")); + CPPUNIT_ASSERT_EQUAL("H'", wxTranslateFromUnicodeFormat("'H''")); + CPPUNIT_ASSERT_EQUAL("'%H", wxTranslateFromUnicodeFormat("''H'")); + CPPUNIT_ASSERT_EQUAL("'H", wxTranslateFromUnicodeFormat("'''H")); + + CPPUNIT_ASSERT_EQUAL("''", wxTranslateFromUnicodeFormat("''''")); + CPPUNIT_ASSERT_EQUAL("%H''", wxTranslateFromUnicodeFormat("H''''")); + CPPUNIT_ASSERT_EQUAL("H'", wxTranslateFromUnicodeFormat("'H'''")); + CPPUNIT_ASSERT_EQUAL("'%H'", wxTranslateFromUnicodeFormat("''H''")); + CPPUNIT_ASSERT_EQUAL("'H", wxTranslateFromUnicodeFormat("'''H'")); + CPPUNIT_ASSERT_EQUAL("''%H", wxTranslateFromUnicodeFormat("''''H")); + + CPPUNIT_ASSERT_EQUAL("'%H o'clock: It's about time'", + wxTranslateFromUnicodeFormat("''H 'o''clock: It''s about time'''")); +} + #endif // wxUSE_DATETIME