Skip to content

Fix email report decimal comma locale. - #13265

Open
mehidi258 wants to merge 4 commits into
developfrom
bug/12867-fix-email-report-decimal-comma-locale
Open

Fix email report decimal comma locale.#13265
mehidi258 wants to merge 4 commits into
developfrom
bug/12867-fix-email-report-decimal-comma-locale

Conversation

@mehidi258

Copy link
Copy Markdown
Collaborator

Summary

Related issue(s):

Relevant technical choices

  • normalize_trends() now formats trends with number_format() (period decimal) instead of number_format_i18n(), since the locale-formatted string (e.g. 6,52%) couldn't be re-parsed by is_numeric() and silently became 0%.
  • parse_change_value() detects the decimal separator structurally instead of assuming one, so it parses both the new canonical format and any legacy locale-formatted values already stored.
  • section-metrics.php / section-page-metrics.php skip the change badge entirely when the value is null, instead of defaulting to 0.
  • Out of scope: build_sections() switches the locale but never restores it on success, so it can leak into later renders — tracked in Email report section builder leaks switched locale on success path #12883.
  • Out of scope: the badge can show -0% for a trend that rounds to negative zero — tracked in Email report change badge shows -0% for near-zero negative trends #13264.

PR Author Checklist

  • My code is tested and passes existing unit tests.
  • My code has an appropriate set of unit tests which all pass.
  • My code is backward-compatible with WordPress 5.2 and PHP 7.4.
  • My code follows the WordPress coding standards.
  • My code has proper inline documentation.
  • I have added a QA Brief on the issue linked above.
  • I have signed the Contributor License Agreement (see https://cla.developers.google.com/).

Do not alter or remove anything below. The following sections will be managed by moderators only.

Code Reviewer Checklist

  • Run the code.
  • Ensure the acceptance criteria are satisfied.
  • Reassess the implementation with the IB.
  • Ensure no unrelated changes are included.
  • Ensure CI checks pass.
  • Check Storybook where applicable.
  • Ensure there is a QA Brief.
  • Ensure there are no unexpected significant changes to file sizes.

Merge Reviewer Checklist

  • Ensure the PR has the correct target branch.
  • Double-check that the PR is okay to be merged.
  • Ensure the corresponding issue has a ZenHub release assigned.
  • Add a changelog message to the issue.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 This comment is automatically updated by CI workflows. Each section is managed independently.

📦 Build files for 747d030:

🎭 Playwright reports for 747d030:

@tofumatt tofumatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect some test cases with large numbers here to ensure we're handling both decimal places and thousands separators properly, and I've left some notes about comments and approach here.

Comment on lines +80 to +81
$change = $data['change'] ?? null;
if ( null !== $change ) :

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's with the indentation here? It seems a bit off 🤔

Also, will $data[ 'change' ] ever be null of its own accord? If not:

Suggested change
$change = $data['change'] ?? null;
if ( null !== $change ) :
if ( undefined !== $data['change'] ) :

seems like it would work 🤔

Comment on lines +104 to +105
$change = $data['changes'][ $index ] ?? null;
if ( null !== $change ) :

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, is this casting to null needed? If so: can you add a comment explaining why?

Comment on lines +10 to +14
* @var float $value The percentage change value. Callers must guard against
* `null` and skip rendering this part entirely when no
* comparison is available, rather than passing a
* default of `0`, which would render a misleading `0%`
* badge.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @var float $value The percentage change value. Callers must guard against
* `null` and skip rendering this part entirely when no
* comparison is available, rather than passing a
* default of `0`, which would render a misleading `0%`
* badge.
* @var float $value The percentage change value. Callers must guard against
* `null` and skip rendering this part entirely when no
* comparison is available, rather than passing a
* default of `0`, which would render a misleading `0%`
* badge.

Why not have this component accept undefined/null values and choose to output nothing? 🤔

Comment on lines +233 to 235
$formatted = number_format( $number, 2, '.', '' );

$output[] = sprintf( '%s%%', $formatted );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to format this as a string at all here? Why not just return the float and do the locale-formatting later on, if this one isn't locale-aware anyway? 🤔

Comment on lines +196 to +202
*
* The trend is kept in a canonical, period-decimal form rather than a
* locale-formatted one, since downstream consumers (the template
* formatter and the change-badge template) always re-parse and
* re-format the value themselves. A locale-formatted string (e.g.
* `6,52%` under a decimal-comma locale) only made the value harder to
* re-parse.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an AI-generated comment and is a bit too verbose. It's documenting, very specifically, the behaviour of this function in the context of this issue's fix, but it doesn't serve the reader of this documentation in-general.

Suggested change
*
* The trend is kept in a canonical, period-decimal form rather than a
* locale-formatted one, since downstream consumers (the template
* formatter and the change-badge template) always re-parse and
* re-format the value themselves. A locale-formatted string (e.g.
* `6,52%` under a decimal-comma locale) only made the value harder to
* re-parse.

Comment on lines +179 to +182
// `es_CO` is not an installed test locale, but `normalize_trends()`
// must not localize the trend regardless of what the active
// locale's number format looks like (simulated above), so the
// locale name here only documents intent.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// `es_CO` is not an installed test locale, but `normalize_trends()`
// must not localize the trend regardless of what the active
// locale's number format looks like (simulated above), so the
// locale name here only documents intent.
// Simulate the `es_CO` locale, which uses commas
// for decimals (eg. `6,52`, not `6.52`).

Comment on lines +154 to +162
public function data_parse_change_value() {
$cases = array();
$values = array(
'6.52%' => 6.52,
'-0.85%' => -0.85,
'6,52%' => 6.52,
'-0,85%' => -0.85,
'0%' => 0.0,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned earlier: some larger values with both commas and decimals should be used here to ensure they behave properly.

Comment on lines +183 to +184
* rather than relying on `switch_to_locale()`, which silently no-ops for
* locales without an installed translation file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* rather than relying on `switch_to_locale()`, which silently no-ops for
* locales without an installed translation file.
* rather than relying on `switch_to_locale()`, which proceeds without warnings
* for locales without an installed translation file.

* rather than relying on `switch_to_locale()`, which silently no-ops for
* locales without an installed translation file.
*
* @param string $locale Locale name (en_US, es_CO, or de_DE).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param string $locale Locale name (en_US, es_CO, or de_DE).
* @param string $locale Locale name (eg. `'en_US'`, etc.).

Comment on lines +120 to +122
// The email's static <style> block always defines `.badge-positive`/
// `.badge-negative` CSS rules, so assert on the rendered `class`
// attribute rather than the bare class name.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The email's static <style> block always defines `.badge-positive`/
// `.badge-negative` CSS rules, so assert on the rendered `class`
// attribute rather than the bare class name.
// The email's static <style> block always defines `.badge-positive`/
// `.badge-negative` CSS rules, so include the `class=""` wrapper to
// ensure we're testing for the existence of the badge markup and not
// just the CSS in the `<style>` tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Email report comparison badges always show 0% for locales that use a decimal comma

2 participants