Issues

ZF-5863: Setting default locale does not work

Description

According to the documentation (example 29.9) we should be able to set an override for the locale. The following code will not work as expected;

if (intval($appCfg->overideLocale) == 1) { $l = new Zend_Locale($appCfg->locale); Zend_Registry::set('Zend_Locale', $l); } else { Zend_Locale::setDefault($appCfg->locale); } $l2 = new Zend_Locale(); Zend_Debug::dump($l2);

If I set my browser (firefox) to use 'fr' but set $appCfg->locale = 'en' and $appCfg->overideLocale = 1 I would expect $l2 to be 'en', but it isn't . It is 'fr'

If I step through Zend_Locale::_prepareLocale() the following lines at line 878 in ZF 1.7.2:

        if (is_array($locale) === true) {
            $locale = key($locale);
        }

will return 'fr' for the call to $l2 = new Zend_Locale(); because the locale array has 'fr' as the highest 'quality' i.e 1, where as 'en' although first in the array has a quality of 0.7. Nowhere is the Zend_Registry interrogated for a default locale value.

I have placed this code before any use of Zend_locale is made in the rest of the application.

Am I missing something or is this a real bug?

Regards

Comments

I am sure the component works as defined. Can you give HTTP_ACCEPT_LANGUAGE for the cases and the result/taken locale ?

To note: According to manual the default locale is used when no known locale can be found.

Also to note: Locales are not taken according to their position, but according to their quality, which is defined from 1 to be best and 0.1 to be least.

Thomas

HTTP_ACCEPT_LANGUAGE = fr,en;q=0.7,en-us;q=0.3

Section 29.1.8 of the manual says "Zend Framework allows the usage of an application wide locale. You simply set an instance of Zend_Locale to the registry with the key 'Zend_Locale'. Then this instance will be used within all locale aware classes of Zend Framework. This way you set one locale within your registry and then you can forget about setting it again. It will automatically be used in all other classes. See the below example for the right usage: "

It then gives the example, from which my code is based.

I understand the point about locales being taken according to their quality. My point is that the predefined locale set into the registry is never taken into account. If I hack Zend_Locale and put in

if ($locale === null &&Zend_Registry::isRegistered('Zend_Locale')) { $locale = Zend_Registry::get('Zend_Locale')->toString(); }

at about line 855 in _prepareLocale() then I get the expected result, i.e the value set in the registry.

I don't think this is a complete answer because I'm not sure that Zend_Translate is always getting its locale from the same place. The point is, I need to be able to force the application to use the locale I set irrespective of any browser set locale and that isn't working. It is far too tedious to go through the entire codebase and set the locale every time I use Zend_Date, Zend_Translate etc etc.

You said that you set "fr" for your browser... from your returned HTTP* I see that you've set "fr", "en" and "en_US" to be accepted. In your case the used locale could be "fr" or "en".

Only when your user requests another locale like "hu", the default locale would come in place. The manual clearly states this: The last sentence of the default locale chapter reads: {quote}In the case that no locale can be detected, automatically the locale de will be used. Otherwise, the detected locale will be used.{quote}

To your second point: {quote}The point is, I need to be able to force the application to use the locale I set irrespective of any browser set locale and that isn't working.{quote} It is...

Reading the manual: {quote}Zend Framework allows the usage of an application wide locale. You simply set an instance of Zend_Locale to the registry with the key 'Zend_Locale'. Then this instance will be used within all locale aware classes of Zend Framework. This way you set one locale within your registry and then you can forget about setting it again. It will automatically be used in all other classes.{quote}

A application wide locale has nothing to do with a default fallback locale.

I would humbly submit that the application wide locale I am setting is NOT being used by all other classes.

I have translation strings in my application for English and French. In this particular situation, I never want the French translation being used, only the English ones. i.e the site must be mono-lingual. However, if I set an application wide locale as discussed above, the system will still pick up the browser set locale (fr in this example) and translate into that language. That is not in my opinion using an application wide locale, but falling back to a default if translations are not available for the browser locale.

I do understand the difference between application wide locale and a default fallback locale. Zend uses Zend_Locale::setDefault() to set the default fallback locale. That is not what I am trying to do in this particular case.

