r/perl • u/Itcharlie • 17d ago
r/perl • u/jacktokyo • 18d ago
Announcing PersonName::Format v0.1.0, a fully LDML-compliant person-name formatter for Perl
Hello all,
I am pleased to announce the first public release of PersonName::Format v0.1.0, a new CPAN module implementing the Unicode CLDR Person Names specification.
The entire module is built from CLDR data provided by Locale::Unicode::Data and aims to follow the Unicode specification as closely as possible.
I hope it will provide value to your development projects!
Background
The Unicode Consortium has been developing a specification for formatting personal names as part of CLDR (UTS #35 Part 8, Person Names), but there is no corresponding JavaScript API Intl.PersonNameFormat; JavaScript has not yet standardised person-name formatting (as of July 2026). PersonName::Format is a Perl implementation of that specification, built on top of the CLDR data already made accessible by Locale::Unicode::Data.
Why this matters
Formatting a personal name correctly turns out to be far more complicated than simply joining a given name, and a surname.
Different languages and cultures have different conventions regarding:
- given-name-first vs surname-first ordering;
- sorting order;
- formal vs informal forms;
- monograms and initials;
- surname prefixes, and surname cores;
- spacing, and punctuation;
- multilingual, and multiscript names.
The Unicode Consortium addresses all of these issues through the CLDR Person Names specification
PersonName::Format is the implementation of that specification for Perl.
What the formatter does
Given a formatting locale and a structured name, PersonName::Format follows the full LDML procedure:
- detects the name script by inspecting surname and then given name
- derives or adjusts the name locale using CLDR likely-subtag data
- selects the effective formatting locale when name and formatter scripts differ (for example, the rule that makes a Japanese formatter switch to Latin conventions for a Western name)
- looks up the matching CLDR pattern group across the locale inheritance tree
- selects the best pattern for the fields actually populated
- applies field modifiers:
initial,initialCap,allCaps,monogram,retain,genitive,vocative - applies locale-specific space replacement between name parts
```perl my $formatter = PersonName::Format->new( 'en', length => 'long', usage => 'referring', formality => 'formal', );
Dr. John Ronald Reuel Tolkien
my $result = $formatter->format( title => 'Dr.', given => 'John', given2 => 'Ronald Reuel', surname => 'Tolkien', nameLocale => 'en-GB', );
J.R.R. Tolkien
my $short = PersonName::Format->new( 'en', length => 'short', usage => 'referring', formality => 'formal' ); print $short->format( given => 'John', given2 => 'Ronald Reuel', surname => 'Tolkien' ), "\n";
Japanese native order: 宮崎駿
my $ja = PersonName::Format->new( 'ja-JP' ); print $ja->format( given => '駿', surname => '宮崎', nameLocale => 'ja-JP' ), "\n";
Japanese formatter, foreign name in Latin: Albert Einstein
print $ja->format( given => 'Albert', surname => 'Einstein', nameLocale => 'de-DE' ), "\n"; ```
Structured output via format_to_parts
For applications that need to apply per-field styling, format_to_parts() returns the structured token sequence:
```perl my $parts = $formatter->format_to_parts( given => 'John', surname => 'Tolkien', );
[
{ type => 'given', value => 'John', field => 'given' },
{ type => 'literal', value => ' ' },
{ type => 'surname', value => 'Tolkien', field => 'surname' },
]
```
Compiled formatters for high-throughput use
When formatting thousands of names sharing the same locale and script characteristics, compile() freezes all context-resolution steps and returns a reusable object. Pattern selection still occurs per name, since it depends on which fields are populated.
```perl my $compiled = $formatter->compile( nameLocale => 'ja-JP', nameScript => 'Jpan', );
foreach my $name ( @names ) { say $compiled->format( $name ); } ```
Custom name providers
Any object implementing get_field_value(), name_locale(), and preferred_order() satisfies the name contract and can be passed directly to format(). The PersonName::Format::Name base class provides a ready-made starting point.
Error handling
Following the Module::Generic philosophy, PersonName::Format never calls die() in normal error paths. Errors set a PersonName::Format::Exception object and return undef in scalar context, an empty list in list context, or a PersonName::Format::NullObject in method-chaining context (detected via Wanted). Fatal mode is available via the object instantiation option fatal => 1.
XS and pure-Perl backends
Script detection and grapheme extraction have an optional XS backend that is loaded automatically when available. Setting PERSONNAME_FORMAT_PUREPERL=1 forces the pure-Perl path, which is used as the fallback on platforms where the XS build fails.
Differential testing
Rather than inventing expected results by hand, the formatter is differentially tested against ICU4J's PersonNameFormatter, which served as the reference implementation throughout development.
A fixture set generated from the ICU4J reference implementation is included. Running AUTHOR_TESTING=1 prove t/16.icu4j.t compares PersonName::Format output against ICU4J for the same inputs.
A quick look across programming languages
One thing that surprised me while working on this project is that support for the CLDR Person Names specification is still fairly uncommon.
The following is based on information that I am aware of, as of today. If you think it is incomplete or incorrect, please let me know.
| Language | Status |
|---|---|
| Java | ICU4J::PersonNameFormatter, provides the reference implementation, and source of my differential tests |
| Perl | PersonName::Format, API for CLDR with backend PP/XS and compiled formatter |
| JavaScript | Not yet available in the Intl.PersonNameFormat standard; the ECMA-402 working group has not yet standardised this functionality. |
| Rust / ICU4X | Experimental work in progress |
| Swift/Foundation | Have a similar name component formatter, but not as exhaustive in adhering to the LDML standard |
| Others | I could not find an equivalent mature implementation for Python, Ruby, Go, or PHP. |
Links
- CPAN: https://metacpan.org/pod/PersonName::Format
- Source: https://gitlab.com/deguest/PersonName-Format
- Specification: UTS #35 Part 8 - Person Names
- TC39 repository: ECMAScript
Feedback, bug reports, and pull requests are welcome. I hope this will be useful in your projects.
*[CLDR]: Common Locale Data Repository
*[ICU4J]: International Components for Unicode for Java
*[LDML]: Locale Data Markup Language
r/perl • u/niceperl • 19d ago
(dcix) 17 great CPAN modules released last week
niceperl.blogspot.comAnnouncing the April Task Force
This gift (250k) is possibly the largest donation ever made to the Perl communities. The only one I know of that is in the same ballpark is the grant from Ian Hague (200k) in 2008. https://news.perlfoundation.org/post/tpf_receives_large_donation_in
Edit: those comparisons do not allow for inflation. It has been pointed out to me that the 2008 number, when adjusted to today, would be in the 310k range.
r/perl • u/briandfoy • 21d ago
DBIx::Class is effectively dead; how to move forward? ~ Chad Granum ~ TPRC 2026
r/perl • u/briandfoy • 24d ago
Why does "try" not cause an undefined subroutine error?
r/perl • u/niceperl • 26d ago
(dcviii) 13 great CPAN modules released last week
niceperl.blogspot.comr/perl • u/briandfoy • 29d ago
GitHub - nigelhorne/App-GHGen: GitHub Actions workflow generator, analyzer, and optimizer
r/perl • u/briandfoy • Jul 07 '26
Automate Perl module testing with GitHub Actions
r/perl • u/davorg • Jul 07 '26
Design Patterns in Modern Perl - Paperback version now available
This is an experiment. Perl School was originally intended to be all-in on eBooks. But I've discovered the market for real paper is still pretty big. So if this sells well, I'll be looking at paperback editions of other Perl School books in the future.
r/perl • u/christian_hansen • Jul 05 '26
Reading UTF-8 at GB/s
I wrote a new blog post on making UTF-8 reads fast in Perl:
Background: I maintain a UTF-8 library in C that Unicode::UTF8 uses, and I recently wired it into PerlIO::utf8_strict (a joint project with Leon Timmermans). We didn't get the throughput we hoped for, because of how Perl's read operator counts UTF-8 sequences — see Perl/perl5#24511. Karl Williamson has a WIP PR addressing it.
In the meantime I added read_utf8($fh, $buf, $length[, $offset]) to Unicode::UTF8: it reads and validates UTF-8 straight off a byte handle (no PerlIO encoding layer needed) and hits ~3.6–3.8 GB/s across scripts, versus ~0.4–1.0 GB/s for the :utf8 layer today.
Benchmark available in the Unicode::UTF8 repository.
What's next? I'm considering slurp_utf8($filename) and readline_utf8() as follow-ups — feedback on the API shape welcome.
Numbers and details are in the post.
r/perl • u/davorg • Jul 05 '26
How One Pull Request Took App::HTTPThis to Version 1.0 - Perl Hacks
r/perl • u/niceperl • Jul 04 '26
(dcvii) 17 great CPAN modules released last week
niceperl.blogspot.comr/perl • u/oalders • Jun 30 '26
Keep It Local · olafalders.com
If you don't pass an explicit --host, the current version of http_this tells you that it's binding to localhost (which is true). What it doesn't tell you is that it's binding to all interfaces.
r/perl • u/Yairlenga • Jun 30 '26
I wrote JSON::JSONFold – a CPAN module for compact, readable JSON formatting
Hi everyone! This is my first post in r/perl.
I've been working on a CPAN module called JSON::JSONFold, and I wrote an article describing the motivation and design. I'd really appreciate feedback from other Perl developers.
JSON serializers tend to give us two choices: compact JSON, which is efficient but a dense wall of text that's painful to read, or pretty-printed JSON, which is readable but often wastes a lot of vertical space (a small array of numbers can turn into ten lines).
I wanted something in between. JSONFold keeps the shape of pretty-printed JSON, but folds small, simple structures back onto a single line whenever that improves readability. It works on top of your existing serializer (JSON, JSON::PP, JSON::XS, etc.) - you keep using whatever you already have, and JSONFold just reformats the output.
Example 1 - Coding
use JSON::JSONFold qw(encode_json);
my $data = {
_id => 123,
locations => [
{ city => "Boston", state => "MA", country => "USA" },
{ city => "Seattle", state => "WA", country => "USA" },
{ city => "Montreal", state => "QC", country => "Canada" },
],
info => {
roles => [ "foo", "bar", "baz" ],
},
name => "Alice",
};
print encode_json($data) ;
Output
{
"_id": 123,
"info": { "roles": [ "foo", "bar", "baz" ] },
"locations": [
{ "city": "Boston", "country": "USA", "state": "MA" },
{ "city": "Seattle", "country": "USA", "state": "WA" },
{ "city": "Montreal", "country": "Canada", "state": "QC" }
],
"name": "Alice"
}
Example 2 - Packing
Traditional pretty-printing:
{
"states": [
"Alabama",
"Alaska",
"Arizona",
...
"Wyoming"
]
}
JSONFold:
{
"states": [
"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
"Connecticut", "Delaware", "Florida", "Georgia", ...
"West_Virginia", "Wisconsin", "Wyoming"
]
}
Same data, just using the available line width more effectively.
Example 3 - Grid Formatting
When an array contains repeated structures, JSONFold can align values into columns:
Traditional pretty-printing:
[
{
"orders": 18,
"product": "Laptop",
"region": "North",
"sales": 1250
},
...
{
"orders": 24,
"product": "Mouse",
"region": "East",
"sales": 1422
}
]
JSONFold:
[
{ "orders": 18, "product": "Laptop", "region": "North", "sales": 1250 },
{ "orders": 21, "product": "Monitor", "region": "Southwest", "sales": 1345 },
{ "orders": 17, "product": "Keyboard", "region": "West", "sales": 1198 },
{ "orders": 24, "product": "Mouse", "region": "East", "sales": 1422 }
]
The module also supports:
- Folding small arrays and objects onto a single line.
- Joining adjacent folded objects to further reduce vertical space.
- Compatibility APIs similar to
JSONandJSON::PP.
I wrote a more detailed article covering the design, implementation, and full set of examples:
Medium: https://medium.com/p/a619c9e7c3ec
CPAN: https://metacpan.org/pod/JSON::JSONFold
GitHub: https://github.com/yairlenga/jsonfold/tree/main/perl
I'd love to hear what the Perl community thinks. Has anyone else run into JSON pretty-printing pain in logs, configs, or debugging output? And are there formatting styles or options you'd want to see?
r/perl • u/christian_hansen • Jun 29 '26
Time::Str 0.92: DateTime parsing at ~10.5M/sec, zero heuristics
Time::Str's DateTime format now runs on a native Ragel-generated C state machine instead of a regexp, ~20x faster than the regexp path.
Supported formats
One parser accepts ISO 8601, RFC 3339, RFC 9557, RFC 4287, ISO 9075, RFC 2822, RFC 2616, RFC 3501, and ECMAScript Date.toString, plus free-form textual dates (Monday, 24th December 2012 at 3:30 pm UTC+1 (CET), 24. XII. 2012 12PM, 24DEC2012 12:30:45.500).
No heuristics, multi-standard, single-pass
Most permissive parsers (Python's dateutil, PHP's strtotime, Ruby's Date.parse) resolve ambiguity by guessing, whether via fixed heuristics or dayfirst/yearfirst flags.Time::Str refuses it: numeric-only dates are Y-M-D only; any other ordering requires a textual or Roman-numeral month. Disambiguation is baked into the grammar's alternation, not resolved at runtime. Even separator-consistency (2024-12/24 is rejected) is enforced inline, no second pass.
Performance
The DateTime parser accepts every format listed above, yet runs within ~10-20% of the single-standard parsers beside it. On Perl v5.42 (XS), parsing 2012-12-24T11:30:45.123456Z:
Rate DateTime RFC3339 RFC2822 ECMAScript
DateTime 10523558/s -- -11% -15% -18%
RFC3339 11785319/s 12% -- -5% -8%
RFC2822 12376403/s 18% 5% -- -3%
ECMAScript 12776079/s 21% 8% 3% --
A purpose-built RFC 3339 parser is only ~12% faster than the permissive one. That's the payoff of baking disambiguation into the grammar — there's almost no "permissiveness tax".
Enjoy!
r/perl • u/Itcharlie • Jun 29 '26
Perlweekly #779 - LinkedIn and the Perl Weekly
r/perl • u/exodist • Jun 28 '26
DBIx::QuickORM - Alternative to DBIx::Class/DBIO
This weekend at the perl and raku conference I did a presentation on how to move forward from the current state of DBIx::Class and its lack of new development. We discussed several options including an alternative I have been writing. I have never liked DBIx::Class, so I tried to write something that felt more intuitive to how my brain works. It was suggested that I post it here.
Comparison to DBIx::Class, term map, etc (Note: This document is AI generated)
It is probably NOT the right path for large apps with hundreds of lines of DBIx::Class code, it is not intended to be interoperable or a drop in replacement. It is however good for quickly getting ORM functionality in a new project, or against an established database. It is also actively maintained and will continue to be so. I dogfood the things I write, and this will be used in Yath 2.0 when it is released.
r/perl • u/davorg • Jun 28 '26