Make WordPress Core

Opened 12 years ago

Last modified 2 months ago

#22225 reviewing enhancement

WordPress does not localize ordinal suffixes in dates

Reported by: mihaimihai's profile mihaimihai Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.4.2
Component: I18N Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

In wp-includes/functions.php function date_i18n(), elements like month, month abbreviation, weekday etc.. are localized but not the ordinal suffixes (e.g. st, nd, rt, th)

effect: when using the ordinal suffixes for dates

e.g.

<?php the_time('F jS, Y'); ?>


on translated/localized page page, the month name is translated (F) but the ordinal suffix no.

Not browser/OS/environment dependent.

Attachments (3)

22225.patch (5.2 KB) - added by realloc 9 years ago.
Patch and Unit tests
22225.2.patch (5.2 KB) - added by realloc 9 years ago.
ordinal suffix for days
22225.3.patch (6.2 KB) - added by realloc 9 years ago.
Patch and Unit tests with tests for filter

Download all attachments as: .zip

Change History (25)

#2 @jrf
12 years ago

+1

#3 @chriscct7
9 years ago

  • Keywords needs-patch added

@realloc
9 years ago

Patch and Unit tests

#4 @realloc
9 years ago

  • Keywords needs-patch removed

I had to extend some functionality in WP_locale too. There were no unit tests for this class so I tested all of the things needed together.

#5 @johnbillion
9 years ago

  • Keywords has-patch has-unit-tests needs-testing added

#6 follow-up: @gibrown
9 years ago

@realloc nice approach of using wp-locale, but I think there is some confusion about 'S'. It is the day of the month rather than the month number. So for instance, the output of

<?php
date_i18n( 'S', 1424001600 ) //Feb 15th, 2015

Should not be expecting 'nd' in the unit test, it should be 'th'.

I think it needs a function that is hardcoded into wp-locale to handle each locale. Maybe something based off of this wikipedia article? For some languages we should entirely remove the 'S'. I ended up here due to Russian and Hebrew localization of 'F jS' where I think I understand the best solution to be removing the 'S' entirely. cc @kovshenin

Also looks like in PHP 5.3.0+ there is support for formatting an ordinal. So maybe should use that with a reasonable fall back for old versions of PHP?

#7 in reply to: ↑ 6 @realloc
9 years ago

Replying to gibrown:

@realloc nice approach of using wp-locale, but I think there is some confusion about 'S'. It is the day of the month rather than the month number. So for instance, the output of

Thanks a lot! After reading http://php.net/manual/en/function.date.php again I have to admit that your are completely right. 'S' is indeed not meant for months but for days.

Also looks like in PHP 5.3.0+ there is support for formatting an ordinal. So maybe should use that with a reasonable fall back for old versions of PHP?

It seems that the class NumberFormatter needs PHP 5 >= 5.3.0 and PECL intl >= 1.0.0 ... I'm sure that discussions about these things will be very interesting in the near future.

Anyway, I worked on a new solution today. ;) I think that WordPress should at least provide the functionality for the English ordinal numbers but should also come with a filter so that a developer could extend it easily. In German the rules are very different for example: they append the suffix 'te' to numbers from 0 to 19 and 'ste' from 20 and above.

@realloc
9 years ago

ordinal suffix for days

#8 follow-up: @gibrown
9 years ago

Feels like it would be good to have test cases in different languages for this to prove out that it works across multiple languages. Looking at the code it is not obvious to me that it would work for how you describe German for instance.

@realloc
9 years ago

Patch and Unit tests with tests for filter

#9 in reply to: ↑ 8 @realloc
9 years ago

Replying to gibrown:

Feels like it would be good to have test cases in different languages for this to prove out that it works across multiple languages.

I just added 2 filter examples to illustrate the idea. Any multilingual plugin could so implement the necessary functionality.

#10 @ocean90
9 years ago

  • Owner set to SergeyBiryukov
  • Status changed from new to reviewing

This ticket was mentioned in Slack in #core-i18n by ocean90. View the logs.


9 years ago

#12 @ocean90
9 years ago

  • Milestone changed from Awaiting Review to 4.6
  • Owner changed from SergeyBiryukov to ocean90

#13 @ocean90
9 years ago

  • Keywords dev-feedback needs-testing removed
  • Milestone changed from 4.6 to Future Release
  • Owner ocean90 deleted

I don't like the filter approach because it doesn't provide out of the box support for any other locale. As you've already noticed Russian doesn't have a specific identifier for ordinals and an empty translations is not supported.

I'd like to see an approach which follows the Plural-Forms entry in a .po file. It's "Plural-Forms: nplurals=2; plural=n != 1;\n" for German or "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" for Russian.
You'll see similar rules in the Unicode CLDR database: http://www.unicode.org/cldr/charts/29/supplemental/language_plural_rules.html.