Currently the only way I can see of getting around this problem is to remove all the French translation strings and set a default fallback locale.

You are speaking of problems with Zend_Locale, but in your above text you note that you have problems with translation.

In no one of your example I can see how you are using Zend_Translate.

Looking at Zend_Translate you will note that in several lines it calls


to get the locale to use.

And the first lines within this method read:
    if ($locale === null) {
        require_once 'Zend/Registry.php';
        if (Zend_Registry::isRegistered('Zend_Locale')) {
            $locale = Zend_Registry::get('Zend_Locale');
        }
    }

```

Only when the registry is not set, it degrades to the detection routines.

{quote}I do understand the difference between application wide locale and a default fallback locale. Zend uses Zend_Locale::setDefault() to set the default fallback locale. That is not what I am trying to do in this particular case.{quote}

Why are you then discussing this point when you know that this not the problem in your case as it's not used ? ;-)

{quote}Currently the only way I can see of getting around this problem is to remove all the French translation strings and set a default fallback locale.{quote}

Use application wide locale as described within the manual. Check if the registry is really set to the expected value within the bootstrap or, if it's not available when calling Zend_Translate.

Degrading priority from Critical to Major as this is a user handling problem and not a bug for the next release.

Thomas

I didn't look in Zend_Translate because I took for granted that when the manual says that Zend_Locale is used by all locale aware parts of ZF I was expecting it to do just that. Silly me :-)

And findLocale() doesn't exist in Zend_Locale (or indeed anywhere), at least not in the V1.7.2 library I am using. So which version are you talking about?

Zend_Locale::_prepareLocale() doesn't check the registry either.

{quote}I didn't look in Zend_Translate because I took for granted that when the manual says that Zend_Locale is used by all locale aware parts of ZF I was expecting it to do just that.{quote}

It is. But when you have problems with Zend_Translate you should look at Zend_Translate and not at Zend_Locale. Writing an issue for another component is not really helpfull as several facts are missing ;-)

{quote}And findLocale() doesn't exist in Zend_Locale (or indeed anywhere), at least not in the V1.7.2 library I am using. So which version are you talking about?{quote}

As you are referring to the manual I am also referring to the release the manual was written for. This is actually 1.7.5... you noted that you are using ZF 1.7.2 in your comment.

As this code and the related sentence / section in the manual was added 18.Jan. it's in release 1.7.4. 1.7.2 simply doesn't have this method.

Please update to 1.7.4 or the actual 1.7.5. There should be no BC breaks when you are already on 1.7.2 (there are no in I18N) as these are mini releases.

Waiting for your reply

OK Thomas, I'll go grab 1.7.5 and try again. I did indicate that this was an issue in 1.7.2 in the bug report though

I'll put the system through a test cycle and see if I get different results. Thanks.

Yes, you have :-)

But the manual is for the actual release, and of course problems told in the past are already solved. I don't know if this is the case for this issue, but as the code differs I expect so.

Using ZF 1.7.5

require_once 'Zend/Loader.php'; Zend_Loader::registerAutoload(); $l1 = new Zend_Locale('en_GB'); Zend_Registry::set('Zend_Locale', $l1); $l2 = new Zend_Locale();

result: HTTP_ACCEPT_LANGUAGE = fr,en;q=0.7,en-us;q=0.3 result: $l1 = 'en_GB' result: $l2 = 'fr'

Therefore setting an application wide locale is not working as documented.

I'll test the Zend_Translate functionality and report any issues separately

The fix for it is to do exactly what has been done in findLocale() in _prepareLocale() and check the registry if the $locale parameter is null

When you register Zend_Locale this locale is used for other components like Zend_Translate, Zend_Currency and so on.

Creating a new locale object means that you create a new instance. A new instance does not use previous stored values as you should get the registry in this case when you want to have the stored object from before. A new locale does ALWAYS use autodetection on browser/system when you do not give a locale.

This is expected, documented and wished behaviour.

As stated in the manual calling new Zend_Locale() returns the browser-environment locales. What you suggests is not a fix but a feature change which would result in a BC break.

Only because something does not work as you expected it does not mean that there is a failure. ;-) Normally there is a reason for it.

Closing as non-issue