NAME

AmberDB::Locale - Locale-aware text processing, formatting, and collation engine

SYNOPSIS

use AmberDB::Locale;

# Create a locale object
my $tr = AmberDB::Locale->new(language => "tr");

# Case Conversions & Comparison
my $upper  = $tr->uc("ığdır");                         # "IĞDIR"
my $lower  = $tr->lc("İSTANBUL");                      # "istanbul"
my $title  = $tr->ucfirst("istanbul büyükşehir");      # "İstanbul Büyükşehir"
my $folded = $tr->fold("İSTANBUL");                    # "istanbul"
my $same   = $tr->ieq("İstanbul", "istanbul");         # 1

# Sorting
my @sorted = $tr->sort(["İzmir", "Ankara", "Van", "Şanlıurfa", "Bursa", "Çanakkale"]);
# => ("Ankara", "Bursa", "Çanakkale", "İzmir", "Şanlıurfa", "Van")

# Text Normalization & Transliteration
my $clean = $tr->normalize("<p>Kâr &amp; zarar</p>"); # "Kar zarar"
my $ascii = $tr->to_ascii("çarşı");                    # "carsi"
my $slug  = $tr->to_ascii("İstanbul", 1);             # "istanbul"

# UTF-8 Safe Substring
my $sub = $tr->substring("Çanakkale", 0, 4);           # "Çana"

# Number to Written Text
my $text = $tr->num2text(1234.56);
# => "Bin İki Yüz Otuz Dört TL Elli Altı KR"

# Formatting Numbers & Currencies
my $num  = $tr->format_number(1234567.89);            # "1.234.567,89"
my $curr = $tr->format_currency(1234.50, "EUR");       # "1.234,50 €"

# Date Formatting & Parsing
my $date = $tr->format_date(time(), "full");          # "Pazar, 9 Ağustos 2026"
my $ep   = $tr->parse_date("09.08.2026");             # Unix timestamp

# Pluralization
my $msg  = $tr->plural(5, { one => "{count} ürün", other => "{count} ürün" });

DESCRIPTION

AmberDB::Locale is a locale-aware text processing engine designed for multilingual Perl applications. It provides a unified, high-level API for case conversion, sorting/collation, ASCII transliteration, written number conversion, date/time formatting, number/currency formatting, HTML entity decoding, CLDR-based plural form selection, and UTF-8 safe substring slicing.

Language-specific rules and datasets are decoupled from the engine logic and provided by language data packages (e.g., AmberDB::Locale::Lang::tr, AmberDB::Locale::Lang::de, etc.).

CONSTRUCTOR

new([%options | $hashref | $language_code])

Creates and returns an AmberDB::Locale instance configured for the specified language.

# Named-parameter API (recommended)
my $lang = AmberDB::Locale->new(language => 'tr');

# Hashref API
my $lang = AmberDB::Locale->new({ language => 'de' });

# Positional string API
my $lang = AmberDB::Locale->new('fr');

# Default (falls back to English 'en')
my $lang = AmberDB::Locale->new();

Language tags can be short ISO codes (e.g., "tr", "en", "de", "fr", "es", "ru", "az", "ar") or common aliases (such as "turkish", "tr_tr", "tr-tr", "english", etc.). If an unsupported language is specified, a warning is issued and the instance falls back to "en".

METHODS

Case Conversions & Comparison

uc($string)

Converts $string to uppercase according to locale-specific rules.

$tr->uc("ığdır");     # "IĞDIR"
$tr->uc("istanbul");  # "İSTANBUL" (Turkish i -> İ)
$de->uc("straße");    # "STRASSE"  (German ß -> SS)

lc($string)

Converts $string to lowercase according to locale-specific rules.

$tr->lc("İSTANBUL");  # "istanbul" (Turkish İ -> i)
$tr->lc("IĞDIR");     # "ığdır"    (Turkish I -> ı)

ucfirst($string)

Capitalizes the first letter of each word in $string under locale rules. The string is first lowercased, and then the first character following word-starting delimiters (spaces, punctuation, brackets) is uppercased.

$tr->ucfirst("istanbul büyükşehir belediyesi");
# "İstanbul Büyükşehir Belediyesi"

