use intl js lib across all phone number fields

This commit is contained in:
johnnyq
2026-08-26 13:53:27 -04:00
parent cfafc385f0
commit 96f2c697c6
107 changed files with 492 additions and 10356 deletions

View File

@@ -75,8 +75,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code">
</div>
</div>
</div>

View File

@@ -119,8 +119,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" placeholder="+" maxlength="4" value="<?= $vendor_phone_country_code ?>">
<input type="tel" class="form-control" name="phone" maxlength="200" value="<?= $vendor_phone ?>">
<input type="hidden" name="phone_country_code" value="<?= $vendor_phone_country_code ?>">
<input type="tel" class="form-control" name="phone" maxlength="200" value="<?= $vendor_phone ?>" data-itflow-phone="phone_country_code">
</div>
</div>
</div>

View File

@@ -96,7 +96,7 @@ $company_initials = escapeHtml(initials($company_name));
<select class="form-select select2" name="country">
<option value="">- Country -</option>
<?php foreach($countries_array as $country_name) { ?>
<option <?php if ($company_country == $country_name) { echo "selected"; } ?>><?= $country_name ?></option>
<option <?php if ($company_country == $country_name) { echo "selected"; } ?> data-iso2="<?= $country_iso2_array[$country_name] ?? '' ?>"><?= $country_name ?></option>
<?php } ?>
</select>
</div>
@@ -108,8 +108,8 @@ $company_initials = escapeHtml(initials($company_name));
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" value="<?= $company_phone_country_code ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" value="<?= $company_phone ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code" value="<?= $company_phone_country_code ?>">
<input type="tel" class="form-control" name="phone" value="<?= $company_phone ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>

View File

@@ -182,7 +182,7 @@ ob_start();
<select class="form-select select2" name="country">
<option value="">- Select Country -</option>
<?php foreach($countries_array as $country_name) { ?>
<option <?php if ($session_company_country == $country_name) { echo "selected"; } ?> ><?= $country_name ?></option>
<option <?php if ($session_company_country == $country_name) { echo "selected"; } ?> data-iso2="<?= $country_iso2_array[$country_name] ?? '' ?>"><?= $country_name ?></option>
<?php } ?>
</select>
</div>
@@ -195,8 +195,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="location_phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="location_phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="location_phone_country_code">
<input type="tel" class="form-control" name="location_phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="location_phone_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>
@@ -213,8 +213,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-fax"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="location_fax_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="location_fax" placeholder="Fax Number" maxlength="200">
<input type="hidden" name="location_fax_country_code">
<input type="tel" class="form-control" name="location_fax" placeholder="Fax Number" maxlength="200" data-itflow-phone="location_fax_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>
@@ -246,8 +246,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="contact_phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="contact_phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="contact_phone_country_code">
<input type="tel" class="form-control" name="contact_phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="contact_phone_country_code">
</div>
</div>
</div>
@@ -264,8 +264,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-mobile-alt"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="contact_mobile_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="contact_mobile" placeholder="Mobile Phone Number" maxlength="200">
<input type="hidden" name="contact_mobile_country_code">
<input type="tel" class="form-control" name="contact_mobile" placeholder="Mobile Phone Number" maxlength="200" data-itflow-phone="contact_mobile_country_code">
</div>
</div>
</div>

View File

