Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ keywords = ["jdk", "java", "jvm", "jre"]
name = "jdk4py"
readme = "README.md"
requires-python = ">=3.10"
version = "25.0.2.0"
version = "25.0.2.1"

[project.urls]
Repository = "https://github.com/activeviam/jdk4py"
Expand All @@ -47,6 +47,7 @@ ignore = [
"D203",
"D211",
"D212",
"E501",
"EM102",
"ISC001",
"S101",
Expand Down
42 changes: 27 additions & 15 deletions src/jdk4py/_included_locales.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
from collections.abc import Collection
from typing import Literal, TypeAlias, get_args

_RegionSpecificLocale: TypeAlias = Literal[
"bn-IN",
"da-DK",
"de-DE",
"en-GB",
"en-US",
"es-ES",
"es-MX",
"fr-FR",
"it-IT",
"ja-JP",
"pt-BR",
"ru-RU",
"zh-CN",
]
_REGION_SPECIFIC_LOCALES: Collection[str] = get_args(_RegionSpecificLocale)

INCLUDED_LOCALES = frozenset(
[
"bn-IN",
"da-DK",
"de-DE",
"en-US",
"en-GB",
"es-ES",
"es-MX",
"fr-FR",
"it-IT",
"ja-JP",
"pt-BR",
"ru-RU",
"zh-CN",
],
{
locale
for tag in _REGION_SPECIFIC_LOCALES
# Expand each region-specific locale to also include its language-only locale so that `jlink --include-locales` retains the language-only locale bundles (e.g. `FormatData_fr.class`).
# See https://github.com/openjdk/jdk/blob/jdk-25%2B35/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java.
for locale in (tag, tag.split("-", maxsplit=1)[0])
},
)
Binary file added tests/resources/PrintLocaleNumberFormats.jar
Binary file not shown.
19 changes: 19 additions & 0 deletions tests/resources/PrintLocaleNumberFormats.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package resources;

import java.text.DecimalFormatSymbols;
import java.util.Locale;

public class PrintLocaleNumberFormats {

public static void main(String[] args) {
for (final Locale locale: DecimalFormatSymbols.getAvailableLocales()) {
final DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
System.out.println(
locale.toLanguageTag()
+ "\t" + ((int) dfs.getDecimalSeparator())
+ "\t" + ((int) dfs.getGroupingSeparator())
);
}
}

}
77 changes: 75 additions & 2 deletions tests/test_jdk4py.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import re
from dataclasses import dataclass
from pathlib import Path
from subprocess import run
from typing import get_args

from jdk4py import JAVA, JAVA_VERSION
from jdk4py._included_locales import INCLUDED_LOCALES
from jdk4py._included_locales import INCLUDED_LOCALES, _RegionSpecificLocale

_TEST_RESOURCES_DIRECTORY = Path(__file__).parent / "resources"

Expand Down Expand Up @@ -43,4 +45,75 @@ def test_included_locales() -> None:
locale.replace("_", "-")
for locale in completed_process.stdout.strip().splitlines()
}
assert locales.issuperset(INCLUDED_LOCALES)
assert locales >= INCLUDED_LOCALES


@dataclass(frozen=True)
class _NumberFormattingSeparators:
decimal_separator: str
grouping_separator: str


_COMMA = ","
_DOT = "."
_NARROW_NO_BREAK_SPACE = chr(0x202F)
_NO_BREAK_SPACE = chr(0x00A0)
Comment thread
NathanEckert marked this conversation as resolved.


def _get_number_formatting_separators(
locale: _RegionSpecificLocale, /
) -> _NumberFormattingSeparators:
Comment thread
NathanEckert marked this conversation as resolved.
match locale:
case "bn-IN" | "en-GB" | "en-US" | "es-MX" | "ja-JP" | "zh-CN":
return _NumberFormattingSeparators(
decimal_separator=_DOT, grouping_separator=_COMMA
)
case "da-DK" | "de-DE" | "es-ES" | "it-IT" | "pt-BR":
return _NumberFormattingSeparators(
decimal_separator=_COMMA, grouping_separator=_DOT
)
case "fr-FR":
return _NumberFormattingSeparators(
decimal_separator=_COMMA,
grouping_separator=_NARROW_NO_BREAK_SPACE,
)
case "ru-RU":
return _NumberFormattingSeparators(
decimal_separator=_COMMA, grouping_separator=_NO_BREAK_SPACE
)


def test_locale_data_inclusion() -> None:
"""
Check that each included locale uses its expected number formatting separators.

``jlink --include-locales=fr-FR`` does not retain ``FormatData_fr.class``,
Comment thread
NathanEckert marked this conversation as resolved.
so ``DecimalFormatSymbols.getInstance(Locale.forLanguageTag("fr-FR"))``
silently returns ROOT symbols.

``INCLUDED_LOCALES`` must therefore list each region-specific locale alongside its language-only parent.
"""
expected = {
locale: _get_number_formatting_separators(locale)
for locale in get_args(_RegionSpecificLocale)
}

completed_process = run( # noqa: S603
[JAVA, "-jar", _TEST_RESOURCES_DIRECTORY / "PrintLocaleNumberFormats.jar"],
capture_output=True,
check=True,
text=True,
)
actual = {
locale: _NumberFormattingSeparators(
decimal_separator=chr(int(decimal_cp)),
grouping_separator=chr(int(grouping_cp)),
)
for line in completed_process.stdout.strip().splitlines()
for locale, decimal_cp, grouping_cp in [line.split("\t")]
if locale in expected
}

assert actual == expected, (
Comment thread
NathanEckert marked this conversation as resolved.
"CLDR data not loaded for some locales (likely a missing language-only bundle)"
)
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading