diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-20 06:37:01 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-20 06:37:01 +0000 |
commit | 7cf1b6ced3b14cce1d66ca0ddc713851f0d37536 (patch) | |
tree | 1c2fc9f4d52bf3046addf820d5eec03a2e150749 /base | |
parent | f9f4841b14a9f309ce5ee613f0d4de6afad88767 (diff) | |
download | chromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.zip chromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.tar.gz chromium_src-7cf1b6ced3b14cce1d66ca0ddc713851f0d37536.tar.bz2 |
Move RTL related functions from app/l10n_util to base/i18n/rtl
TBR=darin
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/1073005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gyp | 3 | ||||
-rw-r--r-- | base/file_path.h | 2 | ||||
-rw-r--r-- | base/i18n/rtl.cc | 228 | ||||
-rw-r--r-- | base/i18n/rtl.h | 121 | ||||
-rw-r--r-- | base/i18n/rtl_unittest.cc | 258 |
5 files changed, 611 insertions, 1 deletions
diff --git a/base/base.gyp b/base/base.gyp index 802147e..581b38b 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -31,6 +31,8 @@ 'i18n/icu_util.h', 'i18n/number_formatting.cc', 'i18n/number_formatting.h', + 'i18n/rtl.cc', + 'i18n/rtl.h', 'i18n/time_formatting.cc', 'i18n/time_formatting.h', 'i18n/word_iterator.cc', @@ -76,6 +78,7 @@ 'id_map_unittest.cc', 'i18n/file_util_icu_unittest.cc', 'i18n/icu_string_conversions_unittest.cc', + 'i18n/rtl_unittest.cc', 'i18n/word_iterator_unittest.cc', 'json/json_reader_unittest.cc', 'json/json_writer_unittest.cc', diff --git a/base/file_path.h b/base/file_path.h index a328c8a..61aa4fb 100644 --- a/base/file_path.h +++ b/base/file_path.h @@ -66,7 +66,7 @@ // // WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even // when the UI language is RTL. This means you always need to pass filepaths -// through l10n_util::WrapPathWithLTRFormatting() before displaying it in the +// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the // RTL UI. // // This is a very common source of bugs, please try to keep this in mind. diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc new file mode 100644 index 0000000..52f7de7 --- /dev/null +++ b/base/i18n/rtl.cc @@ -0,0 +1,228 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/i18n/rtl.h" + +#include "base/file_path.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/sys_string_conversions.h" +#include "unicode/coll.h" +#include "unicode/locid.h" +#include "unicode/uchar.h" +#include "unicode/uscript.h" + +#if defined(TOOLKIT_GTK) +#include <gtk/gtk.h> +#endif + +namespace base { +namespace i18n { + +// Represents the locale-specific ICU text direction. +static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION; + +void GetLanguageAndRegionFromOS(std::string* lang, std::string* region) { + // Later we may have to change this to be OS-dependent so that + // it's not affected by ICU's default locale. It's all right + // to do this way because SetICUDefaultLocale is internal + // to this file and we know that it's not yet called when this function + // is called. + icu::Locale locale = icu::Locale::getDefault(); + const char* language = locale.getLanguage(); + const char* country = locale.getCountry(); + DCHECK(language); + *lang = language; + *region = country; +} + +// Convert Chrome locale name to ICU locale name +std::string ICULocaleName(const std::string& locale_string) { + // If not Spanish, just return it. + if (locale_string.substr(0, 2) != "es") + return locale_string; + // Expand es to es-ES. + if (LowerCaseEqualsASCII(locale_string, "es")) + return "es-ES"; + // Map es-419 (Latin American Spanish) to es-FOO depending on the system + // locale. If it's es-RR other than es-ES, map to es-RR. Otherwise, map + // to es-MX (the most populous in Spanish-speaking Latin America). + if (LowerCaseEqualsASCII(locale_string, "es-419")) { + std::string lang, region; + GetLanguageAndRegionFromOS(&lang, ®ion); + if (LowerCaseEqualsASCII(lang, "es") && + !LowerCaseEqualsASCII(region, "es")) { + lang.append("-"); + lang.append(region); + return lang; + } + return "es-MX"; + } + // Currently, Chrome has only "es" and "es-419", but later we may have + // more specific "es-RR". + return locale_string; +} + +void SetICUDefaultLocale(const std::string& locale_string) { + icu::Locale locale(ICULocaleName(locale_string).c_str()); + UErrorCode error_code = U_ZERO_ERROR; + icu::Locale::setDefault(locale, error_code); + // This return value is actually bogus because Locale object is + // an ID and setDefault seems to always succeed (regardless of the + // presence of actual locale data). However, + // it does not hurt to have it as a sanity check. + DCHECK(U_SUCCESS(error_code)); + g_icu_text_direction = UNKNOWN_DIRECTION; +} + +TextDirection GetICUTextDirection() { + if (g_icu_text_direction == UNKNOWN_DIRECTION) { + const icu::Locale& locale = icu::Locale::getDefault(); + g_icu_text_direction = GetTextDirectionForLocale(locale.getName()); + } + return g_icu_text_direction; +} + +TextDirection GetTextDirection() { +#if defined(TOOLKIT_GTK) + GtkTextDirection gtk_dir = gtk_widget_get_default_direction(); + return (gtk_dir == GTK_TEXT_DIR_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; +#else + return GetICUTextDirection(); +#endif +} + +bool IsRTL() { + return GetTextDirection() == RIGHT_TO_LEFT; +} + +TextDirection GetTextDirectionForLocale(const char* locale_name) { + UErrorCode status = U_ZERO_ERROR; + ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status); + DCHECK(U_SUCCESS(status)); + // Treat anything other than RTL as LTR. + return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; +} + +TextDirection GetFirstStrongCharacterDirection(const std::wstring& text) { +#if defined(WCHAR_T_IS_UTF32) + string16 text_utf16 = WideToUTF16(text); + const UChar* string = text_utf16.c_str(); +#else + const UChar* string = text.c_str(); +#endif + size_t length = text.length(); + size_t position = 0; + while (position < length) { + UChar32 character; + size_t next_position = position; + U16_NEXT(string, next_position, length, character); + + // Now that we have the character, we use ICU in order to query for the + // appropriate Unicode BiDi character type. + int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); + if ((property == U_RIGHT_TO_LEFT) || + (property == U_RIGHT_TO_LEFT_ARABIC) || + (property == U_RIGHT_TO_LEFT_EMBEDDING) || + (property == U_RIGHT_TO_LEFT_OVERRIDE)) { + return RIGHT_TO_LEFT; + } else if ((property == U_LEFT_TO_RIGHT) || + (property == U_LEFT_TO_RIGHT_EMBEDDING) || + (property == U_LEFT_TO_RIGHT_OVERRIDE)) { + return LEFT_TO_RIGHT; + } + + position = next_position; + } + + return LEFT_TO_RIGHT; +} + +bool AdjustStringForLocaleDirection(const std::wstring& text, + std::wstring* localized_text) { + if (GetTextDirection() == LEFT_TO_RIGHT || text.length() == 0) + return false; + + // Marking the string as LTR if the locale is RTL and the string does not + // contain strong RTL characters. Otherwise, mark the string as RTL. + *localized_text = text; + bool has_rtl_chars = StringContainsStrongRTLChars(text); + if (!has_rtl_chars) + WrapStringWithLTRFormatting(localized_text); + else + WrapStringWithRTLFormatting(localized_text); + + return true; +} + +bool StringContainsStrongRTLChars(const std::wstring& text) { +#if defined(WCHAR_T_IS_UTF32) + string16 text_utf16 = WideToUTF16(text); + const UChar* string = text_utf16.c_str(); +#else + const UChar* string = text.c_str(); +#endif + size_t length = text.length(); + size_t position = 0; + while (position < length) { + UChar32 character; + size_t next_position = position; + U16_NEXT(string, next_position, length, character); + + // Now that we have the character, we use ICU in order to query for the + // appropriate Unicode BiDi character type. + int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); + if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC)) + return true; + + position = next_position; + } + + return false; +} + +void WrapStringWithLTRFormatting(std::wstring* text) { + // Inserting an LRE (Left-To-Right Embedding) mark as the first character. + text->insert(0, 1, static_cast<wchar_t>(kLeftToRightEmbeddingMark)); + + // Inserting a PDF (Pop Directional Formatting) mark as the last character. + text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting)); +} + +void WrapStringWithRTLFormatting(std::wstring* text) { + // Inserting an RLE (Right-To-Left Embedding) mark as the first character. + text->insert(0, 1, static_cast<wchar_t>(kRightToLeftEmbeddingMark)); + + // Inserting a PDF (Pop Directional Formatting) mark as the last character. + text->push_back(static_cast<wchar_t>(kPopDirectionalFormatting)); +} + +void WrapPathWithLTRFormatting(const FilePath& path, + string16* rtl_safe_path) { + // Wrap the overall path with LRE-PDF pair which essentialy marks the + // string as a Left-To-Right string. + // Inserting an LRE (Left-To-Right Embedding) mark as the first character. + rtl_safe_path->push_back(kLeftToRightEmbeddingMark); +#if defined(OS_MACOSX) + rtl_safe_path->append(UTF8ToUTF16(path.value())); +#elif defined(OS_WIN) + rtl_safe_path->append(path.value()); +#else // defined(OS_POSIX) && !defined(OS_MACOSX) + std::wstring wide_path = base::SysNativeMBToWide(path.value()); + rtl_safe_path->append(WideToUTF16(wide_path)); +#endif + // Inserting a PDF (Pop Directional Formatting) mark as the last character. + rtl_safe_path->push_back(kPopDirectionalFormatting); +} + +std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text) { + if (GetTextDirection() == RIGHT_TO_LEFT) + WrapStringWithLTRFormatting(text); + return *text; +} + +} // namespace i18n +} // namespace base + diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h new file mode 100644 index 0000000..05a5ff0 --- /dev/null +++ b/base/i18n/rtl.h @@ -0,0 +1,121 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_I18N_RTL_H_ +#define BASE_I18N_RTL_H_ + +#include "base/string16.h" + +class FilePath; + +namespace base { +namespace i18n { + +const char16 kRightToLeftMark = 0x200f; +const char16 kLeftToRightMark = 0x200e; +const char16 kLeftToRightEmbeddingMark = 0x202A; +const char16 kRightToLeftEmbeddingMark = 0x202B; +const char16 kPopDirectionalFormatting = 0x202C; + +// Represents the text direction returned by the GetTextDirection() function. +enum TextDirection { + UNKNOWN_DIRECTION, + RIGHT_TO_LEFT, + LEFT_TO_RIGHT, +}; + +// Get language and region from the OS. +void GetLanguageAndRegionFromOS(std::string* lang, std::string* region); + +// Sets the default locale of ICU. +// Once the application locale of Chrome in GetApplicationLocale is determined, +// the default locale of ICU need to be changed to match the application locale +// so that ICU functions work correctly in a locale-dependent manner. +// This is handy in that we don't have to call GetApplicationLocale() +// everytime we call locale-dependent ICU APIs as long as we make sure +// that this is called before any locale-dependent API is called. +void SetICUDefaultLocale(const std::string& locale_string); + +// Returns the text direction for the default ICU locale. It is assumed +// that SetICUDefaultLocale has been called to set the default locale to +// the UI locale of Chrome. Its return is one of the following three: +// * LEFT_TO_RIGHT: Left-To-Right (e.g. English, Chinese, etc.); +// * RIGHT_TO_LEFT: Right-To-Left (e.g. Arabic, Hebrew, etc.), and; +// * UNKNOWN_DIRECTION: unknown (or error). +TextDirection GetICUTextDirection(); + +// Get the application text direction. (This is just the ICU direction, +// except on GTK.) +TextDirection GetTextDirection(); + +// Returns true if the application text direction is right-to-left. +bool IsRTL(); + +// Returns the text direction for |locale_name|. +TextDirection GetTextDirectionForLocale(const char* locale_name); + +// Given the string in |text|, returns the directionality of the first +// character with strong directionality in the string. If no character in the +// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi +// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong +// directionality characters. Please refer to http://unicode.org/reports/tr9/ +// for more information. +TextDirection GetFirstStrongCharacterDirection(const std::wstring& text); + +// Given the string in |text|, this function creates a copy of the string with +// the appropriate Unicode formatting marks that mark the string direction +// (either left-to-right or right-to-left). The new string is returned in +// |localized_text|. The function checks both the current locale and the +// contents of the string in order to determine the direction of the returned +// string. The function returns true if the string in |text| was properly +// adjusted. +// +// Certain LTR strings are not rendered correctly when the context is RTL. For +// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in +// an RTL context. Calling this function will make sure the returned localized +// string is always treated as a right-to-left string. This is done by +// inserting certain Unicode formatting marks into the returned string. +// +// TODO(idana) bug# 1206120: this function adjusts the string in question only +// if the current locale is right-to-left. The function does not take care of +// the opposite case (an RTL string displayed in an LTR context) since +// adjusting the string involves inserting Unicode formatting characters that +// Windows does not handle well unless right-to-left language support is +// installed. Since the English version of Windows doesn't have right-to-left +// language support installed by default, inserting the direction Unicode mark +// results in Windows displaying squares. +bool AdjustStringForLocaleDirection(const std::wstring& text, + std::wstring* localized_text); + +// Returns true if the string contains at least one character with strong right +// to left directionality; that is, a character with either R or AL Unicode +// BiDi character type. +bool StringContainsStrongRTLChars(const std::wstring& text); + +// Wraps a string with an LRE-PDF pair which essentialy marks the string as a +// Left-To-Right string. Doing this is useful in order to make sure LTR +// strings are rendered properly in an RTL context. +void WrapStringWithLTRFormatting(std::wstring* text); + +// Wraps a string with an RLE-PDF pair which essentialy marks the string as a +// Right-To-Left string. Doing this is useful in order to make sure RTL +// strings are rendered properly in an LTR context. +void WrapStringWithRTLFormatting(std::wstring* text); + +// Wraps file path to get it to display correctly in RTL UI. All filepaths +// should be passed through this function before display in UI for RTL locales. +void WrapPathWithLTRFormatting(const FilePath& path, + string16* rtl_safe_path); + +// Given the string in |text|, this function returns the adjusted string having +// LTR directionality for display purpose. Which means that in RTL locale the +// string is wrapped with LRE (Left-To-Right Embedding) and PDF (Pop +// Directional Formatting) marks and returned. In LTR locale, the string itself +// is returned. +std::wstring GetDisplayStringInLTRDirectionality(std::wstring* text); + +} // namespace i18n +} // namespace base + +#endif // BASE_I18N_RTL_H_ diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc new file mode 100644 index 0000000..65d0f6b --- /dev/null +++ b/base/i18n/rtl_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/i18n/rtl.h" + +#include "base/file_path.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace { +base::i18n::TextDirection GetTextDirection(const char* locale_name) { + return base::i18n::GetTextDirectionForLocale(locale_name); +} +} + +class RTLTest : public PlatformTest { +}; + +TEST_F(RTLTest, GetFirstStrongCharacterDirection) { + // Test pure LTR string. + std::wstring string(L"foo bar"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type L. + string.assign(L"foo \x05d0 bar"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type R. + string.assign(L"\x05d0 foo bar"); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string which starts with a character with weak directionality + // and in which the first character with strong directionality is a character + // with type L. + string.assign(L"!foo \x05d0 bar"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string which starts with a character with weak directionality + // and in which the first character with strong directionality is a character + // with type R. + string.assign(L",\x05d0 foo bar"); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type LRE. + string.assign(L"\x202a \x05d0 foo bar"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type LRO. + string.assign(L"\x202d \x05d0 foo bar"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type RLE. + string.assign(L"\x202b foo \x05d0 bar"); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type RLO. + string.assign(L"\x202e foo \x05d0 bar"); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test bidi string in which the first character with strong directionality + // is a character with type AL. + string.assign(L"\x0622 foo \x05d0 bar"); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test a string without strong directionality characters. + string.assign(L",!.{}"); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test empty string. + string.assign(L""); + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); + + // Test characters in non-BMP (e.g. Phoenician letters. Please refer to + // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more + // information). +#if defined(WCHAR_T_IS_UTF32) + string.assign(L" ! \x10910" L"abc 123"); +#elif defined(WCHAR_T_IS_UTF16) + string.assign(L" ! \xd802\xdd10" L"abc 123"); +#else +#error wchar_t should be either UTF-16 or UTF-32 +#endif + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, + base::i18n::GetFirstStrongCharacterDirection(string)); + +#if defined(WCHAR_T_IS_UTF32) + string.assign(L" ! \x10401" L"abc 123"); +#elif defined(WCHAR_T_IS_UTF16) + string.assign(L" ! \xd801\xdc01" L"abc 123"); +#else +#error wchar_t should be either UTF-16 or UTF-32 +#endif + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, + base::i18n::GetFirstStrongCharacterDirection(string)); +} + +typedef struct { + std::wstring path; + std::wstring wrapped_path; +} PathAndWrappedPath; + +TEST_F(RTLTest, WrapPathWithLTRFormatting) { + std::wstring kSeparator; + kSeparator.push_back(static_cast<wchar_t>(FilePath::kSeparators[0])); + const PathAndWrappedPath test_data[] = { + // Test common path, such as "c:\foo\bar". + { L"c:" + kSeparator + L"foo" + kSeparator + L"bar", + L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator + + L"bar\x202c" + }, + // Test path with file name, such as "c:\foo\bar\test.jpg". + { L"c:" + kSeparator + L"foo" + kSeparator + L"bar" + kSeparator + + L"test.jpg", + L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator + + L"bar" + kSeparator + L"test.jpg\x202c" + }, + // Test path ending with punctuation, such as "c:\(foo)\bar.". + { L"c:" + kSeparator + L"(foo)" + kSeparator + L"bar.", + L"\x202a"L"c:" + kSeparator + L"(foo)" + kSeparator + + L"bar.\x202c" + }, + // Test path ending with separator, such as "c:\foo\bar\". + { L"c:" + kSeparator + L"foo" + kSeparator + L"bar" + kSeparator, + L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator + + L"bar" + kSeparator + L"\x202c", + }, + // Test path with RTL character. + { L"c:" + kSeparator + L"\x05d0", + L"\x202a"L"c:" + kSeparator + L"\x05d0\x202c", + }, + // Test path with 2 level RTL directory names. + { L"c:" + kSeparator + L"\x05d0" + kSeparator + L"\x0622", + L"\x202a"L"c:" + kSeparator + L"\x05d0" + kSeparator + + L"\x0622\x202c", + }, + // Test path with mixed RTL/LTR directory names and ending with punctuation. + { L"c:" + kSeparator + L"\x05d0" + kSeparator + L"\x0622" + kSeparator + + L"(foo)" + kSeparator + L"b.a.r.", + L"\x202a"L"c:" + kSeparator + L"\x05d0" + kSeparator + + L"\x0622" + kSeparator + L"(foo)" + kSeparator + + L"b.a.r.\x202c", + }, + // Test path without driver name, such as "/foo/bar/test/jpg". + { kSeparator + L"foo" + kSeparator + L"bar" + kSeparator + L"test.jpg", + L"\x202a" + kSeparator + L"foo" + kSeparator + L"bar" + + kSeparator + L"test.jpg" + L"\x202c" + }, + // Test path start with current directory, such as "./foo". + { L"." + kSeparator + L"foo", + L"\x202a"L"." + kSeparator + L"foo" + L"\x202c" + }, + // Test path start with parent directory, such as "../foo/bar.jpg". + { L".." + kSeparator + L"foo" + kSeparator + L"bar.jpg", + L"\x202a"L".." + kSeparator + L"foo" + kSeparator + + L"bar.jpg" + L"\x202c" + }, + // Test absolute path, such as "//foo/bar.jpg". + { kSeparator + kSeparator + L"foo" + kSeparator + L"bar.jpg", + L"\x202a" + kSeparator + kSeparator + L"foo" + kSeparator + + L"bar.jpg" + L"\x202c" + }, + // Test path with mixed RTL/LTR directory names. + { L"c:" + kSeparator + L"foo" + kSeparator + L"\x05d0" + kSeparator + + L"\x0622" + kSeparator + L"\x05d1.jpg", + L"\x202a"L"c:" + kSeparator + L"foo" + kSeparator + L"\x05d0" + + kSeparator + L"\x0622" + kSeparator + L"\x05d1.jpg" + L"\x202c", + }, + // Test empty path. + { L"", + L"\x202a\x202c" + } + }; + for (unsigned int i = 0; i < arraysize(test_data); ++i) { + string16 localized_file_path_string; + FilePath path = FilePath::FromWStringHack(test_data[i].path); + base::i18n::WrapPathWithLTRFormatting(path, &localized_file_path_string); + std::wstring wrapped_path = UTF16ToWide(localized_file_path_string); + EXPECT_EQ(wrapped_path, test_data[i].wrapped_path); + } +} + +typedef struct { + std::wstring raw_filename; + std::wstring display_string; +} StringAndLTRString; + +TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) { + const StringAndLTRString test_data[] = { + { L"test", L"\x202atest\x202c" }, + { L"test.html", L"\x202atest.html\x202c" }, + { L"\x05d0\x05d1\x05d2", L"\x202a\x05d0\x05d1\x05d2\x202c" }, + { L"\x05d0\x05d1\x05d2.txt", L"\x202a\x05d0\x05d1\x05d2.txt\x202c" }, + { L"\x05d0"L"abc", L"\x202a\x05d0"L"abc\x202c" }, + { L"\x05d0"L"abc.txt", L"\x202a\x05d0"L"abc.txt\x202c" }, + { L"abc\x05d0\x05d1", L"\x202a"L"abc\x05d0\x05d1\x202c" }, + { L"abc\x05d0\x05d1.jpg", L"\x202a"L"abc\x05d0\x05d1.jpg\x202c" }, + }; + for (unsigned int i = 0; i < arraysize(test_data); ++i) { + std::wstring input = test_data[i].raw_filename; + std::wstring expected = + base::i18n::GetDisplayStringInLTRDirectionality(&input); + if (base::i18n::IsRTL()) + EXPECT_EQ(test_data[i].display_string, expected); + else + EXPECT_EQ(input, expected); + } +} + +TEST_F(RTLTest, GetTextDirection) { + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar")); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ar_EG")); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he")); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("he_IL")); + // iw is an obsolete code for Hebrew. + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("iw")); + // Although we're not yet localized to Farsi and Urdu, we + // do have the text layout direction information for them. + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("fa")); + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("ur")); +#if 0 + // Enable these when we include the minimal locale data for Azerbaijani + // written in Arabic and Dhivehi. At the moment, our copy of + // ICU data does not have entries for them. + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("az_Arab")); + // Dhivehi that uses Thaana script. + EXPECT_EQ(base::i18n::RIGHT_TO_LEFT, GetTextDirection("dv")); +#endif + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("en")); + // Chinese in China with '-'. + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("zh-CN")); + // Filipino : 3-letter code + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("fil")); + // Russian + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ru")); + // Japanese that uses multiple scripts + EXPECT_EQ(base::i18n::LEFT_TO_RIGHT, GetTextDirection("ja")); +}
\ No newline at end of file |