Skip to content

Commit 5d014cc

Browse files
authored
Merge pull request #165 from timvink/86-locale-can-be-longer-than-just-2-letter-code
Support 5 letter locale settings
2 parents 843a33a + 9eb8511 commit 5d014cc

File tree

5 files changed

+105
-27
lines changed

5 files changed

+105
-27
lines changed

Diff for: docs/howto/specify-locale.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Specify a locale
22

3-
`locale` is a two letter [ISO639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code that `git-revision-date-localized` uses to display dates in your preferred language.
3+
`locale` is aa two letter [ISO639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code (f.e. `en`) or [5-letter language code with added territory/region/country](https://www.mkdocs.org/user-guide/localizing-your-theme/#supported-locales) (`en_US`) that `git-revision-date-localized` uses to display dates in your preferred language.
44

55
For example:
66

@@ -68,6 +68,7 @@ plugins:
6868
If no `locale` is specified anywhere, the fallback is English with the US date format (`en`).
6969

7070
!!! info "Supported locales"
71+
7172
- When used in combination with `type: date` or `type: datetime`, translation is done using [babel](https://github.com/python-babel/babel) which supports [these locales](http://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html)
7273

7374
- When used in combination with `type: timeago` then [timeago.js](https://github.com/hustcc/timeago.js) is added to your website, which supports [these locales](https://github.com/hustcc/timeago.js/tree/master/src/lang). If you specify a locale not supported by timeago.js, the fallback is English (`en`)

Diff for: docs/options.md

+14-8
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,33 @@ Default is `UTC`. Specify a time zone database name ([reference](https://en.wiki
5353

5454
## `locale`
5555

56-
Default is `None`. Specify a two letter [ISO639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code to display dates in your preferred language. Note this plugin supports many different ways to [specify the locale](howto/specify-locale.md), but if not specified anywhere the fallback is English (`en`).
56+
Default is `None`. Specify a two letter [ISO639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code (f.e. `en`) or [5-letter language code with added territory/region/country](https://www.mkdocs.org/user-guide/localizing-your-theme/#supported-locales) (`en_US`) to display dates in your preferred language. Note this plugin supports many different ways to [specify the locale](howto/specify-locale.md), but if not specified _anywhere_ the fallback will be English (`en`). `locale` is used to translate timestamps to dates when `type: date` or `type: datetime` (using [babel](https://github.com/python-babel/babel)) as well as to translate datetimes to a relative timeago string when `type: timeago` (using [timeago.js](https://github.com/hustcc/timeago.js)).
5757

5858
Example outputs:
5959

6060
```yaml
61-
April 27, 2021 # `locale: en` with `type: date` (default)
62-
April 27, 2021 13:11:28 # `locale: en` with `type: datetime`
63-
2 weeks ago # `locale: en` with `type: timeago`
64-
27 de marzo de 2021 # `locale: es` with `type: date`
65-
27 de marzo de 2021 13:57:28 # `locale: es` with `type: datetime`
66-
hace 2 semanas # `locale: es` with `type: timeago`
61+
# `locale: en`
62+
April 27, 2021 # with `type: date` (default)
63+
April 27, 2021 13:11:28 # with `type: datetime`
64+
2 weeks ago # with `type: timeago`
65+
# `locale: es`
66+
27 de marzo de 2021 # with `type: date`
67+
27 de marzo de 2021 13:57:28 # with `type: datetime`
68+
hace 2 semanas # with `type: timeago`
6769
```
6870

6971
=== ":octicons-file-code-16: mkdocs.yml"
7072

7173
```yaml
7274
plugins:
7375
- git-revision-date-localized:
74-
locale: en
76+
locale: en_US
7577
```
7678
79+
!!! note when using `type: timeago`
80+
81+
When using `type: timeago` then [timeago.js](https://github.com/hustcc/timeago.js) is added to your website, which supports [these locales](https://github.com/hustcc/timeago.js/tree/master/src/lang). If you specify a locale not supported by timeago.js, the fallback is English (`en`). It might happen that your specific locale is supported by babel (used by date formats) but not by timeago. In that case open an issue with this plugin.
82+
7783

7884
## `fallback_to_build_date`
7985

Diff for: src/mkdocs_git_revision_date_localized_plugin/dates.py

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from babel.dates import format_date, get_timezone
1+
from babel.dates import format_date, get_timezone, format_datetime
22

33
from datetime import datetime, timezone
44
from typing import Any, Dict
@@ -36,5 +36,56 @@ def get_date_formats(
3636
"iso_date": loc_revision_date.strftime("%Y-%m-%d"),
3737
"iso_datetime": loc_revision_date.strftime("%Y-%m-%d %H:%M:%S"),
3838
"timeago": '<span class="timeago" datetime="%s" locale="%s"></span>' % (loc_revision_date.isoformat(), locale),
39-
"custom": loc_revision_date.strftime(custom_format),
39+
"custom": format_datetime(loc_revision_date, format=strftime_to_babel_format(custom_format), locale=locale),
4040
}
41+
42+
43+
def strftime_to_babel_format(fmt: str) -> str:
44+
"""
45+
Convert strftime format string to Babel format pattern.
46+
47+
Args:
48+
fmt (str): strftime format string
49+
50+
Returns:
51+
str: Babel format pattern
52+
"""
53+
# Dictionary mapping strftime directives to Babel format patterns
54+
mapping = {
55+
'%a': 'EEE', # Weekday abbreviated
56+
'%A': 'EEEE', # Weekday full
57+
'%b': 'MMM', # Month abbreviated
58+
'%B': 'MMMM', # Month full
59+
'%c': '', # Locale's date and time (not directly mappable)
60+
'%d': 'dd', # Day of month zero-padded
61+
'%-d': 'd', # Day of month
62+
'%e': 'd', # Day of month space-padded
63+
'%f': 'SSSSSS', # Microsecond
64+
'%H': 'HH', # Hour 24h zero-padded
65+
'%-H': 'H', # Hour 24h
66+
'%I': 'hh', # Hour 12h zero-padded
67+
'%-I': 'h', # Hour 12h
68+
'%j': 'DDD', # Day of year
69+
'%m': 'MM', # Month zero-padded
70+
'%-m': 'M', # Month
71+
'%M': 'mm', # Minute zero-padded
72+
'%-M': 'm', # Minute
73+
'%p': 'a', # AM/PM
74+
'%S': 'ss', # Second zero-padded
75+
'%-S': 's', # Second
76+
'%w': 'e', # Weekday as number
77+
'%W': 'w', # Week of year
78+
'%x': '', # Locale's date (not directly mappable)
79+
'%X': '', # Locale's time (not directly mappable)
80+
'%y': 'yy', # Year without century
81+
'%Y': 'yyyy', # Year with century
82+
'%z': 'Z', # UTC offset
83+
'%Z': 'z', # Timezone name
84+
'%%': '%' # Literal %
85+
}
86+
87+
result = fmt
88+
for strftime_code, babel_code in mapping.items():
89+
result = result.replace(strftime_code, babel_code)
90+
91+
return result

Diff for: src/mkdocs_git_revision_date_localized_plugin/plugin.py

+4-15
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def on_config(self, config: config_options.Config, **kwargs) -> Dict[str, Any]:
8181
# Get locale from plugin configuration
8282
plugin_locale = self.config.get("locale", None)
8383

84-
# theme locale
84+
# Get locale from theme configuration
8585
if "theme" in config and "language" in config.get("theme"):
8686
custom_theme = config.get("theme")
8787
theme_locale = (
@@ -96,7 +96,6 @@ def on_config(self, config: config_options.Config, **kwargs) -> Dict[str, Any]:
9696
custom_theme.locale if Version(mkdocs_version) >= Version("1.6.0") else custom_theme._vars.get("locale")
9797
)
9898
logging.debug("Locale '%s' extracted from the custom theme: '%s'" % (theme_locale, custom_theme.name))
99-
10099
else:
101100
theme_locale = None
102101
logging.debug("No locale found in theme configuration (or no custom theme set)")
@@ -116,9 +115,6 @@ def on_config(self, config: config_options.Config, **kwargs) -> Dict[str, Any]:
116115

117116
# Validate locale
118117
locale_set = str(locale_set)
119-
assert len(locale_set) == 2, (
120-
"locale must be a 2 letter code, see https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"
121-
)
122118

123119
# set locale also in plugin configuration
124120
self.config["locale"] = locale_set
@@ -173,7 +169,6 @@ def on_page_markdown(self, markdown: str, page: Page, config: config_options.Con
173169
# First prio is use mkdocs-static-i18n locale if set
174170
try:
175171
locale = page.file.locale
176-
177172
except AttributeError:
178173
locale = None
179174

@@ -183,18 +178,12 @@ def on_page_markdown(self, markdown: str, page: Page, config: config_options.Con
183178
locale = page.meta["locale"]
184179

185180
# Finally, if no page locale set, we take the locale determined on_config()
181+
# (fourth prio is plugin configuration)
182+
# (firth prio is theme configuration)
183+
# (sixth prio is fallback to English)
186184
if not locale:
187185
locale = self.config.get("locale")
188186

189-
# MkDocs supports 2-letter and 5-letter locales
190-
# https://www.mkdocs.org/user-guide/localizing-your-theme/#supported-locales
191-
# We need the 2 letter variant
192-
if len(locale) == 5:
193-
locale = locale[:2]
194-
assert len(locale) == 2, (
195-
"locale must be a 2 letter code, see https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"
196-
)
197-
198187
# Retrieve git commit timestamp
199188
# Except for generated pages (f.e. by mkdocs-gen-files plugin)
200189
if getattr(page.file, "generated_by", None):

Diff for: tests/test_dates.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
from datetime import datetime, timezone
33
from babel.dates import get_timezone
4-
4+
from babel.core import UnknownLocaleError
55
from mkdocs_git_revision_date_localized_plugin.dates import get_date_formats
66

77

@@ -18,6 +18,37 @@ def test_get_dates():
1818
}
1919
assert get_date_formats(0) == expected_output
2020

21+
# Test with 4-letter locale
22+
new_expected_output = expected_output.copy()
23+
new_expected_output["timeago"] = '<span class="timeago" datetime="1970-01-01T00:00:00+00:00" locale="en_US"></span>'
24+
assert get_date_formats(0, locale="en_US") == new_expected_output
25+
26+
# Test with different locale
27+
expected_output = {
28+
"date": "1 janvier 1970",
29+
"datetime": "1 janvier 1970 00:00:00",
30+
"iso_date": "1970-01-01",
31+
"iso_datetime": "1970-01-01 00:00:00",
32+
"timeago": '<span class="timeago" datetime="1970-01-01T00:00:00+00:00" locale="fr"></span>',
33+
"custom": "01. janvier 1970"
34+
}
35+
assert get_date_formats(0, locale="fr") == expected_output
36+
37+
# Test with pt_BR locale
38+
expected_output = {
39+
"date": "1 de janeiro de 1970",
40+
"datetime": "1 de janeiro de 1970 00:00:00",
41+
"iso_date": "1970-01-01",
42+
"iso_datetime": "1970-01-01 00:00:00",
43+
"timeago": '<span class="timeago" datetime="1970-01-01T00:00:00+00:00" locale="pt_BR"></span>',
44+
"custom": "01. janeiro 1970"
45+
}
46+
assert get_date_formats(0, locale="pt_BR") == expected_output
47+
48+
# Test with non-existing locale
49+
with pytest.raises(UnknownLocaleError):
50+
get_date_formats(0, locale="abcd")
51+
2152
# Test with custom arguments
2253
expected_output = {
2354
"date": "January 1, 1970",

0 commit comments

Comments
 (0)