fold($string)

Applies Unicode NFKC normalization and locale lowercasing to produce a case-folded string suitable for search indexing and matching.

my $key = $tr->fold("İSTANBUL"); # "istanbul"

ieq($str1, $str2)

Performs a locale-aware, case-insensitive comparison between $str1 and $str2. Returns 1 if they are equal under locale rules, 0 otherwise.

$tr->ieq("İstanbul", "istanbul"); # 1 (true)
$tr->ieq("Ankara", "İzmir");      # 0 (false)

Sorting

sort(\@list [, $field_or_index])

Sorts an array reference \@list according to locale collation rules.

# Simple array of strings
my @sorted = $tr->sort(["İzmir", "Ankara", "Van", "Şanlıurfa", "Bursa", "Çanakkale"]);
# => ("Ankara", "Bursa", "Çanakkale", "İzmir", "Şanlıurfa", "Van")

# Array of hash references (sort by hash key)
my @sorted_products = $tr->sort(\@products, "name");

# Array of array references (sort by element index)
my @sorted_rows = $tr->sort(\@rows, 2);

Text Normalization & Transliteration

normalize($string)

Cleans and normalizes $string by decoding HTML entities, stripping HTML tags, mapping locale-specific accents, filtering characters outside the locale's safe character set, and collapsing whitespace.

my $clean = $tr->normalize('<p>Kâr &amp; zarar &ccedil;izelgesi</p>');
# "Kar zarar cizelgesi"

to_ascii($string [, $nonspace])

Transliterates localized text into plain ASCII characters. Useful for generating permalinks, slugs, or safe identifiers.

$tr->to_ascii("çarşı");           # "carsi"
$de->to_ascii("Große Straße");    # "Grosse Strasse"
$de->to_ascii("Müller");          # "Mueller" (DIN 5007-2: ü -> ue)

If $nonspace is true (slug mode), the string is lowercased and spaces/punctuation are converted to single underscores:

$tr->to_ascii("İstanbul", 1);     # "istanbul"
$tr->to_ascii("Kâr & Zarar!", 1); # "kar_zarar"

first_char($string)

Returns the normalized, uppercase first character of $string for alphabetical indexing (e.g. A-Z index headings). Returns "0-9" if the string begins with a digit.

$tr->first_char("  çarşı  ");    # "Ç"
$tr->first_char("123abc");       # "0-9"
$tr->first_char("İzmir");        # "İ"

UTF-8 Safe Substring

substring($string, [$offset], $length)

Extracts a substring from $string based on character count rather than byte count. Prevents cutting multibyte UTF-8 characters in half. Works transparently on both decoded Unicode strings and raw UTF-8 byte strings.

$tr->substring("Çanakkale", 0, 4); # "Çana" (4 characters)
$tr->substring("İstanbul", 2, 3);  # "tan"

# Default offset is 0 if omitted:
$tr->substring("Şanlıurfa", 5);     # "Şanlı"

Number & Currency Processing

num2text($number [, %options])

Converts numeric values (integers or floating-point decimals) into written words in the target locale. Ideal for generating invoices, cheques, or formal document text.

$tr->num2text(0);       # "Sıfır"
$tr->num2text(1);       # "Bir TL"
$tr->num2text(100);     # "Yüz TL"
$tr->num2text(1000);    # "Bin TL"
$tr->num2text(1234.56); # "Bin İki Yüz Otuz Dört TL Elli Altı KR"
$tr->num2text(-42);     # "Eksi Kırk İki TL"

Accepts Eastern Arabic (٠١٢٣٤٥٦٧٨٩) and Persian (۰۱۲۳۴۵۶۷۸۹) digits automatically.

Options:

currency => { main => "...", sub => "..." }

Overrides main and subunit currency names:

$tr->num2text(99.99, currency => { main => "EUR", sub => "cent" });
numbers => \%hash

Overrides number word definitions with custom data.

format_number($number [, %options])

Formats $number with locale-specific decimal and thousand grouping separators.

