Jump to content

Decimal point "." changed to "," in base of setlocale()


Recommended Posts

Hi all,

I have experienced some weird problems when using the Float field combined with the translation of setlocale() arguments.

It seems that with specific setlocale() (in my case setlocale('it_IT')) leads to transform the decimal separator from "."to ","  (for example "2.566" is transformed to "2,566") so all queries contains a "," and mysql stores only the integer part (without any errors).

Good query:

INSERT INTO `field_testfloat` (pages_id, data) VALUES('1024', '24.534') ON DUPLICATE KEY UPDATE data=VALUES(data)

Bad query:

INSERT INTO `field_testfloat` (pages_id, data) VALUES('1024', '24,534') ON DUPLICATE KEY UPDATE data=VALUES(data)

The naive solution is to leave blank setlocale(), but i wonder if it is possibile to correct this behaviour.

Link to comment
Share on other sites

I'm not really sure what the best solution is to this, and how many other locale rules we might have to potentially account for (if any?), but one solution would be for FieldtypeFloat::sleepValue to replace commas with periods. Do you want to try adding the following to your /wire/modules/Fieldtype/FieldtypeFloat.module, or replace with the attached file?

        public function ___sleepValue(Page $page, Field $field, $value) {
                if(strpos($value, ',') !== false) $value = str_replace(',', '.', $value); 
                $value = (float) $value;
                return $value; 
        }

FieldtypeFloat.module

Link to comment
Share on other sites

I'm not really sure what the best solution is to this, and how many other locale rules we might have to potentially account for (if any?), but one solution would be for FieldtypeFloat::sleepValue to replace commas with periods. Do you want to try adding the following to your /wire/modules/Fieldtype/FieldtypeFloat.module, or replace with the attached file?

        public function ___sleepValue(Page $page, Field $field, $value) {
                if(strpos($value, ',') !== false) $value = str_replace(',', '.', $value); 
                $value = (float) $value;
                return $value; 
        }

I've tried with your patch but it seems that when you make the (float) cast the "," returns :(

public function ___sleepValue(Page $page, Field $field, $value) {

        $this->message("pre fix - ".$value); // print : 84,3

        // handle potential issue with other locales
        if(strpos($value, ',') !== false) $value = str_replace(',', '.', $value);

        $this->message("after fix - ".$value); // print : 84.3

        $value = (float) $value;

        $this->message("after cast - ".$value); // print again : 84,3

        return $value; 
}

Another solution seems to add "setlocale(LC_NUMERIC, 'en_US');" in LanguageSupport.module:

wire('config')->dateFormat = $this->_('Y-m-d H:i:s'); // Sortable date format used in the admin
$locale = $this->_('C'); // Value to pass to PHP's setlocale(LC_ALL, 'value') function when initializing this language // Default is 'C'. Specify '0' to skip the setlocale() call (and carry on system default).
		
if($locale != '0') setlocale(LC_ALL, $locale);
        
// Fix for float number with incorrect decimal separator.
setlocale(LC_NUMERIC, 'en_US'); 

Not sure if is the correct way to avoid this problems...

Link to comment
Share on other sites