An example for English could be "Ordinal-Forms: nplurals=4; plural=(n % 10 = 1 && n % 100 != 11) ? 'st' : (n % 10 = 3 && n % 100 != 13) ? 'nd' : (n % 10 = 3 && n % 100 != 13) ? 'rd' : 'th';".

That's something which we can be stored into the translation file and parsed by a WP_Locale::get_ordinal_suffix() method.

This ticket was mentioned in Slack in #core by johnbillion. View the logs.


8 years ago

#15 @tobifjellner
8 years ago

What if we simply drop back the whole solution to something that already works for everyone?, by simply using gettext an already normal translations tools?.
We could add 31 strings to translate, with proper context to make sure that they're understood and correctly translated.

_x( 'st', 'Ordinal suffix for day 1 in month, "-" for empty', 'my-text-domain'
_x( 'nd', 'Ordinal suffix for day 2 in month, "-" for empty', 'my-text-domain'
_x( 'rd', 'Ordinal suffix for day 3 in month, "-" for empty', 'my-text-domain'
_x( 'th', 'Ordinal suffix for day 4 in month, "-" for empty', 'my-text-domain'
_x( 'th', 'Ordinal suffix for day 5 in month, "-" for empty', 'my-text-domain'
_x( 'st', 'Ordinal suffix for day 31 in month, "-" for empty', 'my-text-domain'

...
And then wrap it up in a simple function?

Last edited 8 years ago by tobifjellner (previous) (diff)

#16 @mattkeys
4 years ago

I ran into this today. It seems like this ticket has stalled out many years ago so I just wanted to add here that this is something that people still run into today. I've disabled the ordinal suffix on our site for now as I have no good alternative.

#17 @IronDev
4 years ago

If you are a WPML user and run into this issue, you may want to check the workaround we suggested here.

https://wpml.org/forums/topic/i-am-using-mec-calendar-and-trying-to-translate-2nd-3d-4th/#post-9248019

This ticket was mentioned in PR #7975 on WordPress/wordpress-develop by jayaddison.


2 months ago
#18

The built-in PHP `NumberFormatter` can localize numbers to include ordinal suffixes; however the return value always includes both the numeric value and also the suffix -- e.g. it is not currently possible to request only the suffix.

In the case of date formatting, it's fairly typical that if ordinals are expected, then they will be output for the calendar day number (e.g. the 11 in 2024-01-11) - and that the suffix should appear directly adjacent (e.g. 11th).

Day-of-month should be restricted to values no larger than 31, and should all be integer values, so we shouldn't need to worry about any locale-specific introduction of thousands or decimal place markers.

Based on the above, we can implement limited/restricted localization of day-number-plus-ordinal-suffix in the WordPress date_i18n function by special-case detecting an `S` (ordinal format) character symbol immediately preceded by a `j` (day of the month) format code.

Trac ticket: https://core.trac.wordpress.org/ticket/22225

jayaddison commented on PR #7975:


2 months ago
#19

There seems to be a problem with the HTTP POST to wp-admin/admin-ajax.php when previewing a date format of F jS, Y with these changes in place -- an HTTP 500 error response is received. Moving the pull request into draft status until that is figured out and resolved.

jayaddison commented on PR #7975:


2 months ago
#20

(also: the documentation will need to be updated alongside this modification)

jayaddison commented on PR #7975:


2 months ago
#21

The built-in PHP `NumberFormatter` can localize numbers to include ordinal suffixes; however the return value always includes both the numeric value and also the suffix -- e.g. it is not currently possible to request only the suffix.

It seems that NumberFormatter is provided by the `php-intl` package which isn't guaranteed to be available.

There seems to be a problem with the HTTP POST to wp-admin/admin-ajax.php when previewing a date format of F jS, Y with these changes in place -- an HTTP 500 error response is received. Moving the pull request into draft status until that is figured out and resolved.

The error that appears is:

PHP Fatal error:  Uncaught Error: Class 'NumberFormatter' not found in /wordpress/wp-includes/functions.php:290
Stack trace:
#0 /wordpress/wp-includes/functions.php(192): wp_date('F jS, Y')
#1 /wordpress/wp-admin/includes/ajax-actions.php(2852): date_i18n('F jS, Y')
#2 /wordpress/wp-includes/class-wp-hook.php(324): wp_ajax_date_format('')
#3 /wordpress/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters('', Array)
#4 /wordpress/wp-includes/plugin.php(517): WP_Hook->do_action(Array)
#5 /wordpress/wp-admin/admin-ajax.php(192): do_action('wp_ajax_date_fo...')
#6 {main}
  thrown in /wordpress/wp-includes/functions.php on line 290

jayaddison commented on PR #7975:


2 months ago
#22

The error that appears is:

With the latest pushed commits in this PR, this error is resolved - a NumberFormatter is only constructed if the class exists (in the global namespace) according to check_exists.

One other question I have is whether the logic, if acceptable (it's not exactly an elegant solution) should use get_locale or get_user_locale -- I'm not sure about that.

Note: See TracTickets for help on using tickets.