@@ -12,6 +12,20 @@ if ($client_id) {
$sql_tags_select = mysqli_query($mysqli, "SELECT tag_id, tag_name FROM tags WHERE tag_type = 3 ORDER BY tag_name ASC");
// A contact's phone belongs to the CLIENT's country, not the company's. The
// client's country lives on its primary location; falls through to the
// company default when the client has none.
$client_phone_iso2 = '';
if ($client_id) {
$sql_client_country = mysqli_query($mysqli, "SELECT location_country FROM locations
WHERE location_client_id = $client_id AND location_primary = 1 LIMIT 1");
$row_client_country = mysqli_fetch_assoc($sql_client_country);
if ($row_client_country) {
$client_phone_iso2 = $country_iso2_array[$row_client_country['location_country']] ?? '';
}
}
ob_start();
?>
@@ -20,7 +34,8 @@ ob_start();
<h5 class="modal-title"><i class="fas fa-fw fa-user-plus me-2"></i>New Contact</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off"
data-itflow-phone-country="<?= escapeHtml($client_phone_iso2) ?>">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<div class="modal-body">
@@ -103,8 +118,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code">
</div>
</div>
</div>
@@ -121,8 +136,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-mobile-alt"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="mobile_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="mobile" placeholder="Mobile Phone Number" maxlength="200">
<input type="hidden" name="mobile_country_code">
<input type="tel" class="form-control" name="mobile" placeholder="Mobile Phone Number" maxlength="200" data-itflow-phone="mobile_country_code">
</div>
</div>
</div>

View File

@@ -18,6 +18,20 @@ $sql = mysqli_query($mysqli, "SELECT contact_archived_at, contact_billing, conta
$row = mysqli_fetch_assoc($sql);
$client_id = intval($row['contact_client_id']);
// A contact's phone belongs to the CLIENT's country, not the company's. The
// client's country lives on its primary location; falls through to the
// company default when the client has none.
$client_phone_iso2 = '';
if ($client_id) {
$sql_client_country = mysqli_query($mysqli, "SELECT location_country FROM locations
WHERE location_client_id = $client_id AND location_primary = 1 LIMIT 1");
$row_client_country = mysqli_fetch_assoc($sql_client_country);
if ($row_client_country) {
$client_phone_iso2 = $country_iso2_array[$row_client_country['location_country']] ?? '';
}
}
$contact_name = escapeHtml($row['contact_name']);
$contact_title = escapeHtml($row['contact_title']);
$contact_department = escapeHtml($row['contact_department']);
@@ -59,7 +73,8 @@ ob_start();
<h5 class="modal-title"><i class='fas fa-user-edit me-2'></i>Editing Contact: <strong><?= $contact_name ?></strong></h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off"
data-itflow-phone-country="<?= escapeHtml($client_phone_iso2) ?>">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<input type="hidden" name="contact_id" value="<?= $contact_id ?>">
@@ -119,8 +134,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" value="<?= "$contact_phone_country_code" ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" value="<?= $contact_phone ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code" value="<?= "$contact_phone_country_code" ?>">
<input type="tel" class="form-control" name="phone" value="<?= $contact_phone ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code">
</div>
</div>
</div>
@@ -137,8 +152,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-mobile-alt"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="mobile_country_code" value="<?= "$contact_mobile_country_code" ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="mobile" value="<?= $contact_mobile ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="mobile_country_code" value="<?= "$contact_mobile_country_code" ?>">
<input type="tel" class="form-control" name="mobile" value="<?= $contact_mobile ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="mobile_country_code">
</div>
</div>
</div>

View File

@@ -131,7 +131,7 @@ ob_start();
<select class="form-select select2" name="country">
<option value="">- Country -</option>
<?php foreach($countries_array as $country_name) { ?>
<option <?php if ($session_company_country == $country_name) { echo "selected"; } ?> ><?= $country_name ?></option>
<option <?php if ($session_company_country == $country_name) { echo "selected"; } ?> data-iso2="<?= $country_iso2_array[$country_name] ?? '' ?>"><?= $country_name ?></option>
<?php } ?>
</select>
</div>
@@ -168,8 +168,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>
@@ -186,8 +186,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-fax"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="fax_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="fax" placeholder="Fax Number" maxlength="200">
<input type="hidden" name="fax_country_code">
<input type="tel" class="form-control" name="fax" placeholder="Fax Number" maxlength="200" data-itflow-phone="fax_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>

View File

@@ -152,7 +152,7 @@ ob_start();
<select class="form-select select2" name="country">
<option value="">- Country -</option>
<?php foreach($countries_array as $country_name) { ?>
<option <?php if ($location_country == $country_name) { echo "selected"; } ?>><?= $country_name ?></option>
<option <?php if ($location_country == $country_name) { echo "selected"; } ?> data-iso2="<?= $country_iso2_array[$country_name] ?? '' ?>"><?= $country_name ?></option>
<?php } ?>
</select>
</div>
@@ -195,8 +195,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" value="<?= $location_phone_country_code ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" value="<?= $location_phone ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code" value="<?= $location_phone_country_code ?>">
<input type="tel" class="form-control" name="phone" value="<?= $location_phone ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>
@@ -213,8 +213,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-fax"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="fax_country_code" value="<?= $location_fax_country_code ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="fax" value="<?= $location_fax ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="fax_country_code" value="<?= $location_fax_country_code ?>">
<input type="tel" class="form-control" name="fax" value="<?= $location_fax ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="fax_country_code" data-itflow-phone-country-select="country">
</div>
</div>
</div>

View File

@@ -76,8 +76,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code">
<input type="tel" class="form-control" name="phone" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code">
</div>
</div>
</div>

View File

@@ -124,8 +124,8 @@ ob_start();
<div class="mb-3">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
<input type="tel" class="form-control w-25 flex-grow-0" name="phone_country_code" value="<?= $vendor_phone_country_code ?>" placeholder="+" maxlength="4">
<input type="tel" class="form-control" name="phone" value="<?= $vendor_phone ?>" placeholder="Phone Number" maxlength="200">
<input type="hidden" name="phone_country_code" value="<?= $vendor_phone_country_code ?>">
<input type="tel" class="form-control" name="phone" value="<?= $vendor_phone ?>" placeholder="Phone Number" maxlength="200" data-itflow-phone="phone_country_code">
</div>
</div>
</div>

View File

@@ -1175,6 +1175,57 @@ a:focus {
--lte-primary-color-rgb: 0, 0, 0;
}
/* --- intl-tel-input --------------------------------------------------------
The library wraps the input in a .iti container, which inside an
.input-group becomes the flex item instead of the input. Bootstrap sizes its
children with `.input-group > .form-control { flex: 1 1 auto; width: 1% }`,
and that selector no longer matches the now-nested input - so without these
the wrapper collapses to its content width and the field sits detached from
the addon beside it.
The wrapper takes the sizing the input used to get, and the input inside it
is squared off on the left because .iti draws the country button there and
the addon draws the rounded edge. */
.input-group > .iti {
position: relative;
flex: 1 1 auto;
width: 1%;
min-width: 0;
}
.input-group > .iti > .form-control {
width: 100%;
}
.input-group > .iti:not(:last-child) > .form-control {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .iti:not(:first-child) > .form-control,
.iti--separate-dial-code .form-control {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* the country button is chrome, not a control - keep it on the form-control
palette so it does not read as a raised button in either mode */
.iti__selected-country {
background-color: var(--bs-tertiary-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-right: 0;
border-radius: var(--bs-border-radius) 0 0 var(--bs-border-radius);
}
.iti__country-list,
.iti__dropdown-content {
background-color: var(--bs-body-bg);
color: var(--bs-body-color);
border: var(--bs-border-width) solid var(--bs-border-color);
}
.iti__country.iti__highlight,
.iti__country:hover {
background-color: var(--bs-secondary-bg);
}
.iti__dial-code {
color: var(--bs-secondary-color);
}
/* --- Print ----------------------------------------------------------------
AdminLTE 3 bundled Bootstrap 4, whose print reboot shrank every printout by
declaring `@page { size: a3 }` and letting the browser scale that oversized

View File

@@ -41,7 +41,7 @@ if (basename(dirname($_SERVER['REQUEST_URI'])) === 'guest') { ?>
<script src="/libs/clipboardjs/clipboard.min.js"></script>
<script src="/js/keepalive.js"></script>
<script src="/libs/DataTables/datatables.min.js"></script>
<script src="/libs/intl-tel-input/js/intlTelInput.min.js"></script>
<script src="/libs/intl-tel-input/js/intlTelInputWithUtils.min.js"></script>
<!-- AdminLTE App -->
<script src="/libs/adminlte/js/adminlte.min.js"></script>

View File

@@ -44,6 +44,12 @@ header("X-Frame-Options: DENY");
<!-- Scripts -->
</head>
<body class="layout-fixed sidebar-expand-lg app-loaded theme-<?= escapeHtml($config_theme) ?>" data-lte-primary="<?= escapeHtml($config_theme) ?>">
<?php /* intl-tel-input needs an ISO2 country, the companies table stores a
country NAME - $country_iso2_array bridges the two. Passed as a data
attribute rather than an inline <script> so it does not add to the
CSP unsafe-inline debt. Empty when the company has no country set,
which js/app.js reads as "let the library decide". */ ?>
<body class="layout-fixed sidebar-expand-lg app-loaded theme-<?= escapeHtml($config_theme) ?>" data-lte-primary="<?= escapeHtml($config_theme) ?>"
data-itflow-phone-country="<?= escapeHtml($country_iso2_array[$session_company_country] ?? '') ?>">
<div class="app-wrapper text-sm">

View File

@@ -773,3 +773,210 @@ $locales_array = [
'zu_ZA' => 'Zulu (South Africa)',
'zu' => 'Zulu',
];
// Country name -> ISO 3166-1 alpha-2, keyed by the exact strings in
// $countries_array above. intl-tel-input identifies countries by ISO2, so
// this is what turns the stored company_country into an initialCountry for
// the phone inputs. Sixteen of the names above do not match the library's
// own spelling and are aliased here rather than in JS: "Colombi" (a typo in
// the list), the "Saint X" / "St. X" pair, "Swaziland" -> Eswatini,
// "Macedonia" -> North Macedonia, "Serbia and Montenegro" -> Serbia, and
// the two Koreas. Keep this in step with $countries_array - a name here
// with no entry there is dead, and one there with no entry here falls back
// to the library default.
$country_iso2_array = array(
"Afghanistan" => "af",
"Albania" => "al",
"Algeria" => "dz",
"Andorra" => "ad",
"Angola" => "ao",
"Antigua and Barbuda" => "ag",
"Argentina" => "ar",
"Armenia" => "am",
"Australia" => "au",
"Austria" => "at",
"Azerbaijan" => "az",
"Bahamas" => "bs",
"Bahrain" => "bh",
"Bangladesh" => "bd",
"Barbados" => "bb",
"Belarus" => "by",
"Belgium" => "be",
"Belize" => "bz",
"Benin" => "bj",
"Bhutan" => "bt",
"Bolivia" => "bo",
"Bosnia and Herzegovina" => "ba",
"Botswana" => "bw",
"Brazil" => "br",
"Brunei" => "bn",
"Bulgaria" => "bg",
"Burkina Faso" => "bf",
"Burundi" => "bi",
"Cambodia" => "kh",
"Cameroon" => "cm",
"Canada" => "ca",
"Cape Verde" => "cv",
"Central African Republic" => "cf",
"Chad" => "td",
"Chile" => "cl",
"China" => "cn",
"Colombi" => "co",
"Comoros" => "km",
"Congo (Brazzaville)" => "cg",
"Congo" => "cd",
"Costa Rica" => "cr",
"Cote d'Ivoire" => "ci",
"Croatia" => "hr",
"Cuba" => "cu",
"Cyprus" => "cy",
"Czech Republic" => "cz",
"Denmark" => "dk",
"Djibouti" => "dj",
"Dominica" => "dm",
"Dominican Republic" => "do",
"East Timor (Timor Timur)" => "tl",
"Ecuador" => "ec",
"Egypt" => "eg",
"El Salvador" => "sv",
"Equatorial Guinea" => "gq",
"Eritrea" => "er",
"Estonia" => "ee",
"Ethiopia" => "et",
"Fiji" => "fj",
"Finland" => "fi",
"France" => "fr",
"Gabon" => "ga",
"Gambia, The" => "gm",
"Georgia" => "ge",
"Germany" => "de",
"Ghana" => "gh",
"Gibraltar" => "gi",
"Greece" => "gr",
"Grenada" => "gd",
"Guatemala" => "gt",
"Guinea" => "gn",
"Guinea-Bissau" => "gw",
"Guyana" => "gy",
"Haiti" => "ht",
"Honduras" => "hn",
"Hungary" => "hu",
"Iceland" => "is",
"India" => "in",
"Indonesia" => "id",
"Iran" => "ir",
"Iraq" => "iq",
"Ireland" => "ie",
"Israel" => "il",
"Italy" => "it",
"Jamaica" => "jm",
"Japan" => "jp",
"Jordan" => "jo",
"Kazakhstan" => "kz",
"Kenya" => "ke",
"Kiribati" => "ki",
"Korea, North" => "kp",
"Korea, South" => "kr",
"Kuwait" => "kw",
"Kyrgyzstan" => "kg",
"Laos" => "la",
"Latvia" => "lv",
"Lebanon" => "lb",
"Lesotho" => "ls",
"Liberia" => "lr",
"Libya" => "ly",
"Liechtenstein" => "li",
"Lithuania" => "lt",
"Luxembourg" => "lu",
"Macedonia" => "mk",
"Madagascar" => "mg",
"Malawi" => "mw",
"Malaysia" => "my",
"Maldives" => "mv",
"Mali" => "ml",
"Malta" => "mt",
"Marshall Islands" => "mh",
"Mauritania" => "mr",
"Mauritius" => "mu",
"Mexico" => "mx",
"Micronesia" => "fm",
"Moldova" => "md",
"Monaco" => "mc",
"Mongolia" => "mn",
"Morocco" => "ma",
"Mozambique" => "mz",
"Myanmar" => "mm",
"Namibia" => "na",
"Nauru" => "nr",
"Nepal" => "np",
"Netherlands" => "nl",
"New Zealand" => "nz",
"Nicaragua" => "ni",
"Niger" => "ne",
"Nigeria" => "ng",
"Norway" => "no",
"Oman" => "om",
"Pakistan" => "pk",
"Palau" => "pw",
"Panama" => "pa",
"Papua New Guinea" => "pg",
"Paraguay" => "py",
"Peru" => "pe",
"Philippines" => "ph",
"Poland" => "pl",
"Portugal" => "pt",
"Qatar" => "qa",
"Romania" => "ro",
"Russia" => "ru",
"Rwanda" => "rw",
"Saint Kitts and Nevis" => "kn",
"Saint Lucia" => "lc",
"Saint Vincent" => "vc",
"Samoa" => "ws",
"San Marino" => "sm",
"Sao Tome and Principe" => "st",
"Saudi Arabia" => "sa",
"Senegal" => "sn",
"Serbia and Montenegro" => "rs",
"Seychelles" => "sc",
"Sierra Leone" => "sl",
"Singapore" => "sg",
"Slovakia" => "sk",
"Slovenia" => "si",
"Solomon Islands" => "sb",
"Somalia" => "so",
"South Africa" => "za",
"Spain" => "es",
"Sri Lanka" => "lk",
"Sudan" => "sd",
"Suriname" => "sr",
"Swaziland" => "sz",
"Sweden" => "se",
"Switzerland" => "ch",
"Syria" => "sy",
"Taiwan" => "tw",
"Tajikistan" => "tj",
"Tanzania" => "tz",
"Thailand" => "th",
"Togo" => "tg",
"Tonga" => "to",
"Trinidad and Tobago" => "tt",
"Tunisia" => "tn",
"Turkey" => "tr",
"Turkmenistan" => "tm",
"Tuvalu" => "tv",
"Uganda" => "ug",
"Ukraine" => "ua",
"United Arab Emirates" => "ae",
"United Kingdom" => "gb",
"United States" => "us",
"Uruguay" => "uy",
"Uzbekistan" => "uz",
"Vanuatu" => "vu",
"Vatican City" => "va",
"Venezuela" => "ve",
"Vietnam" => "vn",
"Yemen" => "ye",
"Zambia" => "zm",
"Zimbabwe" => "zw",
);

147
js/app.js
View File

@@ -613,6 +613,9 @@ function itflowInit() {
itflowStep('datatables', function () {
new DataTable('.dataTables');
});
// Phone inputs
itflowStep('phone-inputs', initPhoneInputs);
}
// modal_footer.php re-loads this file on every ajax modal open, so run now if
@@ -963,3 +966,147 @@ function itflowWatchNetworkIp(networkId, ipId) {
input.addEventListener('blur', check);
}
/**
* intl-tel-input on every phone field.
*
* ITFlow stores the dial code and the number in separate columns
* (contact_phone_country_code / contact_phone and friends), so the library runs
* in separateDialCode mode: its dropdown owns the dial code, the visible input
* holds only the national number. That keeps the existing schema, the API and
* every render site untouched.
*
* Markup contract:
* <input type="hidden" name="phone_country_code" value="1">
* <input type="tel" name="phone" data-itflow-phone="phone_country_code">
*
* Which country a field starts on, most specific first:
* 1. data-itflow-phone-country-select on the input names a <select> in the
* same form (the address Country picker) - the field follows it live, so
* changing a client's country re-formats their phone straight away
* 2. data-itflow-phone-country on the form - a record's own country, used by
* the contact modals where there is no country picker but the contact
* belongs to a client that has one
* 3. data-itflow-phone-country on <body> - the company's country
* 4. the dial code already stored on the record
*
* A stored dial code ranks LAST on purpose: +1 alone matches about 25
* countries, so it can only ever recover "some country using this code", while
* every source above it names an actual country.
*/
function initPhoneInputs() {
if (typeof window.intlTelInput !== 'function') {
return;
}
document.querySelectorAll('input[data-itflow-phone]').forEach(function (el) {
// One field must never take the rest down with it. The first version of
// this called v17 API names that v29 dropped, and because the whole
// sweep shared one try/catch the throw on the first phone field meant
// every mobile and fax input after it silently never initialised.
try {
initOnePhoneInput(el);
} catch (e) {
console.error('itflow phone input failed:', el.name, e);
}
});
}
function initOnePhoneInput(el) {
// modal_footer.php re-executes this file on every ajax modal open, so
// without a guard each open would stack another instance on the input.
if (el.dataset.itiReady) {
return;
}
var form = el.form;
var hidden = form ? form.querySelector('input[name="' + el.dataset.itflowPhone + '"]') : null;
if (!hidden) {
return;
}
el.dataset.itiReady = '1';
var countrySelect = null;
if (form && el.dataset.itflowPhoneCountrySelect) {
countrySelect = form.querySelector('[name="' + el.dataset.itflowPhoneCountrySelect + '"]');
}
var initial = isoFromSelect(countrySelect)
|| (form ? (form.dataset.itflowPhoneCountry || '') : '')
|| (document.body.dataset.itflowPhoneCountry || '')
|| isoForDialCode((hidden.value || '').replace(/[^0-9]/g, ''))
|| '';
var iti = window.intlTelInput(el, {
initialCountry: initial.toLowerCase(),
separateDialCode: true,
countrySearch: true,
formatAsYouType: true
});
var sync = function () {
var country = iti.getSelectedCountry();
hidden.value = country && country.dialCode ? country.dialCode : '';
};
el.addEventListener('countrychange', sync);
// Follow the address country picker while the form is open.
if (countrySelect) {
countrySelect.addEventListener('change', function () {
var iso2 = isoFromSelect(countrySelect);
if (iso2) {
iti.setSelectedCountry(iso2.toLowerCase());
sync();
}
});
}
// Belt and braces for a form saved without ever opening the dropdown.
if (form && !form.dataset.itiSyncBound) {
form.dataset.itiSyncBound = '1';
form.addEventListener('submit', function () {
form.querySelectorAll('input[data-itflow-phone]').forEach(function (input) {
var target = form.querySelector('input[name="' + input.dataset.itflowPhone + '"]');
var inst = window.intlTelInput.getInstance(input);
if (target && inst) {
var c = inst.getSelectedCountry();
target.value = c && c.dialCode ? c.dialCode : '';
}
});
});
}
sync();
}
/**
* ISO2 for the country a <select> is currently on.
*
* Each <option> carries data-iso2, stamped by PHP from $country_iso2_array, so
* the 194-entry name -> ISO2 map never has to be duplicated into JS or shipped
* to the browser as a blob. It also sidesteps an inline <script>, which the
* CSP work would have to unpick later.
*/
function isoFromSelect(select) {
if (!select) {
return '';
}
var option = select.selectedOptions ? select.selectedOptions[0] : null;
return option && option.dataset ? (option.dataset.iso2 || '') : '';
}
/**
* First ISO2 whose dial code matches. Ambiguous by nature, which is why this is
* only ever the last resort.
*/
function isoForDialCode(dialCode) {
if (!dialCode || typeof window.intlTelInput.getAllCountries !== 'function') {
return '';
}
var match = window.intlTelInput.getAllCountries().find(function (c) {
return c.dialCode === dialCode;
});
return match ? match.iso2 : '';
}

View File

@@ -1,253 +0,0 @@
/* THIS FILE IS AUTO-GENERATED. DO NOT EDIT. */
:root {
--iti-flag-width: 20px;
--iti-flag-count: 244;
}
.iti__ac { --iti-flag-offset: 0; }
.iti__ad { --iti-flag-offset: -1; }
.iti__ae { --iti-flag-offset: -2; }
.iti__af { --iti-flag-offset: -3; }
.iti__ag { --iti-flag-offset: -4; }
.iti__ai { --iti-flag-offset: -5; }
.iti__al { --iti-flag-offset: -6; }
.iti__am { --iti-flag-offset: -7; }
.iti__ao { --iti-flag-offset: -8; }
.iti__ar { --iti-flag-offset: -9; }
.iti__as { --iti-flag-offset: -10; }
.iti__at { --iti-flag-offset: -11; }
.iti__au { --iti-flag-offset: -12; }
.iti__aw { --iti-flag-offset: -13; }
.iti__ax { --iti-flag-offset: -14; }
.iti__az { --iti-flag-offset: -15; }
.iti__ba { --iti-flag-offset: -16; }
.iti__bb { --iti-flag-offset: -17; }
.iti__bd { --iti-flag-offset: -18; }
.iti__be { --iti-flag-offset: -19; }
.iti__bf { --iti-flag-offset: -20; }
.iti__bg { --iti-flag-offset: -21; }
.iti__bh { --iti-flag-offset: -22; }
.iti__bi { --iti-flag-offset: -23; }
.iti__bj { --iti-flag-offset: -24; }
.iti__bl { --iti-flag-offset: -25; }
.iti__bm { --iti-flag-offset: -26; }
.iti__bn { --iti-flag-offset: -27; }
.iti__bo { --iti-flag-offset: -28; }
.iti__bq { --iti-flag-offset: -29; }
.iti__br { --iti-flag-offset: -30; }
.iti__bs { --iti-flag-offset: -31; }
.iti__bt { --iti-flag-offset: -32; }
.iti__bw { --iti-flag-offset: -33; }
.iti__by { --iti-flag-offset: -34; }
.iti__bz { --iti-flag-offset: -35; }
.iti__ca { --iti-flag-offset: -36; }
.iti__cc { --iti-flag-offset: -37; }
.iti__cd { --iti-flag-offset: -38; }
.iti__cf { --iti-flag-offset: -39; }
.iti__cg { --iti-flag-offset: -40; }
.iti__ch { --iti-flag-offset: -41; }
.iti__ci { --iti-flag-offset: -42; }
.iti__ck { --iti-flag-offset: -43; }
.iti__cl { --iti-flag-offset: -44; }
.iti__cm { --iti-flag-offset: -45; }
.iti__cn { --iti-flag-offset: -46; }
.iti__co { --iti-flag-offset: -47; }
.iti__cr { --iti-flag-offset: -48; }
.iti__cu { --iti-flag-offset: -49; }
.iti__cv { --iti-flag-offset: -50; }
.iti__cw { --iti-flag-offset: -51; }
.iti__cx { --iti-flag-offset: -52; }
.iti__cy { --iti-flag-offset: -53; }
.iti__cz { --iti-flag-offset: -54; }
.iti__de { --iti-flag-offset: -55; }
.iti__dj { --iti-flag-offset: -56; }
.iti__dk { --iti-flag-offset: -57; }
.iti__dm { --iti-flag-offset: -58; }
.iti__do { --iti-flag-offset: -59; }
.iti__dz { --iti-flag-offset: -60; }
.iti__ec { --iti-flag-offset: -61; }
.iti__ee { --iti-flag-offset: -62; }
.iti__eg { --iti-flag-offset: -63; }
.iti__eh { --iti-flag-offset: -64; }
.iti__er { --iti-flag-offset: -65; }
.iti__es { --iti-flag-offset: -66; }
.iti__et { --iti-flag-offset: -67; }
.iti__fi { --iti-flag-offset: -68; }
.iti__fj { --iti-flag-offset: -69; }
.iti__fk { --iti-flag-offset: -70; }
.iti__fm { --iti-flag-offset: -71; }
.iti__fo { --iti-flag-offset: -72; }
.iti__fr { --iti-flag-offset: -73; }
.iti__ga { --iti-flag-offset: -74; }
.iti__gb { --iti-flag-offset: -75; }
.iti__gd { --iti-flag-offset: -76; }
.iti__ge { --iti-flag-offset: -77; }
.iti__gf { --iti-flag-offset: -78; }
.iti__gg { --iti-flag-offset: -79; }
.iti__gh { --iti-flag-offset: -80; }
.iti__gi { --iti-flag-offset: -81; }
.iti__gl { --iti-flag-offset: -82; }
.iti__gm { --iti-flag-offset: -83; }
.iti__gn { --iti-flag-offset: -84; }
.iti__gp { --iti-flag-offset: -85; }
.iti__gq { --iti-flag-offset: -86; }
.iti__gr { --iti-flag-offset: -87; }
.iti__gt { --iti-flag-offset: -88; }
.iti__gu { --iti-flag-offset: -89; }
.iti__gw { --iti-flag-offset: -90; }
.iti__gy { --iti-flag-offset: -91; }
.iti__hk { --iti-flag-offset: -92; }
.iti__hn { --iti-flag-offset: -93; }
.iti__hr { --iti-flag-offset: -94; }
.iti__ht { --iti-flag-offset: -95; }
.iti__hu { --iti-flag-offset: -96; }
.iti__id { --iti-flag-offset: -97; }
.iti__ie { --iti-flag-offset: -98; }
.iti__il { --iti-flag-offset: -99; }
.iti__im { --iti-flag-offset: -100; }
.iti__in { --iti-flag-offset: -101; }
.iti__io { --iti-flag-offset: -102; }
.iti__iq { --iti-flag-offset: -103; }
.iti__ir { --iti-flag-offset: -104; }
.iti__is { --iti-flag-offset: -105; }
.iti__it { --iti-flag-offset: -106; }
.iti__je { --iti-flag-offset: -107; }
.iti__jm { --iti-flag-offset: -108; }
.iti__jo { --iti-flag-offset: -109; }
.iti__jp { --iti-flag-offset: -110; }
.iti__ke { --iti-flag-offset: -111; }
.iti__kg { --iti-flag-offset: -112; }
.iti__kh { --iti-flag-offset: -113; }
.iti__ki { --iti-flag-offset: -114; }
.iti__km { --iti-flag-offset: -115; }
.iti__kn { --iti-flag-offset: -116; }
.iti__kp { --iti-flag-offset: -117; }
.iti__kr { --iti-flag-offset: -118; }
.iti__kw { --iti-flag-offset: -119; }
.iti__ky { --iti-flag-offset: -120; }
.iti__kz { --iti-flag-offset: -121; }
.iti__la { --iti-flag-offset: -122; }
.iti__lb { --iti-flag-offset: -123; }
.iti__lc { --iti-flag-offset: -124; }
.iti__li { --iti-flag-offset: -125; }
.iti__lk { --iti-flag-offset: -126; }
.iti__lr { --iti-flag-offset: -127; }
.iti__ls { --iti-flag-offset: -128; }
.iti__lt { --iti-flag-offset: -129; }
.iti__lu { --iti-flag-offset: -130; }
.iti__lv { --iti-flag-offset: -131; }
.iti__ly { --iti-flag-offset: -132; }
.iti__ma { --iti-flag-offset: -133; }
.iti__mc { --iti-flag-offset: -134; }
.iti__md { --iti-flag-offset: -135; }
.iti__me { --iti-flag-offset: -136; }
.iti__mf { --iti-flag-offset: -137; }
.iti__mg { --iti-flag-offset: -138; }
.iti__mh { --iti-flag-offset: -139; }
.iti__mk { --iti-flag-offset: -140; }
.iti__ml { --iti-flag-offset: -141; }
.iti__mm { --iti-flag-offset: -142; }
.iti__mn { --iti-flag-offset: -143; }
.iti__mo { --iti-flag-offset: -144; }
.iti__mp { --iti-flag-offset: -145; }
.iti__mq { --iti-flag-offset: -146; }
.iti__mr { --iti-flag-offset: -147; }
.iti__ms { --iti-flag-offset: -148; }
.iti__mt { --iti-flag-offset: -149; }
.iti__mu { --iti-flag-offset: -150; }
.iti__mv { --iti-flag-offset: -151; }
.iti__mw { --iti-flag-offset: -152; }
.iti__mx { --iti-flag-offset: -153; }
.iti__my { --iti-flag-offset: -154; }
.iti__mz { --iti-flag-offset: -155; }
.iti__na { --iti-flag-offset: -156; }
.iti__nc { --iti-flag-offset: -157; }
.iti__ne { --iti-flag-offset: -158; }
.iti__nf { --iti-flag-offset: -159; }
.iti__ng { --iti-flag-offset: -160; }
.iti__ni { --iti-flag-offset: -161; }
.iti__nl { --iti-flag-offset: -162; }
.iti__no { --iti-flag-offset: -163; }
.iti__np { --iti-flag-offset: -164; }
.iti__nr { --iti-flag-offset: -165; }
.iti__nu { --iti-flag-offset: -166; }
.iti__nz { --iti-flag-offset: -167; }
.iti__om { --iti-flag-offset: -168; }
.iti__pa { --iti-flag-offset: -169; }
.iti__pe { --iti-flag-offset: -170; }
.iti__pf { --iti-flag-offset: -171; }
.iti__pg { --iti-flag-offset: -172; }
.iti__ph { --iti-flag-offset: -173; }
.iti__pk { --iti-flag-offset: -174; }
.iti__pl { --iti-flag-offset: -175; }
.iti__pm { --iti-flag-offset: -176; }
.iti__pr { --iti-flag-offset: -177; }
.iti__ps { --iti-flag-offset: -178; }
.iti__pt { --iti-flag-offset: -179; }
.iti__pw { --iti-flag-offset: -180; }
.iti__py { --iti-flag-offset: -181; }
.iti__qa { --iti-flag-offset: -182; }
.iti__re { --iti-flag-offset: -183; }
.iti__ro { --iti-flag-offset: -184; }
.iti__rs { --iti-flag-offset: -185; }
.iti__ru { --iti-flag-offset: -186; }
.iti__rw { --iti-flag-offset: -187; }
.iti__sa { --iti-flag-offset: -188; }
.iti__sb { --iti-flag-offset: -189; }
.iti__sc { --iti-flag-offset: -190; }
.iti__sd { --iti-flag-offset: -191; }
.iti__se { --iti-flag-offset: -192; }
.iti__sg { --iti-flag-offset: -193; }
.iti__sh { --iti-flag-offset: -194; }
.iti__si { --iti-flag-offset: -195; }
.iti__sj { --iti-flag-offset: -196; }
.iti__sk { --iti-flag-offset: -197; }
.iti__sl { --iti-flag-offset: -198; }
.iti__sm { --iti-flag-offset: -199; }
.iti__sn { --iti-flag-offset: -200; }
.iti__so { --iti-flag-offset: -201; }
.iti__sr { --iti-flag-offset: -202; }
.iti__ss { --iti-flag-offset: -203; }
.iti__st { --iti-flag-offset: -204; }
.iti__sv { --iti-flag-offset: -205; }
.iti__sx { --iti-flag-offset: -206; }
.iti__sy { --iti-flag-offset: -207; }
.iti__sz { --iti-flag-offset: -208; }
.iti__tc { --iti-flag-offset: -209; }
.iti__td { --iti-flag-offset: -210; }
.iti__tg { --iti-flag-offset: -211; }
.iti__th { --iti-flag-offset: -212; }
.iti__tj { --iti-flag-offset: -213; }
.iti__tk { --iti-flag-offset: -214; }
.iti__tl { --iti-flag-offset: -215; }
.iti__tm { --iti-flag-offset: -216; }
.iti__tn { --iti-flag-offset: -217; }
.iti__to { --iti-flag-offset: -218; }
.iti__tr { --iti-flag-offset: -219; }
.iti__tt { --iti-flag-offset: -220; }
.iti__tv { --iti-flag-offset: -221; }
.iti__tw { --iti-flag-offset: -222; }
.iti__tz { --iti-flag-offset: -223; }
.iti__ua { --iti-flag-offset: -224; }
.iti__ug { --iti-flag-offset: -225; }
.iti__us { --iti-flag-offset: -226; }
.iti__uy { --iti-flag-offset: -227; }
.iti__uz { --iti-flag-offset: -228; }
.iti__va { --iti-flag-offset: -229; }
.iti__vc { --iti-flag-offset: -230; }
.iti__ve { --iti-flag-offset: -231; }
.iti__vg { --iti-flag-offset: -232; }
.iti__vi { --iti-flag-offset: -233; }
.iti__vn { --iti-flag-offset: -234; }
.iti__vu { --iti-flag-offset: -235; }
.iti__wf { --iti-flag-offset: -236; }
.iti__ws { --iti-flag-offset: -237; }
.iti__xk { --iti-flag-offset: -238; }
.iti__ye { --iti-flag-offset: -239; }
.iti__yt { --iti-flag-offset: -240; }
.iti__za { --iti-flag-offset: -241; }
.iti__zm { --iti-flag-offset: -242; }
.iti__zw { --iti-flag-offset: -243; }
/* THIS FILE IS AUTO-GENERATED. DO NOT EDIT. */

View File

@@ -1,558 +0,0 @@
@import "flag-offsets.css";
:root {
/* rgba is needed for the selected country hover state to blend in with the border-highlighting some browsers give the input on focus.
Used as the bg color for both the selected country and the country list items, on hover. */
--iti-hover-color: rgba(0, 0, 0, 0.05);
/* Used for both the country selector border, and the divider under the country search input. */
--iti-border-color: #ccc;
--iti-country-selector-bg: white;
/* icons include: arrow icon, globe icon, search icon, clear icon, check icon */
--iti-icon-color: #555;
/* horizontal spacing around the flag, country name, search icon, clear icon, check icon etc */
--iti-spacer-horizontal: 10px;
/* Flags are a 4:3 aspect ratio, so height is derived from width — consumers only need to override --iti-flag-width to scale.
--iti-flag-width itself is set in flag-offsets.css (auto-generated). */
--iti-flag-height: calc(var(--iti-flag-width) * 3 / 4);
/* Separate height for the globe icon, as it's much thinner than the flags, so nice to have it a bit taller. This is also re-used for the search icon. */
--iti-globe-icon-size: 17px;
/* Separate height for the search clear icon, which looks too big if it's the same as the others. */
--iti-clear-icon-size: 15px;
/* This border width is used for the popup and divider, but it is also assumed to be the border width of the input, which we do not control. */
--iti-border-width: 1px;
/* Arrow */
--iti-arrow-size: 5px;
--iti-arrow-width: 1.5px; /* thickness */
--iti-arrow-padding: 7px;
/* NOTE: image paths are now defined in intlTelInputWithAssets.css */
/* Enough space for them to click off to close. */
--iti-mobile-popup-margin: 30px;
/* Colour used for the flash variant of the strictRejectAnimation option (shown when the user has prefers-reduced-motion). */
--iti-strict-reject-flash-color: rgba(255, 0, 0, 0.12);
}
.iti {
/* We need position on the container so the selected country can be absolutely positioned over the input. */
position: relative;
/* Keep the input's default inline properties. */
display: inline-block;
/* Paul Irish (paulirish) says this is ok.
http://www.paulirish.com/2012/box-sizing-border-box-ftw/ */
* {
box-sizing: border-box;
}
/* Specify types to increase specificity e.g. to override bootstrap v2.3. */
input.iti__tel-input,
input.iti__tel-input[type="text"],
input.iti__tel-input[type="tel"] {
position: relative;
/* Input is bottom level, below selected country and country selector. */
z-index: 0;
/* By default the input is inline, which means any inherited line-height will make the wrapper (and hence the selected country) taller than the input. Block is a better default in this case, given it should fill the wrapper. */
display: block;
/* Ensure the input fills the wrapper e.g. when the wrapper is inside a flex/grid container.
When the wrapper has no explicit width (standard inline-block), this is a cyclic percentage
and resolves to auto per CSS Sizing 3, so it has no effect and any consumer-set width wins. */
min-width: 100%;
/* Since we wrap the input in a container div, any margin here would interfere with the positioning of the selected country. */
margin: 0 !important;
}
}
.iti__a11y-text {
width: 1px;
height: 1px;
clip: rect(1px, 1px, 1px, 1px);
overflow: hidden;
position: absolute;
}
.iti__country-container {
/* Positioned over the top of the input. */
position: absolute;
/* Full height. */
top: 0;
bottom: 0;
left: 0;
/* Prevent the highlighted child from overlapping the input border. */
padding: var(--iti-border-width);
}
/* Now a button element. */
.iti__selected-country {
/* Render above the input. */
z-index: 1;
position: relative;
display: flex;
align-items: center;
/* This must be full-height both for the hover highlight, and to push down the dropdown so it appears below the input. */
height: 100%;
/* Reset button styles (can't use all:unset as lose browser default focus outline styles). */
background: none;
border: 0;
margin: 0;
padding: 0;
font-family: inherit;
font-size: inherit;
color: inherit;
border-radius: 0;
font-weight: inherit;
line-height: inherit;
text-decoration: none;
}
.iti__selected-country-primary {
display: flex;
align-items: center;
/* This must be full-height for the hover highlight. */
height: 100%;
padding: 0 var(--iti-arrow-padding) 0 var(--iti-spacer-horizontal);
}
.iti__selected-dial-code {
margin-left: 4px;
}
.iti__arrow {
margin-left: var(--iti-arrow-padding);
margin-top: -2px;
width: var(--iti-arrow-size);
height: var(--iti-arrow-size);
box-sizing: border-box;
border-right: var(--iti-arrow-width) solid var(--iti-icon-color);
border-bottom: var(--iti-arrow-width) solid var(--iti-icon-color);
transform: rotate(45deg);
}
.iti__arrow--up {
margin-top: 4px;
transform: rotate(-135deg);
}
/* The country selector. */
.iti__country-selector {
border-radius: 3px;
background-color: var(--iti-country-selector-bg);
.iti--inline-country-selector & {
border: var(--iti-border-width) solid var(--iti-border-color);
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
}
/* Note: don't apply these styles when using dropdownParent, as that uses pos:fixed and so this (child) doesn't need pos:absolute */
.iti--inline-country-selector:not(.iti--detached-country-selector) & {
position: absolute;
/* Popup so render above everything else. */
z-index: 2;
left: 0;
}
}
.iti__search-input {
width: 100%;
border-width: 0;
border-radius: 3px;
/* Space for search icon. */
padding-left: calc(
var(--iti-spacer-horizontal) + var(--iti-globe-icon-size) +
var(--iti-spacer-horizontal)
);
/* Space for clear button. */
padding-right: calc(
var(--iti-spacer-horizontal) + var(--iti-clear-icon-size) +
var(--iti-spacer-horizontal)
);
/* RTL: put the icon on the right instead. */
[dir="rtl"] & {
padding-left: inherit;
padding-right: 30px;
background-position: right 8px center;
}
/* hide chrome/safari's native clear button for inputs with type=search */
&::-webkit-search-cancel-button {
appearance: none;
}
}
/* give the search input the same v-padding as the country items, for visual consistency */
.iti__search-input,
.iti__country {
padding-top: 8px;
padding-bottom: 8px;
}
.iti__search-input-wrapper {
position: relative;
display: flex;
align-items: center;
border-bottom: 1px solid var(--iti-border-color);
}
.iti__search-icon {
position: absolute;
left: var(--iti-spacer-horizontal);
display: flex;
pointer-events: none;
[dir="rtl"] & {
left: auto;
right: var(--iti-spacer-horizontal);
}
}
.iti__search-icon-svg {
width: var(--iti-globe-icon-size);
height: var(--iti-globe-icon-size);
display: block;
stroke: var(--iti-icon-color);
fill: none;
stroke-width: 3;
}
.iti__search-clear {
position: absolute;
/* half the spacer value as the other half is in the padding */
right: calc(var(--iti-spacer-horizontal) / 2);
background: transparent;
border: 0;
border-radius: 3px; /* nice on hover state */
cursor: pointer;
padding: calc(var(--iti-spacer-horizontal) / 2);
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.15s ease;
.iti__search-clear-x {
stroke-width: 2;
}
.iti__search-clear-bg {
fill: var(--iti-icon-color);
}
[dir="rtl"] & {
right: auto;
left: var(--iti-spacer-horizontal);
}
&:hover,
&:focus-visible {
background: var(--iti-hover-color);
outline: none;
}
}
.iti__search-clear-svg {
width: var(--iti-clear-icon-size);
height: var(--iti-clear-icon-size);
display: block;
}
.iti__no-results {
text-align: center;
padding: 30px 0;
}
.iti__country-list {
/* Override default list styles. */
list-style: none;
padding: 0;
margin: 0;
cursor: pointer;
overflow-y: scroll;
/* Fixes https://github.com/jackocnr/intl-tel-input/issues/765
Apple still hasn't fixed the issue where setting overflow: scroll on a div element does not use inertia scrolling
If this is not set, then the country list scroll stops moving after raising a finger, and users report that scroll is slow
Stackoverflow question about it: https://stackoverflow.com/questions/33601165/scrolling-slow-on-mobile-ios-when-using-overflowscroll */
-webkit-overflow-scrolling: touch;
.iti--inline-country-selector & {
max-height: 185px;
}
}
.iti--flexible-dropdown-width .iti__country-list {
/* Don't let the contents wrap AKA the container will be as wide as the contents. */
white-space: nowrap;
/* Except on small screens, where we force the dropdown width to match the input. */
@media (max-width: 500px) {
white-space: normal;
}
}
/* Each country item in the list (we must have separate class to differentiate from dividers). */
.iti__country {
/* Note: decided not to use line-height here for alignment because it causes issues e.g. large font-sizes will overlap, and also looks bad if one country overflows onto 2 lines. */
display: flex;
align-items: center;
padding-left: var(--iti-spacer-horizontal);
padding-right: var(--iti-spacer-horizontal);
outline: none;
&.iti__highlight {
background-color: var(--iti-hover-color);
}
}
.iti__country-name {
/* expand to fill available space, so the last flex item, the check mark, is pushed to the right edge */
flex-grow: 1;
}
/* Check icon shown on the right for the selected country. */
.iti__country-check {
margin-left: var(--iti-spacer-horizontal);
display: flex;
align-items: center;
color: var(--iti-icon-color);
}
.iti__country-check-svg {
width: var(--iti-clear-icon-size);
height: var(--iti-clear-icon-size);
display: block;
}
/* Spacing between country flag and country name. */
.iti__country-list .iti__flag {
margin-right: var(--iti-spacer-horizontal);
flex-shrink: 0; /* stop long country names from shrinking the flag */
[dir="rtl"] & {
margin-right: 0;
margin-left: var(--iti-spacer-horizontal);
}
}
.iti--has-country-selector {
/* If the adjacent input is disabled/readonly, ensure the country button doesn't look clickable. */
.iti__country-container:has(+ input[disabled]),
.iti__country-container:has(+ input[readonly]) {
button.iti__selected-country {
cursor: not-allowed;
.iti__arrow {
visibility: hidden;
}
}
}
/* Show the active background colour on the selected flag/arrow when you hover it, or for as long as the country selector (dropdown) is open. Deliberately not applied when hovering the selected dial code, which would feel weird.
Only apply when the input is NOT disabled/readonly. */
.iti__country-container:not(:has(+ input[disabled])):not(:has(+ input[readonly])) {
.iti__selected-country-primary:hover,
.iti__selected-country[aria-expanded="true"] .iti__selected-country-primary {
background-color: var(--iti-hover-color);
}
}
}
/* When the country selector is rendered detached (fullscreen, or dropdown with dropdownParent set), increase z-index to prevent display issues. */
.iti--detached-country-selector {
position: fixed;
top: -1000px;
left: -1000px;
/* Higher than default Bootstrap modal z-index of 1050. */
z-index: 1060;
&:hover {
cursor: pointer;
}
}
/* CSS Anchor Positioning: when supported, the browser keeps the detached country selector
anchored to the input on the compositor (no JS scroll/resize listeners needed) and flips it
above the input automatically via @position-try when there isn't room below. In unsupporting
browsers anchor() is invalid so these declarations are dropped, and ui.ts falls back to
JS-driven positioning (which sets inline top/left, overriding the offscreen defaults above). */
.iti--detached-country-selector {
top: calc(anchor(bottom) + 3px);
left: anchor(left);
position-try-fallbacks: --iti-flip-above;
}
@position-try --iti-flip-above {
top: auto;
bottom: calc(anchor(top) + 3px);
}
/* Put these at the end, so they override other classes with display:flex etc. */
.iti__hide {
display: none;
}
/* Need this during init, to get the height of the country list. */
.iti__v-hide {
visibility: hidden;
}
/* Overrides for mobile popup. */
.iti--fullscreen-popup {
&.iti--detached-country-selector {
background-color: rgba(0, 0, 0, 0.5);
top: 0;
bottom: 0;
left: 0;
right: 0;
position: fixed;
padding: var(--iti-mobile-popup-margin);
/* Short country lists should be vertically centred. */
display: flex;
flex-direction: column;
/* The country search input auto-focuses, so mobile keyboard appears, so stick to top (also because when filter countries down, the height changes and the vertical centring would make it jump around). */
justify-content: flex-start;
}
.iti__country-selector {
display: flex;
flex-direction: column;
max-height: 100%;
position: relative; /* Override needed in order to get full-width working properly. */
}
/* give the search input the same v-padding as the country items, for visual consistency */
.iti__country,
.iti__search-input {
padding-top: 10px;
padding-bottom: 10px;
}
.iti__country {
padding-left: 10px;
padding-right: 10px;
/* Increase line height because country list copy is v likely to overflow on mobile and when it does it needs to be well spaced. */
line-height: 1.5em;
}
}
.iti__flag {
height: var(--iti-flag-height);
width: var(--iti-flag-width);
border-radius: 1px;
box-shadow: 0px 0px 1px 0px #888;
background-image: image-set(
var(--iti-path-flags-1x) 1x,
var(--iti-path-flags-2x) 2x
);
background-repeat: no-repeat;
/* Offset and sprite size are expressed as multiples of --iti-flag-width / --iti-flag-height
so consumers can scale the flags by overriding just those two vars.
The 100 fallback hides all flags when no country class is set (useful for the empty state
shown while initialCountryLookup is resolving) — done via var()'s fallback rather than as a rule
default so the country-specific offsets win regardless of source order. */
background-position: calc(var(--iti-flag-offset, 100) * var(--iti-flag-width)) 0;
background-size: calc(var(--iti-flag-count) * var(--iti-flag-width))
var(--iti-flag-height);
}
/* Loading state (used while initialCountryLookup is resolving the initial country). */
.iti__loading {
position: relative;
background: none;
box-shadow: none;
&::after {
content: "";
position: absolute;
inset: 0;
margin: auto;
width: var(--iti-flag-height);
height: var(--iti-flag-height);
box-sizing: border-box;
border: 2px solid var(--iti-icon-color);
border-right-color: transparent;
border-radius: 50%;
animation: iti-spinner 1s linear infinite;
}
}
@keyframes iti-spinner {
to {
transform: rotate(360deg);
}
}
/* Subtle visual feedback when strictMode rejects the whole input. Opt-in via the strictRejectAnimation option.
Targets the input and selected-country button (not the wrapper), so an open dropdown (e.g. with dropdownAlwaysOpen) doesn't shake along with them. */
.iti__strict-reject-animation {
.iti__tel-input,
.iti__selected-country {
animation: iti-strict-reject-shake 0.3s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}
/* Users who have opted out of motion get a brief background-color flash on the input instead (the selected-country button is skipped to avoid an odd-looking flash on a small UI element). */
@media (prefers-reduced-motion: reduce) {
.iti__tel-input {
animation: iti-strict-reject-flash 0.3s ease-out both;
}
.iti__selected-country {
animation: none;
}
}
}
@keyframes iti-strict-reject-shake {
10%,
90% {
transform: translateX(-1px);
}
20%,
80% {
transform: translateX(2px);
}
30%,
50%,
70% {
transform: translateX(-3px);
}
40%,
60% {
transform: translateX(3px);
}
}
/* Keyframe omits 0%/100% so the element falls back to its base background-color
(important because `both` fill-mode would otherwise persist the last keyframe). */
@keyframes iti-strict-reject-flash {
40% {
background-color: var(--iti-strict-reject-flash-color);
}
}
/* Empty state.
Inline globe icon (now rendered as SVG inside .iti__flag). Keep class for width/position logic and to clear box-shadow. */
.iti__globe {
background: none;
box-shadow: none;
height: var(--iti-globe-icon-size);
display: flex;
align-items: center;
justify-content: center;
padding: 0; /* ensure svg centers */
.iti__globe-svg {
width: 100%;
height: 100%;
fill: var(--iti-icon-color);
}
}
/* Browsers normally add a coloured outline when you focus an input. Chrome adds a blue outline WITHIN the input. If you focus the input and then hover the selected country, it's bg color square overlaps the focus outline and looks bad. Here, @supports is used to target Chrome only, and move the default outline out by 1px so there's no overlap. */
@supports (-webkit-appearance: none) and (not (background: -webkit-canvas(foo))) {
.iti__tel-input:focus {
outline-offset: 1px;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +0,0 @@
@import "intlTelInput.css";
:root {
/* Image related variables. */
--iti-path-flags-1x: url('../img/flags.webp');
--iti-path-flags-2x: url('../img/flags@2x.webp');
}

View File

@@ -1,2 +0,0 @@
declare const styles: string;
export default styles;

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@@ -1,213 +0,0 @@
// Shared constants extracted from intl-tel-input logic to avoid magic strings/numbers
import type { Iso2 } from "./data.js";
export const EVENTS = {
OPEN_COUNTRY_SELECTOR: "open:countryselector",
CLOSE_COUNTRY_SELECTOR: "close:countryselector",
COUNTRY_CHANGE: "countrychange",
INPUT: "input", // used for synthetic input trigger
STRICT_REJECT: "strict:reject",
} as const;
//* The named "slots" (i.e. the elements we generate) that consumers can add their own classes
//* to, via the classNames option. Deliberately decoupled from our internal iti__* class names,
//* so the markup remains an implementation detail. Used to validate the option at runtime, and
//* to derive the ItiClassNames type. Keep in sync with the ItiClassNames interface.
export const ITI_SLOTS = [
"container",
"input",
"countryContainer",
"selectedCountry",
"selectedCountryPrimary",
"selectedFlag",
"arrow",
"selectedDialCode",
"countrySelector",
"countrySelectorContainer",
"searchWrapper",
"searchIcon",
"searchInput",
"searchClear",
"countryList",
"countryListItem",
"countryListItemFlag",
"countryName",
"dialCode",
"countryCheck",
"noResults",
] as const;
export const CLASSES = {
HIDE: "iti__hide",
V_HIDE: "iti__v-hide",
ARROW_UP: "iti__arrow--up",
GLOBE: "iti__globe",
FLAG: "iti__flag",
LOADING: "iti__loading",
COUNTRY_ITEM: "iti__country",
HIGHLIGHT: "iti__highlight",
STRICT_REJECT_ANIMATION: "iti__strict-reject-animation",
} as const;
export const KEYS = {
ARROW_UP: "ArrowUp",
ARROW_DOWN: "ArrowDown",
SPACE: " ",
ENTER: "Enter",
ESC: "Escape",
TAB: "Tab",
} as const;
export const INPUT_TYPES = {
PASTE: "insertFromPaste",
DELETE_FORWARD: "deleteContentForward",
} as const;
export const REGEX = {
ALPHA_UNICODE: /\p{L}/u, // any kind of letter from any language
NON_PLUS_NUMERIC: /[^+0-9]/, // chars that are NOT + or digit
NON_PLUS_NUMERIC_GLOBAL: /[^+0-9]/g, // chars that are NOT + or digit (global)
HIDDEN_SEARCH_CHAR: /^[a-zA-ZÀ-ÿа-яА-Я ]$/, // single acceptable hidden-search char
} as const;
export const TIMINGS = {
SEARCH_DEBOUNCE_MS: 100,
HIDDEN_SEARCH_RESET_MS: 1000,
NEXT_TICK: 0,
} as const;
// Layout / sizing fallbacks (used when measuring elements fails e.g., hidden containers)
// TODO: find a way to pull these out of the CSS, so there's a single source of truth.
export const LAYOUT = {
NARROW_VIEWPORT_WIDTH: 500, // keep in sync with .iti__country-list CSS media query
FALLBACK_SELECTED_COUNTRY_WITH_DIAL_WIDTH: 78, // px width fallback when separateDialCode enabled
FALLBACK_SELECTED_COUNTRY_NO_DIAL_WIDTH: 42, // px width fallback when no separate dial code
INPUT_PADDING_EXTRA_LEFT: 6, // px gap between selected country container and input text
DROPDOWN_MARGIN: 3, // px margin between dropdown and tel input
FALLBACK_DROPDOWN_HEIGHT: 200, // px height fallback for dropdown
} as const;
// Helpful grouping for dial code logic (kept lean; expand only if reused widely)
export const DIAL_CODE = {
PLUS: "+",
NANP: "1", // North American Numbering Plan
} as const;
// E.164 caps a full international number (dial code + national number) at 15
// digits. Used as a fallback max length in strictMode when there is no selected
// country, and so no country-specific max to enforce.
export const E164_MAX_DIGITS = 15;
// Country-specific telephone rules
export const UK = {
ISO2: "gb" as Iso2,
DIAL_CODE: "44", // +44 United Kingdom
MOBILE_PREFIX: "7", // UK mobile numbers start with 7 after national trunk (0) or core section
MOBILE_CORE_LENGTH: 10, // core number length (excluding dial code / national prefix) for mobiles
} as const;
export const US = {
ISO2: "us" as Iso2,
DIAL_CODE: "1", // +1 United States
};
// Public-facing enum constant for placeholderNumberPolicy. Singular to match
// NUMBER_FORMAT / NUMBER_TYPE / VALIDATION_ERROR. Hand-defined (rather than
// derived via toEnumObject) because there's no parallel array to be the source
// of truth.
export const PLACEHOLDER_POLICY = {
AGGRESSIVE: "AGGRESSIVE",
POLITE: "POLITE",
OFF: "OFF",
} as const;
// Valid values for the countrySelectorMode option. The COUNTRY_SELECTOR_MODE
// enum object is derived from this array (below, alongside NUMBER_FORMAT etc).
export const COUNTRY_SELECTOR_MODES = [
"OFF",
"DROPDOWN",
"FULLSCREEN",
"AUTO",
] as const;
// libphonenumber enums - sole source of truth for both the core library (option
// validation, public types) and utils.js (which builds its int maps from
// these arrays at build time via scripts/build-utils.js).
//
// Order matters - the array index is the integer value libphonenumber uses,
// EXCEPT for NUMBER_TYPES.UNKNOWN which libphonenumber maps to -1 (handled
// explicitly in utils.js).
//
// Mirrors:
// - i18n.phonenumbers.PhoneNumberFormat
// - i18n.phonenumbers.PhoneNumberType
// - i18n.phonenumbers.PhoneNumberUtil.ValidationResult
// in third_party/libphonenumber/javascript/i18n/phonenumbers/phonenumberutil.js
export const NUMBER_FORMATS = [
"E164",
"INTERNATIONAL",
"NATIONAL",
"RFC3966",
] as const;
export const NUMBER_TYPES = [
"FIXED_LINE",
"MOBILE",
"FIXED_LINE_OR_MOBILE",
"TOLL_FREE",
"PREMIUM_RATE",
"SHARED_COST",
"VOIP",
"PERSONAL_NUMBER",
"PAGER",
"UAN",
"VOICEMAIL",
"UNKNOWN",
] as const;
export const VALIDATION_ERRORS = [
"IS_POSSIBLE",
"INVALID_COUNTRY_CODE",
"TOO_SHORT",
"TOO_LONG",
"IS_POSSIBLE_LOCAL_ONLY",
"INVALID_LENGTH",
] as const;
// Convenience constants so consumers can write NUMBER_TYPE.MOBILE instead of
// the bare string "MOBILE" - typo-safe and matches the PLACEHOLDER_POLICY style.
// Derived from the arrays above so there's no second list to keep in sync.
const toEnumObject = <T extends readonly string[]>(
arr: T,
): Readonly<{ [K in T[number]]: K }> =>
Object.fromEntries(arr.map((v) => [v, v])) as Readonly<{
[K in T[number]]: K;
}>;
export const NUMBER_FORMAT = toEnumObject(NUMBER_FORMATS);
export const NUMBER_TYPE = toEnumObject(NUMBER_TYPES);
export const VALIDATION_ERROR = toEnumObject(VALIDATION_ERRORS);
export const COUNTRY_SELECTOR_MODE = toEnumObject(COUNTRY_SELECTOR_MODES);
// Data-* keys used on DOM nodes
export const DATA_KEYS = {
// e.g. <li data-iso2="us"> for country items in the country list
ISO2: "iso2",
DIAL_CODE: "dialCode",
// e.g. <input data-intl-tel-input-id="0"> on the input element
INSTANCE_ID: "intlTelInputId",
} as const;
// ARIA attribute names (avoid typos & for potential future refactors)
export const ARIA = {
EXPANDED: "aria-expanded",
LABEL: "aria-label",
SELECTED: "aria-selected",
ACTIVE_DESCENDANT: "aria-activedescendant",
HASPOPUP: "aria-haspopup",
CONTROLS: "aria-controls",
HIDDEN: "aria-hidden",
AUTOCOMPLETE: "aria-autocomplete",
MODAL: "aria-modal",
} as const;

View File

@@ -1,148 +0,0 @@
// * Country search & ranking logic extracted from intlTelInput.ts
// * Maintains original comments/order. Pure functions for reuse & testability.
import type { Country, Iso2 } from "../data.js";
import { normaliseString } from "../helpers/string.js";
export interface SearchTokens {
normalisedName: string;
words: string[];
initials: string;
dialCodePlus: string;
}
export type SearchTokensMap = Map<Iso2, SearchTokens>;
//* Strip all non-letter chars (any script via \p{L}) so separators like "-", ".", "'", "&" all collapse to a single space.
//* Lets queries like "St Pierre" match "St. Pierre & Miquelon", "Sant Elena" match "Sant'Elena", etc., regardless of locale.
const normaliseName = (s: string): string =>
normaliseString(s).replace(/[^\p{L}]+/gu, " ").trim();
//* Precompute country search tokens (normalised name, initials, +dialCode) to speed up filtering.
export const buildSearchTokens = (countries: Country[]): SearchTokensMap => {
const tokens: SearchTokensMap = new Map();
for (const c of countries) {
const normalisedName = normaliseName(c.name);
const words = normalisedName.split(" ").filter(Boolean);
const initials = words.map((w) => w[0] || "").join("");
tokens.set(c.iso2, {
normalisedName,
words,
initials,
dialCodePlus: `+${c.dialCode}`,
});
}
return tokens;
};
/**
* Country search: Given raw query, return ordered list of countries by priority buckets.
* Buckets (in order):
* 1. exact iso2 matches
* 2. name starts with
* 3. name contains
* 4. dial code exact match (bare or with plus)
* 5. dial code contains (with plus form)
* 6. initials match
* 7. word fallback: any query word is a prefix of some word in the name (only when query has 2+ words AND no name bucket hit)
* Each bucket preserves country.priority ordering.
*/
export const getMatchedCountries = (
countries: Country[],
searchTokens: SearchTokensMap,
query: string,
): Country[] => {
//* lowerQuery preserves digits/+ for iso2/dial-code/initials checks; nameQuery strips non-letters for name matching.
const lowerQuery = normaliseString(query);
const nameQuery = normaliseName(query);
//* Skip name buckets if the user typed only non-letters (e.g. "+44") — otherwise empty nameQuery would match everything.
const skipNameBuckets = lowerQuery !== "" && nameQuery === "";
// search result groups, in order of priority
// first, exact iso2 matches, then name starts with, then name contains, dial code match etc.
const iso2Matches: Country[] = [];
const nameStartsWith: Country[] = [];
const nameContains: Country[] = [];
const dialCodeMatches: Country[] = [];
const dialCodeContains: Country[] = [];
const initialsMatches: Country[] = [];
const wordMatches: Country[] = [];
for (const c of countries) {
const t = searchTokens.get(c.iso2)!;
if (c.iso2 === lowerQuery) {
iso2Matches.push(c);
} else if (!skipNameBuckets && t.normalisedName.startsWith(nameQuery)) {
nameStartsWith.push(c);
} else if (!skipNameBuckets && t.normalisedName.includes(nameQuery)) {
nameContains.push(c);
} else if (
lowerQuery === c.dialCode ||
lowerQuery === t.dialCodePlus
) {
dialCodeMatches.push(c);
} else if (t.dialCodePlus.includes(lowerQuery)) {
dialCodeContains.push(c);
} else if (t.initials.includes(lowerQuery)) {
initialsMatches.push(c);
}
}
//* Per-word fallback for multi-word queries that hit no name bucket. A country qualifies when at least one
//* query word is the *prefix of* some word in its name (not a mid-word substring) — so "Saint Hel" finds
//* "St. Helena" via "helena", but does not surface "Seychelles" / "St. Barthélemy" where "hel" sits mid-word.
const queryWords = nameQuery.split(" ").filter(Boolean);
if (
queryWords.length > 1 &&
iso2Matches.length === 0 &&
nameStartsWith.length === 0 &&
nameContains.length === 0
) {
const claimed = new Set<Iso2>([
...dialCodeMatches.map((c) => c.iso2),
...dialCodeContains.map((c) => c.iso2),
...initialsMatches.map((c) => c.iso2),
]);
for (const c of countries) {
if (claimed.has(c.iso2)) {
continue;
}
const t = searchTokens.get(c.iso2)!;
if (queryWords.some((qw) => t.words.some((sw) => sw.startsWith(qw)))) {
wordMatches.push(c);
}
}
}
// Combine result groups in correct order (and respect country priority order within each group e.g. if search +44, then UK appears first above Guernsey etc)
const sortByPriority = (a: Country, b: Country) => a.priority - b.priority;
return [
...iso2Matches,
...nameStartsWith,
...nameContains,
// priority sort is only relevant when showing multiple countries with the same dial code (that's what the priority field is used to distinguish between)
...dialCodeMatches.sort(sortByPriority),
...dialCodeContains.sort(sortByPriority),
...initialsMatches,
...wordMatches,
];
};
/**
* Hidden search (when countrySearch disabled): find first country whose name starts with query (case-insensitive).
*/
export const findFirstCountryStartingWith = (
countries: Country[],
searchTokens: SearchTokensMap,
query: string,
): Country | null => {
const nameQuery = normaliseName(query);
for (const c of countries) {
const { normalisedName } = searchTokens.get(c.iso2)!;
if (normalisedName.startsWith(nameQuery)) {
return c;
}
}
return null;
};

View File

@@ -1,64 +0,0 @@
import { ARIA } from "../constants.js";
type SvgNode = [
tag: string,
attrs?: Record<string, string | number>,
children?: SvgNode[],
];
const SVG_NS = "http://www.w3.org/2000/svg";
const buildSvg = ([tag, attrs, children]: SvgNode): SVGElement => {
const el = document.createElementNS(SVG_NS, tag);
if (attrs) {
for (const k in attrs) {
el.setAttribute(k, String(attrs[k]));
}
}
if (children) {
for (const c of children) {
el.appendChild(buildSvg(c));
}
}
return el;
};
/** Magnifying glass search icon */
export const buildSearchIcon = (): SVGElement => buildSvg(
["svg", { class: "iti__search-icon-svg", width: 14, height: 14, viewBox: "0 0 24 24", focusable: "false", [ARIA.HIDDEN]: "true" }, [
["circle", { cx: 11, cy: 11, r: 7 }],
["line", { x1: 21, y1: 21, x2: 16.65, y2: 16.65 }],
]],
);
/**
* Clear (circle with X) icon
* @param id Instance id used to create a unique mask id.
*/
export const buildClearIcon = (id: number): SVGElement => {
const maskId = `iti-${id}-clear-mask`;
return buildSvg(
["svg", { class: "iti__search-clear-svg", width: 12, height: 12, viewBox: "0 0 16 16", [ARIA.HIDDEN]: "true", focusable: "false" }, [
["mask", { id: maskId, maskUnits: "userSpaceOnUse" }, [
["rect", { width: 16, height: 16, fill: "white" }],
["path", { d: "M5.2 5.2 L10.8 10.8 M10.8 5.2 L5.2 10.8", stroke: "black", "stroke-linecap": "round", class: "iti__search-clear-x" }],
]],
["circle", { cx: 8, cy: 8, r: 8, class: "iti__search-clear-bg", mask: `url(#${maskId})` }],
]],
);
};
/** Check icon shown next to the selected country in the country list. */
export const buildCheckIcon = (): SVGElement => buildSvg(
["svg", { class: "iti__country-check-svg", width: 14, height: 14, viewBox: "0 0 16 16", fill: "currentColor", focusable: "false", [ARIA.HIDDEN]: "true" }, [
["path", { d: "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" }],
]],
);
/** Globe icon used when no country is selected */
export const buildGlobeIcon = (): SVGElement => buildSvg(
["svg", { width: 256, height: 256, viewBox: "0 0 512 512", class: "iti__globe-svg" }, [
["path", { d: "M508 213a240 240 0 0 0-449-87l-2 5-2 5c-8 14-13 30-17 46a65 65 0 0 1 56 4c16-10 35-19 56-27l9-3c-6 23-10 48-10 74h-16l4 6c3 4 5 8 6 13h6c0 22 3 44 8 65l2 10-25-10-4 5 12 18 9 3 6 2 8 3 9 26 1 2 16-7h1l-5-13-1-2c24 6 49 9 75 10v26l11 10 7 7v-30l1-13c22 0 44-3 65-8l10-2-21 48-1 1a317 317 0 0 1-14 23l-21 5h-2c6 16 7 33 1 50a240 240 0 0 0 211-265m-401-56-11 6c19-44 54-79 98-98-11 20-21 44-29 69-21 6-40 15-58 23m154 182v4c-29-1-57-6-81-13-7-25-12-52-13-81h94zm0-109h-94c1-29 6-56 13-81 24-7 52-12 81-13zm0-112c-22 1-44 4-65 8l-10 2 12-30 9-17 1-2a332 332 0 0 1 13-23c13-4 26-6 40-7zm187 69 6 4c4 12 6 25 6 38v1h-68c-1-26-4-51-10-74l48 20 1 1 14 8zm-14-44 10 20c-20-11-43-21-68-29-8-25-18-49-29-69 37 16 67 44 87 78M279 49h1c13 1 27 3 39 7l14 23 1 2a343 343 0 0 1 12 26l2 5 6 16c-23-6-48-9-74-10h-1zm0 87h1c29 1 56 6 81 13 7 24 12 51 12 80v1h-94zm2 207h-2v-94h95c-1 29-6 56-13 81-24 7-51 12-80 13m86 60-20 10c11-20 21-43 29-68 25-8 48-18 68-29-16 37-43 67-77 87m87-115-7 5-16 9-2 1a337 337 0 0 1-47 21c6-24 9-49 10-75h68c0 13-2 27-6 39" }],
["path", { d: "m261 428-2-2-22-21a40 40 0 0 0-32-11h-1a37 37 0 0 0-18 8l-1 1-4 2-2 2-5 4c-9-3-36-31-47-44s-32-45-34-55l3-2a151 151 0 0 0 11-9v-1a39 39 0 0 0 5-48l-3-3-11-19-3-4-5-7h-1l-3-3-4-3-5-2a35 35 0 0 0-16-3h-5c-4 1-14 5-24 11l-4 2-4 3-4 2c-9 8-17 17-18 27a380 380 0 0 0 212 259h3c12 0 25-10 36-21l10-12 6-11a39 39 0 0 0-8-40" }],
]],
);

View File

@@ -1,64 +0,0 @@
export class Numerals {
#userNumeralSet: "ascii" | "arabic-indic" | "persian" | undefined;
//* Stateless conversion of any Arabic-Indic / Persian digits to ASCII 0-9.
//* Use this when you need to normalise digits without affecting any instance's tracked numeral set (e.g. for the country-search query).
public static toAscii(str: string): string {
if (!str) {
return "";
}
// Note: yes it runs two replaces, but a replace call is really a test + manipulate, so for standard ascii input, it just runs 2x tests. Not worth splitting up and adding test guards.
return str
.replace(/[٠-٩]/g, (ch) =>
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x0660)),
)
.replace(/[۰-۹]/g, (ch) =>
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x06f0)),
);
}
constructor(initialValue: string) {
if (initialValue) {
this.#updateNumeralSet(initialValue);
}
}
// If any Arabic-Indic digits, then label it as that set. Same for Persian. Otherwise assume ASCII.
#updateNumeralSet(str: string): void {
if (/[٠-٩]/.test(str)) {
this.#userNumeralSet = "arabic-indic";
} else if (/[۰-۹]/.test(str)) {
this.#userNumeralSet = "persian";
} else {
this.#userNumeralSet = "ascii";
}
}
// Denormalise ASCII 0-9 to the user's numeral set. If not yet known, return as-is.
// NOTE: normalise is always called before this, so it should be impossible for the numeral set to be unknown at this point.
public denormalise(str: string): string {
if (!this.#userNumeralSet || this.#userNumeralSet === "ascii") {
return str;
}
const base = this.#userNumeralSet === "arabic-indic" ? 0x0660 : 0x06f0;
return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
}
// Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9.
// Tracks the user's numeral set as a side effect so denormalise can mirror it back.
public normalise(str: string): string {
if (!str) {
return "";
}
this.#updateNumeralSet(str);
//* Fast-path ASCII (the common case) so we skip both replaces on every keystroke.
if (this.#userNumeralSet === "ascii") {
return str;
}
return Numerals.toAscii(str);
}
public isAscii(): boolean {
return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
}
}

View File

@@ -1,466 +0,0 @@
import {
PLACEHOLDER_POLICY,
NUMBER_FORMAT,
NUMBER_TYPE,
NUMBER_TYPES,
COUNTRY_SELECTOR_MODE,
COUNTRY_SELECTOR_MODES,
ITI_SLOTS,
LAYOUT,
} from "../constants.js";
import defaultEnglishStrings from "../locale/en.js";
import { isIso2, type Iso2 } from "../data.js";
import type { AllOptions, SomeOptions } from "../types/public-api.js";
// Helper for media query evaluation
const mediaQuery = (q: string): boolean =>
typeof window !== "undefined" &&
typeof window.matchMedia === "function" &&
window.matchMedia(q).matches;
const isNarrowViewport = () =>
mediaQuery(`(max-width: ${LAYOUT.NARROW_VIEWPORT_WIDTH}px)`);
//* Heuristic for resolving countrySelectorMode "AUTO" to "FULLSCREEN" or "DROPDOWN".
const resolveAutoCountrySelectorMode = ():
| typeof COUNTRY_SELECTOR_MODE.FULLSCREEN
| typeof COUNTRY_SELECTOR_MODE.DROPDOWN => {
if (typeof navigator !== "undefined" && typeof window !== "undefined") {
const isShortViewport = mediaQuery("(max-height: 600px)");
const isCoarsePointer = mediaQuery("(pointer: coarse)");
/* Heuristic rationale: If narrow width OR (coarse pointer with constrained height) we prefer fullscreen for usability. Coarse pointer usually implies touch (phones/tablets, some hybrids) where larger touch targets help (and virtual keyboards may be used, which consume more vertical space). */
if (isNarrowViewport() || (isCoarsePointer && isShortViewport)) {
return COUNTRY_SELECTOR_MODE.FULLSCREEN;
}
}
return COUNTRY_SELECTOR_MODE.DROPDOWN;
};
export const defaults: AllOptions = {
//* How the country selector is displayed. "DROPDOWN" vs "FULLSCREEN", or "AUTO" to decide itself, or "OFF".
countrySelectorMode: COUNTRY_SELECTOR_MODE.AUTO,
//* The number type to enforce during validation.
allowedNumberTypes: [NUMBER_TYPE.MOBILE, NUMBER_TYPE.FIXED_LINE],
//* Whether or not to allow extensions after the main number.
allowNumberExtensions: false,
// Allow alphanumeric "phonewords" (e.g. +1 800 FLOWERS) as valid numbers
allowPhonewords: false,
//* Add custom classes to the elements we generate, keyed by slot name e.g. { selectedCountry: "rounded-l-lg" }.
classNames: {},
//* Add a custom class to the (injected) container element.
containerClass: "",
//* Locale for localising country names via Intl.DisplayNames.
countryNameLocale: "en",
//* Override individual country names by iso2 code.
countryNameOverrides: {},
//* The order of the countries in the country list. Defaults to alphabetical.
countryOrder: null,
//* Add a country search input at the top of the country selector.
countrySearch: true,
//* Modify the auto placeholder.
customPlaceholder: null,
//* Always show the dropdown
dropdownAlwaysOpen: false,
//* Optional DOM element to append the dropdown to (used to escape ancestors with overflow:hidden, or to mount in a custom container). Only consulted in dropdown rendering; ignored when the country selector renders as a fullscreen popup.
dropdownParent: null,
//* Don't display these countries.
excludeCountries: null,
//* Fix the dropdown width to the input width (rather than being as wide as the longest country name).
matchDropdownWidth: true,
//* Format the number as the user types
formatAsYouType: true,
//* Inject hidden inputs with the names returned from this function, and on submit, populate them with the full number and selected country iso2.
hiddenInputs: null,
//* Translations for the core library UI strings e.g. search input placeholder, country names.
uiTranslations: {},
//* Initial country.
initialCountry: "",
//* Async lookup function used to determine the initial country (e.g. via IP). Ignored if initialCountry is set.
initialCountryLookup: null,
//* A function to load the utils script.
loadUtils: null,
//* Format used when displaying numbers (placeholder examples and stored values). One of "E164", "INTERNATIONAL", "NATIONAL".
numberDisplayFormat: NUMBER_FORMAT.INTERNATIONAL,
//* Display only these countries.
onlyCountries: null,
//* When to set the placeholder to an example number for the selected country: "POLITE" only when the input has no manually-set placeholder, "AGGRESSIVE" always, "OFF" never.
placeholderNumberPolicy: PLACEHOLDER_POLICY.POLITE,
//* Number type to use for placeholders.
placeholderNumberType: NUMBER_TYPE.MOBILE,
//* Add custom classes to the search input element.
searchInputClass: "",
//* Display the international dial code next to the selected flag.
separateDialCode: true,
//* When strictMode rejects a key (etc), play a short feedback animation
strictRejectAnimation: true,
//* Show flags - for both the selected country, and in the country list
showFlags: true,
//* Only allow certain chars e.g. a plus followed by numeric digits, and cap at max valid length.
strictMode: true,
};
const toString = (val: unknown): string => JSON.stringify(val);
const isPlainObject = (val: unknown): val is Record<string, unknown> =>
Boolean(val) && typeof val === "object" && !Array.isArray(val);
const isFunction = (val: unknown): val is (...args: unknown[]) => unknown =>
typeof val === "function";
const isElLike = (val: unknown): val is HTMLElement => {
if (!val || typeof val !== "object") {
return false;
}
const v = val as any;
return (
v.nodeType === 1 &&
typeof v.tagName === "string" &&
typeof v.appendChild === "function"
);
};
const placeholderPolicySet = new Set<string>(Object.values(PLACEHOLDER_POLICY));
const slotSet = new Set<string>(ITI_SLOTS);
const warn = (message: string): void => {
console.warn(`[intl-tel-input] ${message}`);
};
const warnOption = (
optionName: string,
expectedType: string,
actualValue: unknown,
): void => {
warn(
`Option '${optionName}' must be ${expectedType}; got ${toString(actualValue)}. Ignoring.`,
);
};
const validateIso2Array = (key: string, value: unknown): string[] | false => {
const expectedType = "an array of iso2 country code strings";
if (!Array.isArray(value)) {
warnOption(key, expectedType, value);
return false;
}
const valid: string[] = [];
for (const v of value) {
if (typeof v !== "string") {
warnOption(key, expectedType, value);
return false;
}
const lower = v.toLowerCase();
if (!isIso2(lower)) {
warn(`Invalid iso2 code in '${key}': '${v}'. Skipping.`);
} else {
valid.push(v);
}
}
return valid;
};
/**
* Validate runtime init options
*/
export const validateOptions = (customOptions: unknown): SomeOptions => {
if (customOptions === undefined) {
return {};
}
if (!isPlainObject(customOptions)) {
const error = `The second argument must be an options object; got ${toString(customOptions)}. Using defaults.`;
warn(error);
return {};
}
const validatedOptions: Record<string, unknown> = {};
for (const [key, value] of Object.entries(customOptions)) {
// Check option exists
if (!Object.hasOwn(defaults, key)) {
warn(`Unknown option '${key}'. Ignoring.`);
continue;
}
switch (key) {
case "allowNumberExtensions":
case "allowPhonewords":
case "countrySearch":
case "dropdownAlwaysOpen":
case "matchDropdownWidth":
case "formatAsYouType":
case "showFlags":
case "separateDialCode":
case "strictMode":
case "strictRejectAnimation":
if (typeof value !== "boolean") {
warnOption(key, "a boolean", value);
break;
}
validatedOptions[key] = value;
break;
case "countrySelectorMode":
if (
typeof value !== "string" ||
!(COUNTRY_SELECTOR_MODES as readonly string[]).includes(value)
) {
warnOption(
"countrySelectorMode",
`one of ${COUNTRY_SELECTOR_MODES.map((m) => `"${m}"`).join(", ")}`,
value,
);
break;
}
validatedOptions[key] = value;
break;
case "numberDisplayFormat":
if (
typeof value !== "string" ||
value === NUMBER_FORMAT.RFC3966 ||
!(value === NUMBER_FORMAT.E164 ||
value === NUMBER_FORMAT.INTERNATIONAL ||
value === NUMBER_FORMAT.NATIONAL)
) {
warnOption(
"numberDisplayFormat",
'one of "E164", "INTERNATIONAL", "NATIONAL"',
value,
);
break;
}
validatedOptions[key] = value;
break;
case "placeholderNumberPolicy":
if (typeof value !== "string" || !placeholderPolicySet.has(value)) {
const validPolicies = Array.from(placeholderPolicySet).join(", ");
warnOption("placeholderNumberPolicy", `one of ${validPolicies}`, value);
break;
}
validatedOptions[key] = value;
break;
case "containerClass":
case "searchInputClass":
case "countryNameLocale":
if (typeof value !== "string") {
warnOption(key, "a string", value);
break;
}
validatedOptions[key] = value;
break;
case "classNames": {
if (!isPlainObject(value)) {
warnOption("classNames", "an object", value);
break;
}
//* Drop unknown slots and non-string values, so a typo is loud rather than silent.
const validSlots: Record<string, string> = {};
for (const [slot, slotValue] of Object.entries(value)) {
if (!slotSet.has(slot)) {
warn(
`Unknown slot '${slot}' in 'classNames'. Valid slots: ${ITI_SLOTS.join(", ")}. Skipping.`,
);
} else if (typeof slotValue !== "string") {
warnOption(`classNames.${slot}`, "a string", slotValue);
} else {
//* Normalise whitespace, so consumers can be untidy, and we can safely split on single spaces.
validSlots[slot] = slotValue.trim().replace(/\s+/g, " ");
}
}
validatedOptions[key] = validSlots;
break;
}
case "countryOrder": {
if (value === null) {
validatedOptions[key] = value;
} else {
const filtered = validateIso2Array(key, value);
if (filtered !== false) {
validatedOptions[key] = filtered;
}
}
break;
}
case "customPlaceholder":
case "hiddenInputs":
case "initialCountryLookup":
case "loadUtils":
if (value !== null && !isFunction(value)) {
warnOption(key, "a function or null", value);
break;
}
validatedOptions[key] = value;
break;
case "dropdownParent":
if (value !== null && !isElLike(value)) {
warnOption("dropdownParent", "an HTMLElement or null", value);
break;
}
validatedOptions[key] = value;
break;
case "excludeCountries":
case "onlyCountries": {
if (value === null) {
validatedOptions[key] = value;
} else {
const filtered = validateIso2Array(key, value);
if (filtered !== false) {
validatedOptions[key] = filtered;
}
}
break;
}
case "uiTranslations":
if (value && !isPlainObject(value)) {
warnOption("uiTranslations", "an object", value);
break;
}
// don't bother validating the shape of the object, as the standard use is to just pass in one of the provided locale objects.
validatedOptions[key] = value;
break;
case "countryNameOverrides":
if (value && !isPlainObject(value)) {
warnOption("countryNameOverrides", "an object", value);
break;
}
validatedOptions[key] = value;
break;
case "initialCountry": {
if (typeof value !== "string") {
warnOption("initialCountry", "a string", value);
break;
}
const lower = value.toLowerCase();
if (lower && !isIso2(lower)) {
warnOption("initialCountry", "a valid iso2 country code", value);
break;
}
validatedOptions[key] = value;
break;
}
case "placeholderNumberType":
if (
typeof value !== "string" ||
!(NUMBER_TYPES as readonly string[]).includes(value)
) {
const validTypes = NUMBER_TYPES.join(", ");
warnOption("placeholderNumberType", `one of ${validTypes}`, value);
break;
}
validatedOptions[key] = value;
break;
case "allowedNumberTypes":
if (value !== null) {
if (!Array.isArray(value)) {
warnOption(
"allowedNumberTypes",
"an array of number types or null",
value,
);
break;
}
let allValid = true;
for (const v of value as unknown[]) {
if (
typeof v !== "string" ||
!(NUMBER_TYPES as readonly string[]).includes(v)
) {
const validTypes = NUMBER_TYPES.join(", ");
warnOption(
"allowedNumberTypes",
`an array of valid number types (${validTypes})`,
v,
);
allValid = false;
break;
}
}
if (allValid) {
// include it (even if empty)
validatedOptions[key] = value;
}
} else {
validatedOptions[key] = null;
}
break;
}
}
return validatedOptions as SomeOptions;
};
// Normalise option values so downstream code doesn't have to (mutates the passed object).
export const normaliseOptions = (o: AllOptions): void => {
//* Lowercase all iso2 codes so consumers can compare directly.
if (o.initialCountry) {
o.initialCountry = o.initialCountry.toLowerCase() as Iso2 | "";
}
if (o.onlyCountries?.length) {
o.onlyCountries = o.onlyCountries.map((c) => c.toLowerCase() as Iso2);
}
if (o.excludeCountries?.length) {
o.excludeCountries = o.excludeCountries.map((c) => c.toLowerCase() as Iso2);
}
if (o.countryOrder) {
o.countryOrder = o.countryOrder.map((c) => c.toLowerCase() as Iso2);
}
};
// Apply option side-effects (mutates the passed object)
export const applyOptionSideEffects = (o: AllOptions): void => {
//* Resolve "AUTO" to a concrete mode based on the current viewport. Downstream code only ever sees "OFF", "DROPDOWN", or "FULLSCREEN".
if (o.countrySelectorMode === COUNTRY_SELECTOR_MODE.AUTO) {
o.countrySelectorMode = resolveAutoCountrySelectorMode();
}
//* dropdownAlwaysOpen requires the dropdown rendering (fullscreen popup doesn't support always-open, and we need the country selector to exist).
if (o.dropdownAlwaysOpen) {
o.countrySelectorMode = COUNTRY_SELECTOR_MODE.DROPDOWN;
}
//* If showing fullscreen popup, do not fix the width.
if (o.countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN) {
o.matchDropdownWidth = false;
} else {
// if fullscreen popup disabled for whatever reason, but it's still a narrow screen (so full width dropdown wont fit), then the best UX is to fix dropdown width to input width.
if (isNarrowViewport()) {
o.matchDropdownWidth = true;
}
}
//* If theres only one country, then use it!
if (o.onlyCountries?.length === 1) {
o.initialCountry = o.onlyCountries[0];
}
//* When separateDialCode enabled, NATIONAL display is contradictory (the dial code is supposed to be thought of as part of the typed number), so force INTERNATIONAL.
if (o.separateDialCode && o.numberDisplayFormat === NUMBER_FORMAT.NATIONAL) {
o.numberDisplayFormat = NUMBER_FORMAT.INTERNATIONAL;
}
// if there is a country selector, but no flags and no separate dial code, then it suggests that there are multiple countries to choose from, but no way to see which one is currently selected, so we force INTERNATIONAL display, as it doesn't make sense to show a national number placeholder if there's no way to see which country is selected
if (
o.countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF &&
!o.showFlags &&
!o.separateDialCode &&
o.numberDisplayFormat === NUMBER_FORMAT.NATIONAL
) {
o.numberDisplayFormat = NUMBER_FORMAT.INTERNATIONAL;
}
//* Allow overriding the default interface strings.
o.uiTranslations = { ...defaultEnglishStrings, ...o.uiTranslations };
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,168 +0,0 @@
import allCountries, { type Country, type Iso2 } from "../data.js";
import type { AllOptions } from "../types/public-api.js";
export interface ProcessedDialCodes {
dialCodes: Set<string>;
dialCodeMaxLength: number;
dialCodeToIso2Map: Record<string, Iso2[]>;
}
//* Process onlyCountries or excludeCountries array if present.
export const processAllCountries = (options: AllOptions): Country[] => {
const { onlyCountries, excludeCountries } = options;
if (onlyCountries?.length) {
return allCountries.filter((country) =>
onlyCountries.includes(country.iso2),
);
} else if (excludeCountries?.length) {
return allCountries.filter(
(country) => !excludeCountries.includes(country.iso2),
);
}
//* Create new array so avoid a bug where multiple instances with different countryOrder options interfere with each other (as they were sharing the same allCountries array, which is mutated by sortCountries).
return [...allCountries];
};
//* Generate country names using Intl.DisplayNames
export const generateCountryNames = (
countries: Country[],
options: AllOptions,
): void => {
const { countryNameLocale, countryNameOverrides, uiTranslations } = options;
//* Some locales (e.g. bs, hy, is, mk, sq, uz) bundle their own country names
//* because certain browsers' Intl.DisplayNames lacks region data for them and
//* silently falls back to English (notably Chrome desktop). When the active
//* uiTranslations carries these, they take precedence over Intl.DisplayNames.
const bundledCountryNames = uiTranslations?.countryNames;
//* Populate country names using Intl.DisplayNames (per instance) with countryNameLocale.
let displayNames;
try {
const hasDisplayNames =
typeof Intl !== "undefined" &&
typeof (Intl as any).DisplayNames === "function";
if (hasDisplayNames) {
displayNames = new (Intl as any).DisplayNames(countryNameLocale, {
type: "region",
});
} else {
displayNames = null;
}
} catch (e) {
console.error(e);
displayNames = null;
}
for (const c of countries) {
c.name =
countryNameOverrides[c.iso2] ||
bundledCountryNames?.[c.iso2] ||
displayNames?.of(c.iso2.toUpperCase()) ||
"";
}
};
//* Generate dialCodes and dialCodeToIso2Map.
export const processDialCodes = (
countries: Country[],
): ProcessedDialCodes => {
//* Here we store just dial codes, where the key is the dial code, and the value is true
//* e.g. { 1: true, 7: true, 20: true, ... }.
const dialCodes = new Set<string>();
let dialCodeMaxLength = 0;
//* Here we map dialCodes (inc both dialCode and dialCode+areaCode) to iso2 codes e.g.
/*
* {
* 1: [ 'us', 'ca', ... ], # all NANP countries (with dial code "1")
* 12: [ 'us', 'ca', ... ], # subset of NANP countries (that have area codes starting with "2")
* 120: [ 'us', 'ca' ], # just US and Canada (that have area codes starting "20")
* 1204: [ 'ca' ], # only Canada (that has a "204" area code)
* ...
* }
*/
const dialCodeToIso2Map: Record<string, Iso2[]> = {};
//* Add a dial code to this.dialCodeToIso2Map.
const addToDialCodeMap = (iso2: Iso2, dialCode: string) => {
// Bail if no iso2 or dialCode (this can happen with onlyCountries or excludeCountries options).
if (!iso2 || !dialCode) {
return;
}
//* Update dialCodeMaxLength.
if (dialCode.length > dialCodeMaxLength) {
dialCodeMaxLength = dialCode.length;
}
//* If this entry doesn't already exist, then create it.
if (!Object.hasOwn(dialCodeToIso2Map, dialCode)) {
dialCodeToIso2Map[dialCode] = [];
}
const iso2List = dialCodeToIso2Map[dialCode];
//* Bail if we already have this country for this dialCode.
if (iso2List.includes(iso2)) {
return;
}
iso2List.push(iso2);
};
// Sort countries by priority so that when we add to the dialCodeToIso2Map, higher priority countries come first
const countriesSortedByPriority = [...countries].sort(
(a, b) => a.priority - b.priority,
);
for (const c of countriesSortedByPriority) {
if (!dialCodes.has(c.dialCode)) {
dialCodes.add(c.dialCode);
}
// add the dial code partial matches to the map
for (let k = 1; k < c.dialCode.length; k++) {
const partialDialCode = c.dialCode.substring(0, k);
addToDialCodeMap(c.iso2, partialDialCode);
}
// add the full dial code to the map
addToDialCodeMap(c.iso2, c.dialCode);
if (c.areaCodes) {
const rootIso2Code = dialCodeToIso2Map[c.dialCode][0];
//* For each area code.
for (const areaCode of c.areaCodes) {
//* Add partial matches: For each digit in the area code
for (let k = 1; k < areaCode.length; k++) {
const partialAreaCode = areaCode.substring(0, k);
const partialDialCode = c.dialCode + partialAreaCode;
//* Start with the root country, as that also matches this partial dial code.
addToDialCodeMap(rootIso2Code, partialDialCode);
addToDialCodeMap(c.iso2, partialDialCode);
}
//* Add the full area code.
addToDialCodeMap(c.iso2, c.dialCode + areaCode);
}
}
}
return { dialCodes, dialCodeMaxLength, dialCodeToIso2Map };
};
//* Sort countries by countryOrder option (if present), then name.
export const sortCountries = (
countries: Country[],
options: AllOptions,
): void => {
const { countryOrder } = options;
countries.sort((a: Country, b: Country): number => {
//* Primary sort: countryOrder option
if (countryOrder) {
const aIndex = countryOrder.indexOf(a.iso2);
const bIndex = countryOrder.indexOf(b.iso2);
const aIndexExists = aIndex > -1;
const bIndexExists = bIndex > -1;
if (aIndexExists || bIndexExists) {
if (aIndexExists && bIndexExists) {
return aIndex - bIndex;
}
return aIndexExists ? -1 : 1;
}
}
//* Secondary sort: country name
return a.name.localeCompare(b.name);
});
};

View File

@@ -1,20 +0,0 @@
import { getNumeric } from "../helpers/string.js";
// Non-geographic / regionless international dial codes that should always be
// treated as international numbers (no associated iso2 country).
// e.g. +800 is the Universal International Freephone Service (UIFS), which is not associated with any country
export const regionlessDialCodes: Set<string> = new Set([
"800",
"808",
"870",
"881",
"882",
"883",
"888",
"979",
]);
export const hasRegionlessDialCode = (number: string): boolean => {
const dialCode = getNumeric(number).slice(0, 3);
return number.startsWith("+") && regionlessDialCodes.has(dialCode);
};

View File

@@ -1,37 +0,0 @@
import { DIAL_CODE } from "../constants.js";
import { getNumeric } from "../helpers/string.js";
// NANP (North American Numbering Plan) countries (e.g. USA, Canada, and many more) use +1 as their international dial code
//* https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
// e.g. +1800 is a toll-free number, which can be used across NANP countries and is not associated with any specific country
// NOTE: this export is used in the tests!
export const regionlessNanpAreaCodes = new Set([
"800",
"822",
"833",
"844",
"855",
"866",
"877",
"880",
"881",
"882",
"883",
"884",
"885",
"886",
"887",
"888",
"889",
]);
//* Check if the given number is a regionless NANP number (expects the number to contain an international dial code)
export const isRegionlessNanp = (number: string): boolean => {
const numeric = getNumeric(number);
if (numeric.startsWith(DIAL_CODE.NANP) && numeric.length >= 4) {
const areaCode = numeric.substring(1, 4);
return regionlessNanpAreaCodes.has(areaCode);
}
return false;
};

View File

@@ -1,32 +0,0 @@
//* Iterate through the formattedValue until hit the right number of relevant chars.
export const computeNewCaretPosition = (
relevantChars: number,
formattedValue: string,
prevCaretPos: number,
isDeleteForwards: boolean,
): number => {
//* If the first char is a formatting char, and they backspace delete it:
//* Cursor should stay at the start (pos 0), rather than stick to the first digit (pos 1).
if (prevCaretPos === 0 && !isDeleteForwards) {
return 0;
}
let relevantCharCount = 0;
for (let i = 0; i < formattedValue.length; i++) {
//* Count this as a relevant char if it's a + or a digit.
if (/[+0-9]/.test(formattedValue[i])) {
relevantCharCount++;
}
//* Normal case: stop when you hit the right number of relevant chars
//* (cursor will be just after the final relevant char).
if (relevantCharCount === relevantChars && !isDeleteForwards) {
return i + 1;
}
//* Special case: delete forwards (fn + delete on a mac):
//* Wait until hit one extra relevant char, and put the cursor just before it (after any formatting chars).
if (isDeleteForwards && relevantCharCount === relevantChars + 1) {
return i;
}
}
return formattedValue.length;
};

View File

@@ -1,48 +0,0 @@
import type { ItiUtils, SelectedCountry } from "../types/public-api.js";
//* Remove the dial code if separateDialCode is enabled
export const stripSeparateDialCode = (
fullNumber: string,
hasValidDialCode: boolean,
separateDialCode: boolean,
selectedCountry: SelectedCountry,
): string => {
if (!separateDialCode || !hasValidDialCode) {
return fullNumber;
}
//* In case getDialCode returned an area code as well.
const dialCode = `+${selectedCountry!.dialCode}`;
//* a lot of numbers will have a space separating the dial code and the main number, and
//* some NANP numbers will have a hyphen e.g. +1 684-733-1234 - in both cases we want to get rid of it.
//* NOTE: Don't just trim all non-numerics as may want to preserve an open parenthesis etc.
const start =
fullNumber[dialCode.length] === " " || fullNumber[dialCode.length] === "-"
? dialCode.length + 1
: dialCode.length;
return fullNumber.substring(start);
};
//* Format the number as the user types.
export const formatNumberAsYouType = (
fullNumber: string,
telInputValue: string,
utils: ItiUtils | undefined,
selectedCountry: SelectedCountry,
separateDialCode: boolean,
): string => {
const result = utils
? utils.formatNumberAsYouType(fullNumber, selectedCountry?.iso2)
: fullNumber;
//* If separateDialCode and they haven't (re)typed the dial code in the input as well, then remove the dial code.
const dialCode = selectedCountry?.dialCode;
if (
separateDialCode &&
telInputValue.charAt(0) !== "+" &&
result.includes(`+${dialCode}`)
) {
const afterDialCode = result.split(`+${dialCode}`)[1] || "";
return afterDialCode.trim();
}
return result;
};

View File

@@ -1,26 +0,0 @@
/**
* Build a space-delimited class string from an object map of className -> truthy/falsey.
* Only keys with truthy values are included.
*/
export const buildClassNames = (flags: Record<string, unknown>): string =>
Object.keys(flags)
.filter((k) => Boolean(flags[k]))
.join(" ");
//* Create a DOM element.
export const createEl = (
tagName: string,
attrs?: object | null,
container?: HTMLElement,
): HTMLElement => {
const el = document.createElement(tagName);
if (attrs) {
Object.entries(attrs).forEach(([key, value]) =>
el.setAttribute(key, value),
);
}
if (container) {
container.appendChild(el);
}
return el;
};

View File

@@ -1,10 +0,0 @@
//* Extract the numeric digits from the given string (\D matches any non-digit).
export const getNumeric = (s: string): string => s.replace(/\D/g, "");
//* Normalise string: turns "Réunion" into "Reunion".
//* from https://stackoverflow.com/a/37511463
export const normaliseString = (s: string = ""): string =>
s
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
import intlTelInput from "./intlTelInput.js";
import utils from "utils-compiled";
intlTelInput.utils = utils;
export default intlTelInput;

View File

@@ -1,34 +0,0 @@
//* Arabic. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"تغيير الدولة لرقم الهاتف، المحددة ${countryName} (${dialCode})",
noCountrySelected: "اختر دولة لرقم الهاتف",
countryListAriaLabel: "قائمة الدول",
searchPlaceholder: "بحث",
clearSearchAriaLabel: "مسح البحث",
searchEmptyState: "لم يتم العثور على نتائج",
searchSummaryAria(count) {
if (count === 0) {
return "لم يتم العثور على نتائج";
}
if (count === 1) {
return "تم العثور على نتيجة واحدة";
}
if (count === 2) {
return "تم العثور على نتيجتين";
}
// Numbers ending in 3-10
if (count % 100 >= 3 && count % 100 <= 10) {
return `تم العثور على ${count} نتائج`;
}
return `تم العثور على ${count} نتيجة`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Bulgarian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Промени държавата за телефонен номер, избрана ${countryName} (${dialCode})",
noCountrySelected: "Избери държава за телефонен номер",
countryListAriaLabel: "Списък на страните",
searchPlaceholder: "Търсене",
clearSearchAriaLabel: "Изчистване на търсенето",
searchEmptyState: "Няма намерени резултати",
searchSummaryAria(count) {
if (count === 0) {
return "Няма намерени резултати";
}
if (count === 1) {
return "Намерен е 1 резултат";
}
return `${count} намерени резултата`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Bengali. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"ফোন নম্বরের জন্য দেশ পরিবর্তন করুন, নির্বাচিত ${countryName} (${dialCode})",
noCountrySelected: "ফোন নম্বরের জন্য দেশ নির্বাচন করুন",
countryListAriaLabel: "দেশের তালিকা",
searchPlaceholder: "অনুসন্ধান করুন",
clearSearchAriaLabel: "অনুসন্ধান পরিষ্কার করুন",
searchEmptyState: "কোন ফলাফল পাওয়া যায়নি",
searchSummaryAria(count) {
if (count === 0) {
return "কোন ফলাফল পাওয়া যায়নি";
}
if (count === 1) {
return "1টি ফলাফল পাওয়া গেছে";
}
return `${count} ফলাফল পাওয়া গেছে`;
},
};
export default interfaceTranslations;

View File

@@ -1,37 +0,0 @@
//* Bosnian. Translated by: Harun Sabljaković (sabljak) */
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/bs.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Promijeni zemlju za telefonski broj, izabrano ${countryName} (${dialCode})",
noCountrySelected: "Odaberi zemlju za telefonski broj",
countryListAriaLabel: "Lista zemalja",
searchPlaceholder: "Pretraži",
clearSearchAriaLabel: "Očisti pretragu",
searchEmptyState: "Nema pronađenih rezultata",
searchSummaryAria(count) {
if (count === 0) {
return "Nema pronađenih rezultata";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Pronađen ${count} rezultat`;
}
// Numbers ending in 2-4, but not 12-14
const isFew = mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14);
if (isFew) {
return `Pronađena ${count} rezultata`;
}
return `Pronađeno ${count} rezultata`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,24 +0,0 @@
//* Catalan. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Canvia el país per al número de telèfon, seleccionat ${countryName} (${dialCode})",
noCountrySelected: "Selecciona el país per al número de telèfon",
countryListAriaLabel: "Llista de països",
searchPlaceholder: "Cerca",
clearSearchAriaLabel: "Esborra la cerca",
searchEmptyState: "Sense resultats",
searchSummaryAria(count) {
if (count === 0) {
return "Sense resultats";
}
if (count === 1) {
return "1 resultat trobat";
}
return `${count} resultats trobats`;
},
};
export default interfaceTranslations;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "bs", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Afganistan",
ax: "Olandska ostrva",
al: "Albanija",
dz: "Alžir",
as: "Američka Samoa",
ad: "Andora",
ao: "Angola",
ai: "Angvila",
ag: "Antigva i Barbuda",
ar: "Argentina",
am: "Armenija",
aw: "Aruba",
ac: "Ostrvo Ascension",
au: "Australija",
at: "Austrija",
az: "Azerbejdžan",
bs: "Bahami",
bh: "Bahrein",
bd: "Bangladeš",
bb: "Barbados",
by: "Bjelorusija",
be: "Belgija",
bz: "Belize",
bj: "Benin",
bm: "Bermuda",
bt: "Butan",
bo: "Bolivija",
ba: "Bosna i Hercegovina",
bw: "Bocvana",
br: "Brazil",
io: "Britanska Teritorija u Indijskom Okeanu",
vg: "Britanska Djevičanska ostrva",
bn: "Brunej",
bg: "Bugarska",
bf: "Burkina Faso",
bi: "Burundi",
kh: "Kambodža",
cm: "Kamerun",
ca: "Kanada",
cv: "Zelenortska Ostrva",
bq: "Karipska Holandija",
ky: "Kajmanska ostrva",
cf: "Centralnoafrička Republika",
td: "Čad",
cl: "Čile",
cn: "Kina",
cx: "Božićno ostrvo",
cc: "Kokosova (Keelingova) ostrva",
co: "Kolumbija",
km: "Komori",
cg: "Kongo",
cd: "Demokratska Republika Kongo",
ck: "Kukova ostrva",
cr: "Kostarika",
ci: "Obala Slonovače",
hr: "Hrvatska",
cu: "Kuba",
cw: "Kurasao",
cy: "Kipar",
cz: "Češka",
dk: "Danska",
dj: "Džibuti",
dm: "Dominika",
do: "Dominikanska Republika",
ec: "Ekvador",
eg: "Egipat",
sv: "Salvador",
gq: "Ekvatorijalna Gvineja",
er: "Eritreja",
ee: "Estonija",
sz: "Esvatini",
et: "Etiopija",
fk: "Folklandska ostrva",
fo: "Farska ostrva",
fj: "Fidži",
fi: "Finska",
fr: "Francuska",
gf: "Francuska Gvajana",
pf: "Francuska Polinezija",
ga: "Gabon",
gm: "Gambija",
ge: "Gruzija",
de: "Njemačka",
gh: "Gana",
gi: "Gibraltar",
gr: "Grčka",
gl: "Grenland",
gd: "Grenada",
gp: "Gvadalupe",
gu: "Guam",
gt: "Gvatemala",
gg: "Guernsey",
gn: "Gvineja",
gw: "Gvineja-Bisao",
gy: "Gvajana",
ht: "Haiti",
hn: "Honduras",
hk: "Hong Kong (SAR Kina)",
hu: "Mađarska",
is: "Island",
in: "Indija",
id: "Indonezija",
ir: "Iran",
iq: "Irak",
ie: "Irska",
im: "Ostrvo Man",
il: "Izrael",
it: "Italija",
jm: "Jamajka",
jp: "Japan",
je: "Jersey",
jo: "Jordan",
kz: "Kazahstan",
ke: "Kenija",
ki: "Kiribati",
xk: "Kosovo",
kw: "Kuvajt",
kg: "Kirgistan",
la: "Laos",
lv: "Latvija",
lb: "Liban",
ls: "Lesoto",
lr: "Liberija",
ly: "Libija",
li: "Lihtenštajn",
lt: "Litvanija",
lu: "Luksemburg",
mo: "Makao (SAR Kina)",
mg: "Madagaskar",
mw: "Malavi",
my: "Malezija",
mv: "Maldivi",
ml: "Mali",
mt: "Malta",
mh: "Maršalova ostrva",
mq: "Martinik",
mr: "Mauritanija",
mu: "Mauricijus",
yt: "Majote",
mx: "Meksiko",
fm: "Mikronezija",
md: "Moldavija",
mc: "Monako",
mn: "Mongolija",
me: "Crna Gora",
ms: "Monserat",
ma: "Maroko",
mz: "Mozambik",
mm: "Mijanmar",
na: "Namibija",
nr: "Nauru",
np: "Nepal",
nl: "Nizozemska",
nc: "Nova Kaledonija",
nz: "Novi Zeland",
ni: "Nikaragva",
ne: "Niger",
ng: "Nigerija",
nu: "Niue",
nf: "Ostrvo Norfolk",
kp: "Sjeverna Koreja",
mk: "Sjeverna Makedonija",
mp: "Sjeverna Marijanska ostrva",
no: "Norveška",
om: "Oman",
pk: "Pakistan",
pw: "Palau",
ps: "Palestinska Teritorija",
pa: "Panama",
pg: "Papua Nova Gvineja",
py: "Paragvaj",
pe: "Peru",
ph: "Filipini",
pl: "Poljska",
pt: "Portugal",
pr: "Porto Riko",
qa: "Katar",
re: "Reunion",
ro: "Rumunija",
ru: "Rusija",
rw: "Ruanda",
ws: "Samoa",
sm: "San Marino",
st: "Sao Tome i Principe",
sa: "Saudijska Arabija",
sn: "Senegal",
rs: "Srbija",
sc: "Sejšeli",
sl: "Sijera Leone",
sg: "Singapur",
sx: "Sint Marten",
sk: "Slovačka",
si: "Slovenija",
sb: "Solomonska Ostrva",
so: "Somalija",
za: "Južnoafrička Republika",
kr: "Južna Koreja",
ss: "Južni Sudan",
es: "Španija",
lk: "Šri Lanka",
bl: "Sveti Bartolomej",
sh: "Sveta Helena",
kn: "Sveti Kits i Nevis",
lc: "Sveta Lucija",
mf: "Sveti Martin",
pm: "Sveti Petar i Mikelon",
vc: "Sveti Vinsent i Grenadin",
sd: "Sudan",
sr: "Surinam",
sj: "Svalbard i Jan Mayen",
se: "Švedska",
ch: "Švicarska",
sy: "Sirija",
tw: "Tajvan",
tj: "Tadžikistan",
tz: "Tanzanija",
th: "Tajland",
tl: "Istočni Timor",
tg: "Togo",
tk: "Tokelau",
to: "Tonga",
tt: "Trinidad i Tobago",
tn: "Tunis",
tr: "Turska",
tm: "Turkmenistan",
tc: "Ostrva Turks i Kaikos",
tv: "Tuvalu",
vi: "Američka Djevičanska ostrva",
ug: "Uganda",
ua: "Ukrajina",
ae: "Ujedinjeni Arapski Emirati",
gb: "Ujedinjeno Kraljevstvo",
us: "Sjedinjene Države",
uy: "Urugvaj",
uz: "Uzbekistan",
vu: "Vanuatu",
va: "Vatikan",
ve: "Venecuela",
vn: "Vijetnam",
wf: "Ostrva Valis i Futuna",
eh: "Zapadna Sahara",
ye: "Jemen",
zm: "Zambija",
zw: "Zimbabve",
};
export default countryNames;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "hy", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Աֆղանստան",
ax: "Ալանդյան կղզիներ",
al: "Ալբանիա",
dz: "Ալժիր",
as: "Ամերիկյան Սամոա",
ad: "Անդորրա",
ao: "Անգոլա",
ai: "Անգուիլա",
ag: "Անտիգուա և Բարբուդա",
ar: "Արգենտինա",
am: "Հայաստան",
aw: "Արուբա",
ac: "Համբարձման կղզի",
au: "Ավստրալիա",
at: "Ավստրիա",
az: "Ադրբեջան",
bs: "Բահամյան կղզիներ",
bh: "Բահրեյն",
bd: "Բանգլադեշ",
bb: "Բարբադոս",
by: "Բելառուս",
be: "Բելգիա",
bz: "Բելիզ",
bj: "Բենին",
bm: "Բերմուդներ",
bt: "Բութան",
bo: "Բոլիվիա",
ba: "Բոսնիա և Հերցեգովինա",
bw: "Բոտսվանա",
br: "Բրազիլիա",
io: "Բրիտանական տարածք Հնդկական Օվկիանոսում",
vg: "Բրիտանական Վիրջինյան կղզիներ",
bn: "Բրունեյ",
bg: "Բուլղարիա",
bf: "Բուրկինա Ֆասո",
bi: "Բուրունդի",
kh: "Կամբոջա",
cm: "Կամերուն",
ca: "Կանադա",
cv: "Կաբո Վերդե",
bq: "Կարիբյան Նիդեռլանդներ",
ky: "Կայմանյան կղզիներ",
cf: "Կենտրոնական Աֆրիկյան Հանրապետություն",
td: "Չադ",
cl: "Չիլի",
cn: "Չինաստան",
cx: "Սուրբ Ծննդյան կղզի",
cc: "Կոկոսյան (Քիլինգ) կղզիներ",
co: "Կոլումբիա",
km: "Կոմորյան կղզիներ",
cg: "Կոնգո - Բրազավիլ",
cd: "Կոնգո - Կինշասա",
ck: "Կուկի կղզիներ",
cr: "Կոստա Ռիկա",
ci: "Կոտ դ՚Իվուար",
hr: "Խորվաթիա",
cu: "Կուբա",
cw: "Կյուրասաո",
cy: "Կիպրոս",
cz: "Չեխիա",
dk: "Դանիա",
dj: "Ջիբութի",
dm: "Դոմինիկա",
do: "Դոմինիկյան Հանրապետություն",
ec: "Էկվադոր",
eg: "Եգիպտոս",
sv: "Սալվադոր",
gq: "Հասարակածային Գվինեա",
er: "Էրիթրեա",
ee: "Էստոնիա",
sz: "Էսվատինի",
et: "Եթովպիա",
fk: "Ֆոլքլենդյան կղզիներ",
fo: "Ֆարերյան կղզիներ",
fj: "Ֆիջի",
fi: "Ֆինլանդիա",
fr: "Ֆրանսիա",
gf: "Ֆրանսիական Գվիանա",
pf: "Ֆրանսիական Պոլինեզիա",
ga: "Գաբոն",
gm: "Գամբիա",
ge: "Վրաստան",
de: "Գերմանիա",
gh: "Գանա",
gi: "Ջիբրալթար",
gr: "Հունաստան",
gl: "Գրենլանդիա",
gd: "Գրենադա",
gp: "Գվադելուպա",
gu: "Գուամ",
gt: "Գվատեմալա",
gg: "Գերնսի",
gn: "Գվինեա",
gw: "Գվինեա-Բիսաու",
gy: "Գայանա",
ht: "Հայիթի",
hn: "Հոնդուրաս",
hk: "Հոնկոնգի ՀՎՇ",
hu: "Հունգարիա",
is: "Իսլանդիա",
in: "Հնդկաստան",
id: "Ինդոնեզիա",
ir: "Իրան",
iq: "Իրաք",
ie: "Իռլանդիա",
im: "Մեն կղզի",
il: "Իսրայել",
it: "Իտալիա",
jm: "Ճամայկա",
jp: "Ճապոնիա",
je: "Ջերսի",
jo: "Հորդանան",
kz: "Ղազախստան",
ke: "Քենիա",
ki: "Կիրիբատի",
xk: "Կոսովո",
kw: "Քուվեյթ",
kg: "Ղրղզստան",
la: "Լաոս",
lv: "Լատվիա",
lb: "Լիբանան",
ls: "Լեսոտո",
lr: "Լիբերիա",
ly: "Լիբիա",
li: "Լիխտենշտեյն",
lt: "Լիտվա",
lu: "Լյուքսեմբուրգ",
mo: "Չինաստանի Մակաո ՀՎՇ",
mg: "Մադագասկար",
mw: "Մալավի",
my: "Մալայզիա",
mv: "Մալդիվներ",
ml: "Մալի",
mt: "Մալթա",
mh: "Մարշալյան կղզիներ",
mq: "Մարտինիկա",
mr: "Մավրիտանիա",
mu: "Մավրիկիոս",
yt: "Մայոտ",
mx: "Մեքսիկա",
fm: "Միկրոնեզիա",
md: "Մոլդովա",
mc: "Մոնակո",
mn: "Մոնղոլիա",
me: "Չեռնոգորիա",
ms: "Մոնսեռատ",
ma: "Մարոկկո",
mz: "Մոզամբիկ",
mm: "Մյանմա (Բիրմա)",
na: "Նամիբիա",
nr: "Նաուրու",
np: "Նեպալ",
nl: "Նիդեռլանդներ",
nc: "Նոր Կալեդոնիա",
nz: "Նոր Զելանդիա",
ni: "Նիկարագուա",
ne: "Նիգեր",
ng: "Նիգերիա",
nu: "Նիուե",
nf: "Նորֆոլկ կղզի",
kp: "Հյուսիսային Կորեա",
mk: "Հյուսիսային Մակեդոնիա",
mp: "Հյուսիսային Մարիանյան կղզիներ",
no: "Նորվեգիա",
om: "Օման",
pk: "Պակիստան",
pw: "Պալաու",
ps: "Պաղեստինյան տարածքներ",
pa: "Պանամա",
pg: "Պապուա Նոր Գվինեա",
py: "Պարագվայ",
pe: "Պերու",
ph: "Ֆիլիպիններ",
pl: "Լեհաստան",
pt: "Պորտուգալիա",
pr: "Պուերտո Ռիկո",
qa: "Կատար",
re: "Ռեյունիոն",
ro: "Ռումինիա",
ru: "Ռուսաստան",
rw: "Ռուանդա",
ws: "Սամոա",
sm: "Սան Մարինո",
st: "Սան Տոմե և Փրինսիպի",
sa: "Սաուդյան Արաբիա",
sn: "Սենեգալ",
rs: "Սերբիա",
sc: "Սեյշելներ",
sl: "Սիեռա Լեոնե",
sg: "Սինգապուր",
sx: "Սինտ Մարտեն",
sk: "Սլովակիա",
si: "Սլովենիա",
sb: "Սողոմոնյան կղզիներ",
so: "Սոմալի",
za: "Հարավաֆրիկյան Հանրապետություն",
kr: "Հարավային Կորեա",
ss: "Հարավային Սուդան",
es: "Իսպանիա",
lk: "Շրի Լանկա",
bl: "Սուրբ Բարդուղիմեոս",
sh: "Սուրբ Հեղինեի կղզի",
kn: "Սենթ Քիտս և Նևիս",
lc: "Սենթ Լյուսիա",
mf: "Սեն Մարտեն",
pm: "Սեն Պիեռ և Միքելոն",
vc: "Սենթ Վինսենթ և Գրենադիններ",
sd: "Սուդան",
sr: "Սուրինամ",
sj: "Սվալբարդ և Յան Մայեն",
se: "Շվեդիա",
ch: "Շվեյցարիա",
sy: "Սիրիա",
tw: "Թայվան",
tj: "Տաջիկստան",
tz: "Տանզանիա",
th: "Թաիլանդ",
tl: "Թիմոր Լեշտի",
tg: "Տոգո",
tk: "Տոկելաու",
to: "Տոնգա",
tt: "Տրինիդադ և Տոբագո",
tn: "Թունիս",
tr: "Թուրքիա",
tm: "Թուրքմենստան",
tc: "Թըրքս և Կայկոս կղզիներ",
tv: "Տուվալու",
vi: "ԱՄՆ Վիրջինյան կղզիներ",
ug: "Ուգանդա",
ua: "Ուկրաինա",
ae: "Արաբական Միացյալ Էմիրություններ",
gb: "Միացյալ Թագավորություն",
us: "Միացյալ Նահանգներ",
uy: "Ուրուգվայ",
uz: "Ուզբեկստան",
vu: "Վանուատու",
va: "Վատիկան",
ve: "Վենեսուելա",
vn: "Վիետնամ",
wf: "Ուոլիս և Ֆուտունա",
eh: "Արևմտյան Սահարա",
ye: "Եմեն",
zm: "Զամբիա",
zw: "Զիմբաբվե",
};
export default countryNames;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "is", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Afganistan",
ax: "Álandseyjar",
al: "Albanía",
dz: "Alsír",
as: "Bandaríska Samóa",
ad: "Andorra",
ao: "Angóla",
ai: "Angvilla",
ag: "Antígva og Barbúda",
ar: "Argentína",
am: "Armenía",
aw: "Arúba",
ac: "Ascension-eyja",
au: "Ástralía",
at: "Austurríki",
az: "Aserbaídsjan",
bs: "Bahamaeyjar",
bh: "Barein",
bd: "Bangladess",
bb: "Barbados",
by: "Hvíta-Rússland",
be: "Belgía",
bz: "Belís",
bj: "Benín",
bm: "Bermúdaeyjar",
bt: "Bútan",
bo: "Bólivía",
ba: "Bosnía og Hersegóvína",
bw: "Botsvana",
br: "Brasilía",
io: "Bresku Indlandshafseyjar",
vg: "Bresku Jómfrúaeyjar",
bn: "Brúnei",
bg: "Búlgaría",
bf: "Búrkína Fasó",
bi: "Búrúndí",
kh: "Kambódía",
cm: "Kamerún",
ca: "Kanada",
cv: "Grænhöfðaeyjar",
bq: "Karíbahafshluti Hollands",
ky: "Caymaneyjar",
cf: "Mið-Afríkulýðveldið",
td: "Tsjad",
cl: "Síle",
cn: "Kína",
cx: "Jólaey",
cc: "Kókoseyjar (Keeling)",
co: "Kólumbía",
km: "Kómoreyjar",
cg: "Kongó-Brazzaville",
cd: "Kongó-Kinshasa",
ck: "Cooks-eyjar",
cr: "Kostaríka",
ci: "Fílabeinsströndin",
hr: "Króatía",
cu: "Kúba",
cw: "Curacao",
cy: "Kýpur",
cz: "Tékkland",
dk: "Danmörk",
dj: "Djíbútí",
dm: "Dóminíka",
do: "Dóminíska lýðveldið",
ec: "Ekvador",
eg: "Egyptaland",
sv: "El Salvador",
gq: "Miðbaugs-Gínea",
er: "Erítrea",
ee: "Eistland",
sz: "Esvatíní",
et: "Eþíópía",
fk: "Falklandseyjar",
fo: "Færeyjar",
fj: "Fídjíeyjar",
fi: "Finnland",
fr: "Frakkland",
gf: "Franska Gvæjana",
pf: "Franska Pólýnesía",
ga: "Gabon",
gm: "Gambía",
ge: "Georgía",
de: "Þýskaland",
gh: "Gana",
gi: "Gíbraltar",
gr: "Grikkland",
gl: "Grænland",
gd: "Grenada",
gp: "Gvadelúpeyjar",
gu: "Gvam",
gt: "Gvatemala",
gg: "Guernsey",
gn: "Gínea",
gw: "Gínea-Bissá",
gy: "Gvæjana",
ht: "Haítí",
hn: "Hondúras",
hk: "sérstjórnarsvæðið Hong Kong",
hu: "Ungverjaland",
is: "Ísland",
in: "Indland",
id: "Indónesía",
ir: "Íran",
iq: "Írak",
ie: "Írland",
im: "Mön",
il: "Ísrael",
it: "Ítalía",
jm: "Jamaíka",
jp: "Japan",
je: "Jersey",
jo: "Jórdanía",
kz: "Kasakstan",
ke: "Kenía",
ki: "Kíribatí",
xk: "Kósóvó",
kw: "Kúveit",
kg: "Kirgistan",
la: "Laos",
lv: "Lettland",
lb: "Líbanon",
ls: "Lesótó",
lr: "Líbería",
ly: "Líbía",
li: "Liechtenstein",
lt: "Litháen",
lu: "Lúxemborg",
mo: "sérstjórnarsvæðið Makaó",
mg: "Madagaskar",
mw: "Malaví",
my: "Malasía",
mv: "Maldíveyjar",
ml: "Malí",
mt: "Malta",
mh: "Marshalleyjar",
mq: "Martiník",
mr: "Máritanía",
mu: "Máritíus",
yt: "Mayotte",
mx: "Mexíkó",
fm: "Míkrónesía",
md: "Moldóva",
mc: "Mónakó",
mn: "Mongólía",
me: "Svartfjallaland",
ms: "Montserrat",
ma: "Marokkó",
mz: "Mósambík",
mm: "Mjanmar (Búrma)",
na: "Namibía",
nr: "Nárú",
np: "Nepal",
nl: "Holland",
nc: "Nýja-Kaledónía",
nz: "Nýja-Sjáland",
ni: "Níkaragva",
ne: "Níger",
ng: "Nígería",
nu: "Niue",
nf: "Norfolkeyja",
kp: "Norður-Kórea",
mk: "Norður-Makedónía",
mp: "Norður-Maríanaeyjar",
no: "Noregur",
om: "Óman",
pk: "Pakistan",
pw: "Palá",
ps: "Heimastjórnarsvæði Palestínumanna",
pa: "Panama",
pg: "Papúa Nýja-Gínea",
py: "Paragvæ",
pe: "Perú",
ph: "Filippseyjar",
pl: "Pólland",
pt: "Portúgal",
pr: "Púertó Ríkó",
qa: "Katar",
re: "Réunion",
ro: "Rúmenía",
ru: "Rússland",
rw: "Rúanda",
ws: "Samóa",
sm: "San Marínó",
st: "Saó Tóme og Prinsípe",
sa: "Sádi-Arabía",
sn: "Senegal",
rs: "Serbía",
sc: "Seychelles-eyjar",
sl: "Síerra Leóne",
sg: "Singapúr",
sx: "Sint Maarten",
sk: "Slóvakía",
si: "Slóvenía",
sb: "Salómonseyjar",
so: "Sómalía",
za: "Suður-Afríka",
kr: "Suður-Kórea",
ss: "Suður-Súdan",
es: "Spánn",
lk: "Srí Lanka",
bl: "Sankti Bartólómeusareyjar",
sh: "Sankti Helena",
kn: "Sankti Kitts og Nevis",
lc: "Sankti Lúsía",
mf: "Saint-Martin",
pm: "Sankti Pierre og Miquelon",
vc: "Sankti Vinsent og Grenadíneyjar",
sd: "Súdan",
sr: "Súrínam",
sj: "Svalbarði og Jan Mayen",
se: "Svíþjóð",
ch: "Sviss",
sy: "Sýrland",
tw: "Taívan",
tj: "Tadsíkistan",
tz: "Tansanía",
th: "Taíland",
tl: "Tímor-Leste",
tg: "Tógó",
tk: "Tókelá",
to: "Tonga",
tt: "Trínidad og Tóbagó",
tn: "Túnis",
tr: "Tyrkland",
tm: "Túrkmenistan",
tc: "Turks- og Caicoseyjar",
tv: "Túvalú",
vi: "Bandarísku Jómfrúaeyjar",
ug: "Úganda",
ua: "Úkraína",
ae: "Sameinuðu arabísku furstadæmin",
gb: "Bretland",
us: "Bandaríkin",
uy: "Úrúgvæ",
uz: "Úsbekistan",
vu: "Vanúatú",
va: "Vatíkanið",
ve: "Venesúela",
vn: "Víetnam",
wf: "Wallis- og Fútúnaeyjar",
eh: "Vestur-Sahara",
ye: "Jemen",
zm: "Sambía",
zw: "Simbabve",
};
export default countryNames;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "mk", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Авганистан",
ax: "Оландски Острови",
al: "Албанија",
dz: "Алжир",
as: "Американска Самоа",
ad: "Андора",
ao: "Ангола",
ai: "Ангвила",
ag: "Антига и Барбуда",
ar: "Аргентина",
am: "Ерменија",
aw: "Аруба",
ac: "Остров Асенсион",
au: "Австралија",
at: "Австрија",
az: "Азербејџан",
bs: "Бахами",
bh: "Бахреин",
bd: "Бангладеш",
bb: "Барбадос",
by: "Белорусија",
be: "Белгија",
bz: "Белизе",
bj: "Бенин",
bm: "Бермуди",
bt: "Бутан",
bo: "Боливија",
ba: "Босна и Херцеговина",
bw: "Боцвана",
br: "Бразил",
io: "Британска Индоокеанска Територија",
vg: "Британски Девствени Острови",
bn: "Брунеј",
bg: "Бугарија",
bf: "Буркина Фасо",
bi: "Бурунди",
kh: "Камбоџа",
cm: "Камерун",
ca: "Канада",
cv: "Кабо Верде",
bq: "Карипска Холандија",
ky: "Кајмански Острови",
cf: "Централноафриканска Република",
td: "Чад",
cl: "Чиле",
cn: "Кина",
cx: "Божиќен Остров",
cc: "Кокосови (Килиншки) Острови",
co: "Колумбија",
km: "Коморски Острови",
cg: "Конго - Бразавил",
cd: "Конго - Киншаса",
ck: "Кукови Острови",
cr: "Костарика",
ci: "Брегот на Слоновата Коска",
hr: "Хрватска",
cu: "Куба",
cw: "Курасао",
cy: "Кипар",
cz: "Чешка",
dk: "Данска",
dj: "Џибути",
dm: "Доминика",
do: "Доминиканска Република",
ec: "Еквадор",
eg: "Египет",
sv: "Ел Салвадор",
gq: "Екваторска Гвинеја",
er: "Еритреја",
ee: "Естонија",
sz: "Есватини",
et: "Етиопија",
fk: "Фолкландски Острови",
fo: "Фарски Острови",
fj: "Фиџи",
fi: "Финска",
fr: "Франција",
gf: "Француска Гвајана",
pf: "Француска Полинезија",
ga: "Габон",
gm: "Гамбија",
ge: "Грузија",
de: "Германија",
gh: "Гана",
gi: "Гибралтар",
gr: "Грција",
gl: "Гренланд",
gd: "Гренада",
gp: "Гвадалупе",
gu: "Гуам",
gt: "Гватемала",
gg: "Гернзи",
gn: "Гвинеја",
gw: "Гвинеја Бисао",
gy: "Гвајана",
ht: "Хаити",
hn: "Хондурас",
hk: "Хонгконг САР Кина",
hu: "Унгарија",
is: "Исланд",
in: "Индија",
id: "Индонезија",
ir: "Иран",
iq: "Ирак",
ie: "Ирска",
im: "Остров Ман",
il: "Израел",
it: "Италија",
jm: "Јамајка",
jp: "Јапонија",
je: "Џерси",
jo: "Јордан",
kz: "Казахстан",
ke: "Кенија",
ki: "Кирибати",
xk: "Косово",
kw: "Кувајт",
kg: "Киргистан",
la: "Лаос",
lv: "Латвија",
lb: "Либан",
ls: "Лесото",
lr: "Либерија",
ly: "Либија",
li: "Лихтенштајн",
lt: "Литванија",
lu: "Луксембург",
mo: "Макао САР",
mg: "Мадагаскар",
mw: "Малави",
my: "Малезија",
mv: "Малдиви",
ml: "Мали",
mt: "Малта",
mh: "Маршалски Острови",
mq: "Мартиник",
mr: "Мавританија",
mu: "Маврициус",
yt: "Мајот",
mx: "Мексико",
fm: "Микронезија",
md: "Молдавија",
mc: "Монако",
mn: "Монголија",
me: "Црна Гора",
ms: "Монсерат",
ma: "Мароко",
mz: "Мозамбик",
mm: "Мјанмар (Бурма)",
na: "Намибија",
nr: "Науру",
np: "Непал",
nl: "Холандија",
nc: "Нова Каледонија",
nz: "Нов Зеланд",
ni: "Никарагва",
ne: "Нигер",
ng: "Нигерија",
nu: "Ниује",
nf: "Норфолшки Остров",
kp: "Северна Кореја",
mk: "Северна Македонија",
mp: "Северни Маријански Острови",
no: "Норвешка",
om: "Оман",
pk: "Пакистан",
pw: "Палау",
ps: "Палестински Територии",
pa: "Панама",
pg: "Папуа Нова Гвинеја",
py: "Парагвај",
pe: "Перу",
ph: "Филипини",
pl: "Полска",
pt: "Португалија",
pr: "Порторико",
qa: "Катар",
re: "Рејунион",
ro: "Романија",
ru: "Русија",
rw: "Руанда",
ws: "Самоа",
sm: "Сан Марино",
st: "Саун Томе и Принсип",
sa: "Саудиска Арабија",
sn: "Сенегал",
rs: "Србија",
sc: "Сејшели",
sl: "Сиера Леоне",
sg: "Сингапур",
sx: "Свети Мартин",
sk: "Словачка",
si: "Словенија",
sb: "Соломонски Острови",
so: "Сомалија",
za: "Јужноафриканска Република",
kr: "Јужна Кореја",
ss: "Јужен Судан",
es: "Шпанија",
lk: "Шри Ланка",
bl: "Свети Вартоломеј",
sh: "Света Елена",
kn: "Свети Китс и Невис",
lc: "Сент Лусија",
mf: "Сент Мартин",
pm: "Сент Пјер и Микелан",
vc: "Сент Винсент и Гренадини",
sd: "Судан",
sr: "Суринам",
sj: "Свалбард и Јан Мајен",
se: "Шведска",
ch: "Швајцарија",
sy: "Сирија",
tw: "Тајван",
tj: "Таџикистан",
tz: "Танзанија",
th: "Тајланд",
tl: "Тимор Лесте",
tg: "Того",
tk: "Токелау",
to: "Тонга",
tt: "Тринидад и Тобаго",
tn: "Тунис",
tr: "Турција",
tm: "Туркменистан",
tc: "Острови Туркс и Каикос",
tv: "Тувалу",
vi: "Американски Девствени Острови",
ug: "Уганда",
ua: "Украина",
ae: "Обединети Арапски Емирати",
gb: "Обединето Кралство",
us: "Соединети Американски Држави",
uy: "Уругвај",
uz: "Узбекистан",
vu: "Вануату",
va: "Ватикан",
ve: "Венецуела",
vn: "Виетнам",
wf: "Валис и Футуна",
eh: "Западна Сахара",
ye: "Јемен",
zm: "Замбија",
zw: "Зимбабве",
};
export default countryNames;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "sq", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Afganistan",
ax: "Ishujt Alandë",
al: "Shqipëri",
dz: "Algjeri",
as: "Samoa Amerikane",
ad: "Andorrë",
ao: "Angolë",
ai: "Anguilë",
ag: "Antigua e Barbuda",
ar: "Argjentinë",
am: "Armeni",
aw: "Arubë",
ac: "Ishulli Asenshion",
au: "Australi",
at: "Austri",
az: "Azerbajxhan",
bs: "Bahama",
bh: "Bahrejn",
bd: "Bangladesh",
bb: "Barbados",
by: "Bjellorusi",
be: "Belgjikë",
bz: "Belizë",
bj: "Benin",
bm: "Bermude",
bt: "Butan",
bo: "Bolivi",
ba: "Bosnjë-Hercegovinë",
bw: "Botsvanë",
br: "Brazil",
io: "Territori Britanik i Oqeanit Indian",
vg: "Ishujt e Virgjër Britanikë",
bn: "Brunei",
bg: "Bullgari",
bf: "Burkina-Faso",
bi: "Burundi",
kh: "Kamboxhia",
cm: "Kamerun",
ca: "Kanada",
cv: "Kepi i Gjelbër",
bq: "Karaibet holandeze",
ky: "Ishujt Kajman",
cf: "Republika e Afrikës Qendrore",
td: "Çad",
cl: "Kili",
cn: "Kinë",
cx: "Ishulli i Krishtlindjes",
cc: "Ishujt Kokos",
co: "Kolumbi",
km: "Komore",
cg: "Kongo-Brazavilë",
cd: "Kongo-Kinshasa",
ck: "Ishujt Kuk",
cr: "Kosta-Rikë",
ci: "Côte dIvoire",
hr: "Kroaci",
cu: "Kubë",
cw: "Kurasao",
cy: "Qipro",
cz: "Çeki",
dk: "Danimarkë",
dj: "Xhibuti",
dm: "Dominikë",
do: "Republika Dominikane",
ec: "Ekuador",
eg: "Egjipt",
sv: "Salvador",
gq: "Guineja Ekuatoriale",
er: "Eritre",
ee: "Estoni",
sz: "Esvatini",
et: "Etiopi",
fk: "Ishujt Falkland",
fo: "Ishujt Faroe",
fj: "Fixhi",
fi: "Finlandë",
fr: "Francë",
gf: "Guajana Franceze",
pf: "Polinezia Franceze",
ga: "Gabon",
gm: "Gambi",
ge: "Gjeorgji",
de: "Gjermani",
gh: "Ganë",
gi: "Gjibraltar",
gr: "Greqi",
gl: "Grënlandë",
gd: "Granadë",
gp: "Guadelupë",
gu: "Guam",
gt: "Guatemalë",
gg: "Gernsej",
gn: "Guine",
gw: "Guine-Bisau",
gy: "Guajanë",
ht: "Haiti",
hn: "Honduras",
hk: "RPA i Hong-Kongut",
hu: "Hungari",
is: "Islandë",
in: "Indi",
id: "Indonezi",
ir: "Iran",
iq: "Irak",
ie: "Irlandë",
im: "Ishulli i Manit",
il: "Izrael",
it: "Itali",
jm: "Xhamajkë",
jp: "Japoni",
je: "Xhersej",
jo: "Jordani",
kz: "Kazakistan",
ke: "Kenia",
ki: "Kiribati",
xk: "Kosovë",
kw: "Kuvajt",
kg: "Kirgizi",
la: "Laos",
lv: "Letoni",
lb: "Liban",
ls: "Lesoto",
lr: "Liberi",
ly: "Libi",
li: "Lihtenshtajn",
lt: "Lituani",
lu: "Luksemburg",
mo: "RPA i Makaos",
mg: "Madagaskar",
mw: "Malavi",
my: "Malajzi",
mv: "Maldive",
ml: "Mali",
mt: "Maltë",
mh: "Ishujt Marshall",
mq: "Martinikë",
mr: "Mauritani",
mu: "Mauritius",
yt: "Majotë",
mx: "Meksikë",
fm: "Mikronezi",
md: "Moldavi",
mc: "Monako",
mn: "Mongoli",
me: "Mal i Zi",
ms: "Montserat",
ma: "Marok",
mz: "Mozambik",
mm: "Mianmar (Burmë)",
na: "Namibi",
nr: "Nauru",
np: "Nepal",
nl: "Holandë",
nc: "Kaledoni e Re",
nz: "Zelandë e Re",
ni: "Nikaragua",
ne: "Niger",
ng: "Nigeri",
nu: "Niue",
nf: "Ishulli Norfolk",
kp: "Kore e Veriut",
mk: "Maqedonia e Veriut",
mp: "Ishujt e Marianës Veriore",
no: "Norvegji",
om: "Oman",
pk: "Pakistan",
pw: "Palau",
ps: "Territoret Palestineze",
pa: "Panama",
pg: "Guineja e Re-Papua",
py: "Paraguai",
pe: "Peru",
ph: "Filipine",
pl: "Poloni",
pt: "Portugali",
pr: "Porto-Riko",
qa: "Katar",
re: "Reunion",
ro: "Rumani",
ru: "Rusi",
rw: "Ruandë",
ws: "Samoa",
sm: "San-Marino",
st: "Sao-Tome e Principe",
sa: "Arabi Saudite",
sn: "Senegal",
rs: "Serbi",
sc: "Sejshelle",
sl: "Sierra-Leone",
sg: "Singapor",
sx: "Sint-Marten",
sk: "Sllovaki",
si: "Slloveni",
sb: "Ishujt Solomon",
so: "Somali",
za: "Afrika e Jugut",
kr: "Kore e Jugut",
ss: "Sudani i Jugut",
es: "Spanjë",
lk: "Sri-Lankë",
bl: "Sen-Bartelemi",
sh: "Shën-Elenë",
kn: "Shën-Kits dhe Nevis",
lc: "Shën-Luçia",
mf: "Sen-Marten",
pm: "Shën-Pier dhe Mikelon",
vc: "Shën-Vincent dhe Grenadine",
sd: "Sudan",
sr: "Surinami",
sj: "Svalbard e Jan-Majen",
se: "Suedi",
ch: "Zvicër",
sy: "Siri",
tw: "Tajvan",
tj: "Taxhikistan",
tz: "Tanzani",
th: "Tajlandë",
tl: "Timor-Leste",
tg: "Togo",
tk: "Tokelau",
to: "Tonga",
tt: "Trinidad e Tobago",
tn: "Tunizi",
tr: "Turqi",
tm: "Turkmenistan",
tc: "Ishujt Turks dhe Kaikos",
tv: "Tuvalu",
vi: "Ishujt e Virgjër të SHBA-së",
ug: "Ugandë",
ua: "Ukrainë",
ae: "Emiratet e Bashkuara Arabe",
gb: "Mbretëria e Bashkuar",
us: "SHBA",
uy: "Uruguai",
uz: "Uzbekistan",
vu: "Vanuatu",
va: "Vatikan",
ve: "Venezuelë",
vn: "Vietnam",
wf: "Uollis e Futuna",
eh: "Saharaja Perëndimore",
ye: "Jemen",
zm: "Zambi",
zw: "Zimbabve",
};
export default countryNames;

View File

@@ -1,253 +0,0 @@
//* THIS FILE IS AUTO-GENERATED BY scripts/generate-country-names.js. DO NOT EDIT.
//* Fallback country names for "uz", for browsers whose Intl.DisplayNames
//* lacks region data for this locale (e.g. Chrome desktop falls back to English).
import type { Iso2 } from "../../data.js";
const countryNames: Partial<Record<Iso2, string>> = {
af: "Afgʻoniston",
ax: "Aland orollari",
al: "Albaniya",
dz: "Jazoir",
as: "Amerika Samoasi",
ad: "Andorra",
ao: "Angola",
ai: "Angilya",
ag: "Antigua va Barbuda",
ar: "Argentina",
am: "Armaniston",
aw: "Aruba",
ac: "Meroj oroli",
au: "Avstraliya",
at: "Avstriya",
az: "Ozarbayjon",
bs: "Bagama orollari",
bh: "Bahrayn",
bd: "Bangladesh",
bb: "Barbados",
by: "Belarus",
be: "Belgiya",
bz: "Beliz",
bj: "Benin",
bm: "Bermuda orollari",
bt: "Butan",
bo: "Boliviya",
ba: "Bosniya va Gertsegovina",
bw: "Botsvana",
br: "Braziliya",
io: "Britaniyaning Hind okeanidagi hududi",
vg: "Britaniya Virgin orollari",
bn: "Bruney",
bg: "Bolgariya",
bf: "Burkina-Faso",
bi: "Burundi",
kh: "Kambodja",
cm: "Kamerun",
ca: "Kanada",
cv: "Kabo-Verde",
bq: "Boneyr, Sint-Estatius va Saba",
ky: "Kayman orollari",
cf: "Markaziy Afrika Respublikasi",
td: "Chad",
cl: "Chili",
cn: "Xitoy",
cx: "Rojdestvo oroli",
cc: "Kokos (Kiling) orollari",
co: "Kolumbiya",
km: "Komor orollari",
cg: "Kongo Brazzavil",
cd: "Kongo Kinshasa",
ck: "Kuk orollari",
cr: "Kosta-Rika",
ci: "Kot-dIvuar",
hr: "Xorvatiya",
cu: "Kuba",
cw: "Kyurasao",
cy: "Kipr",
cz: "Chexiya",
dk: "Daniya",
dj: "Jibuti",
dm: "Dominika",
do: "Dominikan Respublikasi",
ec: "Ekvador",
eg: "Misr",
sv: "Salvador",
gq: "Ekvatorial Gvineya",
er: "Eritreya",
ee: "Estoniya",
sz: "Svazilend",
et: "Efiopiya",
fk: "Folklend orollari",
fo: "Farer orollari",
fj: "Fiji",
fi: "Finlandiya",
fr: "Fransiya",
gf: "Fransuz Gvianasi",
pf: "Fransuz Polineziyasi",
ga: "Gabon",
gm: "Gambiya",
ge: "Gruziya",
de: "Germaniya",
gh: "Gana",
gi: "Gibraltar",
gr: "Gretsiya",
gl: "Grenlandiya",
gd: "Grenada",
gp: "Gvadelupe",
gu: "Guam",
gt: "Gvatemala",
gg: "Gernsi",
gn: "Gvineya",
gw: "Gvineya-Bisau",
gy: "Gayana",
ht: "Gaiti",
hn: "Gonduras",
hk: "Gonkong (Xitoy MMH)",
hu: "Vengriya",
is: "Islandiya",
in: "Hindiston",
id: "Indoneziya",
ir: "Eron",
iq: "Iroq",
ie: "Irlandiya",
im: "Men oroli",
il: "Isroil",
it: "Italiya",
jm: "Yamayka",
jp: "Yaponiya",
je: "Jersi",
jo: "Iordaniya",
kz: "Qozogʻiston",
ke: "Keniya",
ki: "Kiribati",
xk: "Kosovo",
kw: "Quvayt",
kg: "Qirgʻiziston",
la: "Laos",
lv: "Latviya",
lb: "Livan",
ls: "Lesoto",
lr: "Liberiya",
ly: "Liviya",
li: "Lixtenshteyn",
lt: "Litva",
lu: "Lyuksemburg",
mo: "Makao (Xitoy MMH)",
mg: "Madagaskar",
mw: "Malavi",
my: "Malayziya",
mv: "Maldiv orollari",
ml: "Mali",
mt: "Malta",
mh: "Marshall orollari",
mq: "Martinika",
mr: "Mavritaniya",
mu: "Mavrikiy",
yt: "Mayotta",
mx: "Meksika",
fm: "Mikroneziya",
md: "Moldova",
mc: "Monako",
mn: "Mongoliya",
me: "Chernogoriya",
ms: "Montserrat",
ma: "Marokash",
mz: "Mozambik",
mm: "Myanma (Birma)",
na: "Namibiya",
nr: "Nauru",
np: "Nepal",
nl: "Niderlandiya",
nc: "Yangi Kaledoniya",
nz: "Yangi Zelandiya",
ni: "Nikaragua",
ne: "Niger",
ng: "Nigeriya",
nu: "Niue",
nf: "Norfolk oroli",
kp: "Shimoliy Koreya",
mk: "Shimoliy Makedoniya",
mp: "Shimoliy Mariana orollari",
no: "Norvegiya",
om: "Ummon",
pk: "Pokiston",
pw: "Palau",
ps: "Falastin hududlari",
pa: "Panama",
pg: "Papua Yangi Gvineya",
py: "Paragvay",
pe: "Peru",
ph: "Filippin",
pl: "Polsha",
pt: "Portugaliya",
pr: "Puerto-Riko",
qa: "Qatar",
re: "Reyunion",
ro: "Ruminiya",
ru: "Rossiya",
rw: "Ruanda",
ws: "Samoa",
sm: "San-Marino",
st: "San-Tome va Prinsipi",
sa: "Saudiya Arabistoni",
sn: "Senegal",
rs: "Serbiya",
sc: "Seyshel orollari",
sl: "Syerra-Leone",
sg: "Singapur",
sx: "Sint-Marten",
sk: "Slovakiya",
si: "Sloveniya",
sb: "Solomon orollari",
so: "Somali",
za: "Janubiy Afrika Respublikasi",
kr: "Janubiy Koreya",
ss: "Janubiy Sudan",
es: "Ispaniya",
lk: "Shri-Lanka",
bl: "Sen-Bartelemi",
sh: "Muqaddas Yelena oroli",
kn: "Sent-Kits va Nevis",
lc: "Sent-Lyusiya",
mf: "Sent-Martin",
pm: "Sen-Pyer va Mikelon",
vc: "Sent-Vinsent va Grenadin",
sd: "Sudan",
sr: "Surinam",
sj: "Shpitsbergen va Yan-Mayen",
se: "Shvetsiya",
ch: "Shveytsariya",
sy: "Suriya",
tw: "Tayvan",
tj: "Tojikiston",
tz: "Tanzaniya",
th: "Tailand",
tl: "Timor-Leste",
tg: "Togo",
tk: "Tokelau",
to: "Tonga",
tt: "Trinidad va Tobago",
tn: "Tunis",
tr: "Turkiya",
tm: "Turkmaniston",
tc: "Turks va Kaykos orollari",
tv: "Tuvalu",
vi: "AQSH Virgin orollari",
ug: "Uganda",
ua: "Ukraina",
ae: "Birlashgan Arab Amirliklari",
gb: "Buyuk Britaniya",
us: "Amerika Qoshma Shtatlari",
uy: "Urugvay",
uz: "Oʻzbekiston",
vu: "Vanuatu",
va: "Vatikan",
ve: "Venesuela",
vn: "Vyetnam",
wf: "Uollis va Futuna",
eh: "Garbiy Sahroi Kabir",
ye: "Yaman",
zm: "Zambiya",
zw: "Zimbabve",
};
export default countryNames;

View File

@@ -1,29 +0,0 @@
//* Czech. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Změnit zemi pro telefonní číslo, vybráno ${countryName} (${dialCode})",
noCountrySelected: "Vyberte zemi pro telefonní číslo",
countryListAriaLabel: "Seznam zemí",
searchPlaceholder: "Vyhledat",
clearSearchAriaLabel: "Vymazat vyhledávání",
searchEmptyState: "Nebyly nalezeny žádné výsledky",
searchSummaryAria(count) {
if (count === 0) {
return "Nebyly nalezeny žádné výsledky";
}
if (count === 1) {
return "Nalezen 1 výsledek";
}
if (count >= 2 && count <= 4) {
return `Nalezeny ${count} výsledky`;
}
return `Nalezeno ${count} výsledků`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Danish. Translated by: Matthias Dilger (matthiasdilger).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Skift land til telefonnummer, valgt ${countryName} (${dialCode})",
noCountrySelected: "Vælg land til telefonnummer",
countryListAriaLabel: "Liste over lande",
searchPlaceholder: "Søg",
clearSearchAriaLabel: "Ryd søgning",
searchEmptyState: "Ingen resultater fundet",
searchSummaryAria(count) {
if (count === 0) {
return "Ingen resultater fundet";
}
if (count === 1) {
return "1 resultat fundet";
}
return `${count} resultater fundet`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* German. Translated by: Jack O'Connor (jackocnr).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Land der Telefonnummer ändern, ausgewählt ${countryName} (${dialCode})",
noCountrySelected: "Land der Telefonnummer auswählen",
countryListAriaLabel: "Liste der Länder",
searchPlaceholder: "Suchen",
clearSearchAriaLabel: "Suche löschen",
searchEmptyState: "Keine Suchergebnisse",
searchSummaryAria(count) {
if (count === 0) {
return "Keine Suchergebnisse";
}
if (count === 1) {
return "1 Suchergebnis";
}
return `${count} Suchergebnisse`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Greek. Translated by: Anthony Veaudry (anthony0030).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Αλλαγή χώρας για τον αριθμό τηλεφώνου, επιλεγμένη ${countryName} (${dialCode})",
noCountrySelected: "Επιλέξτε χώρα για τον αριθμό τηλεφώνου",
countryListAriaLabel: "Κατάλογος χωρών",
searchPlaceholder: "Αναζήτηση",
clearSearchAriaLabel: "Εκκαθάριση αναζήτησης",
searchEmptyState: "Δεν βρέθηκαν αποτελέσματα",
searchSummaryAria(count) {
if (count === 0) {
return "Δεν βρέθηκαν αποτελέσματα";
}
if (count === 1) {
return "Βρέθηκε 1 αποτέλεσμα";
}
return `Βρέθηκαν ${count} αποτελέσματα`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* English. Translated by: Jack O'Connor (jackocnr).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Change country for phone number, currently selected ${countryName} (${dialCode})",
noCountrySelected: "Select country for phone number",
countryListAriaLabel: "List of countries",
searchPlaceholder: "Search",
clearSearchAriaLabel: "Clear search",
searchEmptyState: "No results found",
searchSummaryAria(count) {
if (count === 0) {
return "No results found";
}
if (count === 1) {
return "1 result found";
}
return `${count} results found`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Spanish. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Cambiar país para el número de teléfono, seleccionado ${countryName} (${dialCode})",
noCountrySelected: "Selecciona el país para el número de teléfono",
countryListAriaLabel: "Lista de países",
searchPlaceholder: "Buscar",
clearSearchAriaLabel: "Borrar búsqueda",
searchEmptyState: "No se han encontrado resultados",
searchSummaryAria(count) {
if (count === 0) {
return "No se han encontrado resultados";
}
if (count === 1) {
return "1 resultado encontrado";
}
return `${count} resultados encontrados`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Estonian. Translated by: Maksim Maksimov (4matic).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Muuda riiki telefoninumbri jaoks, valitud ${countryName} (${dialCode})",
noCountrySelected: "Vali riik telefoninumbri jaoks",
countryListAriaLabel: "Riikide nimekiri",
searchPlaceholder: "Otsi",
clearSearchAriaLabel: "Tühjenda otsing",
searchEmptyState: "Tulemusi ei leitud",
searchSummaryAria(count) {
if (count === 0) {
return "Tulemusi ei leitud";
}
if (count === 1) {
return "1 tulemus leitud";
}
return `${count} tulemust leitud`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Farsi/Persian. Translated by: Mahyar SBT (mahyarsbt).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"تغییر کشور برای شماره تلفن، انتخاب شده ${countryName} (${dialCode})",
noCountrySelected: "کشور را برای شماره تلفن انتخاب کنید",
countryListAriaLabel: "لیست کشورها",
searchPlaceholder: "جستجو",
clearSearchAriaLabel: "پاک کردن جستجو",
searchEmptyState: "هیچ نتیجه‌ای یافت نشد",
searchSummaryAria(count) {
if (count === 0) {
return "هیچ نتیجه‌ای یافت نشد";
}
return `${count} نتیجه یافت شد`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Finnish. Translated by: Michael Winton (mrwinton).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Vaihda maa puhelinnumeroa varten, valittu ${countryName} (${dialCode})",
noCountrySelected: "Valitse maa puhelinnumeroa varten",
countryListAriaLabel: "Luettelo maista",
searchPlaceholder: "Haku",
clearSearchAriaLabel: "Tyhjennä haku",
searchEmptyState: "Ei tuloksia",
searchSummaryAria(count) {
if (count === 0) {
return "Ei tuloksia";
}
if (count === 1) {
return "1 tulos löytyi";
}
return `${count} tulosta löytyi`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Filipino. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Baguhin ang bansa para sa numero ng telepono, napili ang ${countryName} (${dialCode})",
noCountrySelected: "Pumili ng bansa para sa numero ng telepono",
countryListAriaLabel: "Listahan ng mga bansa",
searchPlaceholder: "Maghanap",
clearSearchAriaLabel: "I-clear ang paghahanap",
searchEmptyState: "Walang nakitang resulta",
searchSummaryAria(count) {
if (count === 0) {
return "Walang nakitang resulta";
}
return `${count} resulta ang nakita`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* French. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Changer le pays du numéro de téléphone, sélectionné ${countryName} (${dialCode})",
noCountrySelected: "Sélectionnez le pays du numéro de téléphone",
countryListAriaLabel: "Liste des pays",
searchPlaceholder: "Recherche",
clearSearchAriaLabel: "Effacer la recherche",
searchEmptyState: "Aucun résultat trouvé",
searchSummaryAria(count) {
if (count === 0) {
return "Aucun résultat trouvé";
}
if (count === 1) {
return "1 résultat trouvé";
}
return `${count} résultats trouvés`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Hebrew. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"שנה מדינה עבור מספר הטלפון, נבחרה ${countryName} (${dialCode})",
noCountrySelected: "בחר מדינה עבור מספר הטלפון",
countryListAriaLabel: "רשימת מדינות",
searchPlaceholder: "חיפוש",
clearSearchAriaLabel: "נקה חיפוש",
searchEmptyState: "לא נמצאו תוצאות",
searchSummaryAria(count) {
if (count === 0) {
return "לא נמצאו תוצאות";
}
if (count === 1) {
return "נמצאה תוצאה אחת";
}
return `נמצאו ${count} תוצאות`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Hindi. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"फ़ोन नंबर के लिए देश बदलें, चयनित ${countryName} (${dialCode})",
noCountrySelected: "फ़ोन नंबर के लिए देश चुनें",
countryListAriaLabel: "देशों की सूची",
searchPlaceholder: "खोज",
clearSearchAriaLabel: "खोज साफ़ करें",
searchEmptyState: "कोई परिणाम नहीं मिला",
searchSummaryAria(count) {
if (count === 0) {
return "कोई परिणाम नहीं मिला";
}
if (count === 1) {
return "1 परिणाम मिला";
}
return `${count} परिणाम मिले`;
},
};
export default interfaceTranslations;

View File

@@ -1,36 +0,0 @@
//* Croatian. Translated by: Harun Sabljaković (sabljak) */
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Promijeni zemlju za telefonski broj, izabrano ${countryName} (${dialCode})",
noCountrySelected: "Odaberi zemlju za telefonski broj",
countryListAriaLabel: "Lista zemalja",
searchPlaceholder: "Pretraži",
clearSearchAriaLabel: "Očisti pretragu",
searchEmptyState: "Nema pronađenih rezultata",
searchSummaryAria(count) {
if (count === 0) {
return "Nema pronađenih rezultata";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Pronađen ${count} rezultat`;
}
// Numbers ending in 2-4, but not 12-14
const isFew = mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14);
if (isFew) {
return `Pronađena ${count} rezultata`;
}
return `Pronađeno ${count} rezultata`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Hungarian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Telefonszám országának módosítása, kiválasztva: ${countryName} (${dialCode})",
noCountrySelected: "Válassz országot a telefonszámhoz",
countryListAriaLabel: "Országok listája",
searchPlaceholder: "Keresés",
clearSearchAriaLabel: "Keresés törlése",
searchEmptyState: "Nincs találat",
searchSummaryAria(count) {
if (count === 0) {
return "Nincs találat";
}
return `${count} találat`;
},
};
export default interfaceTranslations;

View File

@@ -1,25 +0,0 @@
//* Armenian. Translated by: Claude.
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/hy.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Փոխել երկիրը հեռախոսահամարի համար, ընտրված է ${countryName} (${dialCode})",
noCountrySelected: "Ընտրեք երկիր հեռախոսահամարի համար",
countryListAriaLabel: "Երկրների ցանկ",
searchPlaceholder: "Որոնում",
clearSearchAriaLabel: "Մաքրել որոնումը",
searchEmptyState: "Արդյունքներ չեն գտնվել",
searchSummaryAria(count) {
if (count === 0) {
return "Արդյունքներ չեն գտնվել";
}
if (count === 1) {
return "Գտնվել է 1 արդյունք";
}
return `Գտնվել են ${count} արդյունք`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,21 +0,0 @@
//* Indonesian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Ubah negara untuk nomor telepon, dipilih ${countryName} (${dialCode})",
noCountrySelected: "Pilih negara untuk nomor telepon",
countryListAriaLabel: "Daftar negara",
searchPlaceholder: "Mencari",
clearSearchAriaLabel: "Hapus pencarian",
searchEmptyState: "Tidak ada hasil yang ditemukan",
searchSummaryAria(count) {
if (count === 0) {
return "Tidak ada hasil yang ditemukan";
}
return `${count} hasil ditemukan`;
},
};
export default interfaceTranslations;

View File

@@ -1,55 +0,0 @@
//* THIS FILE IS AUTO-GENERATED. DO NOT EDIT.
export { default as ar } from "./ar.js";
export { default as bg } from "./bg.js";
export { default as bn } from "./bn.js";
export { default as bs } from "./bs.js";
export { default as ca } from "./ca.js";
export { default as cs } from "./cs.js";
export { default as da } from "./da.js";
export { default as de } from "./de.js";
export { default as el } from "./el.js";
export { default as en } from "./en.js";
export { default as es } from "./es.js";
export { default as et } from "./et.js";
export { default as fa } from "./fa.js";
export { default as fi } from "./fi.js";
export { default as fil } from "./fil.js";
export { default as fr } from "./fr.js";
export { default as he } from "./he.js";
export { default as hi } from "./hi.js";
export { default as hr } from "./hr.js";
export { default as hu } from "./hu.js";
export { default as hy } from "./hy.js";
export { default as id } from "./id.js";
export { default as is } from "./is.js";
export { default as it } from "./it.js";
export { default as ja } from "./ja.js";
export { default as kn } from "./kn.js";
export { default as ko } from "./ko.js";
export { default as lt } from "./lt.js";
export { default as lv } from "./lv.js";
export { default as mk } from "./mk.js";
export { default as mr } from "./mr.js";
export { default as ms } from "./ms.js";
export { default as nl } from "./nl.js";
export { default as no } from "./no.js";
export { default as pl } from "./pl.js";
export { default as pt } from "./pt.js";
export { default as ro } from "./ro.js";
export { default as ru } from "./ru.js";
export { default as sk } from "./sk.js";
export { default as sl } from "./sl.js";
export { default as sq } from "./sq.js";
export { default as sr } from "./sr.js";
export { default as sv } from "./sv.js";
export { default as sw } from "./sw.js";
export { default as ta } from "./ta.js";
export { default as te } from "./te.js";
export { default as th } from "./th.js";
export { default as tr } from "./tr.js";
export { default as uk } from "./uk.js";
export { default as ur } from "./ur.js";
export { default as uz } from "./uz.js";
export { default as vi } from "./vi.js";
export { default as zh } from "./zh.js";
export { default as zhHk } from "./zh-hk.js";

View File

@@ -1,30 +0,0 @@
//* Icelandic. Translated by: Claude.
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/is.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Breyta landi fyrir símanúmer, valið ${countryName} (${dialCode})",
noCountrySelected: "Veldu land fyrir símanúmer",
countryListAriaLabel: "Listi yfir lönd",
searchPlaceholder: "Leita",
clearSearchAriaLabel: "Hreinsa leit",
searchEmptyState: "Engar niðurstöður fundust",
searchSummaryAria(count) {
if (count === 0) {
return "Engar niðurstöður fundust";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `${count} niðurstaða fannst`;
}
return `${count} niðurstöður fundust`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,24 +0,0 @@
//* Italian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Cambia il paese del numero di telefono, selezionato ${countryName} (${dialCode})",
noCountrySelected: "Seleziona il paese del numero di telefono",
countryListAriaLabel: "Elenco dei paesi",
searchPlaceholder: "Ricerca",
clearSearchAriaLabel: "Cancella ricerca",
searchEmptyState: "Nessun risultato trovato",
searchSummaryAria(count) {
if (count === 0) {
return "Nessun risultato trovato";
}
if (count === 1) {
return "1 risultato trovato";
}
return `${count} risultati trovati`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Japanese. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"電話番号の国を変更、選択中: ${countryName} (${dialCode})",
noCountrySelected: "電話番号の国を選択",
countryListAriaLabel: "国のリスト",
searchPlaceholder: "検索",
clearSearchAriaLabel: "検索をクリア",
searchEmptyState: "結果が見つかりません",
searchSummaryAria(count) {
if (count === 0) {
return "結果が見つかりません";
}
return `${count} 件の結果が見つかりました`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Kannada (ಕನ್ನಡ) Translated by: Mohammed Rashad Qadri (https://github.com/rashadmehtab)
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"ಫೋನ್ ಸಂಖ್ಯೆಗಾಗಿ ದೇಶವನ್ನು ಬದಲಾಯಿಸಿ, ಆಯ್ಕೆಯಾಗಿದೆ ${countryName} (${dialCode})",
noCountrySelected: "ಫೋನ್ ಸಂಖ್ಯೆಗಾಗಿ ದೇಶವನ್ನು ಆಯ್ಕೆಮಾಡಿ",
countryListAriaLabel: "ದೇಶಗಳ ಪಟ್ಟಿ",
searchPlaceholder: "ಹುಡುಕಿ",
clearSearchAriaLabel: "ಹುಡುಕಾಟ ಅಳಿಸಿ",
searchEmptyState: "ಯಾವುದೇ ಫಲಿತಾಂಶಗಳಿಲ್ಲ",
searchSummaryAria(count) {
if (count === 0) {
return "ಯಾವುದೇ ಫಲಿತಾಂಶಗಳಿಲ್ಲ";
}
if (count === 1) {
return "1 ಫಲಿತಾಂಶ ಕಂಡುಬಂದಿದೆ";
}
return `${count} ಫಲಿತಾಂಶಗಳು ಕಂಡುಬಂದಿವೆ`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Korean. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"전화번호 국가 변경, 선택됨: ${countryName} (${dialCode})",
noCountrySelected: "전화번호 국가 선택",
countryListAriaLabel: "국가 목록",
searchPlaceholder: "검색",
clearSearchAriaLabel: "검색 지우기",
searchEmptyState: "검색 결과가 없습니다",
searchSummaryAria(count) {
if (count === 0) {
return "검색 결과가 없습니다";
}
return `${count}개의 결과를 찾았습니다.`;
},
};
export default interfaceTranslations;

View File

@@ -1,38 +0,0 @@
//* Lithuanian. Translated by: ChatGPT 5.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Pakeisti šalį telefono numeriui, pasirinkta ${countryName} (${dialCode})",
noCountrySelected: "Pasirinkite šalį telefono numeriui",
countryListAriaLabel: "Šalių sąrašas",
searchPlaceholder: "Paieška",
clearSearchAriaLabel: "Išvalyti paiešką",
searchEmptyState: "Rezultatų nerasta",
searchSummaryAria(count) {
if (count === 0) {
return "Rezultatų nerasta";
}
if (count === 1) {
return "Rastas 1 rezultatas";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Rasti ${count} rezultatas`;
}
// Numbers ending in 2-9, but not 11-19
if (mod10 >= 2 && mod10 <= 9 && !(mod100 >= 11 && mod100 <= 19)) {
return `Rasti ${count} rezultatai`;
}
return `Rasta ${count} rezultatų`;
},
};
export default interfaceTranslations;

View File

@@ -1,34 +0,0 @@
//* Latvian. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Mainīt valsti tālruņa numuram, izvēlēta ${countryName} (${dialCode})",
noCountrySelected: "Izvēlieties valsti tālruņa numuram",
countryListAriaLabel: "Valstu saraksts",
searchPlaceholder: "Meklēt",
clearSearchAriaLabel: "Notīrīt meklēšanu",
searchEmptyState: "Rezultāti nav atrasti",
searchSummaryAria(count) {
if (count === 0) {
return "Rezultāti nav atrasti";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Atrasts ${count} rezultāts`;
}
// Numbers ending in 0, or 11-19
if (mod10 === 0 || (mod100 >= 11 && mod100 <= 19)) {
return `Atrasti ${count} rezultātu`;
}
return `Atrasti ${count} rezultāti`;
},
};
export default interfaceTranslations;

View File

@@ -1,30 +0,0 @@
//* Macedonian. Translated by: Claude.
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/mk.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Промени држава за телефонски број, избрана ${countryName} (${dialCode})",
noCountrySelected: "Избери држава за телефонски број",
countryListAriaLabel: "Листа на држави",
searchPlaceholder: "Пребарување",
clearSearchAriaLabel: "Исчисти пребарување",
searchEmptyState: "Нема резултати",
searchSummaryAria(count) {
if (count === 0) {
return "Нема резултати";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Пронајден е ${count} резултат`;
}
return `Пронајдени се ${count} резултати`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,24 +0,0 @@
//* Marathi. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"फोन नंबरसाठी देश बदला, निवडलेला ${countryName} (${dialCode})",
noCountrySelected: "फोन नंबरसाठी देश निवडा",
countryListAriaLabel: "देशांची यादी",
searchPlaceholder: "शोधा",
clearSearchAriaLabel: "शोध साफ करा",
searchEmptyState: "कोणतेही परिणाम आढळले नाहीत",
searchSummaryAria(count) {
if (count === 0) {
return "कोणतेही परिणाम आढळले नाहीत";
}
if (count === 1) {
return "1 परिणाम आढळला";
}
return `${count} परिणाम आढळले`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Malay. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Tukar negara untuk nombor telefon, dipilih ${countryName} (${dialCode})",
noCountrySelected: "Pilih negara untuk nombor telefon",
countryListAriaLabel: "Senarai negara",
searchPlaceholder: "Cari",
clearSearchAriaLabel: "Kosongkan carian",
searchEmptyState: "Tiada hasil ditemui",
searchSummaryAria(count) {
if (count === 0) {
return "Tiada hasil ditemui";
}
return `${count} hasil ditemui`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Dutch. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Land van telefoonnummer wijzigen, geselecteerd ${countryName} (${dialCode})",
noCountrySelected: "Selecteer land van telefoonnummer",
countryListAriaLabel: "Lijst met landen",
searchPlaceholder: "Zoekopdracht",
clearSearchAriaLabel: "Zoekopdracht wissen",
searchEmptyState: "Geen resultaten gevonden",
searchSummaryAria(count) {
if (count === 0) {
return "Geen resultaten gevonden";
}
if (count === 1) {
return "1 resultaat gevonden";
}
return `${count} resultaten gevonden`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Norwegian. Translated by: Eric Pastoor (epastoor) with help of google translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Endre land for telefonnummer, valgt ${countryName} (${dialCode})",
noCountrySelected: "Velg land for telefonnummer",
countryListAriaLabel: "Liste over land",
searchPlaceholder: "Søk",
clearSearchAriaLabel: "Tøm søk",
searchEmptyState: "Ingen resultater funnet",
searchSummaryAria(count) {
if (count === 0) {
return "Ingen resultater funnet";
}
if (count === 1) {
return "1 resultat funnet";
}
return `${count} resultater funnet`;
},
};
export default interfaceTranslations;

View File

@@ -1,34 +0,0 @@
//* Polish. Translated by: Mateusz Bronis (bronisMateusz) https://github.com/bronisMateusz.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Zmień kraj dla numeru telefonu, wybrano ${countryName} (${dialCode})",
noCountrySelected: "Wybierz kraj dla numeru telefonu",
countryListAriaLabel: "Lista krajów",
searchPlaceholder: "Szukaj",
clearSearchAriaLabel: "Wyczyść wyszukiwanie",
searchEmptyState: "Nie znaleziono wyników",
searchSummaryAria(count) {
if (count === 0) {
return "Nie znaleziono wyników";
}
if (count === 1) {
return "Znaleziono 1 wynik";
}
// Numbers ending with 2, 3, 4 (except those ending with 12, 13, 14) use "wyniki". All others use "wyników".
const isFew =
count % 10 >= 2 &&
count % 10 <= 4 &&
!(count % 100 >= 12 && count % 100 <= 14);
if (isFew) {
return `Znaleziono ${count} wyniki`;
}
return `Znaleziono ${count} wyników`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Portuguese. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Alterar país para o número de telefone, selecionado ${countryName} (${dialCode})",
noCountrySelected: "Selecionar país para o número de telefone",
countryListAriaLabel: "Lista de países",
searchPlaceholder: "Procurar",
clearSearchAriaLabel: "Limpar pesquisa",
searchEmptyState: "Nenhum resultado encontrado",
searchSummaryAria(count) {
if (count === 0) {
return "Nenhum resultado encontrado";
}
if (count === 1) {
return "1 resultado encontrado";
}
return `${count} resultados encontrados`;
},
};
export default interfaceTranslations;

View File

@@ -1,30 +0,0 @@
//* Romanian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Schimbă țara pentru numărul de telefon, selectată ${countryName} (${dialCode})",
noCountrySelected: "Selectează țara pentru numărul de telefon",
countryListAriaLabel: "Lista țărilor",
searchPlaceholder: "Căutare",
clearSearchAriaLabel: "Șterge căutarea",
searchEmptyState: "Nici un rezultat găsit",
searchSummaryAria(count) {
if (count === 0) {
return "Nici un rezultat găsit";
}
if (count === 1) {
return "1 rezultat găsit";
}
const isFew = count % 100 >= 1 && count % 100 <= 19;
if (isFew) {
return `${count} rezultate găsite`;
}
return `${count} de rezultate găsite`;
},
};
export default interfaceTranslations;

View File

@@ -1,35 +0,0 @@
//* Russian. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Изменить страну для номера телефона, выбрана ${countryName} (${dialCode})",
noCountrySelected: "Выберите страну для номера телефона",
countryListAriaLabel: "Список стран",
searchPlaceholder: "Поиск",
clearSearchAriaLabel: "Очистить поиск",
searchEmptyState: "результатов не найдено",
searchSummaryAria(count) {
if (count === 0) {
return "результатов не найдено";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `найден ${count} результат`;
}
// Numbers ending in 2-4, but not 12-14
const isFew = mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14);
if (isFew) {
return `Найдено ${count} результата`;
}
return `Найдено ${count} результатов`;
},
};
export default interfaceTranslations;

View File

@@ -1,27 +0,0 @@
//* Slovak. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Zmeniť krajinu pre telefónne číslo, vybraná ${countryName} (${dialCode})",
noCountrySelected: "Vyberte krajinu pre telefónne číslo",
countryListAriaLabel: "Zoznam krajín",
searchPlaceholder: "Vyhľadať",
clearSearchAriaLabel: "Vymazať vyhľadávanie",
searchEmptyState: "Neboli nájdené žiadne výsledky",
searchSummaryAria(count) {
if (count === 0) {
return "Neboli nájdené žiadne výsledky";
}
if (count === 1) {
return "1 výsledok nájdený";
}
if (count >= 2 && count <= 4) {
return `${count} výsledky nájdené`;
}
return `${count} výsledkov nájdených`;
},
};
export default interfaceTranslations;

View File

@@ -1,39 +0,0 @@
//* Slovenian. Translated by: ChatGPT 5.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Spremeni državo za telefonsko številko, izbrano ${countryName} (${dialCode})",
noCountrySelected: "Izberi državo za telefonsko številko",
countryListAriaLabel: "Seznam držav",
searchPlaceholder: "Išči",
clearSearchAriaLabel: "Počisti iskanje",
searchEmptyState: "Ni rezultatov",
searchSummaryAria(count) {
if (count === 0) {
return "Ni rezultatov";
}
// Slovenian pluralisation is determined by the last two digits
const mod100 = count % 100;
// Numbers ending in 01
if (mod100 === 1) {
return `Najden ${count} rezultat`;
}
// Numbers ending in 02
if (mod100 === 2) {
return `Najdena ${count} rezultata`;
}
// Numbers ending in 03 or 04
if (mod100 === 3 || mod100 === 4) {
return `Najdeni ${count} rezultati`;
}
return `Najdenih ${count} rezultatov`;
},
};
export default interfaceTranslations;

View File

@@ -1,25 +0,0 @@
//* Shqip (Albanian). Translated by: ChatGPT 5.
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/sq.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Ndrysho vendin për numrin e telefonit, i zgjedhur ${countryName} (${dialCode})",
noCountrySelected: "Zgjidh vendin për numrin e telefonit",
countryListAriaLabel: "Lista e vendeve",
searchPlaceholder: "Kërko",
clearSearchAriaLabel: "Pastro kërkimin",
searchEmptyState: "Nuk u gjet asnjë rezultat",
searchSummaryAria(count) {
if (count === 0) {
return "Nuk u gjet asnjë rezultat";
}
if (count === 1) {
return "U gjet 1 rezultat";
}
return `U gjetën ${count} rezultate`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,35 +0,0 @@
//* Serbian. Translated by: ChatGPT 5.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Промени земљу за телефонски број, изабрано ${countryName} (${dialCode})",
noCountrySelected: "Изабери земљу за телефонски број",
countryListAriaLabel: "Листа земаља",
searchPlaceholder: "Претрага",
clearSearchAriaLabel: "Обриши претрагу",
searchEmptyState: "Нема резултата",
searchSummaryAria(count) {
if (count === 0) {
return "Нема резултата";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Пронађен ${count} резултат`;
}
// Numbers ending in 2-4, but not 12-14
const isFew = mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14);
if (isFew) {
return `Пронађена ${count} резултата`;
}
return `Пронађено ${count} резултата`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Swedish. Translated by: Nhi Tran.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Byt land för telefonnummer, valt ${countryName} (${dialCode})",
noCountrySelected: "Välj land för telefonnummer",
countryListAriaLabel: "Lista över länder",
searchPlaceholder: "Sök",
clearSearchAriaLabel: "Rensa sökning",
searchEmptyState: "Inga resultat hittades",
searchSummaryAria(count) {
if (count === 0) {
return "Inga resultat hittades";
}
return `${count} resultat hittades`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Swahili. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Badilisha nchi kwa nambari ya simu, imechaguliwa ${countryName} (${dialCode})",
noCountrySelected: "Chagua nchi kwa nambari ya simu",
countryListAriaLabel: "Orodha ya nchi",
searchPlaceholder: "Tafuta",
clearSearchAriaLabel: "Futa utafutaji",
searchEmptyState: "Hakuna matokeo yaliyopatikana",
searchSummaryAria(count) {
if (count === 0) {
return "Hakuna matokeo yaliyopatikana";
}
if (count === 1) {
return "Tokeo 1 limepatikana";
}
return `Matokeo ${count} yamepatikana`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Tamil. Translated by: Claude.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"தொலைபேசி எண்ணுக்கு நாட்டை மாற்று, தேர்ந்தெடுக்கப்பட்டது ${countryName} (${dialCode})",
noCountrySelected: "தொலைபேசி எண்ணுக்கு நாட்டைத் தேர்ந்தெடுக்கவும்",
countryListAriaLabel: "நாடுகளின் பட்டியல்",
searchPlaceholder: "தேடு",
clearSearchAriaLabel: "தேடலை அழி",
searchEmptyState: "முடிவுகள் எதுவும் கிடைக்கவில்லை",
searchSummaryAria(count) {
if (count === 0) {
return "முடிவுகள் எதுவும் கிடைக்கவில்லை";
}
if (count === 1) {
return "1 முடிவு கிடைத்தது";
}
return `${count} முடிவுகள் கிடைத்தன`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Telugu. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"ఫోన్ నంబర్ కోసం దేశాన్ని మార్చండి, ఎంచుకున్నది ${countryName} (${dialCode})",
noCountrySelected: "ఫోన్ నంబర్ కోసం దేశాన్ని ఎంచుకోండి",
countryListAriaLabel: "దేశాల జాబితా",
searchPlaceholder: "వెతకండి",
clearSearchAriaLabel: "శోధనను క్లియర్ చేయండి",
searchEmptyState: "ఎటువంటి ఫలితాలు లభించలేదు",
searchSummaryAria(count) {
if (count === 0) {
return "ఎటువంటి ఫలితాలు లభించలేదు";
}
if (count === 1) {
return "1 ఫలితం కనుగొనబడింది";
}
return `${count} ఫలితాలు కనుగొనబడ్డాయి`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Thai. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"เปลี่ยนประเทศสำหรับหมายเลขโทรศัพท์, เลือก ${countryName} (${dialCode})",
noCountrySelected: "เลือกประเทศสำหรับหมายเลขโทรศัพท์",
countryListAriaLabel: "รายชื่อประเทศ",
searchPlaceholder: "ค้นหา",
clearSearchAriaLabel: "ล้างการค้นหา",
searchEmptyState: "ไม่พบผลลัพธ์",
searchSummaryAria(count) {
if (count === 0) {
return "ไม่พบผลลัพธ์";
}
return `พบผลลัพธ์ ${count} รายการ`;
},
};
export default interfaceTranslations;

View File

@@ -1,21 +0,0 @@
//* Turkish. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Telefon numarası için ülke değiştir, seçili ${countryName} (${dialCode})",
noCountrySelected: "Telefon numarası için ülke seç",
countryListAriaLabel: "Ülke listesi",
searchPlaceholder: "Ara",
clearSearchAriaLabel: "Aramayı temizle",
searchEmptyState: "Sonuç bulunamadı",
searchSummaryAria(count) {
if (count === 0) {
return "Sonuç bulunamadı";
}
return `${count} sonuç bulundu`;
},
};
export default interfaceTranslations;

View File

@@ -1,17 +0,0 @@
import type { Iso2 } from "../data.js";
// UI strings shown by the core library.
export type UiTranslations = {
selectedCountryAriaLabel?: string;
searchPlaceholder?: string;
clearSearchAriaLabel?: string;
countryListAriaLabel?: string;
noCountrySelected?: string;
searchEmptyState?: string;
searchSummaryAria?: (count: number) => string;
//* Translated country names, keyed by iso2. Only bundled for locales whose
//* region display names are missing from some browsers' Intl.DisplayNames data
//* (e.g. Chrome desktop falls back to English for bs, hy, is, mk, sq, uz). When
//* present, these take precedence over Intl.DisplayNames. See country-data.ts.
countryNames?: Partial<Record<Iso2, string>>;
};

View File

@@ -1,35 +0,0 @@
//* Ukrainian. Translated by: Oleksandr Shyrykalov (JustSanya).
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Змінити країну для номера телефону, обрана ${countryName} (${dialCode})",
noCountrySelected: "Виберіть країну для номера телефону",
countryListAriaLabel: "Список країн",
searchPlaceholder: "Шукати",
clearSearchAriaLabel: "Очистити пошук",
searchEmptyState: "Результатів не знайдено",
searchSummaryAria(count) {
if (count === 0) {
return "Результатів не знайдено";
}
const mod10 = count % 10;
const mod100 = count % 100;
// Numbers ending in 1, but not 11
if (mod10 === 1 && mod100 !== 11) {
return `Знайдено ${count} результат`;
}
// Numbers ending in 2-4, but not 12-14
const isFew = mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14);
if (isFew) {
return `Знайдено ${count} результати`;
}
return `Знайдено ${count} результатів`;
},
};
export default interfaceTranslations;

View File

@@ -1,24 +0,0 @@
//* Urdu. Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"فون نمبر کے لیے ملک تبدیل کریں، منتخب ${countryName} (${dialCode})",
noCountrySelected: "فون نمبر کے لیے ملک منتخب کریں",
countryListAriaLabel: "ممالک کی فہرست",
searchPlaceholder: "تلاش کریں۔",
clearSearchAriaLabel: "تلاش صاف کریں",
searchEmptyState: "کوئی نتیجہ نہیں",
searchSummaryAria(count) {
if (count === 0) {
return "کوئی نتیجہ نہیں";
}
if (count === 1) {
return "1 نتیجہ ملا";
}
return `${count} نتائج ملے`;
},
};
export default interfaceTranslations;

View File

@@ -1,22 +0,0 @@
//* English. Translated by: Mukhammadkhojiakbar Khusanov (khusanov-m).
import type { UiTranslations } from "./types.js";
import countryNames from "./country-names/uz.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Telefon raqami uchun davlatni o'zgartirish, tanlangan ${countryName} (${dialCode})",
noCountrySelected: "Telefon raqami uchun davlatni tanlang",
countryListAriaLabel: "Davlatlar roʻyxati",
searchPlaceholder: "Davlatni qidiring",
clearSearchAriaLabel: "Qidiruvni tozalang",
searchEmptyState: "Natija topilmadi",
searchSummaryAria(count) {
if (count === 0) {
return "Natija topilmadi";
}
return `${count}-ta natija topildi`;
},
};
export default { ...interfaceTranslations, countryNames };

View File

@@ -1,21 +0,0 @@
//* Vietnamese. Translated by: Eric Pastoor (epastoor) with help of google translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel:
"Thay đổi quốc gia cho số điện thoại, đã chọn ${countryName} (${dialCode})",
noCountrySelected: "Chọn quốc gia cho số điện thoại",
countryListAriaLabel: "Danh sách các quốc gia",
searchPlaceholder: "Khám xét",
clearSearchAriaLabel: "Xóa tìm kiếm",
searchEmptyState: "Không tìm thấy kết quả nào",
searchSummaryAria(count) {
if (count === 0) {
return "Không tìm thấy kết quả nào";
}
return `Đã tìm thấy ${count} kết quả`;
},
};
export default interfaceTranslations;

View File

@@ -1,20 +0,0 @@
//* Chinese (Hong Kong). Translated by: Google Translate.
import type { UiTranslations } from "./types.js";
const interfaceTranslations: UiTranslations = {
selectedCountryAriaLabel: "更改電話號碼的國家,選擇「${countryName}」(${dialCode}",
noCountrySelected: "選擇電話號碼的國家",
countryListAriaLabel: "國家清單",
searchPlaceholder: "搜尋",
clearSearchAriaLabel: "清除搜尋",
searchEmptyState: "未找到相關項目",
searchSummaryAria(count) {
if (count === 0) {
return "未找到相關項目";
}
return `找到 ${count} 個相關項目`;
},
};
export default interfaceTranslations;

Some files were not shown because too many files have changed in this diff Show More