Thanks for trying it out. I didn't realize that locale settings went as far as typecasting. Seems like typecasting should be about maintaining a type for the language, not for display. While we could set the LC_NUMERIC, and maybe that's the right way to go (I'm not yet sure), I'd be worried about the situations when someone wants to override the numeric stuff. Perhaps FieldtypeFloat needs to do this in the sleepValue method: save the locale, set it to something compatible with PHP and MySQL, then set it back to whatever it was. That seems like maybe the way to add this with least impact. 

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

I have different languages in the backend, a template with a field of type float. I cannot save a float in other languages (polish and german) than default (english). The floats are rounded to full integer value and stored like this.


added 30 October 2013 09:37 AM
To prevent language troubles I am using a workaround now:
input type text instead of float with a regex (settings > pattern):

\d{1,4}([\.]\d{1,3})?

For validation of a weight of max. 10,000 kg (9999.999 kg) with max. 3 decimal places, only the dot is allowed as seperator.

 

Link to comment
Share on other sites

If anyone knows of a good permanent solution for this issue that doesn't break in one language or another, please let me know or submit PR or patch. It seems like PHP has setup numerous tripwires on this one for us. Until we get this one figured out, I think Kixe's solution is probably the best way to go if you need to reliably store floats across languages that use different things for decimals. But I'd like to get a permanent solution in place for FieldtypeFloat, as text is not the ideal way to store these numbers from the DB, or make them searchable. But at least it's reliable. 

Link to comment
Share on other sites

What about to use "number_format"  in FieldtypeFloat.module ?

It should be reliable because it is language independed and (maybe) when the queries are constructed all the values are treated as strings, so you dont'need to have a "float" value anymore.

    public function ___sleepValue(Page $page, Field $field, $value) {
        // Field converted in string with number format.
        $value = number_format($value, $field->precision, ".","");
        return $value; 
    } 

FieldtypeFloat.module

  • Like 1
Link to comment
Share on other sites

What about to use "number_format"  in FieldtypeFloat.module ?

It should be reliable because it is language independed and (maybe) when the queries are constructed all the values are treated as strings, so you dont'need to have a "float" value anymore.

    public function ___sleepValue(Page $page, Field $field, $value) {
        // Field converted in string with number format.
        $value = number_format($value, $field->precision, ".","");
        return $value; 
    } 

attachicon.gifFieldtypeFloat.module

Anybody tried this out?

Link to comment
Share on other sites

Alessio, i think your solution might be the one we've been looking for. While sleepValue() would ideally return a float, that's just not possible here unless MySQL recognizes the same float format as the PHP locale (which apparently it does not). So converting to a string actually seems like quite a good idea. I am going to make this change on the dev branch and test it some here, but so far I think this seems like the best solution. 

  • Like 1
Link to comment
Share on other sites

  • 10 months later...
  • 2 years later...

The simpler solution is to always use: setlocale(LC_NUMERIC, 'C') after setting LC_ALL to custom locale. 

This helps avoiding a lot of issues as LC_NUMERIC tells the code parser how to output numeric expressions. For instance with:

setlocale(LC_ALL, 'it_IT.UTF-8');

1.234 will be written as 1,234 when used as string, like in string concatenation (as in db query builders) . But database and most other data endpoints still expect 1.234 for decimals. 

It is always better to use LC_NUMERIC 'C' and call numeric/monetary output formatting helpers explicitly in templates.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By daniel_puehringer
      Hey community,
      first of all: I love this CMS! But unfortunately my Code Internationalization (i18n) doesn´t work within included php files:
      I´m using the module Pro Fields Page Table, the regular Languages Support Module and no template caching. The website has 2 Languages (DE as default, EN as second language)
      Problem:
      Using
      <?php echo(__('Test')); ?> within /site/templates/home.php works without any problems and gets translated correctly
      However using
      <?php echo($this->_('Headline'));?> within /site/templates/components/component.php does not work.
      Note: using
      <?php echo(__('Headline'));?> in .../component.php throws an error and therefore cannot be used.
       
      Example:
      /site/templates/ce-includer.php (Template with the dynamic text-field 'filepath'):
      include('components/'.$page->filepath); this correclty includes the file "/site/templates/components/home-content.php"
      Code in home-content.php:
      <h1><?php echo($this->_('Headline'));?></h1>
      Output for both pages (DE and EN version - the string was translated to "Headline DE" in german and "Headline EN" in english):
      <h1>Headline</h1> Does anyone know how to use Code Internationalization in such a szenario?

      All the best and keep up the great work!
      Daniel
    • By donatas
      Hello,
      how would I do a multi-language website search with just a selector?
      I have many multi-lang fields and I want to do a search through all of them at once and through all of their language values.
      Is there a "selector way" of doing this? Maybe something like `title|title:de|title:it`? It seems I have seen this somewhere a long time ago but can't find in any documentation or forum search...
      Or the only way of doing it is by running separate searches for each language with output formatting off and then consolidating it all in one single results array?
      Because I still want to give users a result, even if it is in another language than current $user. Visitors mostly will be searching for specific terms that are very similar in all languages, but might be not used in one language version of a single page, for example. Or the user might not have switched language tohis prefered and did the search first, etc.. (many use cases in my situation)
      Example:
      $pages->find('title~='.$q) - maybe different operator is needed? /en/search/?q=visit = 1 results /it/search/?q=visit = 0 results Thanks for any advice!
    • By sebr
      Hello
      One of my customers needs to have his site translated by a publisher. He asks me if it is possible to create a role that could only edit the German version of the pages, without permission on the English version.
      I haven't found any permission related to this need, but maybe it's possible from a hook?
      Thank you for your help
       
    • By Noel Boss
      Hi everyone 🙌
      Is there a way to order the language tabs in the backend? Currently, they seem to be ordered based on the created date (or id?) …
      ( time passes … ⏰ 🚶‍♂️)
      Just answered my own question. One can reorder the languages in the page tree under admin » languages or directly in the DB » pages » template_id=54 » sord field.
      Anyone knows if there are side effects when moving the default language from sort 0 to somewhere higher?
    • By gerritvanaaken
      Wouldn’t it be cool to have whole repeater items (or even repeater matrix items) language-specific. Some of my clients do have pages that are 90% identical in German and English, but there are some sections that should not appear in one or another language. I attached a concept screenshot.
      Would something like this be possible with some simple backend hooks and "hidden checkbox fields"? Or is it way more complicated?
       

×
×
  • Create New...