Problem/Motivation

Browsers understand language codes differently to Drupal. The issue was originally created to because this causes serious problems for Simplified Chinese. IE and Firefox will send 'zh-cn', but Drupal understands this language as 'zh-hans'. However this applies to other languages as well.

Proposed resolution

A mapping system to map external language codes to internal language codes and default mappings for some common situations.

This has been committed and pushed to 8.x (in #365615-99: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings), #365615-103: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) and #365615-231: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings)) and is being backported to 7.x.

Steps to reproduce

Instructions for Firefox 19.0.2 running on OS 10.7.5
From Firefox, go to the following Menu progression:
View > Character Encoding > Auto-Detect > Simplified Chinese
Make sure "Simplified Chinese" has a check next to it.
There are multiple Simplified Chinese encodings. The step above SHOULD detect them all (that's still being researched). To test the individual Simplified Chinese encodings, take the following menu progression:
View > Character Encoding > More Encodings > East Asian
This will lead you to a list of multiple encodings for Simplified Chinese, along with other East Asian languages. Choose the encoding you wish to test.

Once you've adjusted your language detections settings, be sure you have an up-to-date install of Drupal 7.x. See the Drupal Core Git instructions section on 'Getting ready to create or apply patches' for details on updating your installation.

Once your install is updated, log in and be sure the "Locale" module is active. Go to "DrupalSite/admin/modules" OR from the administration menu at the top of the screen, click "Modules". The Locale module is part of the Core group. Module names are listed in alphabetic order. Be sure the box next to "Locale" is checked, then scroll to the bottom of the page and click the "Save Configuration" button.

Next, go to your Drupal 7.x installation and go to "admin/config/regional/language/configure". Here, be sure the "Browser" detection method is enabled and drag it to the top of the list of detection methods. Click the "Save Settings" button at the bottom of the screen. Nothing should happen.

Next, apply the patch from comment 139.

NEXT: Description of what should happen after the patch is applied.

Remaining tasks

Reroll. Review. Commit.

User interface changes

A new user interface is added to edit mappings of external vs. internal language codes.

D8 screenshot in #92
D7 screenshot in #131
Before and after screenshots of entry point in D7 in #132

Original report by yang_yi_cn

language.inc, line 95, in function language_from_browser() :

change from

  foreach ($browser_langs as $langcode => $q) {
    if (isset($languages['1'][$langcode])) {
      return $languages['1'][$langcode];
    }
  }

to

  foreach ($browser_langs as $langcode => $q) {
    if (($langcode == 'zh-cn') && isset($languages['1']['zh-hans'])) {
      return $languages['1']['zh-hans'];
    }
    if (isset($languages['1'][$langcode])) {
      return $languages['1'][$langcode];
    }
  }

As you can see, for Simplified Chinese langugage, both IE and Firefox will send 'zh-cn' as the preferred language code, which is different from Drupal's 'zh-hans' code, thus the browser detection will not work for Simplified Chinese.

Maybe there's also some other languages having this issue, but this is what I got now.

CommentFileSizeAuthor
#228 i365615-228.patch8.97 KBGábor Hojtsy
#227 interdiff.txt3.36 KBGábor Hojtsy
#227 i365615-227.patch8.94 KBGábor Hojtsy
#220 interdiff.365615.202.220.txt6.11 KBYesCT
#220 i365615-220.patch8.94 KBYesCT
#220 interdiff.365615.217.220.txt1.34 KBYesCT
#217 i365615-217.patch8.32 KBYesCT
#217 interdiff.365615.215.217.txt566 bytesYesCT
#215 i365615-215.patch8.38 KBYesCT
#215 interdiff.365615.213.215.txt621 bytesYesCT
#213 i365615-213.patch8.06 KBYesCT
#213 interdiff.365615.211.213.txt2.06 KBYesCT
#212 emptytable.png164.11 KBYesCT
#211 i365615-211.patch6.71 KBYesCT
#211 interdiff.365615.206.211.txt731 bytesYesCT
#207 i365615-checkthedeletetest-shouldfail.patch842 bytesYesCT
#207 i365615-206-testchangeonly.patch1006 bytesYesCT
#207 i365615-206.patch6.72 KBYesCT
#207 interdiff.365615.205.206.txt2.04 KBYesCT
#207 logdeleted.png187.07 KBYesCT
#207 saysdeleted.png289.19 KBYesCT
#206 deletingmessage.png136.01 KBYesCT
#206 deletingsayssaved.png302.31 KBYesCT
#205 interdiff.365615.202.205.txt1.13 KBYesCT
#205 i365615-205.patch5.47 KBYesCT
#205 helptext-neg.png321.27 KBYesCT
#204 class-withpatch.png298.06 KBYesCT
#204 class-nopatch.png277.13 KBYesCT
#202 interdiff.txt1.15 KBGábor Hojtsy
#202 i365615-202.patch5.35 KBGábor Hojtsy
#198 i365615-198.patch5.49 KBGábor Hojtsy
#198 interdiff.txt1.35 KBGábor Hojtsy
#197 i365615-172-rerolled-at-197.patch6.83 KBGábor Hojtsy
#193 i365615-172-rerolled-at-193.patch6.82 KBmgifford
#191 i365615-172-rerolled-at-191.patch6.81 KBmgifford
#186 chinese-language-detection-365615-186.patch9.07 KBmgifford
#183 i365615-183.patch9.17 KBmgifford
#180 i365615-180.patch9.18 KBwebwarrior
#172 i365615-172.patch7.19 KBAlbert Volkman
#172 interdiff.txt1.89 KBAlbert Volkman
#171 i365615-171.patch7.13 KBAlbert Volkman
#163 interdiff.txt520 bytesattiks
#163 i365615-163.patch8.46 KBattiks
#161 i365615-161.patch8.46 KBattiks
#159 interdiff.txt7.21 KBattiks
#159 i365615-159.patch23 KBattiks
#158 interdiff-123-153.txt3.74 KBDavid_Rothstein
#153 i365615-153.patch22.5 KBYesCT
#145 drupal-languages-list.jpg58.44 KBlixiphp
#145 drupal-language-detection-selection.jpg56.81 KBlixiphp
#145 Chinese-simplified-language-preferred.jpg33.55 KBlixiphp
#140 Browser language detection configuration | Drupal 7.x.png96.38 KBpameeela
#139 i365615-139.patch22.49 KBattiks
#136 i365615-136.png15.8 KBattiks
#132 d7ui-without-path.png105.02 KBpameeela
#132 d7ui-with-patch.png328.3 KBpameeela
#131 d7-ui.png114.74 KBpameeela
#130 Browser language detection configuration | Drupal 7.x.png114.74 KBpameeela
#127 interdiff.txt3.06 KBattiks
#127 i365615-127.patch22.5 KBattiks
#123 i365615-123.patch22.52 KBplach
#120 i365615-120.patch22.58 KBplach
#119 interdiff.txt2.43 KBattiks
#119 i365615-119.patch22.58 KBattiks
#118 i365615-118.patch21.44 KBattiks
#102 i365615.langauge-to-language.patch2.81 KBattiks
#101 langauge-typo.patch1.17 KBGábor Hojtsy
#96 interdiff.txt7.29 KBattiks
#96 i365615-chinese-96.patch22.04 KBattiks
#93 interdiff.txt6.99 KBattiks
#93 i365615-chinese-93.patch21.88 KBattiks
#92 i365615-92.png59.91 KBattiks
#89 interdiff.txt4.89 KBattiks
#89 i365615-chinese-89.patch22.3 KBattiks
#88 BrowserLanguageMapping-2.jpg73.97 KBGábor Hojtsy
#87 interdiff.txt5.23 KBattiks
#87 i365615-chinese-87.patch23.2 KBattiks
#79 interdiff.txt681 bytesattiks
#79 i365615-chinese-79.patch22.34 KBattiks
#76 interdiff.txt1.65 KBattiks
#76 i365615-chinese-76.patch22.36 KBattiks
#71 InPlaceURLPrefixes.png86.44 KBGábor Hojtsy
#71 InPlaceTranslation.png93.76 KBGábor Hojtsy
#71 BookInlineEdit.png31.16 KBGábor Hojtsy
#70 interdiff.txt8.75 KBattiks
#70 i365615-chinese-70.patch21.75 KBattiks
#65 i365615-chinese-65.patch19.55 KBattiks
#65 interdiff.txt1.43 KBattiks
#62 interdiff.txt6.13 KBattiks
#62 i365615-chinese.patch19.56 KBattiks
#60 i365615-chinese.patch15.04 KBattiks
#60 i365615-chinese.interdiff.txt10.02 KBattiks
#54 i365615-configure.png37.31 KBattiks
#53 i365615-chinese.patch14.69 KBattiks
#53 i365615-chinese.interdiff.txt8.75 KBattiks
#48 i365615.png35.86 KBattiks
#37 i365615-chinese.patch6.61 KBattiks
#37 i365615-chinese.interdiff.txt5.63 KBattiks
#32 i365615-chinese.patch3.73 KBattiks
#32 i365615-chinese.interdiff.txt719 bytesattiks
#26 i365615-chinese.patch3.53 KBattiks
#26 i365615-chinese.interdiff-branch.txt2.04 KBattiks
#18 i365615-18.patch3.15 KBpenyaskito
#16 i365615-16.patch3.13 KBattiks
#15 i365615.patch3.8 KBattiks
#10 language_negotiation-6.x-zh.patch670 bytessmokris
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kcouch’s picture

I was also testing the browser detection for Simplified Chinese, and this seems to be an issue in 5.15 as well. However, yang_yi_cn's code changes seem to be specific for Drupal 6. Does anyone know how to resolve this for 5.x?

Pasqualle’s picture

Version: 6.9 » 7.x-dev
Status: Needs review » Needs work

Firefox 3 still uses zh-cn
http://www.w3.org/International/questions/qa-lang-priorities#answer

the correct xml:lang is zh-Hans
http://www.w3.org/International/questions/qa-css-lang#colon-lang
http://www.w3.org/International/articles/language-tags

Mandarin Chinese, Simplified Script: zh-Hans or zh-CN
http://tlt.its.psu.edu/suggestions/international/bylanguage/chinese.html...
http://www.w3.org/International/questions/qa-css-lang#bytheway

I am in favor to correctly map Firefox 3 (or other browser) languages with Drupal basic languages. So, fixing only 1 language is just a start, it is not a solution (although it is a most used language). And we need to allow any mapping of browser languages with Drupal languages, but it should be left for a contrib module.

shenzhuxi’s picture

Just change ""zh-hans" => array("Chinese, Simplified", "简体中文")," into "zh-cn" => array("Chinese, Simplified", "简体中文")," in locale.inc.
It'll be crazy to wait for browsers.

cshuangtw’s picture

Version: 7.x-dev » 6.13

I use Drupal 6.13 for a multi language website, it works very smart, but in Chinese system it's not work.
I traced source code include/language.inc change code
line 83
if (preg_match("!([a-z-]+)(;q=([0-9\\.]+))?!", trim($browser_accept[$i]), $found)) {
to
if (preg_match("!([a-z-]+)(;q=([0-9\\.]+))?!", trim(strtolower($browser_accept[$i])), $found)) {
if ($found[1] == 'zh-tw') { $found[1] = 'zh-hant';}
if ($found[1] == 'zh-cn') { $found[1] = 'zh-hans';}
In firefox $_SERVER[HTTP_ACCEPT_LANGUAGE] would return zh-tw,zh-cn but IE 8 and Chrome would return zh-TW - for traditional Chinese and zh-CN for Simpled Chinese
than it work fine.

juhovh’s picture

I would like to add that zh-hk and zh-sg are also used. Since Hong Kong uses traditional Chinese and Singapore uses simplified Chinese, I changed the patch of cshuangtw to:

if (preg_match("!([a-z-]+)(;q=([0-9\\.]+))?!", trim(strtolower($browser_accept[$i])), $found)) {
  if ($found[1] == 'zh-tw' || $found[1] == 'zh-hk') { $found[1] = 'zh-hant';}
  if ($found[1] == 'zh-cn' || $found[1] == 'zh-sg') { $found[1] = 'zh-hans';}

Now it seems to work with all Chinese variations quite nicely, at least I'm happy. Thanks for finding the correct piece of code.

Pasqualle’s picture

Version: 6.13 » 7.x-dev
GiorgosK’s picture

Status: Needs work » Closed (duplicate)
juhovh’s picture

Status: Closed (duplicate) » Needs work

This is not a duplicate of #221712, but somewhat related.

The bug #221712 is about language "en-us" not mapping to generic language "en" used by drupal. The proposed and probably correct solution there is to add the language "en" to the list of supported languages so that it will match.

This won't work for Chinese, because there is no generic language of Chinese as in "zh". Chinese has to be always defined as either simplified ("zh-hans") or traditional ("zh-hant"). This bug is about browsers using outdated country specific language identifiers (like "zh-cn" or "zh-tw") instead of the new standard and politically correct identifiers. The solution proposed in #221712 doesn't work here, instead there has to be some manual mapping of language identifiers as proposed above.

Chinese is the only language I know of, where the variants ("zh-hans" and "zh-hant") can't be determined from the language code. That is because some traditional Chinese users won't understand the simplified Chinese and vice versa. It's quite likely that English speakers in New Zealand are able to understand the US English, even though there might be small differences.

plach’s picture

Version: 7.x-dev » 8.x-dev
Status: Needs work » Active
smokris’s picture

Attached is a patch for Drupal 6.x Core, rewriting the "zh-tw" and "zh-cn" values provided by the browser into "zh-hant" and "zh-hans", respectively, to be what Drupal Core's language system expects. Uses str_replace(), which is a bit simpler and faster than mucking with regular expressions.

Garrett Albright’s picture

Title: language_from_browser cannot get correct language from browser's code sent » Language detection not working correctly for most Chinese readers
Priority: Normal » Major

"WormFood" in #drupal brought this to my attention today.

This is pretty bad, guys. Right now, browser-based language detection for traditional or simplified Chinese does not work for many browsers. And I'm not talking old ones here; I just tested with Opera 11 and Safari 5.1, and both sent zh-cn and zh-tw instead of zh-hans and zh-hant. Firefox 13 sends zh-hans/t, but apparently this is a recent development (see OP). I don't have access to IE to test.

Yes, the browsers are in violation of a standard, blah blah - that can only take us so far. This is twenty percent or so of the world's population we're talking about here. We need to fix this. Whether that's a one-off that just fixes it for Chinese, or a more generic way to "alias" language codes (perhaps an alter hook invocation in _locale_prepare_predefined_list() or something), it needs to be done, and I'm willing to help.

WormFood’s picture

I too agree, that something needs to be done, and I also am willing to help. I'm a native English speaker, currently living in China, and I want to see this problem get fixed.

I'm setting up a mutlilanguage Drupal 7 site, and I'm testing it with various browsers, and they all seem to work (didn't work last time I tried ), except for Epiphany/2.30.6. So I fired up the 'ole packet sniffer, to see exactly what language codes are being sent, and this is what I've discovered.

Mozilla (firefox 13), sends a language code of:
"Accept-Language: zh-cn,en-us;q=0.7,en;q=0.3", which works fine.

Epiphany, on the other hand, sends:
"Accept-Language: zh-cn, en-us;q=0.90, en;q=0.80, zh;q=0.70", which I expected to work, but it does not.

I am using netcat, and echo in my testing (I'm a Linux guy), so I can customize the header to anything I want. Changing the zh-cn, to zh-hans, makes it work as expected. Why is it that firefox works, but not Epiphany? Is Drupal stripping the "zh-cn" down to "zh", and matching that? That is what it seems to me, because if I use the Epiphany language string, and change the zh q= code to 0.81, I'll get the page in Chinese.

WormFood’s picture

Drupal 7 patch, to change zh-cn to zh-hans internally

Post #3 gives the suggestion of adding the language code zn-cn to the language array in iso.inc (in Drupal 7), but that won't work, because it will change Drupal's internal code to zh-cn, and will then Drupal will not not be able to find the language files (unless you want to change everything, but why work against the flow?), and won't be able to automatically update the core language files.

A few people at the top of this node, give a patch for Drupal 6. Here is my adaptation of that patch for Drupal 7 that fixes this problem, and will allow browsers sending a code of zh-cn to be properly detected internally to drupal, as zh-hans.

find function locale_language_from_browser($languages), in locale.inc, and change it from:

  if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']), $matches, PREG_SET_ORDER)) {
    foreach ($matches as $match) {
      // We can safely use strtolower() here, tags are ASCII.
      // RFC2616 mandates that the decimal part is no more than three digits,
      // so we multiply the qvalue by 1000 to avoid floating point comparisons.
      $langcode = strtolower($match[1]);
      $qvalue = isset($match[2]) ? (float) $match[2] : 1;
      $browser_langcodes[$langcode] = (int) ($qvalue * 1000);
    }

to (insert 6 lines)

  if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']), $matches, PREG_SET_ORDER)) {
    foreach ($matches as $match) {
      // We can safely use strtolower() here, tags are ASCII.
      // RFC2616 mandates that the decimal part is no more than three digits,
      // so we multiply the qvalue by 1000 to avoid floating point comparisons.
      if (strtolower($match[1]) == 'zh-tw') { 
        $match[1] = 'zh-hant';
      }
      if (strtolower($match[1]) == 'zh-cn') { 
        $match[1] = 'zh-hans';
      }
      $langcode = strtolower($match[1]);
      $qvalue = isset($match[2]) ? (float) $match[2] : 1;
      $browser_langcodes[$langcode] = (int) ($qvalue * 1000);
    }

Do not change "zh" to "zh-hans", (like the D6 patch does) because it will (probably) cause problems.

attiks’s picture

Assigned: Unassigned » attiks
attiks’s picture

Status: Active » Needs review
Issue tags: +Needs backport to D6, +Needs backport to D7, +D8MI, +sprint, +language-base
FileSize
3.8 KB

Patch against D8 fixing this, the logic is fixed as well.

attiks’s picture

FileSize
3.13 KB

New patch without colors

lazysoundsystem’s picture

Status: Needs review » Reviewed & tested by the community

I've checked this and it looks good.

penyaskito’s picture

FileSize
3.15 KB

Rerolled because of #1739994: Use the Language class universally instead of stdObj instances.

Relevant changed part:

+      // Chinese languages.
-       'zh-hans' => (object) array(
++      'zh-hans' => new Language(array(
 +        'langcode' => 'zh-hans',
-       ),
-       'zh-hant' => (object) array(
++      )),
++      'zh-hant' => new Language(array(
 +        'langcode' => 'zh-hant',
-       ),
++      )),
Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/language/language.negotiation.incundefined
@@ -102,7 +111,7 @@ function language_from_browser($languages) {
-      $browser_langcodes[$generic_tag] = $qvalue;
+      $browser_langcodes[$generic_tag] = $qvalue - 1;

Why do we need this change? Since the languages are ordered by qvalue, this would just put the list a bit lower with the same ordering, no?

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.phpundefined
@@ -66,8 +73,8 @@ class LanguageBrowserDetectionUnitTest extends UnitTestBase {
-      'en-US,fr' => 'en',
-      'fr,en-US' => 'en',
+      'en-US,fr' => 'en-US',
+      'fr,en-US' => 'en-US',

Why would these change. This change does not seem related to the other changes and is not explained. How is the new behavior now logical while the old behavior was passing tests and theoretically nothing changes to make it work like this?

attiks’s picture

Status: Needs work » Needs review

Gabor, I thought we discussed this, but here it goes

Languages are ordered by qvalue, but the $generic_tag (ex zh) is getting the qvalue from the passed value (zh-tw => zh-hant), so you end up with:
$browser_langcodes[zh] = 1000;
$browser_langcodes[zh-hant] = 1000;

Since the logic only changes the langcode if the weight is higher than the previously selected, it will never change to zh-hant, because zh-hans is defined first in the list of available languages.

You can easily test this by removing the - 1 and running the test again.

Besides that: if I browser specifies 'en-US,fr' as available languages and the site has a language en-us if should be the one used in favor of en. This patch fixes that as well: "Always use the most specific one, regardless of the order of the languages inside the array". The reason why this works now is because of the $qvalue - 1

Gábor Hojtsy’s picture

@attiks: thanks, I certainly understand it a bit better now :) We did some epic discussions in #221712: locale_language_from_browser() doesn't parse language tags correctly, has a broken logic though originally when we put the current logic in place, and would love to take opinions of those people to make sure we are not flip-flopping between different preferences. I think the intention there was that if you need to have specific languages before general languages, you should set your language list up like that, period. It also sounds like an edge case to have specific languages and generic languages both installed on a site.

I just want to get this right since there was so much work there already. I hope my cross-comment will get some interest here. Thanks!

attiks’s picture

The problem is that there's a difference between en-US and zh-hans, the first is English in the US, the second is Chinese

Quoting from #221712-25: locale_language_from_browser() doesn't parse language tags correctly, has a broken logic: "When making the choice of linguistic preference available to the user, we remind implementors of the fact that users are not familiar with the details of language matching as described above, and should provide appropriate guidance. As an example, users might assume that on selecting "en-gb", they will be served any kind of English document if British English is not available. A user agent might suggest in such a case to add "en" to get the best matching behavior."

So we have to pich the most specific one, if it's available regardless of the order defined in Drupal.

WormFood’s picture

For what it is worth, the patch I'm actually using is slightly different from what I posted here. I probably should have included zh-hk in addition to zh-tw in my original patch. I did a little more research into the Chinese language codes available, and I've also added zh-sg (Singapore) and zh-mo (Macau) into the patch I'm using on my drupal sites.

if (strtolower($match[1]) == 'zh-tw' || strtolower($match[1]) == 'zh-hk' || strtolower($match[1]) == 'zh-mo') {
$match[1] = 'zh-hant';
}
if (strtolower($match[1]) == 'zh-cn' || strtolower($match[1]) == 'zh-sg') {
$match[1] = 'zh-hans';
}

attiks’s picture

@WormFood: do you by any change have a list of all possible values? My knowledge about Chinese is a bit limited to say the least ;-)

WormFood’s picture

@attiks: Those 5 language codes I listed in my last post are the only ones I'm aware of.
zh-cn (mainland China), and zh-sg (Singapore) use simplified Chinese.
zh-hk (Hong Kong), zh-tw (Taiwan), and zh-mo (Macau) use traditional Chinese.
I did find reference to a zh-chs (simplified), and zh-cht (traditional) language codes, but I suspect those have not been in use by web browsers for a very long time, if ever.

I know this is more than you asked for, but sometimes it helps to make more sense of things, if you understand some of the background. I'll try to keep this short. After the communists took over China, some of the Chinese characters were "simplified". Since Taiwan, Hong Kong, and Macau were not under communist control, they never changed their writing system, and they continue to use the "traditional" Chinese characters today. The Chinese written in Singapore has more of a mainland Chinese influence, so they use simplified characters in Singapore.

In case you're wondering where the "zh" part of the language code comes from; that is for "zhong guo" (中国), the name of China, in Chinese. The "han" part is probably for "han zi" (汉字 ), which is the word for "Chinese character", in Chinese. The "s" or "t", if you didn't guess by now, is for Simplified or Traditional. Chinese written with Latin (Western) letters is called "pinyin" (拼音 literally "spell sound"), and there may be a language code for pinyin, but I couldn't find reference to one.

Thank you attiks, and everyone else working on this issue. I'm very happy to finally see some actions being taken to fix this. I don't quite understand the testing framework part of the patch, otherwise I'd be trying to help in that area.

attiks’s picture

New patch, I also added zh-chs and zh-cht

@WormFood: thanks for the explanation, good to know

Gábor Hojtsy’s picture

Quoting from #221712-25: locale_language_from_browser() doesn't parse language tags correctly, has a broken logic: "When making the choice of linguistic preference available to the user, we remind implementors of the fact that users are not familiar with the details of language matching as described above, and should provide appropriate guidance. As an example, users might assume that on selecting "en-gb", they will be served any kind of English document if British English is not available. A user agent might suggest in such a case to add "en" to get the best matching behavior."

So we have to pich the most specific one, if it's available regardless of the order defined in Drupal.

Well, the text you quote says we should pick the more general one when the user provided the more specific one. This patch looks like makes the change to the other way around instead, to pick the more specific one if the general was provided.

Either way it seems to be shaping up to be a more over-arching mapping of external language codes to internal language codes problem similar to #580260: Map local language codes to remote language codes. Not really sure if we want to go down on that route, and I acknowledge that Chinese has this problem the most badly. :/

attiks’s picture

@Gabor: the quote says the UA might suggest to add more generic one to get the best UX. Drupal as a platform can add automatic fallback to the most generic one in case the more specific one isn't defined, but that isn't part of the RFC.

Examples (assuming no qvalue are set):
Browser send en-us and Drupal defines en => use en // generic one (courtesy of Drupal)
Browser send en-us and Drupal defines en + en-us => use en-us // exact match
Browser send en-us and Drupal defines en + en-uk => use en // generic one (courtesy of Drupal)

Browser send en-us, fr and Drupal defines en, fr => use fr // exact match
Browser send en-us, fr and Drupal defines en, en-us + fr => use en-us // exact match, first one selected
Browser send en-us, fr and Drupal defines en, en-uk + fr => use fr // exact match

Damien Tournoud’s picture

Status: Needs review » Needs work

The change makes sense: we use the generic language if it is not specified, but we give it a slightly lower priority so as not to prevent more-specific matches from happening.

Obviously, we need to add a very detailed explanation of why we do that right above this line.

I also suggest we replace - 1 by - 0.1 so that we don't risk a collision with another weight specified in the header.

Needs work for documentation.

Gábor Hojtsy’s picture

@Damien: thanks for you review and encouragement. It makes me much more comfortable saying this is a good direction :) @attiks: let's document this and then we can get it in. We can still figure out more generic language matching at #580260: Map local language codes to remote language codes (or its core equivalent) later.

shenzhuxi’s picture

I think this issue has the same condition http://drupal.org/node/870350

attiks’s picture

Status: Needs work » Needs review
FileSize
719 bytes
3.73 KB

@Damien thanks for reviewing, new patch attached.

Status: Needs review » Needs work
Issue tags: -Needs backport to D6, -Needs backport to D7, -D8MI, -sprint, -language-base

The last submitted patch, i365615-chinese.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review
Issue tags: +Needs backport to D6, +Needs backport to D7, +D8MI, +sprint, +language-base

#32: i365615-chinese.patch queued for re-testing.

Damien Tournoud’s picture

+      // Handle Chinese so it maps right, some browsers are sending
+      // wrong langcodes.

Please elaborate more on why this is needed. Especially, mention that browsers are sending a langcode that is not a valid IETF language tag.

attiks’s picture

What about "Handle Chinese so it maps right, some browsers are sending non standard langcodes, we map them to the right ones."

attiks’s picture

I discussed this a bit with damien in IRC

http://www.iana.org/assignments/language-subtag-registry defines the following

zh-Hans - simplified Chinese
zh-Hans-CN - PRC Mainland Chinese in simplified script
zh-Hans-HK - Hong Kong Chinese in simplified script
zh-Hans-MO - Macao Chinese in simplified script
zh-Hans-SG - Singapore Chinese in simplified script
zh-Hans-TW - Taiwan Chinese in simplified script

zh-Hant - traditional Chinese
zh-Hant-CN - PRC Mainland Chinese in traditional script
zh-Hant-HK - Hong Kong Chinese in traditional script
zh-Hant-MO - Macao Chinese in traditional script
zh-Hant-SG - Singapore Chinese in traditional script
zh-Hant-TW - Taiwan Chinese in traditional script

So we need mappings as follows:

zh-tw --> zh-hant-tw
zh-hk --> zh-hant-hk
zh-mo --> zh-hant-mo
zh-cht --> zh-hant

zh-cn --> zh-hans-cn
zh-sg --> zh-hans-sg
zh-chs --> zh-hans

Mappings are now defined in language.mappings.yml
The test is now a WebTest since it needs to load the config

1 todo left: how to make it easy for others to add/override the mappings

Status: Needs review » Needs work
Issue tags: -Needs backport to D6, -Needs backport to D7, -D8MI, -sprint, -language-base

The last submitted patch, i365615-chinese.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review

#37: i365615-chinese.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, i365615-chinese.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review

#37: i365615-chinese.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, i365615-chinese.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review
Issue tags: +Needs backport to D6, +Needs backport to D7, +D8MI, +sprint, +language-base

#37: i365615-chinese.patch queued for re-testing.

Gábor Hojtsy’s picture

I agree it is the best to have a general mapping solution for language codes instead of just hard-wiring specific mappings. This was underlined in #580260: Map local language codes to remote language codes too. I thought it would be too much of a burden to solve here, but looks like you have a good handle on it :)

attiks’s picture

Anybody has an idea on how to make this easy for others to add new mappings? Is this solved by CMI, or do we have to read all configs of the form language.mappings.*?

attiks’s picture

Status: Needs review » Needs work

I had a quick talk with heyrocker and we need to add an UI for this

WormFood’s picture

Status: Needs work » Needs review

I think the ancient zh-chs and zh-cht language codes are totally unnecessary. I'm pretty sure that if web browsers ever sent that language code, it was a very long time ago. The real problem with Drupal, was not recognizing zh-cn/zh-tw/etc as a legitimate language code.

I was reading about the different language codes, trying to understand the logic behind codes like zh-sg, and zh-mo, and it is my understanding is that while the written part may be the same language, but other aspects may be different for that locale, like the currency symbol, or the date format. How is drupal supposed to properly support this aspect of the differences in locales? This question also applies to languages more familiar to us, like en-us and en-gb. Slight spelling differences aside, we have other differences like date format and currency symbols. How are we supposed to change those settings for the different regional differences? I haven't installed Drupal 8 yet, but with Drupal 7, even tho I can change the date formats for the different languages, I don't have the choice to display the date in Chinese.

I agree, there should be some easy way to map the language codes to whatever you want. I think there should be a generic way, to map whatever language code the browser is sending, into whatever internal language code you want, and be able to set the date format accordingly. For example, maybe zh-cn will give you simplified Chinese, with a date format one way, but zh-sg will give you the same language, but with a different date format. This will give the site owner maximum flexibility, and would even allow them to configure their own custom language codes (maybe for testing) and date formats.

Also, the simple patch I posted to fix this problem seems to be identical for Drupal 8, as it is for Drupal 7, but Drupal 6 will be slightly different. If this is changed into a full fledged feature, rather than just a quick'n dirty hack, will it be backported to Drupal 6/7?

[edit] oops. I changed the status unintentionally. I don't see how to revert that, without a new post.

attiks’s picture

FileSize
35.86 KB

We can add a configure link at admin/config/regional/language/detection and just show everything in a huge textarea

OK?

i365615.png

attiks’s picture

Status: Needs review » Needs work

What is the problem with Chinese dates? And will it not be fixed by the new mappings?
zh-tw: zh-hant-tw
zh-hk: zh-hant-hk
zh-mo: zh-hant-mo
zh-cht: zh-hant
zh-cn: zh-hans-cn
zh-sg: zh-hans-sg
zh-chs: zh-hans

will it be backported to Drupal 6/7?

It should be not a huge problem, the only difference is that config will get replaced by variable_get/variable_set

WormFood’s picture

Not sure if that will be fixed by the new language mappings. Is it your intent to add zh-hant-tw, zh-hant-hk, zh-hant-mo, etc language codes? Because really, they're all the same languages. The only differences may be their date format. I'm not too sure in this area. I know regular Chinese dates are in the format of 2012年08月30日, but I don't get that option with Drupal 7. I'm not sure what date format is regular in those other locales (Taiwan, Hong Kong, Macau, Singapore), they may not need to be changed at all.

Also, I noticed in the list of language codes, that there is a code for Chinese written in pinyin, and Wades-Giles (using the Latin alphabet). For example, 北京, the nation's capital is written as "Beijing" in pinyin, and "Peking" in Wades-Giles. People don't usually use pinyin for every day use, it is more of a teaching language. I don't think that needs to be added as a language option (I think it would be a little silly), however, it would make Drupal support a complete set of Chinese language options. It would be a cool option for a Chinese language learning site.

As far as a big text area goes, I think that would be fine for testing, but I think it should have a normal interface, like the rest of the Drupal admin areas. Personally, I think it would be better to pick the date formats, at the same place you configure the language. Perhaps have the ability to add your language code (zh-cn) for example, map it to the proper internal code (zh-hans), and select the date/time formats at the same place. Then you could add zh-sg and zh-hans-sg, and also map them to zh-hans, but have a different date/time format. Keep the date format menu item in the same place, but just have it direct you to the language page, where those settings are. Just my 2 cents worth.

attiks’s picture

I see what you mean, let's first try to solve to language detection problem and open a new issue for the date problem.

Basically you have 1 site in zh-hans, but you want different date formats for zh-hans-tw and zh-hans-cn, right?

PS: If you open a new issue can you post the link in this one, thanks

attiks’s picture

In Drupal 7 I can do dates like 2012年03月09日 at en/admin/config/regional/date-time/locale

attiks’s picture

Status: Needs work » Needs review
FileSize
8.75 KB
14.69 KB

new patch including 'proper' admin interface

attiks’s picture

FileSize
37.31 KB

And a screenshot

Status: Needs review » Needs work
Issue tags: -Needs backport to D6, -Needs backport to D7, -D8MI, -sprint, -language-base

The last submitted patch, i365615-chinese.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review
Issue tags: +Needs backport to D6, +Needs backport to D7, +D8MI, +sprint, +language-base

#53: i365615-chinese.patch queued for re-testing.

attiks’s picture

penyaskito’s picture

Status: Needs review » Needs work
+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,183 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+    '#markup' => t("You can add custom mappings to map browser languages to Drupal languages."),

Use single quotes.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,183 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+ * Theme browser configuration form as table.

Requires "@ingroup themeable" phpdoc.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,183 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+  $question = t('Are you sure you want to delete %browser_langcode', array(

We need the question mark.

+++ b/core/modules/language/language.moduleundefined
@@ -596,3 +616,23 @@ function language_url_outbound_alter(&$path, &$options, $original_path) {
+function language_get_mappings() {
...
+function language_set_mappings($mappings) {

Clever, backporting made easy :-)

+++ b/core/modules/language/language.negotiation.incundefined
@@ -100,9 +111,20 @@ function language_from_browser($languages) {
+    // For chinese languages the generic tag is either zh-hans or zh-hant, so we
+    // need to handle this separately.
+    $generic_tag = '';
+    if (strlen($langcode) > 7 && (substr($langcode, 0, 7) == 'zh-hant' || substr($langcode, 0, 7) == 'zh-hans')) {
+      $generic_tag = substr($langcode, 0, 7);
+    }
+    else {
+      $generic_tag = strtok($langcode, '-');
+    }
+    if (!empty($generic_tag) && !isset($browser_langcodes[$generic_tag])) {
+      // Add the generic langcode, but make sure it has a lower qvalue as the
+      // more specific one, so the more specific one gets selected if it's
+      // defined by both the browser and Drupal.
+      $browser_langcodes[$generic_tag] = $qvalue - 0.1;

Do we need this chinese specific code now that we have the mapping configurable?

penyaskito’s picture

+++ b/core/modules/language/language.negotiation.incundefined
@@ -81,7 +81,18 @@ function language_from_browser($languages) {
+    $mappings = language_get_mappings();

language.negotiation.inc is included in install.core.inc for calling language_from_browser(). language_get_mappings() is defined in language.module, so it needs to be imported too in install.core.inc for the installation to work, or move language_get_mappings to language.negotiation.inc.

Otherwise you got an WSOD on installation.

attiks’s picture

Status: Needs work » Needs review
FileSize
10.02 KB
15.04 KB

New patch adresssing feedback from #58 and #59

We need "For chinese languages the generic tag is either zh-hans or zh-hant, so we need to handle this separately." because there's no 'zh' language, so the only way to find this generic Chinese language is to handle it separately.

Gábor Hojtsy’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Good stuff, looks like a useful UI to me. However, now we'd need tests for adding to/changing the config. Apart of that, minor comment mistakes:

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,189 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+  // Add empty row

Dot at end of line.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,189 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+/**
+ * Delete a language mapping form.
+ */
...
+/**
+ * Delete a language mapping submit.
+ */

Delete a mapping form? A mapping submit?!

+++ b/core/modules/language/language.moduleundefined
@@ -596,3 +616,24 @@ function language_url_outbound_alter(&$path, &$options, $original_path) {
+  $config->save();
+}
\ No newline at end of file

Should have a newline at end of file.

attiks’s picture

Status: Needs work » Needs review
FileSize
19.56 KB
6.13 KB

comments fixed, tests added.

attiks’s picture

Issue tags: -Needs tests

Tests added, tag removed

penyaskito’s picture

Status: Needs review » Needs work
+++ b/core/modules/language/language.admin.incundefined
@@ -970,7 +973,7 @@
+ * Delete a browser language negotiation mapping.

@@ -982,7 +985,7 @@
+ * Delete a browser language negotiation mapping.

Should we say "Form for deleting a browser language negotiation mapping." and "Submit handler for deleting a browser language negotiation mapping."?

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.phpundefined
@@ -28,7 +28,7 @@
-  function testLanguageFromBrowser() {
+  function testLanguamergeFromBrowser() {

Typo. Should be testLanguageFromBrowser.

It should be the last review before RTBC :-)
Thanks attiks!

attiks’s picture

Status: Needs work » Needs review
FileSize
1.43 KB
19.55 KB

should be ok

penyaskito’s picture

If tests pass, it's fine for me. :)

penyaskito’s picture

Status: Needs review » Reviewed & tested by the community

RTBC

webchick’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Usability

First off, WOW! How nice that you not only solved the immediate problem but gave people the ability to solve this on their own for future issues, too. :)

Since this is slated for D7 backport I need to be a bit more of a hard-ass on this review. Apologies in advance.

+++ b/core/modules/language/language.moduleundefined
@@ -596,3 +616,24 @@ function language_url_outbound_alter(&$path, &$options, $original_path) {
+ * Returns language mappings.
...
+ * Stores language mappings.

Could we get a bit more info here? I can imagine reading this function out of context of this issue and asking the question, "Language mappings between what and what?"

In fact, should we name this function something with "browser" in the name to help with that?

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,192 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+    '#markup' => t('You can add custom mappings to map browser languages to Drupal languages.'),

Can you add a sentence that explains why I would want to / how I know I need to do that?

+++ b/core/modules/language/config/language.mappings.ymlundefined
@@ -0,0 +1,7 @@
+zh-tw: zh-hant-tw
+zh-hk: zh-hant-hk
+zh-mo: zh-hant-mo
+zh-cht: zh-hant
+zh-cn: zh-hans-cn
+zh-sg: zh-hans-sg
+zh-chs: zh-hans

We don't typically put comments in the default YML files that come with modules, but in this case I think it'd be a really good idea, because I can't imagine another place to document why we have these defaults and what specific problem we're trying to solve.

Just a line or two that summarizes it would suffice.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,192 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+  foreach ($mappings as $browser_langcode => $drupal_langcode) {
+    $form['mappings'][$browser_langcode] = array(
+      'browser_langcode' => array(
+        '#type' => 'textfield',
+        '#default_value' => $browser_langcode,
+        '#size' => 20,
+      ),
+      'drupal_langcode' => array(
+        '#type' => 'textfield',
+        '#default_value' => $drupal_langcode,
+        '#size' => 20,
+      ),
...
+  $form['mappings']['_new'] = array(

This seems to be breaking a UX pattern used elsewhere in Drupal, which is that anytime we show a list of things in a table, it's simply that: a list of things in a table. If you want to edit then, that's a separate "edit" action.

Doing the same here would allow us to get rid of that funky and special "_new" keyname, in favour of something more consistent and legible like "language_mapping."

So unless I'm wrong and we already do this in other places in the interface, I think we should move to that.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,192 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+        // Make sure browser_langcode is unique
...
+        // Make sure browser_langcode is unique

(nitpick) Periods at the end of these sentences.

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,192 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+        elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
+          form_set_error('mappings][' . $key . '][browser_langcode', 'Browser language codes can only contain lowercase letters and a hyphen(-).');
+        }
+        elseif (preg_match('/[^a-z\-]/', $data['drupal_langcode'])) {
+          form_set_error('mappings][' . $key . '][drupal_langcode', 'Drupal language codes can only contain lowercase letters and a hyphen(-).');
+        }

Just asking, but is there a way to consolidate this into one if statement somehow?

+++ b/core/modules/language/language.admin.incundefined
@@ -807,3 +807,192 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+        form_set_error('mappings][' . $key . '][drupal_langcode', 'Both browser and Drupal language codes must be provided.');

Can we not just make these required fields then?

+++ b/core/modules/language/language.negotiation.incundefined
@@ -100,9 +111,20 @@ function language_from_browser($languages) {
+    // For chinese languages the generic tag is either zh-hans or zh-hant, so we

(nitpick) Capitalize "Chinese."

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.phpundefined
@@ -66,8 +75,8 @@ class LanguageBrowserDetectionUnitTest extends UnitTestBase {
-      'en-US,fr' => 'en',
-      'fr,en-US' => 'en',
+      'en-US,fr' => 'en-US',
+      'fr,en-US' => 'en-US',

There was some really good discussion above as to why we changed this; can we make sure some of this is captured in code comments here so the next person doesn't flag an issue with these being inconsistent with the lines above?

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.phpundefined
@@ -128,4 +152,80 @@ class LanguageBrowserDetectionUnitTest extends UnitTestBase {
+  function testUIBrowserLanguageMappings() {

Let's get a one-liner of PHPDoc above this to explain what it's doing.

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.phpundefined
@@ -128,4 +152,80 @@ class LanguageBrowserDetectionUnitTest extends UnitTestBase {
+    $message = t('Are you sure you want to delete !browser_langcode?', array(
+      '!browser_langcode' => $browser_langcode,

Is there a reason we do ! here rather than @? This is just plain-text, right?

webchick’s picture

Oh son of a monkey. I accidentally pasted my Dreditor review twice. If you got that in e-mail, please read again, it's a lot less confusing now. ;P

attiks’s picture

Status: Needs work » Needs review
FileSize
21.75 KB
8.75 KB

Thanks for reviewing, new patch attached:

  • all feedback processed
  • UI is still the same but I don't mind changing it, I'll try pinging Bojhan
  • consolidating the validation logic isn't going to improve readability
Gábor Hojtsy’s picture

@webchick, @attiks: it is not entirely true Drupal 7 did not have any in-place editing on the admin UI. It might be a bit obscure, but the book outline admin page lets you reoder and retitle book pages in a book (with edit links going to the full node page):

BookInlineEdit.png

Drupal 7 also has in-place addition in the roles configuration screen and the fields configuration screen. As for more examples of in-place editing, the language UIs in fact introduced this earlier at two places in Drupal 8.

1. For URL prefix/domain editing, it makes ton of sense to have them edit all at once, since if you eg. need to swap domains, you can easily end up on different language admin pages, while you remove the domain from one language and add on another. Sensitive configuration that is likely changed all at once:

InPlaceURLPrefixes.png

2. For interface translation, what we found is that the pattern is that people work with short strings and usually want to edit multiple of them for the same language is very short succession. This workflow is in part where the success of l10n_client module came from. So introduced the same thing:

InPlaceTranslation.png

In summary, I'd argue there are multiple places in core in Drupal 7 where in-place addition in a table was working and at least one place with in-place editing on the admin UI. Now there are at least two more places in Drupal 8 where in-place editing of multiple things at once is present on the admin UI.

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

Moving back to RTBC on those grounds and that @attiks took care of the rest of the concerns.

Bojhan’s picture

I am not particularly excited about introducing this pattern, it is uncommon and has all kinds of issues (e.g. people not clicking save, changing things then pressing delete, etc.). However in this case I can see that its useful, because you are going to be mapping a lot of languages, rather than just one (fyi, book and roles are really poor examples, they shouldn't have this pattern).

I do wish to note, that the description is a little bit strange. It should help in filling out this form, most users won't know what to fill in here - perhaps that can be part of release nodes orso.

attiks’s picture

Description is strange indeed, but people setting up multilingual sites and having this kind of problems are likely going to know a bit about how to handle the language problem, up till now they didn't had any way to do this.

Trying to explain this problem in a couple of lines is likely going to fail, because it depends on the browsers, languages defined in Drupal, use case, ...

attiks’s picture

Status: Reviewed & tested by the community » Needs work

[12:50] GaborHojtsy attiks: well, the language_negotiation_configure_browser_form() 'help' markup text should be in a hook_help() with language module really
[12:53] GaborHojtsy attiks: and then it can be a little expanded like "Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the language codes used by Drupal."

attiks’s picture

Status: Needs work » Needs review
FileSize
22.36 KB
1.65 KB

moved help to hook_help and changed the wording

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

Even resolved Bojhan's concerns now. :)

Dries’s picture

Status: Reviewed & tested by the community » Needs work
@@ -0,0 +1,9 @@
+# Most browser do not send abbreviated languages codes not standard

This doesn't sound like proper English. Needs a bit of tweaking. (Update: DrEditor cut off the next line it seems.)

+++ b/core/modules/language/language.moduleundefined
@@ -37,6 +37,10 @@ function language_help($path, $arg) {
+    case 'admin/config/regional/language/detection/browser':
+      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the language codes used by Drupal.') . '</p>';
+      return $output;

One thing that came to mind when reviewing this patch and looking at the screenshots was: how do people know what language codes Drupal supports? I felt that could use a bit more documentation/guidance for site builders. See #54 for example. That UI made me believe that I need to know the Drupal language codes, or that I need to look up the Drupal language codes somewhere. If they are pre-defined, it might make more sense to have a drop-down menu for the Drupal ones? I don't know. Maybe I'm slightly confused about this but as an end-user I feel a bit lost with the current UI.

attiks’s picture

Status: Needs work » Needs review
FileSize
22.34 KB
681 bytes

Thanks for the review, I changed the wording inside the .yml file

The second comment is a bit more difficult:
1/ drop-down isn't going to work, because it implies that the default aren't going to be loaded, since you need the language module to define the new languages first you'll end up with a chicken and egg problem. If we really want a drop-down we need to define all possible language code (2 characters, 3 characters, 2 characters + country/region, ...) and it means we need to maintain that list as well. Related issue #923304-20: zh-cn and zh-tw incorrectly used

2/ a user has to know about language codes, but it's almost the same as Drupal 7, this patch only allows you to fine-tune how language codes are handled (new optional feature) and will probably be used by 'Chinese' sites so solve their problems and huge multilingual sites that for instance wants to use nl-nl and nl-be, instead of just nl (ex: 'kleed' versus 'jurk').

3/ we can link to http://www.w3.org/International/articles/language-tags/ but i doubt that it will help somebody that has no idea what to do on this screen in the first place.

PS: I know UI/UX is not optimal compared with adding a new language (admin/config/regional/language/add) and I'm open for any suggestions.

Gábor Hojtsy’s picture

I guess, the only way to provide a dropdown would be if it would contain all predefined and all configued languages, like the locale import form. The chicken and egg problem is if the dropdown only has configured languages, then we cannot ship with the Chinese defaults, since it would not be editable on non-Chinese sites.

Gábor Hojtsy’s picture

Also, I assume tHe drop-down would be for the target (internal to Drupal) language codes. Dropdowns for the external language code do not seem possible.

attiks’s picture

#80I completely agree
#81Providing a list for internal languages is not possible either, for the moment Drupal only ships with language codes, not language + country/region or something like language-extlang-script-region-variant-extension-privateuse (source)

If this is the only reason to hold back on this patch, can you open a follow-up issue to address this, so we can start backporting this?

Gábor Hojtsy’s picture

If the target (internal) languages are not among ones shipped with Drupal, then why we do we map to them? Id they are among the ones shipped, we could build a dropdown like the import form, with the configured AND predefind languages along each other, no?

attiks’s picture

@Gabor, because you a user can define custom languages like nl-be and he probably wants to map nl to nl-be at that time as well, in theory we can use a drop down for the target (Drupal) language, but not if we want to ship the defaults needed to solve the 'Chinese' problem.

I think we just have to decide:

  1. Use textboxes for both languages as it's right now
  2. Use a dropdown for the target (Drupal) language code and ship without defaults

Personally I prefer option 1, but I'm fine with 2.

Gábor Hojtsy’s picture

If the target (Drupal) language codes are not actually ones predefined in Drupal (ie. translated on localize.drupal.org), then people would use different language codes (ones equal to codes on localize.drupal.org) to sync with the community, right? How do we plan to bridge that gap and what sense does this mapping have if it does not actually map to language codes that people will use?

attiks’s picture

if I was to setup a site for the Benelux I would define my languages as follows: nl-be, nl-nl, fr-be and fr-lu because there're regional difference between nl-be and nl-nl. As a start I would copy nl.po to nl-be.po and nl-nl.po as a start, but I would tweak the translations based on the region.

How to sync back to the community is a different (but also important) issue, but in the long wrong we need some system that allows extending/overriding a 'base' language. 99% of the translations are the same in Dutch, so we would have nl, but also nl-nl and nl-be that contain small alterations of nl. If a site is using nl-be right now, it shouldn't be allowed to sync back to l.d.o.

My browser languages are setup as "nl-be, nl, nl-nl, en" so it can be important for a site admin to alter this depending on his/her target audience/browser (nl-nl isn't listed in FF, but it is in IE)

attiks’s picture

FileSize
23.2 KB
5.23 KB

New patch after discussion in irc

[15:15]	GaborHojtsy attiks: I think its concerning that we configure this up in a way that is not compatible with other parts of our configuration
[15:16]	GaborHojtsy	attiks: so if you add all Chinese from the default list of languages in Drupal
[15:16]	GaborHojtsy	attiks: it would still not work at all, right?
[15:16]	GaborHojtsy	attiks: it does not really solve the problem unless you add all your Chinese as custom languages
[15:17]	attiks	GaborHojtsy: simplified and tradition Cinese is in the list, but you'll need the mapping
[15:17]	attiks	GaborHojtsy: no need to define a custom Chinese language
[15:18]	GaborHojtsy	attiks: so zh-hant and zh-hans
[15:19]	attiks	GaborHojtsy: are provided by Drupal
[15:27]	GaborHojtsy	attiks: yeah, ok
[15:28]	GaborHojtsy	attiks: so this is pretty confusing that we'd ship with mapping for languages that Drupal does not ship with or support via UI translation, etc.
[15:28]	GaborHojtsy	attiks: were these all part of the original problem space or it just extended to this point?
[15:29]	attiks	GaborHojtsy: most are from original problem, they are extended to handle all Chinese variants
[15:30]	attiks	GaborHojtsy: if it makes you feel better, we can ship with other defaults
[15:30]	attiks	GaborHojtsy: +# Browsers use different language codes to refer to the same languages,
[15:30]	attiks	+# these defaults handles the most common cases.
[15:30]	attiks	+zh-tw: zh-hant # Taiwan Chinese in traditional script
[15:30]	attiks	+zh-hk: zh-hant # Hong Kong Chinese in traditional script
[15:30]	attiks	+zh-mo: zh-hant # Macao Chinese in traditional script
[15:30]	attiks	+zh-cht: zh-hant # traditional Chinese
[15:30]	attiks	+zh-cn: zh-hans # PRC Mainland Chinese in simplified script
[15:30]	attiks	+zh-sg: zh-hans # Singapore Chinese in simplified script
[15:30]	attiks	+zh-chs: zh-hans # simplified Chinese
[15:33]	GaborHojtsy	attiks: yup, that sounds like would fit in with our model of languages
[15:33]	attiks	GaborHojtsy: I'll reroll the patch
[15:34]	GaborHojtsy	attiks: which would then allow us to have a *dropdown* for target language
[15:34]	GaborHojtsy	attiks: which was Dries' main concern
[15:34]	GaborHojtsy	attiks: that you'd need to cross-check target langcodes manually
[15:35]	attiks	GaborHojtsy: so target -> dropdown limited to what list?
[15:35]	GaborHojtsy	attiks: I'd use the same list as the .po import form (copy-paste code?
[15:35]	GaborHojtsy	attiks: i.e the configured languages and the predefined languages
[15:35]	attiks	GaborHojtsy: will do
[15:35]	GaborHojtsy	attiks: once someone configures a more fine-tuned Chinese language
[15:36]	GaborHojtsy	attiks: they could assign that as a target language AFTER that
[15:36]	attiks	GaborHojtsy: correct
Gábor Hojtsy’s picture

Status: Needs review » Needs work
FileSize
73.97 KB

Much better UX IMHO, reflects on what Dries proposed, very close :)

There are some minor UI label fixes now that we display languages vs. request the more obscure language codes. And one more remaining piece for me looks like where a new item is added, it is not possible to specify the language in a dropdown. It should be the same for consistency (and data validation automatically provided by the dropdown). If we are concerned that its cumbersome to figure out you still need to add a corresponding language, we can link the "languages used by Drupal" to the language list. We do the same at other places to backlink there for quick navigation.

BrowserLanguageMapping-2.jpg

attiks’s picture

Status: Needs work » Needs review
FileSize
22.3 KB
4.89 KB

no idea what I was thinking, but this one should be better.

Bojhan’s picture

What is that bottom row?

attiks’s picture

To add a new mapping

attiks’s picture

FileSize
59.91 KB

Screenie of new UI as briefly discussed with Bojhan

EDIT: Fieldset is collapsed by default.

i365615-92.png

attiks’s picture

FileSize
21.88 KB
6.99 KB

Patch implementing the new UI

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me., resolves Dries' concern, resolves Bojhan's concerns :)

sun’s picture

Status: Reviewed & tested by the community » Needs work

Great work all! :)

I reviewed this patch in some more detail and found the following issues:

+++ b/core/modules/language/language.admin.inc
@@ -813,3 +813,203 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+function language_negotiation_configure_browser_form($form, &$form_state) {
...
+  // Initialize a language list to the ones available, including English.
+  drupal_static_reset('language_list');
+  $languages = language_list();

It would be great to have a code comment here that explains why this static needs to be reset. Even better would be to eliminate it, if possible.

+++ b/core/modules/language/language.admin.inc
@@ -813,3 +813,203 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+  $form['mappings'] = array(
+    '#type' => 'container',

AFAICS, the #type container is not needed here and can be removed.

+++ b/core/modules/language/language.admin.inc
@@ -813,3 +813,203 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+  $form_state['redirect'] = 'admin/config/regional/language/detection';

Normally, this is specified in the form submission handler. Any particular reason for why it's specified in the constructor?

+++ b/core/modules/language/language.admin.inc
@@ -813,3 +813,203 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+function language_negotiation_configure_browser_form_validate($form, &$form_state) {
...
+  // Check all mappings.
+  $mappings = array();
+  if (isset($form_state['values']['mappings'])) {
+    $mappings = $form_state['values']['mappings'];
+    foreach ($mappings as $key => $data) {
+      // Make sure browser_langcode is unique.
+      if (array_key_exists($data['browser_langcode'], $unique_values)) {
+        form_set_error('mappings][' . $key . '][browser_langcode', 'Browser language codes must be unique.');
+      }
+      elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
+        form_set_error('mappings][' . $key . '][browser_langcode', 'Browser language codes can only contain lowercase letters and a hyphen(-).');
+      }
+      $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
+    }
+  }
+
+  // Check new mapping.
+  $data = $form_state['values']['new_mapping'];
+  if (!empty($data['browser_langcode'])) {
+    // Make sure browser_langcode is unique.
+    if (array_key_exists($data['browser_langcode'], $unique_values)) {
+      form_set_error('mappings][' . $key . '][browser_langcode', 'Browser language codes must be unique.');
+    }
+    elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
+      form_set_error('mappings][' . $key . '][browser_langcode', 'Browser language codes can only contain lowercase letters and a hyphen(-).');
+    }
+    $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
+  }

1) We're missing t() around the error messages.

2) It looks like the second loop does exactly the same as the first, only on a different element. We can eliminate it entirely by creating a new array upfront and merging the 'mappings' with the 'new_mapping', so that there is only one loop.

+++ b/core/modules/language/language.module
@@ -581,3 +605,32 @@ function language_url_outbound_alter(&$path, &$options, $original_path) {
+function language_get_browser_drupal_langcode_mappings() {
...
+  if ($config->isNew()) {
+    config_install_default_config('module', 'language');
+    $config = config('language.mappings');
+  }

If browser language negotiation is enabled, this code runs on every request. Drupal should not dynamically create or change configuration on arbitrary requests.

The calling code seems to be perfectly able to handle an empty mapping. So let's just remove this automatic creation, please.

+++ b/core/modules/language/language.negotiation.inc
@@ -105,9 +125,20 @@ function language_from_browser($languages) {
+    // For Chinese languages the generic tag is either zh-hans or zh-hant, so we
+    // need to handle this separately.

Any chance to explain the code logic for the Chinese language handling a bit more? It's not easy to follow what is being done, and more importantly, why it's being done.

+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
@@ -128,4 +159,68 @@ class LanguageBrowserDetectionUnitTest extends UnitTestBase {
+    $this->assertRaw($message, 'Question found.');
...
+    $this->assertText('Browser language codes must be unique.', 'Error message displayed.');
...
+    $this->assertText(t('Browser language codes must be unique.'), 'Error message displayed.');

When asserting literal/human-readable strings on a page, it is much better for debugging to not specify a custom assertion message - so if the test will fail, then it is immediately clear what string was expected but didn't appear.

attiks’s picture

Status: Needs work » Needs review
FileSize
22.04 KB
7.29 KB

Thanks for the review, new patch addressing all but one of Sun's concerns:

language_negotiation_configure_browser_form_validate is still split in 2 similar parts: the first part is checking existing entries, the second part is checking a new entry, if one is provided. I had it with an array merge before, but it wasn't easy to read.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Thanks! :)

Alright, let's go with this! (There are still some minor issues in the code, but let's not hold up this great patch on them.)

attiks’s picture

@sun if you can create a follow-up issue for the minor stuff, I'll fix them

webchick’s picture

Version: 8.x-dev » 7.x-dev
Assigned: attiks » David_Rothstein
Status: Reviewed & tested by the community » Patch (to be ported)

Really awesome work on this, attiks! Looks good from my side, too.

Committed and pushed to 8.x. YAY! Moving to 7.x for backport. Backporting something of this magnitude, however, will need David's sign-off. Temporarily re-assigning to him.

Tor Arne Thune’s picture

Version: 7.x-dev » 8.x-dev
Status: Patch (to be ported) » Needs work
+++ b/core/modules/language/language.admin.incundefined
@@ -813,3 +813,200 @@ function language_negotiation_configure_session_form($form, &$form_state) {
+    '#title' => t('Drupal langauge'),

Typo in the UI text.

Gábor Hojtsy’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
1.17 KB

Also added a short changelog entry, since we will not be able to track this easily if it falls back into Drupal 7.

attiks’s picture

I found 2 more 'langauges'

webchick’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Oops. :P

Committed and pushed to 8.x. Back to 7.x.

Gábor Hojtsy’s picture

Issue tags: -sprint

Removing sprint tag. We don't really have the luxury to direct D8 developers to work on backports given the close proximity of the D8 feature freeze.

Gábor Hojtsy’s picture

Adde change notice at http://drupal.org/node/1776566 (for front facing changes). Feel free to update/change as needed. I consider this done for D8.

David_Rothstein’s picture

Assigned: David_Rothstein » Unassigned

I just read through this issue, and it seems pretty awesome despite the fact that I only understand about half of it :)

What's the benefit of introducing a giant user interface for this in Drupal 7, vs. leaving it to a contrib module? (Are the bugs/use cases that require a new user interface to fix actually that common?) From what I could tell, this issue started off focused on the specific issue with Chinese, but then expanded... So for Drupal 7, is it possible to fix the Chinese issue in core and also add enough of the "language mappings" API that a contrib module could expand on it, but leave the user interface and the rest out? That would seem to be a more traditional (and safer) bug fix for a stable release.

Hard for me to comment more, so I'm unassigning myself for now :)

attiks’s picture

#106 they are pretty common, it affects all multilingual Chinese sites, so that's lots of people. But it also affects sites using country specific language codes (like en-us, en-uk)

We should be able to split it into UI and API, but the UI is pretty straight forward, so I don't think we gain a lot by splitting it. If we split it, it means somebody has to write and maintain this in contrib and a lot of people are not going to find it.

My 2c: backport everything. I don't mind doing the backport, but I would like to know if backporting the whole patch is acceptable.

attiks’s picture

Status: Patch (to be ported) » Needs work
Gábor Hojtsy’s picture

I think it would be fine/safe to backport the whole thing, its just new configuration at a place where we never had config.

WormFood’s picture

Status: Needs work » Patch (to be ported)

I would like to strongly recommend that the zh-chs and zh-cht language codes are removed from this patch. They're very old language codes, that are simply not being used anymore. I don't think they were ever sent by web browsers, or if they were, it was a very long time ago. It is just more stuff that just does not need to be there. I only mentioned those codes before, as other Chinese language codes, but didn't expect them to be included in the patch.

By the way, great job! I hope this helps the adoption of Drupal in China. I really think this is one factor that was hindering that.

WormFood’s picture

Status: Patch (to be ported) » Needs work

oops, changed the status by mistake (damn GUIs). Changing it back.

Kevin Morse’s picture

Damn... My biggest client is having this problem on 10+ D7 sites. Roughly 90% of their users are Chinese speaking and from Google Analytics I'm seeing that between 10 and 40% of browsers are reporting zh-cn, zh-tw, or zh-hk (0% are reporting hans or hant). Unfortunately, only 3% of visitors are actually starting out on the correct language sub-domain front page which is not the best user experience.

I'm going to see if my client gives me the go ahead to work on the backport. Otherwise I'll use some of the older code and just implement the hack version. Thanks everyone who worked so hard to get this sorted out!

attiks’s picture

#112: Kevin, are you able to work on this?

attiks’s picture

#106: @David_Rothstein, can you give feedback on "My 2c: backport everything. I don't mind doing the backport, but I would like to know if backporting the whole patch is acceptable."

YesCT’s picture

Making a contrib module to fix seems like overkill in this case.
Better to fix it in core.
But, if feeling strongly that it should be in contrib... maybe it could be part of a module multilingual sites are probably already using and we could work with such a maintainer to incorporate into an update to their module?

Kevin Morse’s picture

At the moment the priority was on getting the site up and running so I've implemented the hacked version. I have started playing around with the backport but honestly have not had much time.

Preferably the whole thing would be backported but if that can't happen then at least the hard coded zh-cn, zh-tw, and zh-hk should be done.

David_Rothstein’s picture

#106: @David_Rothstein, can you give feedback on "My 2c: backport everything. I don't mind doing the backport, but I would like to know if backporting the whole patch is acceptable."

I don't see a problem backporting the whole thing, but I also think it's going to require a lot of testing and review to make sure it's working correctly (and mostly bug-free) before we add a new user interface like this in the middle of a stable release. (It's effectively the equivalent of adding a new module, even if the code doesn't live in its own module.)

So I would think it would be a lot quicker just to fix the Chinese issue directly and deal with the new user interface elsewhere (or later)?... but whichever works is OK.

attiks’s picture

Status: Needs work » Needs review
FileSize
21.44 KB

Straight backport

attiks’s picture

FileSize
22.58 KB
2.43 KB

New (working) patch, update function added, tests fixed

plach’s picture

FileSize
22.58 KB

I tested this and it works beautifully in D7 too. I just fixed some minor stuff that in the D8 patch was already correct.

+++ b/includes/locale.inc
@@ -118,6 +118,14 @@ function locale_language_from_interface() {
+ * The algorithm works as follows:

Missing empty line above.

+++ b/modules/locale/locale.admin.inc
@@ -1436,3 +1436,201 @@ function locale_date_format_reset_form_submit($form, &$form_state) {
+

Surplus empty line.

plach’s picture

Status: Needs review » Reviewed & tested by the community

As per @David's request above other peole are strongly encouraged to test this.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, i365615-120.patch, failed testing.

plach’s picture

Status: Needs work » Needs review
FileSize
22.52 KB

Rerolled after the latest commits.

plach’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC.

Again, as per @David's request above other people are strongly encouraged to test this before and after commit.

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work

It's been a month and no more reviews so I looked at this for a little bit. This is not a complete review though.

Code:

  1. +function language_negotiation_configure_browser_form($form, &$form_state) {
    +  $form = array();
    

    Why is this destroying the $form array that was passed in?

  2. The new items in hook_menu() appear to have been added to the wrong section (all the existing menu items are grouped by functionality, but this one got added underneath a section with a code comment that says "Localize date formats" which makes no sense).
  3. Several places in the patch use array_key_exists() rather than isset()... is there a reason for that?
  4. +  $form['new_mapping']['drupal_langcode'] = array(
    +    '#type' => 'select',
    +    '#title' => t('Drupal language'),
    +    '#options' => $language_options,
    +    '#default_value' => '',
    +  );
    

    I can't figure out why the default value is an empty string - that's not one of the options, is it? Just leave it off if the idea is to have no default value.

User interface:

  1. This patch uses "Drupal language" as a form element label and other references to the word "Drupal" in the UI... generally we avoid that (see "Wording" section of http://drupal.org/node/604342). I think having "Drupal" appear in help text sometimes is probably unavoidable and not so bad, but I'm not sure I've ever seen it used extensively in form labels like it is being used here.
  2. Editing an existing row and leaving the language code blank gave me a form error with no error message when I submitted. That's an edge case, but it was pretty weird.
  3. Saving the form sends me back to admin/config/regional/language/configure with no confirmation message, rather than leaving me on the same page (and displaying a confirmation message) like the other language detection configuration pages do... that's inconsistent and also left me wondering a bit if my changes were actually saved (though they in fact were).
  4. On the delete confirmation form, the breadcrumbs are messed up (they just say "Home") - I think that's because this was defined as MENU_CALLBACK rather than MENU_VISIBLE_IN_BREADCRUMB. Why?
  5. The delete confirmation form has a completely blank description, which is pretty nonstandard. I think that's because an empty string was explicitly passed here:
    +  return confirm_form($form, $question, $path, '');
    

    Any reason?

I stopped reviewing after that - I think this patch needs more review and testing before it's ready to be included in a stable release. (And maybe a real usability review too - from someone who knows more about that than me :)

In terms of timing, this patch adds lots of new translatable strings, so I don't think we can slip it in right before a release. The next D7 bugfix release will probably either be February 6 or March 6 (not really sure yet)... if this issue is completely ready by early February it could still get into a March release, I think (or whichever one comes after that if we release in February). Obviously a more limited initial patch that just dealt with the Chinese language issue (and no user interface changes) still would have a chance to get in as soon as it's ready, but it's up to you all :)

YesCT’s picture

adding steps to test will help get more people to test this, and that's pretty important for this issue.

attiks’s picture

Status: Needs work » Needs review
Issue tags: -Needs steps to reproduce
FileSize
22.5 KB
3.06 KB

#125 This is a straight backport from Drupal 8, using the same code and UI language

Code:
1/ fixed
2/ fixed
3/ straight backport
4/ fixed

UI:
1/ straight backport
2/ you're right, the field is set as required, so should show an error message, but not sure if this is related to this patch.
3/ changed, you now stay on the same form
4/ fixed
5/ fixed

attiks’s picture

#126Testing is covered by the test framework, not sure what other testing you would like to see.

The easiest way to test this is using http://simplytest.me/project/drupal/7.x
Open advanced options, click 'Add a patch' and paste http://drupal.org/files/i365615-127.patch in the field
Hit launch sandbox
Once installed, log in and enable the locale module
Go to admin/config/regional/language and add a new language
Go to admin/config/regional/language/configure/browser

YesCT’s picture

@attiks I'm not sure that covers the issue for chinese readers...

when we add a new language, we should pick chinese?
what would be the steps to set chinese as a browser language, and then ... make content, and view it?

YesCT’s picture

Issue summary: View changes

Updated to use issue summary template.

pameeela’s picture

Screenshot of latest D7 UI. Note fieldset is collapsed by default.

pameeela’s picture

FileSize
114.74 KB

Updated with embedded image.

Screenshot of D7 UI

pameeela’s picture

Issue summary: View changes

Adds link to D8 screenshot

pameeela’s picture

FileSize
328.3 KB
105.02 KB

Screenshot of 7.x entry point before patch is applied:

Screenshot of entry page before patch

Screenshot of 7.x entry point after patch is applied:

Screenshot of entry page after patch

pameeela’s picture

@David_Rothstein, in #117 you said:

I don't see a problem backporting the whole thing, but I also think it's going to require a lot of testing and review to make sure it's working correctly (and mostly bug-free) before we add a new user interface like this in the middle of a stable release.

Can you provide any details about what to check for?

Here are some really basic steps to test for issues on existing sites:

1) Set up a site with language settings
2) Confirm that language detection does not work correctly for Simplified Chinese in Firefox
3) Apply patch
4) Update site
5) Confirm that language detection is working correctly
6) Check for any problems with existing language settings

pameeela’s picture

Issue summary: View changes

Adds D7 UI screenshot

YesCT’s picture

Issue summary: View changes

added remaining task for improving steps to test, and made it a list

David_Rothstein’s picture

Re #127, yeah, we can probably let array_key_exists() slide to another issue, but I don't think violating Drupal's UI guidelines is something we should introduce in a stable release and then fix later. Some of this might need to be fixed in Drupal 8 too (I didn't check).

@pameeela, no specific details that I can think of... what I did in #125 was just play around with all the options on the new UI and tried to find ways it broke or was inconsistent. Basically, imagine that it's going to be released to hundreds of thousands of production websites soon after it's committed, and test accordingly :)

YesCT’s picture

Status: Needs review » Needs work

OK. next steps here are to address at least the ui points of #125

attiks’s picture

Status: Needs work » Needs review
FileSize
15.8 KB

Alternative UI, feedback needed:

  • Separate edit screen
  • 'Drupal language' replaced by 'Site language'
  • 'Edit / Delete' replaced with 'edit / delete' to be conform with other screens

i365615-136.png

pameeela’s picture

@David_Rothstein:

OK makes sense. YesCT mentioned testing whether it breaks anything on a site that is using one of the languages affected (such as Simplified Chinese), and how to make sure it wouldn't interfere with the existing detection settings, so I was wondering about this as well. Are there steps to test the browser detection before and after? Or is this not a major concern?

David_Rothstein’s picture

In general #136 makes sense to me (and good catch on the capitalization issue). I don't know about the separate edit screen, though... I wouldn't say that's a blocker for D7 backport or anything, and from what I can see that issue was discussed for a long time above before the final UI here (without the separate edit screen) was decided on, so it seems OK as is.

#137, that sounds like a good test to me. It doesn't look to me like the functional code in this patch has a chance to interfere with the other language detection settings (because it's modifying code that's already there rather than changing when it runs) but wouldn't hurt to check that anyway. Maybe somone else has a better idea of how exactly to test the Chinese issues? My basic understanding of that is (1) broken before patch, (2) works sensibly after applying the patch, (3) works however you configure it after changing the configuration via the new UI.... but it's pretty simplistic :)

attiks’s picture

FileSize
22.49 KB

New patch:
'Drupal language' replaced by 'Site language'
'Delete' replaced with 'delete' to be conform with other screens

pameeela’s picture

New screenshot with updated UI:

Browser language detection configuration | Drupal 7.x.png

I've had a play with the UI and seems to address all of the concerns. But does the actual browser detection need testing still? If so what are the steps for this?

TransitionKojo’s picture

I'll be writing steps to reproduce this issue by or during the 2013-03-08 Wednesday 16:00 - 18:00 UTC Core Mentoring Hours. That should make it easier to get more people to test this.

YesCT’s picture

actually, operations are being capitalized because it makes translation easier (see #421118: [Meta] Standardize capitalization on actions)
that is clear for drupal 8. I'm not sure about what to do in 7 here.

YesCT’s picture

Issue summary: View changes

Adds link to before & after screenshots and updates wording throughout

TransitionKojo’s picture

I updated the Issue Summary with Steps to reproduce for Firefox. The steps go up through applying the patch in #139. I'll add the steps AFTER the patch has been applied a bit later, unless someone else gets to it first.

I also added two more Remaining Tasks. Does anyone know if selecting "Simplified Chinese" uses ALL the various Simplified Chinese encodings, or just certain ones? If no one here knows, I'll ask around in Mozilla's IRC channels. That's something I'd like to know anyway, as I use a decent amount of Chinese text.

Garrett Albright’s picture

Transition, the steps you've added do not change the Accept-Language header that Firefox sends, if that's what you're thinking; instead, it will re-interpret the page in the current window with the selected encodings if the server or page lied about or didn't tell the browser what encoding the page was in and Firefox guessed incorrectly.

To change how Firefox sends Accept-Language headers, go to Preferences, the Content tab, then the "Choose…" button by "Choose your preferred language for displaying pages." For Safari, I think it uses languages you've set as preferred in System Preferences somehow - I can't recall the specifics.

lixiphp’s picture

1) Set up a Drupal site with Locale and Content translation module.
2) Config Drupal site with multiple languages with Chinese Simplified, Chinese Traditional, English(Default)
drupal-languages-list.jpg by lixiphp
3) Config language detection and enable "Browser" Detection method(determine the language from the browser's language settings).
drupal-language-detection-selection.jpg by lixiphp
4) Change how Firefox sends Accept-Language headers. Go to Preferences, the Content tab, then the "Choose…" button by "Choose your preferred language for displaying pages."
Chinese-simplified-language-preferred.jpg by lixiphp
5) Confirm that language detection is working correctly with English Accept-Language headers.

Request Headers:
Accept-Language: en-us,en;q=0.5

Response Headers:
HTTP/1.1 301 Moved Permanently
Location: http://www.lixiphp.com/en

6) Confirm that language detection is working correctly with Chinse Simplified Accept-Language headers.

Request Headers:
Accept-Language: zh-cn,en-us;q=0.7,en;q=0.3

Response Headers:
HTTP/1.1 301 Moved Permanently
Location: http://www.lixiphp.com/zh-hans

7) Confirm that language detection does not work correctly with Chinese Traditional Accept-Language headers. which default go to zh-hans.

Request Headers:
Accept-Language: zh-tw,en-us;q=0.7,en;q=0.3

Response Headers:
HTTP/1.1 301 Moved Permanently
Location: http://www.lixiphp.com/zh-hans

Get the browser detection bugs from zh-tw Accept-Language header.

test site: http://www.lixiphp.com

lixiphp’s picture

8) Apply patch
9) Update site with Accept-Language header.
10) Confirm that language detection is working correctly with Chinese Traditional Accept-Language headers.

Request Headers:
Accept-Language: zh-tw,en-us;q=0.7,en;q=0.3

Response Headers:
HTTP/1.1 301 Moved Permanently
Location: http://www.lixiphp.com/zh-hant

@attiks the patch works well, nice work.
@YesCT finish the patch review, reproduce the bugs and solved by patch from #128.

Garrett Albright’s picture

FWIW, rather than reconfiguring browsers to send proper headers, you may find it easier to use cURL for testing.

curl -I -H 'Accept-Language: zh-tw' http://example.com/

-I says "just show me the response's HTTP headers, not the response body" (this actually causes curl to make a HTTP HEAD request instead of GET, which some misconfigured web servers may not handle correctly, but in most cases it should work), and -H says "send the following outgoing HTTP header."

attiks’s picture

Can somebody mark this RTBC?

pameeela’s picture

Status: Needs review » Reviewed & tested by the community
YesCT’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs backport to D6, +Usability, +Needs backport to D7, +D8MI, +language-base

The last submitted patch, i365615-139.patch, failed testing.

YesCT’s picture

Assigned: Unassigned » YesCT

I'll try to reroll this.

YesCT’s picture

Status: Needs work » Needs review
FileSize
22.5 KB

during http://drupal.org/patch/reroll

$ git rebase 7.x
First, rewinding head to replay your work on top of it...
Applying: 139
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging modules/locale/locale.test

So here it is. No interdiff... just a reroll

attiks’s picture

Status: Needs review » Reviewed & tested by the community

@YesCT thanks for the re roll, back to TRBC

attiks’s picture

YesCT’s picture

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work

Thanks for the continued work on this. I spent more time with this and gave it a complete review. I found a number of issues still, though, including some that are definitely commit blockers.

Here's the list (in rough priority order):

  1.  /**
    + * Set default mappings for Chinese languages.
    + */
    +function locale_update_7006() {
    +  language_set_browser_drupal_langcode_mappings(array(
    

    This will cause a fatal error if the update is run while the module is disabled (since the API function won't be loaded). The function is a simple wrapper around variable_set(), so I'd suggest just calling variable_set() directly.

  2. @@ -161,9 +181,23 @@ function locale_language_from_browser($languages) {
    .........
    +      // Add the generic langcode, but make sure it has a lower qvalue as the
    +      // more specific one, so the more specific one gets selected if it's
    +      // defined by both the browser and Drupal.
    +      $browser_langcodes[$generic_tag] = $qvalue - 0.1;
    .........
    @@ -1690,8 +1708,8 @@ class LocaleBrowserDetectionTest extends DrupalUnitTestCase {
           'en-US,en,fr-CA,fr,es-MX' => 'en',
           'fr,en' => 'en',
           'en,fr' => 'en',
    -      'en-US,fr' => 'en',
    -      'fr,en-US' => 'en',
    +      'en-US,fr' => 'en-US',
    +      'fr,en-US' => 'en-US',
    

    While this looks like it makes sense, it's a behavior change for existing sites and I'm trying to figure out the impact. After reading comments #19 through #28, it sounds like the biggest change is a situation like this:

    Browser send en-us, fr and Drupal defines en, fr => use fr // exact match

    Whereas previously, English would be used? Is that a concern - do we have to worry about sites starting to report in the issue queue that people who are used to see English are now seeing other languages instead and don't know why, and/or the site needs to add "en-us" as a custom language to get around it? I'm having trouble evaluating the impact of making this change in a stable release even if it was deemed a good idea for Drupal 8.

  3. +    $form['mappings'][$browser_langcode] = array(
    +      'browser_langcode' => array(
    +        '#type' => 'textfield',
    +        '#default_value' => $browser_langcode,
    +        '#size' => 20,
    +        '#required' => TRUE,
    +      ),
    +      'drupal_langcode' => array(
    +        '#type' => 'select',
    +        '#options' => $language_options,
    +        '#default_value' => $drupal_langcode,
    +        '#required' => TRUE,
    +      ),
    +    );
    

    These form elements have no titles, which is bad for accessibility. (This is also most likely the cause of the issue I found in my previous review: "Editing an existing row and leaving the language code blank gave me a form error with no error message when I submitted.")

    I think you can just add a #title which is the same as the column name, but then also set #title_display to 'invisible' and it should work fine.

  4. +function language_negotiation_configure_browser_form($form, &$form_state) {
    +  // Initialize a language list to the ones available, including English.
    +  $languages = language_list();
    +
    +  $existing_languages = array();
    +  foreach ($languages as $langcode => $language) {
    +    $existing_languages[$langcode] = $language->name;
    +  }
    +
    +  // If we have no languages available, present the list of predefined languages
    +  // only. If we do have already added languages, set up two option groups with
    +  // the list of existing and then predefined languages.
    +  if (empty($existing_languages)) {
    +    $language_options = language_list();
    +    $default = key($language_options);
    +  }
    

    This logic doesn't make sense to me - $existing_languages will only be empty if language_list() is empty too, right? So the code in the if() statement looks broken. Also, at least with Drupal core, is it even possible for the language list to be empty? (I always have at least "English" in there.) But maybe it's possible with contrib.

  5. In the same area of the code as above:
    +  if (empty($existing_languages)) {
    +    $language_options = language_list();
    +    $default = key($language_options);
    +  }
    +  else {
    +    $default = key($existing_languages);
    +    $language_options = array(
    

    $default is defined but doesn't appear to ever be used.

  6. +  $data = $form_state['values']['new_mapping'];
    +  if (!empty($data['browser_langcode'])) {
    +    // Make sure browser_langcode is unique.
    +    if (array_key_exists($data['browser_langcode'], $unique_values)) {
    +      form_set_error('mappings][' . $key . '][browser_langcode', t('Browser language codes must be unique.'));
    +    }
    +    elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
    +      form_set_error('mappings][' . $key . '][browser_langcode', t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
    

    $key is the wrong variable here (and results in the error message being set on the wrong form element if there's a validation error when adding a new mapping).

  7. +    case 'admin/config/regional/language/configure/browser':
    +      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>.', array('@configure-languages' => url('admin/config/regional/language'))) . '</p>';
    +      return $output;
    

    This help text seems a bit incomplete... as written, it almost implies that Drupal won't recognize a browser language if it isn't in this table. I was a little confused by that (at least until I read the rest of the code). Perhaps it needs to state that this table is for custom mappings only, and that Drupal will make a best effort to map any language code defined by the browser even if it's not listed here?

  8. +function theme_language_negotiation_configure_browser_form_table($variables) {
    +  $form = $variables['form'];
    +  $rows = array();
    +  $link_attributes = array(
    +    'attributes' => array(
    +      'class' => array('image-style-link'),
    +    ),
    +  );
    

    "image-style-link" definitely doesn't look like the correct class here...

  9. +  $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'lang-neg-browser')));
    

    I think this needs 'empty' text for when the table is empty, to match the pattern used elsewhere in Drupal. Something like "No browser language mappings available."

    Also (minor): The abbreviation in the HTML ID looks a little odd to me (I thought we tried to avoid abbreviations)... would "language-negotiation-browser" be a problem?

  10. Related to my earlier review: There's still no confirmation message whatsoever when you submit the form? (All the other language detection configuration forms do "The configuration options have been saved."
  11. +class LocaleBrowserDetectionTest extends DrupalWebTestCase {
    +
    +  public static $modules = array('locale');
    

    This looks like Drupal 8 code which slipped into the Drupal 7 backport.

  12. +/**
    + * Browser language negotiation form validation.
    + */
    +function language_negotiation_configure_browser_form_validate($form, &$form_state) {
    

    Here (and in the other form definition functions) the API docs seem to be missing several things; see the "Form-generating functions" section of https://drupal.org/coding-standards/docs#functions.

David_Rothstein’s picture

Version: 7.x-dev » 8.x-dev
FileSize
3.74 KB

Also, I think we may be getting into the territory where there are too many fixes being made for Drupal 7 only... The normal procedure is to fix issues in Drupal 8 first before backporting. (If it's only a few fixes, I'd let them slip and forward-port to Drupal 8 afterwards, given that this is a big patch, but it's getting to be a lot of them.)

To help facilitate that, here's an interdiff between the Drupal 7 patches in #123 and #153... As far as I can see, most of these things aren't in Drupal 8 yet but would need to be. (As well as some of the new issues I mentioned in my review above, and maybe some other people's reviews too?)

attiks’s picture

Version: 8.x-dev » 7.x-dev
Status: Needs work » Needs review
FileSize
23 KB
7.21 KB

#157 I addressed all comments

Regarding "Browser send en-us, fr and Drupal defines en, fr => use fr // exact match": most browser will add en automatically in this case (checked on chrome and ff)

Back to D7 for testbot, change it back later

#158 So we need to fix it in D8 first?

YesCT’s picture

Version: 7.x-dev » 8.x-dev
Assigned: YesCT » Unassigned

the new patch for d7 has come back green from the testbot. (noting that in case we retest it later and lose that info)

oops. Didn't mean to keep this assigned to me. Unassigning.

Yeah, looks like the improvements that are needed should be done to in d8, and then can come back here to do it all in d7.

attiks’s picture

FileSize
8.46 KB

New patch for D8, contains:

Status: Needs review » Needs work

The last submitted patch, i365615-161.patch, failed testing.

attiks’s picture

Status: Needs work » Needs review
FileSize
8.46 KB
520 bytes

grrrr, typo

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

All right, code changes look good. I don't think those two language codes will damage the site if they keep being there, but its fine. All other things are straightforward cleanups.

catch’s picture

Status: Reviewed & tested by the community » Needs review

Most of these changes look completely unrelated to the Chinese support, why are they all in here?

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

@catch: the Chinese support is already committed above. The code style, etc. issues found by David Rothstein can be forked into another issue, if that is preferred, but the whole patch is about cleaning up what was already committed, so it can be more directly committed to Drupal 7. Sounds like opening yet another issue for the minor(er) cleanups and leave this for the not so minor cleanups may not be very effective at the end?!

catch’s picture

Priority: Major » Minor
David_Rothstein’s picture

Priority: Minor » Major
Status: Reviewed & tested by the community » Needs work

These aren't all minor cleanups, actually; they include an accessibility fix and fixes for some very non-standard UI patterns.

Reviewing #163:

  1. A few things from #158 that look relevant for D8 also are still missing from the D8 patch:
    • Removal of $form_state['redirect'] in language_negotiation_configure_browser_form_submit() to fix the confusing redirect after submit.
    • Incorrect breadcrumbs due to MENU_CALLBACK rather than MENU_VISIBLE_IN_BREADCRUMB on admin/config/regional/language/configure/browser/delete/%.
    • Removal of $form = array() at the top of language_negotiation_configure_browser_form().
    • Removal of '#default_value' => '' on the 'new_mapping' select element at the bottom of language_negotiation_configure_browser_form().
  2. @@ -768,7 +782,6 @@ function language_negotiation_configure_browser_delete_form_submit($form, &$form
         unset($mappings[$browser_langcode]);
         language_set_browser_drupal_langcode_mappings($mappings);
       }
    -  $form_state['redirect'] = 'admin/config/regional/language/detection/browser';
    

    This isn't right; it results in the user remaining on the delete confirmation form after confirming the deletion! (Actually, that probably explains the first point above also; I think $form_state['redirect'] was removed from this form but should have been removed from the other instead.)

  3. +    drupal_set_message('The configuration options have been saved.');
    

    Missing t().

  4. -      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>.', array('@configure-languages' => url('admin/config/regional/language'))) . '</p>';
    +      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>, without a custom mapping Drupal will make a best effort to map it.', array('@configure-languages' => url('admin/config/regional/language'))) . '</p>';
    

    This is grammatically incorrect. How about something like:

    Browsers use different language codes to refer to the same languages. Drupal will make a best effort to determine the correct language based on the code that the browser sends, but for finer control you can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>.

David_Rothstein’s picture

Title: Language detection not working correctly for most Chinese readers » Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings)

Also, this issue hasn't been only about the Chinese support for a while, actually?

jair’s picture

Issue tags: +Needs reroll

Needs reroll

Albert Volkman’s picture

FileSize
7.13 KB

Re-roll.

Albert Volkman’s picture

Status: Needs work » Needs review
FileSize
1.89 KB
7.19 KB

Addressing issues in #168.

Nitesh Sethia’s picture

Assigned: Unassigned » Nitesh Sethia

This patch is working properly and there is no need for rerolling the stuff

mgifford’s picture

#172: i365615-172.patch queued for re-testing.

mgifford’s picture

@David_Rothstein In #168 I'm assuming your suggesting that the accessibility fix should be brought into a separate issue. I'm still not clear what that fix was.

Status: Needs review » Needs work
Issue tags: -Needs backport to D6, -Usability, -Needs backport to D7, -D8MI, -language-base, -Needs reroll

The last submitted patch, i365615-172.patch, failed testing.

Anonymous’s picture

Issue summary: View changes

Updated issue summary with Steps to reproduce in Firefox, UP TO applying the patch in Comment 139; need to finish steps AFTER patch is applied

heddn’s picture

nikhilsukul’s picture

Assigned: Nitesh Sethia » nikhilsukul
nikhilsukul’s picture

Assigned: nikhilsukul » Unassigned
webwarrior’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
9.18 KB
mgifford’s picture

180: i365615-180.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 180: i365615-180.patch, failed testing.

mgifford’s picture

Status: Needs work » Needs review
FileSize
9.17 KB

reroll

alansaviolobo queued 183: i365615-183.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 183: i365615-183.patch, failed testing.

mgifford’s picture

Status: Needs work » Needs review
FileSize
9.07 KB

This is a pretty important issue!

alexpott’s picture

Status: Needs review » Needs work

The rerolls from #180 on are missing the point. We need to be making changes to NegotiationBrowserForm. Adding language_negotiation_configure_browser_form(), language_negotiation_configure_browser_form_validate(), and language_negotiation_configure_browser_form_submit() back is incorrect.

This also means that we're forgetting to manually test patches before uploading them.

Gábor Hojtsy’s picture

@mgifford: yeah the rolls that include adding back the procedural functions instead of modifying where the code went are not good. We need to modify the actual code not add back one parallel copy.

mgifford’s picture

Thanks @alexpott & Gábor Hojtsy

As usual I'm trying to nudge ahead issues between other priorities. I do really think that this needs to be resolved before the release of D8. Hopefully someone else can step up and take on modifying the relevant code.

Gábor Hojtsy’s picture

Issue tags: +Needs reroll

Well, just to make it clear, the fix itself is in Drupal 8, the cleanups suggested are not, but that does not make the D8 feature not work. Looks like this needs to be rolled again from #172.

mgifford’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
6.81 KB

Ok, let's see if this works...

Status: Needs review » Needs work

The last submitted patch, 191: i365615-172-rerolled-at-191.patch, failed testing.

mgifford’s picture

Bloody ";"'s...

Gábor Hojtsy’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 193: i365615-172-rerolled-at-193.patch, failed testing.

Gábor Hojtsy’s picture

It was said multiple times above that zh-chs and zh-cht are so ancient and never actually used by browsers that we should remove the mapping. Note that the mapping does not hurt anyone, I mean we could map 'bacon' to 'en' for whatever we want. Looking for proof of the non-use of these two Chinese language codes, I found that Bing translator in fact documents they support Chinese exactly with these language codes. See http://msdn.microsoft.com/en-us/library/hh456380.aspx As of Feb 2014. So I would refrain from removing them in this patch (or not adding them to Drupal 7). They do not hurt for people who don't use it but they are definitely useful for people who do.

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
6.83 KB

Rerolled the patch first.

Gábor Hojtsy’s picture

FileSize
1.35 KB
5.49 KB

Rolled without the removal of those mappings as per #196.

Gábor Hojtsy’s picture

Title: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) » Followups: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings)
Issue tags: +sprint

Also bring on the D8MI sprint.

YesCT’s picture

+++ b/core/modules/language/language.module
@@ -63,7 +63,7 @@ function language_help($route_name, RouteMatchInterface $route_match) {
-      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="!configure-languages">languages used</a>.', array('!configure-languages' => \Drupal::url('language.admin_overview'))) . '</p>';
+      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. Drupal will make a best effort to determine the correct language based on the code that the browser sends, but for finer control you can add and edit mappings from browser language codes to the <a href="!configure-languages">languages used by Drupal</a>.', array('!configure-languages' => \Drupal::url('language.admin_overview'))) . '</p>';

Can we reword this so the word Drupal is not in the UI?

still needs an issue summary update. (could be a bit time consuming, but should be done)

We should also explain in the summary why this is a bug report with no test addition or test changes.

YesCT’s picture

Maybe instead of

Drupal will make a best effort to determine

A best effort will be made to determine

Gábor Hojtsy’s picture

Issue summary: View changes
FileSize
5.35 KB
1.15 KB

I think the intention there is to make clear who are the actors. The browser and Drupal. What about

Browsers use different language codes to refer to the same languages. This language mapping list allows to match those to the <a href="!configure-languages">languages used internally</a>.

As for the issue summary, it would be sad to loose the summary for the Drupal 7 change, which is still accurate. I think everyone hoped that the D8 port of the changes would be swiftly committed without much tossing around, especially not for a year. So it would be great to finally let this in D8 and continue backporting to D7.

YesCT’s picture

Thanks. That little summary update helped me remember what was going on here.
I'm going to review this now.

YesCT’s picture

FileSize
277.13 KB
298.06 KB
+++ b/core/modules/language/language.admin.inc
@@ -115,9 +115,6 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
-      'attributes' => array(
-        'class' => array('image-style-link'),
-      ),

Yeah, this was added by the patch from #96 that was committed in #99 (and then moved via #1480854: Convert operation links to '#type' => 'operations').

I agree with @David_Rothstein in #157 8, that this looks like the wrong class.

I can't find where that might have been copied from (to maybe confirm it might have been a copy and paste error) and I can't think of what it should be instead. I also cant figure out what it was intended to do. And it looks fine without it.

It is limited to this negotiation form: /admin/config/regional/language/detection/browser

So that change, removing that class, looks ok.

without patch, that button:

with patch, that button:

---
next, reviewing the other changes here.

YesCT’s picture

+++ b/core/modules/language/language.module
@@ -63,7 +63,7 @@ function language_help($route_name, RouteMatchInterface $route_match) {
-      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="!configure-languages">languages used</a>.', array('!configure-languages' => \Drupal::url('language.admin_overview'))) . '</p>';
+      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. This language mapping list allows to match those to the <a href="!configure-languages">languages used internally</a>.', array('!configure-languages' => \Drupal::url('language.admin_overview'))) . '</p>';

"allows to make" is a little awkward.

and looking into this more,
the feedback that sparked this change from #157 was

This help text seems a bit incomplete... as written, it almost implies that Drupal won't recognize a browser language if it isn't in this table. I was a little confused by that (at least until I read the rest of the code). Perhaps it needs to state that this table is for custom mappings only, and that Drupal will make a best effort to map any language code defined by the browser even if it's not listed here?

I think we lost what David was looking for.

in #168 @David_Rothstein suggested:

Browsers use different language codes to refer to the same languages. Drupal will make a best effort to determine the correct language based on the code that the browser sends, but for finer control you can add and edit mappings from browser language codes to the languages used by Drupal.

I've given it another try, using @Gábor's idea of referring to what drupal does as: internally, and also the new label in the table (site language instead of Drupal language).

Browsers use different language codes to refer to the same languages. Internally, a best effort is made to determine the correct language based on the code that the browser sends. You can add and edit additional mappings from browser language codes to <a href="!configure-languages">site languages</a>.

It might be odd to say ...add and edit additional... but was hoping to convey that these are not the only mappings and people dont have to add a mapping every time they add a language. (for example, I added Afrikaans. and there is no mapping here for a browser code, but it will get mapped by that best guess.)

and here it is in context.

YesCT’s picture

Status: Needs review » Needs work
FileSize
302.31 KB
136.01 KB
+++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
@@ -65,6 +65,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
+      drupal_set_message(t('The configuration options have been saved.'));

I tried deleting a mapping to make sure this message showed ok.

It does show.

But since i used the delete button and not the save configuration button, the message was a little weird.

I looked for where we have another similar situation, like a table of things with delete buttons on each and one save for the whole form.
There is one on the language admin page.

The Albanian (sq) language has been removed.

It says:

The Albanian (sq) language has been removed.

I think we should do something similar here.

looking in
core/modules/language/src/Form/LanguageDeleteForm.php

----

I'm going to make that change now.

----
... do we also want a log message?

YesCT’s picture

changed the message, added a test for it.
also logged it.

ps. why is this test file called *unit* test?

attached a tests only patch.

Also, I was curious if the assert no after this would work since it might not be on the page listing the other browser codes.
So I have a file to check if that fails if the delete doesn't happen (or rather to see if it passes even if the delete doesn't happen).

[edit:]
this is the test I'm wondering fails

// Check that ch-zn no longer exists.
$this->assertNoField('edit-mappings-zh-cn-browser-langcode', 'Chinese browser language code no longer exists.');

The last submitted patch, 207: i365615-206-testchangeonly.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 207: i365615-checkthedeletetest-shouldfail.patch, failed testing.

The last submitted patch, 207: i365615-206.patch, failed testing.

YesCT’s picture

Status: Needs work » Needs review
FileSize
731 bytes
6.71 KB

oh, good that fails test does catch the code not being deleted.

let's see if this fixes the test I wrote.

YesCT’s picture

FileSize
164.11 KB

nice. the empty text shows up for an empty table.

YesCT’s picture

hm.

delete confirm goes back to
admin/config/regional/language/detection/browser
(the table of mappings)

but adding one,
or editing one and using the save configuration button,
goes back to
admin/config/regional/language/detection
(the negotiation and detection page)

that's why the test for adding looks like

  $this->drupalPostForm('admin/config/regional/language/detection/browser', $edit, t('Save configuration'));
  $this->drupalGet('admin/config/regional/language/detection/browser');
  $this->assertField('edit-mappings-xx-browser-langcode', 'xx', 'Browser language code found.');

it has to do the get to go back to the browser page.
maybe the test should check it goes back to the browser page and then check if the code is found.

in LanguageListTest it does

    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
    $this->assertUrl(\Drupal::url('language.admin_overview', [], ['absolute' => TRUE]));
    $this->assertRaw('"edit-languages-' . $langcode .'-weight"', 'Language code found.');

so changing the tests to assert they return to the place they should, based on the route.

(this will fail on the add and change test, but I'll fix that next)

Status: Needs review » Needs work

The last submitted patch, 213: i365615-213.patch, failed testing.

YesCT’s picture

Status: Needs work » Needs review
FileSize
621 bytes
8.38 KB

great that failed just right.
now the fix.

YesCT’s picture

+++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
@@ -89,12 +89,16 @@ public function buildForm(array $form, FormStateInterface $form_state) {
+          '#title' => t('Browser language code'),
+          '#title_display' => 'invisible',
...
+          '#title' => t('Site language'),
+          '#title_display' => 'invisible',

I see these as labels when I inspect the html of the page. But they do not get read (when I turn on voice over on my Mac in my accessibility settings, in chrome).

So it looks ok to me, but we might want @mgifford or someone to check that the title is doing what we expect.

YesCT’s picture

reading #168 1. from @David_Rothstein
maybe we dont need to specify the redirect in the submit anyway... yep. worked locally. uploading taking out that redirect.

YesCT’s picture

OK.
I'm done (at least for now)
remaining:
aside from the small accessibility question about why we have a id on the table and #216 about the #title.
and a review of my changes.

mgifford’s picture

#1 - Thanks for putting so much into this today! This is great and the screenshots are quite helpful.

I read through the patch. Looks good to me.

Installed with Chinese. Installed with English & then with Simplified Chinese Added.

The id's I think you are referring to are from #864006: Improve table semantics by adding scope or headers/id attributes

Deleting here seems to work as expected with the patch now admin/config/regional/language/detection/browser

YesCT’s picture

Sigh, I know I said I was done, but I went back and read #168 1. again, and I think I found the last things from there.

Also attached an interdiff to 202 for @Gábor Hojtsy

mgifford’s picture

Issue tags: -Needs backport to D6

Oh ya, it seems to work fine for me in VoiceOver & ChromeVox. I think the labels are set up properly.

YesCT’s picture

Issue summary: View changes

did you mean to take off the d6 tag?

mgifford’s picture

@YesCT - Ya. I'd love to see the backported, but it takes long enough to get things into d7 and really doesn't make sense to be investing much in d6 these days. I should have been specific about that though.

Gábor Hojtsy’s picture

@mgifford: Good enough for RTBC?

mgifford’s picture

Status: Needs review » Reviewed & tested by the community

Yes, I think so.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Some minor nits.

  1. +++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
    @@ -65,6 +65,14 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    +      $t_args = array(
    +        '%browser' => $this->browserLangcode,
    +      );
    ...
    +      $this->logger('language')->notice('The browser language detection mapping for the %browser browser language code has been deleted.', $t_args);
    

    How about just $args since this is not only being used with $this->t()

  2. +++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
    @@ -65,6 +65,14 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    +      drupal_set_message(t('The mapping for the %browser browser language code has been deleted.', $t_args));
    
    +++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
    @@ -89,12 +89,16 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    +          '#title' => t('Browser language code'),
    ...
    +          '#title' => t('Site language'),
    
    @@ -134,16 +136,15 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    +          $form_state->setErrorByName('mappings][new_mapping][browser_langcode', t('Browser language codes must be unique.'));
    ...
    +          $form_state->setErrorByName('mappings][new_mapping][browser_langcode', t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
    

    Should all be $this->t() - in fact this patch is a regresses some previous conversions.

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
8.94 KB
3.36 KB

Good finds, indeed. Fixed those. @mgifford: want to do a once-over again? :)

Gábor Hojtsy’s picture

FileSize
8.97 KB

Duh, rolled 227 wrong, so it does not actually contain anything from the interdiff. Here is the good one. This should have been 227.

The last submitted patch, 227: i365615-227.patch, failed testing.

mgifford’s picture

Status: Needs review » Reviewed & tested by the community

Great! I looked at the interdiff & compared that with @alexpott's suggestions. They look good to me.

I also installed it again & went through the steps to verify that it worked the same as before.

I'm happy to RTBC this again. Thanks Gábor!

alexpott’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Whilst I've stopped committing on issue follow-ups since they confuse everything (see the issue summary for an example of how) I'm going to commit this one because of the age and number of comments. This issue addresses a major bug and is allowed per #2350615: [policy, no patch] What changes can be accepted during the Drupal 8 beta phase?. Committed 2095c89 and pushed to 8.0.x. Thanks!

  • alexpott committed 2095c89 on 8.0.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...
Gábor Hojtsy’s picture

Title: Followups: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) » Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings)
Issue summary: View changes
Issue tags: -sprint

Thanks all! I agree committing followups from an issue is confusing, but there was already one D8 followup committed here and the D7 maintainer pushed this back to D8 for followup work.

For the new D7 backport, I collected where were commits on this issue:

#365615-99: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) (comment 99)
#365615-103: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) (comment 103)
#365615-231: Language detection not working correctly for most Chinese readers (and add a user interface for all browser language mappings) (comment 231)

The merge of these should be backported to Drupal 7.

  • alexpott committed 2095c89 on 8.1.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...
aniket_m’s picture

Hi,

Anybody has an idea on how to load css only for Chinese site in Internet Explorer?

I'm setting up a multi-folder Drupal 7 site for various languages, I'm testing it with various browsers, and they all seem to works fine, except for Internet Explorer for only chinese site.

I tried various solutions, but not succeed in that.

Thanks in advance.

aniket_m’s picture

And finally I solve my problem for Internet Explorer for only chinese site.

Very strange issue. I disabled JS aggregation and i no longer got the js errors. I then disabled CSS aggregation and the page loads ok. When I aggregate the CSS the aggregated files are empty in IE, hence my site not displaying properly.

  • webchick committed 369d68a on 8.3.x
    Issue #365615 by attiks, smokris, penyaskito, Gábor Hojtsy, Bojhan,...
  • webchick committed e904f78 on 8.3.x
    Issue #365615 follow-up by attiks, Gábor Hojtsy: Fix typos, add...
  • alexpott committed 2095c89 on 8.3.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...

  • webchick committed 369d68a on 8.3.x
    Issue #365615 by attiks, smokris, penyaskito, Gábor Hojtsy, Bojhan,...
  • webchick committed e904f78 on 8.3.x
    Issue #365615 follow-up by attiks, Gábor Hojtsy: Fix typos, add...
  • alexpott committed 2095c89 on 8.3.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...

  • webchick committed 369d68a on 8.4.x
    Issue #365615 by attiks, smokris, penyaskito, Gábor Hojtsy, Bojhan,...
  • webchick committed e904f78 on 8.4.x
    Issue #365615 follow-up by attiks, Gábor Hojtsy: Fix typos, add...
  • alexpott committed 2095c89 on 8.4.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...

  • webchick committed 369d68a on 8.4.x
    Issue #365615 by attiks, smokris, penyaskito, Gábor Hojtsy, Bojhan,...
  • webchick committed e904f78 on 8.4.x
    Issue #365615 follow-up by attiks, Gábor Hojtsy: Fix typos, add...
  • alexpott committed 2095c89 on 8.4.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...

  • webchick committed 369d68a on 9.1.x
    Issue #365615 by attiks, smokris, penyaskito, Gábor Hojtsy, Bojhan,...
  • webchick committed e904f78 on 9.1.x
    Issue #365615 follow-up by attiks, Gábor Hojtsy: Fix typos, add...
  • alexpott committed 2095c89 on 9.1.x
    Issue #365615 followup by attiks, YesCT, Gábor Hojtsy, mgifford, Albert...