Title: [200105] trunk
Revision
200105
Author
fpi...@apple.com
Date
2016-04-26 13:01:13 -0700 (Tue, 26 Apr 2016)

Log Message

WebCore on Mac ignores the user's preferred region (country) while getting the language
https://bugs.webkit.org/show_bug.cgi?id=156993

Reviewed by Geoffrey Garen.

Source/WebCore:

This is tested by the NavigatorLanguage API test.
        
WebCore was previously getting the list of preferred languages, and for each one, deducing
the default region. That's wrong, since for example it doesn't respect the user's choice (in
System Preferences) to display dates/calenders/etc according to a different region (like how
I have my machine set to en-pl right now).
        
It might be possible for the country code we get via kCFLocaleCountryCode to be something
that our ICU doesn't handle. To defend against this, we search for the resulting country
code in ICU's ISO countries list. If it doesn't appear in that list, we fall back on old
behavior.

* platform/mac/Language.mm:
(WebCore::httpStyleLanguageCode):
(WebCore::isValidICUCountryCode):
(WebCore::platformUserPreferredLanguages):

Tools:

Change the test expectations for this test. If the variant is not explicitly specified in
the AppleLanguage, then we use the locale's country code, which this test assumes is US.

* TestWebKitAPI/Tests/mac/NavigatorLanguage.mm:
(TestWebKitAPI::languageForSystemLanguage):
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (200104 => 200105)


--- trunk/Source/WebCore/ChangeLog	2016-04-26 19:49:19 UTC (rev 200104)
+++ trunk/Source/WebCore/ChangeLog	2016-04-26 20:01:13 UTC (rev 200105)
@@ -1,3 +1,27 @@
+2016-04-26  Filip Pizlo  <fpi...@apple.com>
+
+        WebCore on Mac ignores the user's preferred region (country) while getting the language
+        https://bugs.webkit.org/show_bug.cgi?id=156993
+
+        Reviewed by Geoffrey Garen.
+
+        This is tested by the NavigatorLanguage API test.
+        
+        WebCore was previously getting the list of preferred languages, and for each one, deducing
+        the default region. That's wrong, since for example it doesn't respect the user's choice (in
+        System Preferences) to display dates/calenders/etc according to a different region (like how
+        I have my machine set to en-pl right now).
+        
+        It might be possible for the country code we get via kCFLocaleCountryCode to be something
+        that our ICU doesn't handle. To defend against this, we search for the resulting country
+        code in ICU's ISO countries list. If it doesn't appear in that list, we fall back on old
+        behavior.
+
+        * platform/mac/Language.mm:
+        (WebCore::httpStyleLanguageCode):
+        (WebCore::isValidICUCountryCode):
+        (WebCore::platformUserPreferredLanguages):
+
 2016-04-26  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Use auto-generated operators in FontPlatformData

Modified: trunk/Source/WebCore/platform/mac/Language.mm (200104 => 200105)


--- trunk/Source/WebCore/platform/mac/Language.mm	2016-04-26 19:49:19 UTC (rev 200104)
+++ trunk/Source/WebCore/platform/mac/Language.mm	2016-04-26 20:01:13 UTC (rev 200105)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003, 2005, 2006, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2005, 2006, 2010, 2011, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 #import "CFBundleSPI.h"
 #import "WebCoreNSStringExtras.h"
 #import <mutex>
+#import <unicode/uloc.h>
 #import <wtf/Assertions.h>
 #import <wtf/Lock.h>
 #import <wtf/NeverDestroyed.h>
