123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- // This function is copy-pasted from
- // https://github.com/googlei18n/libphonenumber/blob/master/javascript/i18n/phonenumbers/phonenumberutil.js
- // It hasn't been tested. It's not currently exported.
- // Carriers codes aren't part of this library.
- // Send a PR if you want to add them.
- import Metadata from './metadata.js'
- import format from './format.js'
- import getNumberType from './helpers/getNumberType.js'
- import checkNumberLength from './helpers/checkNumberLength.js'
- import getCountryCallingCode from './getCountryCallingCode.js'
- const REGION_CODE_FOR_NON_GEO_ENTITY = '001'
- /**
- * Returns a number formatted in such a way that it can be dialed from a mobile
- * phone in a specific region. If the number cannot be reached from the region
- * (e.g. some countries block toll-free numbers from being called outside of the
- * country), the method returns an empty string.
- *
- * @param {object} number - a `parse()`d phone number to be formatted.
- * @param {string} from_country - the region where the call is being placed.
- * @param {boolean} with_formatting - whether the number should be returned with
- * formatting symbols, such as spaces and dashes.
- * @return {string}
- */
- export default function(number, from_country, with_formatting, metadata) {
- metadata = new Metadata(metadata)
- // Validate `from_country`.
- if (!metadata.hasCountry(from_country)) {
- throw new Error(`Unknown country: ${from_country}`)
- }
- // Not using the extension, as that part cannot normally be dialed
- // together with the main number.
- number = {
- phone: number.phone,
- country: number.country
- }
- const number_type = getNumberType(number, undefined, metadata.metadata)
- const is_valid_number = number_type === number
- let formatted_number
- if (country === from_country) {
- const is_fixed_line_or_mobile =
- number_type === 'FIXED_LINE' ||
- number_type === 'MOBILE' ||
- number_type === 'FIXED_LINE_OR_MOBILE'
- // Carrier codes may be needed in some countries. We handle this here.
- if (country == 'BR' && is_fixed_line_or_mobile) {
- formatted_number =
- carrierCode ?
- formatNationalNumberWithPreferredCarrierCode(number) :
- // Brazilian fixed line and mobile numbers need to be dialed with a
- // carrier code when called within Brazil. Without that, most of the
- // carriers won't connect the call. Because of that, we return an
- // empty string here.
- ''
- } else if (getCountryCallingCode(country, metadata.metadata) === '1') {
- // For NANPA countries, we output international format for numbers that
- // can be dialed internationally, since that always works, except for
- // numbers which might potentially be short numbers, which are always
- // dialled in national format.
- // Select country for `checkNumberLength()`.
- metadata.country(country)
- if (can_be_internationally_dialled(number) &&
- checkNumberLength(number.phone, metadata) !== 'TOO_SHORT') {
- formatted_number = format(number, 'INTERNATIONAL', metadata.metadata)
- }
- else {
- formatted_number = format(number, 'NATIONAL', metadata.metadata)
- }
- }
- else {
- // For non-geographic countries, Mexican and Chilean fixed line and
- // mobile numbers, we output international format for numbers that can be
- // dialed internationally, as that always works.
- if (
- (
- country === REGION_CODE_FOR_NON_GEO_ENTITY
- ||
- // MX fixed line and mobile numbers should always be formatted in
- // international format, even when dialed within MX. For national
- // format to work, a carrier code needs to be used, and the correct
- // carrier code depends on if the caller and callee are from the
- // same local area. It is trickier to get that to work correctly than
- // using international format, which is tested to work fine on all
- // carriers.
- //
- // CL fixed line numbers need the national prefix when dialing in the
- // national format, but don't have it when used for display. The
- // reverse is true for mobile numbers. As a result, we output them in
- // the international format to make it work.
- //
- // UZ mobile and fixed-line numbers have to be formatted in
- // international format or prefixed with special codes like 03, 04
- // (for fixed-line) and 05 (for mobile) for dialling successfully
- // from mobile devices. As we do not have complete information on
- // special codes and to be consistent with formatting across all
- // phone types we return the number in international format here.
- //
- ((country === 'MX' || country === 'CL' || country == 'UZ') && is_fixed_line_or_mobile)
- )
- &&
- can_be_internationally_dialled(number)
- ) {
- formatted_number = format(number, 'INTERNATIONAL')
- }
- else {
- formatted_number = format(number, 'NATIONAL')
- }
- }
- }
- else if (is_valid_number && can_be_internationally_dialled(number)) {
- // We assume that short numbers are not diallable from outside their region,
- // so if a number is not a valid regular length phone number, we treat it as
- // if it cannot be internationally dialled.
- return with_formatting ?
- format(number, 'INTERNATIONAL', metadata.metadata) :
- format(number, 'E.164', metadata.metadata)
- }
- if (!with_formatting) {
- return diallable_chars(formatted_number)
- }
- return formatted_number
- }
- function can_be_internationally_dialled(number) {
- return true
- }
- /**
- * A map that contains characters that are essential when dialling. That means
- * any of the characters in this map must not be removed from a number when
- * dialling, otherwise the call will not reach the intended destination.
- */
- const DIALLABLE_CHARACTERS = {
- '0': '0',
- '1': '1',
- '2': '2',
- '3': '3',
- '4': '4',
- '5': '5',
- '6': '6',
- '7': '7',
- '8': '8',
- '9': '9',
- '+': '+',
- '*': '*',
- '#': '#'
- }
- function diallable_chars(formatted_number) {
- let result = ''
- let i = 0
- while (i < formatted_number.length) {
- const character = formatted_number[i]
- if (DIALLABLE_CHARACTERS[character]) {
- result += character
- }
- i++
- }
- return result
- }
- function getPreferredDomesticCarrierCodeOrDefault() {
- throw new Error('carrier codes are not part of this library')
- }
- function formatNationalNumberWithCarrierCode() {
- throw new Error('carrier codes are not part of this library')
- }
- /**
- * Formats a phone number in national format for dialing using the carrier as
- * specified in the preferred_domestic_carrier_code field of the PhoneNumber
- * object passed in. If that is missing, use the {@code fallbackCarrierCode}
- * passed in instead. If there is no {@code preferred_domestic_carrier_code},
- * and the {@code fallbackCarrierCode} contains an empty string, return the
- * number in national format without any carrier code.
- *
- * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier
- * code passed in should take precedence over the number's
- * {@code preferred_domestic_carrier_code} when formatting.
- *
- * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
- * formatted.
- * @param {string} fallbackCarrierCode the carrier selection code to be used, if
- * none is found in the phone number itself.
- * @return {string} the formatted phone number in national format for dialing
- * using the number's preferred_domestic_carrier_code, or the
- * {@code fallbackCarrierCode} passed in if none is found.
- */
- function formatNationalNumberWithPreferredCarrierCode(number) {
- return formatNationalNumberWithCarrierCode(
- number,
- carrierCode
- );
- }
|