$tr->format_number(1234567.89);                # "1.234.567,89"
$tr->format_number(1234567.89, decimals => 0); # "1.234.568"
$tr->format_number(1234567.89, decimals => 3); # "1.234.567,890"

my $en = AmberDB::Locale->new(language => "en");
$en->format_number(1234567.89);                # "1,234,567.89"

my $fr = AmberDB::Locale->new(language => "fr");
$fr->format_number(1234567.89);                # "1 234 567,89"

Available options: decimals, decimal_sep, group_sep.

format_currency($amount [, $currency_code | %options])

Formats monetary amounts using locale conventions or specific ISO 4217 currency settings.

$tr->format_currency(1234.50);                    # "₺1.234,50"
$tr->format_currency(1234.50, 'EUR');             # "1.234,50 €"
$tr->format_currency(1234.50, currency => 'USD'); # "$1.234,50"

Options can override formatting attributes:

$tr->format_currency(100, symbol => 'TL', position => 'suffix', space => 1);
# "100,00 TL"

Date & Time Operations

format_date($time_or_string [, $pattern_or_style])

Formats a Unix timestamp or date string into a localized date/time representation.

my $epoch = time();
$tr->format_date($epoch);             # "09.08.2026" (short, default)
$tr->format_date($epoch, 'medium');   # "9 Ağu 2026"
$tr->format_date($epoch, 'long');     # "9 Ağustos 2026"
$tr->format_date($epoch, 'full');     # "Pazar, 9 Ağustos 2026"
$tr->format_date($epoch, 'time');     # "14:30"
$tr->format_date($epoch, 'datetime'); # "09.08.2026 14:30"

# Custom format tokens:
$tr->format_date($epoch, 'YYYY-MM-DD'); # "2026-08-09"
$tr->format_date($epoch, 'DD/MM/YYYY'); # "09/08/2026"

# Input can also be ISO date strings:
$tr->format_date("2026-08-09", 'full'); # "Pazar, 9 Ağustos 2026"

Supported pattern tokens:

  • YYYY, YY - 4-digit / 2-digit year

  • MMMM, MMM, MM, M - Full month name, short month, 2-digit month, 1-digit month

  • DD, D - 2-digit day, 1-digit day

  • dddd, ddd - Full day name, short day name

  • HH, H - Hour

  • mm, m - Minute

  • ss, s - Second

parse_date($string [, %options])

Parses a localized date string (e.g. "09.08.2026" or "2026-08-09 14:30:00") back into a Unix timestamp or component hash.

my $epoch = $tr->parse_date("09.08.2026"); # Unix timestamp

my $hash = $tr->parse_date("09.08.2026", hash => 1);
# { year => 2026, month => 8, day => 9, hour => 0, minute => 0, second => 0 }

HTML Entity Decoding

decode_entities($string)

Decodes numeric (hex &#x...;, decimal &#...;) and named HTML entities in $string, incorporating both universal HTML entities and locale-specific extra entities.

$tr->decode_entities("&amp; &lt; &gt; &#x20AC; &ccedil;");
# "& < > € ç"

Pluralization

plural($count, \%forms)

Selects and interpolates the appropriate plural form from \%forms based on CLDR plural rules for the active locale.

my $en = AmberDB::Locale->new(language => "en");
$en->plural(1, { one => "{count} item",  other => "{count} items" }); # "1 item"
$en->plural(5, { one => "{count} item",  other => "{count} items" }); # "5 items"

my $ru = AmberDB::Locale->new(language => "ru");
$ru->plural(1, { one => "{count} яблоко", few => "{count} яблока",
                 many => "{count} яблок",  other => "{count} яблока" });
# "1 яблоко"

Placeholders {count} or {n} in template strings are automatically replaced with formatted number values.

Accessors

language()

Returns the active language tag (e.g., "tr", "en").

months()

Returns an array reference containing the 12 localized month names.

days()

Returns an array reference containing the 7 localized day names starting from Sunday.

AUTHOR

Maruf Cetin <marufcetin@gmail.com>

LICENSE AND COPYRIGHT

Copyright (C) 2026 Maruf Cetin.

This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 1162:

Non-ASCII character seen before =encoding in '$tr->uc("ığdır");'. Assuming UTF-8