@@ -69,12 +70,14 @@
 
 namespace WebCore {
 
-static String httpStyleLanguageCode(NSString *language)
+static String httpStyleLanguageCode(NSString *language, NSString *country)
 {
     SInt32 languageCode;
     SInt32 regionCode; 
     SInt32 scriptCode; 
-    CFStringEncoding stringEncoding; 
+    CFStringEncoding stringEncoding;
+    
+    bool languageDidSpecifyExplicitVariant = [language rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]].location != NSNotFound;
 
     // FIXME: This transformation is very wrong:
     // 1. There is no reason why CFBundle localization names would be at all related to language names as used on the Web.
@@ -87,9 +90,19 @@
 
     // Make the string lowercase.
     NSString *lowercaseLanguageCode = [language lowercaseString];
-
-    // Turn a '_' into a '-' if it appears after a 2-letter language code.
+    NSString *lowercaseCountryCode = [country lowercaseString];
+    
+    // If we see a "_" after a 2-letter language code:
+    // If the country is valid and the language did not specify a variant, replace the "_" and
+    // whatever comes after it with "-" followed by the country code.
+    // Otherwise, replace the "_" with a "-" and use whatever country
+    // CFBundleCopyLocalizationForLocalizationInfo() returned.
     if ([lowercaseLanguageCode length] >= 3 && [lowercaseLanguageCode characterAtIndex:2] == '_') {
+        if (country && !languageDidSpecifyExplicitVariant)
+            return [NSString stringWithFormat:@"%@-%@", [lowercaseLanguageCode substringWithRange:NSMakeRange(0, 2)], lowercaseCountryCode];
+        
+        // Fall back to older behavior, which used the original language-based code but just changed
+        // the "_" to a "-".
         RetainPtr<NSMutableString> mutableLanguageCode = adoptNS([lowercaseLanguageCode mutableCopy]);
         [mutableLanguageCode.get() replaceCharactersInRange:NSMakeRange(2, 1) withString:@"-"];
         return mutableLanguageCode.get();
@@ -98,6 +111,18 @@
     return lowercaseLanguageCode;
 }
 
+static bool isValidICUCountryCode(NSString* countryCode)
+{
+    const char* const* countries = uloc_getISOCountries();
+    const char* countryUTF8 = [countryCode UTF8String];
+    for (unsigned i = 0; countries[i]; ++i) {
+        const char* possibleCountry = countries[i];
+        if (!strcmp(countryUTF8, possibleCountry))
+            return true;
+    }
+    return false;
+}
+
 Vector<String> platformUserPreferredLanguages()
 {
 #if PLATFORM(MAC)
@@ -113,13 +138,19 @@
     Vector<String>& userPreferredLanguages = preferredLanguages();
 
     if (userPreferredLanguages.isEmpty()) {
+        RetainPtr<CFLocaleRef> locale = adoptCF(CFLocaleCopyCurrent());
+        NSString *countryCode = (NSString *)CFLocaleGetValue(locale.get(), kCFLocaleCountryCode);
+        
+        if (!isValidICUCountryCode(countryCode))
+            countryCode = nil;
+        
         RetainPtr<CFArrayRef> languages = adoptCF(CFLocaleCopyPreferredLanguages());
         CFIndex languageCount = CFArrayGetCount(languages.get());
         if (!languageCount)
             userPreferredLanguages.append("en");
         else {
             for (CFIndex i = 0; i < languageCount; i++)
-                userPreferredLanguages.append(httpStyleLanguageCode((NSString *)CFArrayGetValueAtIndex(languages.get(), i)));
+                userPreferredLanguages.append(httpStyleLanguageCode((NSString *)CFArrayGetValueAtIndex(languages.get(), i), countryCode));
         }
     }
 

Modified: trunk/Tools/ChangeLog (200104 => 200105)


--- trunk/Tools/ChangeLog	2016-04-26 19:49:19 UTC (rev 200104)
+++ trunk/Tools/ChangeLog	2016-04-26 20:01:13 UTC (rev 200105)
@@ -1,3 +1,17 @@
+2016-04-26  Filip Pizlo  <fpi...@apple.com>
+
+        WebCore on Mac ignores the user's preferred region (country) while getting the language
+        https://bugs.webkit.org/show_bug.cgi?id=156993
+
+        Reviewed by Geoffrey Garen.
+
+        Change the test expectations for this test. If the variant is not explicitly specified in
+        the AppleLanguage, then we use the locale's country code, which this test assumes is US.
+
+        * TestWebKitAPI/Tests/mac/NavigatorLanguage.mm:
+        (TestWebKitAPI::languageForSystemLanguage):
+        (TestWebKitAPI::TEST):
+
 2016-04-25  Ryosuke Niwa  <rn...@webkit.org>
 
         Remove the build flag for template elements

Modified: trunk/Tools/TestWebKitAPI/Tests/mac/NavigatorLanguage.mm (200104 => 200105)


--- trunk/Tools/TestWebKitAPI/Tests/mac/NavigatorLanguage.mm	2016-04-26 19:49:19 UTC (rev 200104)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/NavigatorLanguage.mm	2016-04-26 20:01:13 UTC (rev 200105)
@@ -68,17 +68,21 @@
     return [webView stringByEvaluatingJavaScriptFromString:@"navigator.language"];
 }
 
-// These tests document current behavior. Some of the current results may not be right.
+// These tests document current behavior. Some of the current results may not be right. Note that
+// this oddly assumes that the user has set their language to something possibly-foreign but still
+// left their region as US. Hence the "-us" variants.
+// FIXME: These tests should also set the region to see how WebKit will handle that.
+// https://bugs.webkit.org/show_bug.cgi?id=157039
 NSArray *tests = @[
-    @[@"ru", @"ru-ru"], // This does not match other browsers or CFNetwork's Accept-Language, which all use "ru".
+    @[@"ru", @"ru-us"], // This does not match other browsers or CFNetwork's Accept-Language, which all use "ru".
     @[@"en", @"en-us"],
     @[@"en-GB", @"en-gb"],
     @[@"en-US", @"en-us"],
-    @[@"ja", @"ja-jp"],
-    @[@"hi", @"hi-in"],
+    @[@"ja", @"ja-us"],
+    @[@"hi", @"hi-us"],
     @[@"zh-TW", @"zh-tw"], // This should not map to the generic zh-hant, see rdar://problem/21395180.
     @[@"zh-HK", @"zh-tw"],
-    @[@"es", @"es-es"],
+    @[@"es", @"es-us"],
     @[@"es-MX", @"es-xl"],
     @[@"es-ES", @"es-es"],
     @[@"es-419", @"es-xl"],
@@ -86,7 +90,7 @@
     @[@"zh-Hant", @"zh-tw"],
     @[@"pt-BR", @"pt-br"],
     @[@"pt-PT", @"pt-pt"],
-    @[@"fr", @"fr-fr"],
+    @[@"fr", @"fr-us"],
     @[@"fr-CA", @"fr-ca"],
 ];
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to