google-libphonenumber
Version:
A browserify-compatible wrapper for Google's libphonenumber.
1,542 lines (1,381 loc) • 163 kB
JavaScript
/**
* @license
* Copyright (C) 2010 The Libphonenumber Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utility for international phone numbers.
* Functionality includes formatting, parsing and validation.
* (based on the java implementation).
*
* NOTE: A lot of methods in this class require Region Code strings. These must
* be provided using ISO 3166-1 two-letter country-code format. These should be
* in upper-case (but for compatibility lower-case is also allowed). The list of
* the codes can be found here:
* http://www.iso.org/iso/english_country_names_and_code_elements
*
* @author Nikolaos Trogkanis
*/
goog.provide('i18n.phonenumbers.Error');
goog.provide('i18n.phonenumbers.PhoneNumberFormat');
goog.provide('i18n.phonenumbers.PhoneNumberType');
goog.provide('i18n.phonenumbers.PhoneNumberUtil');
goog.provide('i18n.phonenumbers.PhoneNumberUtil.MatchType');
goog.provide('i18n.phonenumbers.PhoneNumberUtil.ValidationResult');
goog.require('goog.array');
goog.require('goog.proto2.PbLiteSerializer');
goog.require('goog.string');
goog.require('goog.string.StringBuffer');
goog.require('i18n.phonenumbers.NumberFormat');
goog.require('i18n.phonenumbers.PhoneMetadata');
goog.require('i18n.phonenumbers.PhoneMetadataCollection');
goog.require('i18n.phonenumbers.PhoneNumber');
goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
goog.require('i18n.phonenumbers.PhoneNumberDesc');
goog.require('i18n.phonenumbers.metadata');
/**
* @constructor
* @private
*/
i18n.phonenumbers.PhoneNumberUtil = function() {
/**
* A mapping from a region code to the PhoneMetadata for that region.
* @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
*/
this.regionToMetadataMap = {};
};
goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil);
/**
* Errors encountered when parsing phone numbers.
*
* @enum {string}
*/
i18n.phonenumbers.Error = {
INVALID_COUNTRY_CODE: 'Invalid country calling code',
// This generally indicates the string passed in had less than 3 digits in it.
// More specifically, the number failed to match the regular expression
// VALID_PHONE_NUMBER.
NOT_A_NUMBER: 'The string supplied did not seem to be a phone number',
// This indicates the string started with an international dialing prefix, but
// after this was stripped from the number, had less digits than any valid
// phone number (including country calling code) could have.
TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD',
// This indicates the string, after any country calling code has been
// stripped, had less digits than any valid phone number could have.
TOO_SHORT_NSN: 'The string supplied is too short to be a phone number',
// This indicates the string had more digits than any valid phone number could
// have.
TOO_LONG: 'The string supplied is too long to be a phone number'
};
/**
* @const
* @type {number}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1;
/**
* The minimum length of the national significant number.
*
* @const
* @type {number}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 2;
/**
* The ITU says the maximum length should be 15, but we have found longer
* numbers in Germany.
*
* @const
* @type {number}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 17;
/**
* The maximum length of the country calling code.
*
* @const
* @type {number}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3;
/**
* We don't allow input strings for parsing to be longer than 250 chars. This
* prevents malicious input from consuming CPU.
*
* @const
* @type {number}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_ = 250;
/**
* Region-code for the unknown region.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ';
/**
* The prefix that needs to be inserted in front of a Colombian landline number
* when dialed from a mobile phone in Colombia.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = '3';
/**
* Map of country calling codes that use a mobile token before the area code.
* One example of when this is relevant is when determining the length of the
* national destination code, which should be the length of the area code plus
* the length of the mobile token.
*
* @const
* @type {!Object.<number, string>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = {
52: '1',
54: '9'
};
/**
* Set of country calling codes that have geographically assigned mobile
* numbers. This may not be complete; we add calling codes case by case, as we
* find geographical mobile numbers or hear from user reports.
*
* @const
* @type {!Array.<number>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_ = [
52, // Mexico
54, // Argentina
55 // Brazil
];
/**
* The PLUS_SIGN signifies the international prefix.
*
* @const
* @type {string}
*/
i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+';
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ = '*';
/**
* The RFC 3966 format for extensions.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ = ';ext=';
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ = 'tel:';
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_ = ';phone-context=';
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_ = ';isub=';
/**
* These mappings map a character (key) to a specific digit that should replace
* it for normalization purposes. Non-European digits that may be used in phone
* numbers are mapped to a European equivalent.
*
* @const
* @type {!Object.<string, string>}
*/
i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'\uFF10': '0', // Fullwidth digit 0
'\uFF11': '1', // Fullwidth digit 1
'\uFF12': '2', // Fullwidth digit 2
'\uFF13': '3', // Fullwidth digit 3
'\uFF14': '4', // Fullwidth digit 4
'\uFF15': '5', // Fullwidth digit 5
'\uFF16': '6', // Fullwidth digit 6
'\uFF17': '7', // Fullwidth digit 7
'\uFF18': '8', // Fullwidth digit 8
'\uFF19': '9', // Fullwidth digit 9
'\u0660': '0', // Arabic-indic digit 0
'\u0661': '1', // Arabic-indic digit 1
'\u0662': '2', // Arabic-indic digit 2
'\u0663': '3', // Arabic-indic digit 3
'\u0664': '4', // Arabic-indic digit 4
'\u0665': '5', // Arabic-indic digit 5
'\u0666': '6', // Arabic-indic digit 6
'\u0667': '7', // Arabic-indic digit 7
'\u0668': '8', // Arabic-indic digit 8
'\u0669': '9', // Arabic-indic digit 9
'\u06F0': '0', // Eastern-Arabic digit 0
'\u06F1': '1', // Eastern-Arabic digit 1
'\u06F2': '2', // Eastern-Arabic digit 2
'\u06F3': '3', // Eastern-Arabic digit 3
'\u06F4': '4', // Eastern-Arabic digit 4
'\u06F5': '5', // Eastern-Arabic digit 5
'\u06F6': '6', // Eastern-Arabic digit 6
'\u06F7': '7', // Eastern-Arabic digit 7
'\u06F8': '8', // Eastern-Arabic digit 8
'\u06F9': '9' // Eastern-Arabic digit 9
};
/**
* 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
* @type {!Object.<string, string>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_ = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'+': i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN,
'*': '*'
};
/**
* Only upper-case variants of alpha characters are stored.
*
* @const
* @type {!Object.<string, string>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = {
'A': '2',
'B': '2',
'C': '2',
'D': '3',
'E': '3',
'F': '3',
'G': '4',
'H': '4',
'I': '4',
'J': '5',
'K': '5',
'L': '5',
'M': '6',
'N': '6',
'O': '6',
'P': '7',
'Q': '7',
'R': '7',
'S': '7',
'T': '8',
'U': '8',
'V': '8',
'W': '9',
'X': '9',
'Y': '9',
'Z': '9'
};
/**
* For performance reasons, amalgamate both into one map.
*
* @const
* @type {!Object.<string, string>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'\uFF10': '0', // Fullwidth digit 0
'\uFF11': '1', // Fullwidth digit 1
'\uFF12': '2', // Fullwidth digit 2
'\uFF13': '3', // Fullwidth digit 3
'\uFF14': '4', // Fullwidth digit 4
'\uFF15': '5', // Fullwidth digit 5
'\uFF16': '6', // Fullwidth digit 6
'\uFF17': '7', // Fullwidth digit 7
'\uFF18': '8', // Fullwidth digit 8
'\uFF19': '9', // Fullwidth digit 9
'\u0660': '0', // Arabic-indic digit 0
'\u0661': '1', // Arabic-indic digit 1
'\u0662': '2', // Arabic-indic digit 2
'\u0663': '3', // Arabic-indic digit 3
'\u0664': '4', // Arabic-indic digit 4
'\u0665': '5', // Arabic-indic digit 5
'\u0666': '6', // Arabic-indic digit 6
'\u0667': '7', // Arabic-indic digit 7
'\u0668': '8', // Arabic-indic digit 8
'\u0669': '9', // Arabic-indic digit 9
'\u06F0': '0', // Eastern-Arabic digit 0
'\u06F1': '1', // Eastern-Arabic digit 1
'\u06F2': '2', // Eastern-Arabic digit 2
'\u06F3': '3', // Eastern-Arabic digit 3
'\u06F4': '4', // Eastern-Arabic digit 4
'\u06F5': '5', // Eastern-Arabic digit 5
'\u06F6': '6', // Eastern-Arabic digit 6
'\u06F7': '7', // Eastern-Arabic digit 7
'\u06F8': '8', // Eastern-Arabic digit 8
'\u06F9': '9', // Eastern-Arabic digit 9
'A': '2',
'B': '2',
'C': '2',
'D': '3',
'E': '3',
'F': '3',
'G': '4',
'H': '4',
'I': '4',
'J': '5',
'K': '5',
'L': '5',
'M': '6',
'N': '6',
'O': '6',
'P': '7',
'Q': '7',
'R': '7',
'S': '7',
'T': '8',
'U': '8',
'V': '8',
'W': '9',
'X': '9',
'Y': '9',
'Z': '9'
};
/**
* Separate map of all symbols that we wish to retain when formatting alpha
* numbers. This includes digits, ASCII letters and number grouping symbols such
* as '-' and ' '.
*
* @const
* @type {!Object.<string, string>}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
'4': '4',
'5': '5',
'6': '6',
'7': '7',
'8': '8',
'9': '9',
'A': 'A',
'B': 'B',
'C': 'C',
'D': 'D',
'E': 'E',
'F': 'F',
'G': 'G',
'H': 'H',
'I': 'I',
'J': 'J',
'K': 'K',
'L': 'L',
'M': 'M',
'N': 'N',
'O': 'O',
'P': 'P',
'Q': 'Q',
'R': 'R',
'S': 'S',
'T': 'T',
'U': 'U',
'V': 'V',
'W': 'W',
'X': 'X',
'Y': 'Y',
'Z': 'Z',
'a': 'A',
'b': 'B',
'c': 'C',
'd': 'D',
'e': 'E',
'f': 'F',
'g': 'G',
'h': 'H',
'i': 'I',
'j': 'J',
'k': 'K',
'l': 'L',
'm': 'M',
'n': 'N',
'o': 'O',
'p': 'P',
'q': 'Q',
'r': 'R',
's': 'S',
't': 'T',
'u': 'U',
'v': 'V',
'w': 'W',
'x': 'X',
'y': 'Y',
'z': 'Z',
'-': '-',
'\uFF0D': '-',
'\u2010': '-',
'\u2011': '-',
'\u2012': '-',
'\u2013': '-',
'\u2014': '-',
'\u2015': '-',
'\u2212': '-',
'/': '/',
'\uFF0F': '/',
' ': ' ',
'\u3000': ' ',
'\u2060': ' ',
'.': '.',
'\uFF0E': '.'
};
/**
* Pattern that makes it easy to distinguish whether a region has a unique
* international dialing prefix or not. If a region has a unique international
* prefix (e.g. 011 in USA), it will be represented as a string that contains a
* sequence of ASCII digits. If there are multiple available international
* prefixes in a region, they will be represented as a regex string that always
* contains character(s) other than ASCII digits. Note this regex also includes
* tilde, which signals waiting for the tone.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_ =
/[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/;
/**
* Regular expression of acceptable punctuation found in phone numbers. This
* excludes punctuation found as a leading character only. This consists of dash
* characters, white space characters, full stops, slashes, square brackets,
* parentheses and tildes. It also includes the letter 'x' as that is found as a
* placeholder for carrier information in some phone numbers. Full-width
* variants are also present.
*
* @const
* @type {string}
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION =
'-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u00AD\u200B\u2060\u3000' +
'()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E';
/**
* Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern
* arabic digits).
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ =
'0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9';
/**
* We accept alpha characters in phone numbers, ASCII only, upper and lower
* case.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z';
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B';
/**
* @const
* @type {!RegExp}
*/
i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN =
new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
/**
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_ =
new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
/**
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_ =
'[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + ']+';
/**
* @const
* @type {!RegExp}
*/
i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN =
new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])');
/**
* Regular expression of acceptable characters that may start a phone number for
* the purposes of parsing. This allows us to strip away meaningless prefixes to
* phone numbers that may be mistakenly given to us. This consists of digits,
* the plus symbol and arabic-indic digits. This does not contain alpha
* characters, although they may be used later in the number. It also does not
* include other punctuation, as this will be stripped later during parsing and
* is of no information value when parsing a number.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_ =
new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']');
/**
* Regular expression of characters typically used to start a second phone
* number for the purposes of parsing. This allows us to strip off parts of the
* number that are actually the start of another number, such as for:
* (530) 583-6985 x302/x2303 -> the second extension here makes this actually
* two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove
* the second extension so that the first number is parsed correctly.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/;
/**
* Regular expression of trailing characters that we want to remove. We remove
* all characters that are not alpha or numerical characters. The hash character
* is retained here, as it may signify the previous block was an extension.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ =
new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ +
i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$');
/**
* We use this pattern to check if the phone number has at least three letters
* in it - if so, then we treat it as a number where some phone-number digits
* are represented by letters.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ =
/(?:.*?[A-Za-z]){3}.*/;
/**
* Regular expression of viable phone numbers. This is location independent.
* Checks we have at least three leading digits, and only valid punctuation,
* alpha characters and digits in the phone number. Does not include extension
* data. The symbol 'x' is allowed here as valid punctuation since it is often
* used as a placeholder for carrier codes, for example in Brazilian phone
* numbers. We also allow multiple '+' characters at the start.
* Corresponds to the following:
* [digits]{minLengthNsn}|
* plus_sign*
* (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
*
* The first reg-ex is to allow short numbers (two digits long) to be parsed if
* they are entered as "15" etc, but only if there is no punctuation in them.
* The second expression restricts the number of digits to three or more, but
* then allows them to be in international form, and to have alpha-characters
* and punctuation. We split up the two reg-exes here and combine them when
* creating the reg-ex VALID_PHONE_NUMBER_PATTERN_ itself so we can prefix it
* with ^ and append $ to each branch.
*
* Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ =
'[' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{' +
i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ + '}';
/**
* See MIN_LENGTH_PHONE_NUMBER_PATTERN_ for a full description of this reg-exp.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ =
'[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' +
i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ + ']*[' +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' +
i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ +
i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ +
i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*';
/**
* Default extension prefix to use when formatting. This will be put in front of
* any extension component of the number, after the main national number is
* formatted. For example, if you wish the default extension formatting to be
* ' extn: 3456', then you should specify ' extn: ' here as the default
* extension prefix. This can be overridden by region-specific preferences.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. ';
/**
* Pattern to capture digits used in an extension.
* Places a maximum length of '7' for an extension.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ =
'([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})';
/**
* Regexp of all possible ways to write extensions, for use when parsing. This
* will be run as a case-insensitive regexp match. Wide character versions are
* also provided after each ASCII version. There are three regular expressions
* here. The first covers RFC 3966 format, where the extension is added using
* ';ext='. The second more generic one starts with optional white space and
* ends with an optional full stop (.), followed by zero or more spaces/tabs and
* then the numbers themselves. The other one covers the special case of
* American numbers where the extension is written with a hash at the end, such
* as '- 503#'. Note that the only capturing groups should be around the digits
* that you want to capture as part of the extension, or else parsing will fail!
* We allow two options for representing the accented o - the character itself,
* and one in the unicode decomposed form with the combining acute accent.
*
* @const
* @type {string}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ =
i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ +
i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '|' +
'[ \u00A0\\t,]*' +
'(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|' +
'[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
'[:\\.\uFF0E]?[ \u00A0\\t,-]*' +
i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '#?|' +
'[- ]+([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
/**
* Regexp of all known extension prefixes used by different regions followed by
* 1 or more valid digits, for use when parsing.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ =
new RegExp('(?:' +
i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
')$', 'i');
/**
* We append optionally the extension pattern to the end here, as a valid phone
* number may have an extension prefix appended, followed by 1 or more digits.
*
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ =
new RegExp(
'^' +
i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ +
'$|' +
'^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ +
'(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
')?' + '$', 'i');
/**
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/;
/**
* This was originally set to $1 but there are some countries for which the
* first group is not used in the national pattern (e.g. Argentina) so the $1
* group does not match correctly. Therefore, we use \d, so that the first
* group actually used in the pattern will be matched.
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$\d)/;
/**
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/;
/**
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
/**
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
/**
* A pattern that is used to determine if the national prefix formatting rule
* has the first group only, i.e., does not start with the national prefix.
* Note that the pattern explicitly allows for unbalanced parentheses.
* @const
* @type {!RegExp}
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_ =
/^\(?\$1\)?$/;
/**
* @const
* @type {string}
*/
i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY = '001';
/**
* INTERNATIONAL and NATIONAL formats are consistent with the definition in
* ITU-T Recommendation E123. For example, the number of the Google Switzerland
* office will be written as '+41 44 668 1800' in INTERNATIONAL format, and as
* '044 668 1800' in NATIONAL format. E164 format is as per INTERNATIONAL format
* but with no formatting applied, e.g. '+41446681800'. RFC3966 is as per
* INTERNATIONAL format, but with all spaces and other separating symbols
* replaced with a hyphen, and with any phone number extension appended with
* ';ext='. It also will have a prefix of 'tel:' added, e.g.
* 'tel:+41-44-668-1800'.
*
* Note: If you are considering storing the number in a neutral format, you are
* highly advised to use the PhoneNumber class.
* @enum {number}
*/
i18n.phonenumbers.PhoneNumberFormat = {
E164: 0,
INTERNATIONAL: 1,
NATIONAL: 2,
RFC3966: 3
};
/**
* Type of phone numbers.
*
* @enum {number}
*/
i18n.phonenumbers.PhoneNumberType = {
FIXED_LINE: 0,
MOBILE: 1,
// In some regions (e.g. the USA), it is impossible to distinguish between
// fixed-line and mobile numbers by looking at the phone number itself.
FIXED_LINE_OR_MOBILE: 2,
// Freephone lines
TOLL_FREE: 3,
PREMIUM_RATE: 4,
// The cost of this call is shared between the caller and the recipient, and
// is hence typically less than PREMIUM_RATE calls. See
// http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
SHARED_COST: 5,
// Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
VOIP: 6,
// A personal number is associated with a particular person, and may be routed
// to either a MOBILE or FIXED_LINE number. Some more information can be found
// here: http://en.wikipedia.org/wiki/Personal_Numbers
PERSONAL_NUMBER: 7,
PAGER: 8,
// Used for 'Universal Access Numbers' or 'Company Numbers'. They may be
// further routed to specific offices, but allow one number to be used for a
// company.
UAN: 9,
// Used for 'Voice Mail Access Numbers'.
VOICEMAIL: 10,
// A phone number is of type UNKNOWN when it does not fit any of the known
// patterns for a specific region.
UNKNOWN: -1
};
/**
* Types of phone number matches. See detailed description beside the
* isNumberMatch() method.
*
* @enum {number}
*/
i18n.phonenumbers.PhoneNumberUtil.MatchType = {
NOT_A_NUMBER: 0,
NO_MATCH: 1,
SHORT_NSN_MATCH: 2,
NSN_MATCH: 3,
EXACT_MATCH: 4
};
/**
* Possible outcomes when testing if a PhoneNumber is possible.
*
* @enum {number}
*/
i18n.phonenumbers.PhoneNumberUtil.ValidationResult = {
IS_POSSIBLE: 0,
INVALID_COUNTRY_CODE: 1,
TOO_SHORT: 2,
TOO_LONG: 3
};
/**
* Attempts to extract a possible number from the string passed in. This
* currently strips all leading characters that cannot be used to start a phone
* number. Characters that can be used to start a phone number are defined in
* the VALID_START_CHAR_PATTERN. If none of these characters are found in the
* number passed in, an empty string is returned. This function also attempts to
* strip off any alternative extensions or endings if two or more are present,
* such as in the case of: (530) 583-6985 x302/x2303. The second extension here
* makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
* x2303. We remove the second extension so that the first number is parsed
* correctly.
*
* @param {string} number the string that might contain a phone number.
* @return {string} the number, stripped of any non-phone-number prefix (such as
* 'Tel:') or an empty string if no character used to start phone numbers
* (such as + or any digit) is found in the number.
*/
i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) {
/** @type {string} */
var possibleNumber;
/** @type {number} */
var start = number
.search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_);
if (start >= 0) {
possibleNumber = number.substring(start);
// Remove trailing non-alpha non-numerical characters.
possibleNumber = possibleNumber.replace(
i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, '');
// Check for extra numbers at the end.
/** @type {number} */
var secondNumberStart = possibleNumber
.search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_);
if (secondNumberStart >= 0) {
possibleNumber = possibleNumber.substring(0, secondNumberStart);
}
} else {
possibleNumber = '';
}
return possibleNumber;
};
/**
* Checks to see if the string of characters could possibly be a phone number at
* all. At the moment, checks to see that the string begins with at least 2
* digits, ignoring any punctuation commonly found in phone numbers. This method
* does not require the number to be normalized in advance - but does assume
* that leading non-number symbols have been removed, such as by the method
* extractPossibleNumber.
*
* @param {string} number string to be checked for viability as a phone number.
* @return {boolean} true if the number could be a phone number of some sort,
* otherwise false.
*/
i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) {
if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
return false;
}
return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number);
};
/**
* Normalizes a string of characters representing a phone number. This performs
* the following conversions:
* Punctuation is stripped.
* For ALPHA/VANITY numbers:
* Letters are converted to their numeric representation on a telephone
* keypad. The keypad used here is the one defined in ITU Recommendation
* E.161. This is only done if there are 3 or more letters in the number,
* to lessen the risk that such letters are typos.
* For other numbers:
* Wide-ascii digits are converted to normal ASCII (European) digits.
* Arabic-Indic numerals are converted to European numerals.
* Spurious alpha characters are stripped.
*
* @param {string} number a string of characters representing a phone number.
* @return {string} the normalized string version of the phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) {
if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) {
return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true);
} else {
return i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number);
}
};
/**
* Normalizes a string of characters representing a phone number. This is a
* wrapper for normalize(String number) but does in-place normalization of the
* StringBuffer provided.
*
* @param {!goog.string.StringBuffer} number a StringBuffer of characters
* representing a phone number that will be normalized in place.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) {
/** @type {string} */
var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number
.toString());
number.clear();
number.append(normalizedNumber);
};
/**
* Normalizes a string of characters representing a phone number. This converts
* wide-ascii and arabic-indic numerals to European numerals, and strips
* punctuation and alpha characters.
*
* @param {string} number a string of characters representing a phone number.
* @return {string} the normalized string version of the phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) {
return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
};
/**
* Converts all alpha characters in a number to their respective digits on a
* keypad, but retains existing formatting. Also converts wide-ascii digits to
* normal ascii digits, and converts Arabic-Indic numerals to European numerals.
*
* @param {string} number a string of characters representing a phone number.
* @return {string} the normalized string version of the phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber =
function(number) {
return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false);
};
/**
* Gets the length of the geographical area code from the
* {@code national_number} field of the PhoneNumber object passed in, so that
* clients could use it to split a national significant number into geographical
* area code and subscriber number. It works in such a way that the resultant
* subscriber number should be diallable, at least on some devices. An example
* of how this could be used:
*
* <pre>
* var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
* var number = phoneUtil.parse('16502530000', 'US');
* var nationalSignificantNumber =
* phoneUtil.getNationalSignificantNumber(number);
* var areaCode;
* var subscriberNumber;
*
* var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
* if (areaCodeLength > 0) {
* areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
* subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
* } else {
* areaCode = '';
* subscriberNumber = nationalSignificantNumber;
* }
* </pre>
*
* N.B.: area code is a very ambiguous concept, so the I18N team generally
* recommends against using it for most purposes, but recommends using the more
* general {@code national_number} instead. Read the following carefully before
* deciding to use this method:
* <ul>
* <li> geographical area codes change over time, and this method honors those
* changes; therefore, it doesn't guarantee the stability of the result it
* produces.
* <li> subscriber numbers may not be diallable from all devices (notably
* mobile devices, which typically requires the full national_number to be
* dialled in most regions).
* <li> most non-geographical numbers have no area codes, including numbers
* from non-geographical entities.
* <li> some geographical numbers have no area codes.
* </ul>
*
* @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
* which clients want to know the length of the area code.
* @return {number} the length of area code of the PhoneNumber object passed in.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
function(number) {
/** @type {i18n.phonenumbers.PhoneMetadata} */
var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number));
if (metadata == null) {
return 0;
}
// If a country doesn't use a national prefix, and this number doesn't have
// an Italian leading zero, we assume it is a closed dialling plan with no
// area codes.
if (!metadata.hasNationalPrefix() && !number.hasItalianLeadingZero()) {
return 0;
}
if (!this.isNumberGeographical(number)) {
return 0;
}
return this.getLengthOfNationalDestinationCode(number);
};
/**
* Gets the length of the national destination code (NDC) from the PhoneNumber
* object passed in, so that clients could use it to split a national
* significant number into NDC and subscriber number. The NDC of a phone number
* is normally the first group of digit(s) right after the country calling code
* when the number is formatted in the international format, if there is a
* subscriber number part that follows. An example of how this could be used:
*
* <pre>
* var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
* var number = phoneUtil.parse('18002530000', 'US');
* var nationalSignificantNumber =
* phoneUtil.getNationalSignificantNumber(number);
* var nationalDestinationCode;
* var subscriberNumber;
*
* var nationalDestinationCodeLength =
* phoneUtil.getLengthOfNationalDestinationCode(number);
* if (nationalDestinationCodeLength > 0) {
* nationalDestinationCode =
* nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
* subscriberNumber =
* nationalSignificantNumber.substring(nationalDestinationCodeLength);
* } else {
* nationalDestinationCode = '';
* subscriberNumber = nationalSignificantNumber;
* }
* </pre>
*
* Refer to the unittests to see the difference between this function and
* {@link #getLengthOfGeographicalAreaCode}.
*
* @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
* which clients want to know the length of the NDC.
* @return {number} the length of NDC of the PhoneNumber object passed in.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode =
function(number) {
/** @type {i18n.phonenumbers.PhoneNumber} */
var copiedProto;
if (number.hasExtension()) {
// We don't want to alter the proto given to us, but we don't want to
// include the extension when we format it, so we copy it and clear the
// extension here.
copiedProto = number.clone();
copiedProto.clearExtension();
} else {
copiedProto = number;
}
/** @type {string} */
var nationalSignificantNumber = this.format(copiedProto,
i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
/** @type {!Array.<string>} */
var numberGroups = nationalSignificantNumber.split(
i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
// The pattern will start with '+COUNTRY_CODE ' so the first group will always
// be the empty string (before the + symbol) and the second group will be the
// country calling code. The third group will be area code if it is not the
// last group.
// NOTE: On IE the first group that is supposed to be the empty string does
// not appear in the array of number groups... so make the result on non-IE
// browsers to be that of IE.
if (numberGroups[0].length == 0) {
numberGroups.shift();
}
if (numberGroups.length <= 2) {
return 0;
}
if (this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) {
// For example Argentinian mobile numbers, when formatted in the
// international format, are in the form of +54 9 NDC XXXX.... As a result,
// we take the length of the third group (NDC) and add the length of the
// mobile token, which also forms part of the national significant number.
// This assumes that the mobile token is always formatted separately from
// the rest of the phone number.
/** @type {string} */
var mobileToken = i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken(
number.getCountryCodeOrDefault());
if (mobileToken != '') {
return numberGroups[2].length + mobileToken.length;
}
}
return numberGroups[1].length;
};
/**
* Returns the mobile token for the provided country calling code if it has
* one, otherwise returns an empty string. A mobile token is a number inserted
* before the area code when dialing a mobile number from that country from
* abroad.
*
* @param {number} countryCallingCode the country calling code for which we
* want the mobile token.
* @return {string} the mobile token for the given country calling code.
*/
i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken =
function(countryCallingCode) {
return i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_[
countryCallingCode] || '';
};
/**
* Convenience method to get a list of what regions the library has metadata
* for.
* @return {!Array.<string>} region codes supported by the library.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedRegions = function() {
return goog.array.filter(
Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
function(regionCode) {
return isNaN(regionCode);
});
};
/**
* Convenience method to get a list of what global network calling codes the
* library has metadata for.
* @return {!Array.<number>} global network calling codes supported by the
* library.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.
getSupportedGlobalNetworkCallingCodes = function() {
var callingCodesAsStrings = goog.array.filter(
Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
function(regionCode) {
return !isNaN(regionCode);
});
return goog.array.map(callingCodesAsStrings,
function(callingCode) {
return parseInt(callingCode, 10);
});
};
/**
* Normalizes a string of characters representing a phone number by replacing
* all characters found in the accompanying map with the values therein, and
* stripping all other characters if removeNonMatches is true.
*
* @param {string} number a string of characters representing a phone number.
* @param {!Object.<string, string>} normalizationReplacements a mapping of
* characters to what they should be replaced by in the normalized version
* of the phone number.
* @param {boolean} removeNonMatches indicates whether characters that are not
* able to be replaced should be stripped from the number. If this is false,
* they will be left unchanged in the number.
* @return {string} the normalized string version of the phone number.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ =
function(number, normalizationReplacements, removeNonMatches) {
/** @type {!goog.string.StringBuffer} */
var normalizedNumber = new goog.string.StringBuffer();
/** @type {string} */
var character;
/** @type {string} */
var newDigit;
/** @type {number} */
var numberLength = number.length;
for (var i = 0; i < numberLength; ++i) {
character = number.charAt(i);
newDigit = normalizationReplacements[character.toUpperCase()];
if (newDigit != null) {
normalizedNumber.append(newDigit);
} else if (!removeNonMatches) {
normalizedNumber.append(character);
}
// If neither of the above are true, we remove this character.
}
return normalizedNumber.toString();
};
/**
* Helper function to check if the national prefix formatting rule has the first
* group only, i.e., does not start with the national prefix.
*
* @param {string} nationalPrefixFormattingRule The formatting rule for the
* national prefix.
* @return {boolean} true if the national prefix formatting rule has the first
* group only.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.formattingRuleHasFirstGroupOnly =
function(nationalPrefixFormattingRule) {
return nationalPrefixFormattingRule.length == 0 ||
i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_.
test(nationalPrefixFormattingRule);
};
/**
* Tests whether a phone number has a geographical association. It checks if
* the number is associated to a certain region in the country where it belongs
* to. Note that this doesn't verify if the number is actually in use.
*
* @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test.
* @return {boolean} true if the phone number has a geographical association.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberGeographical =
function(phoneNumber) {
/** @type {i18n.phonenumbers.PhoneNumberType} */
var numberType = this.getNumberType(phoneNumber);
return numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE ||
numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE ||
(goog.array.contains(
i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_,
phoneNumber.getCountryCodeOrDefault()) &&
numberType == i18n.phonenumbers.PhoneNumberType.MOBILE);
};
/**
* Helper function to check region code is not unknown or null.
*
* @param {?string} regionCode the ISO 3166-1 two-letter region code.
* @return {boolean} true if region code is valid.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
function(regionCode) {
// In Java we check whether the regionCode is contained in supportedRegions
// that is built out of all the values of countryCallingCodeToRegionCodeMap
// (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY.
// In JS we check whether the regionCode is contained in the keys of
// countryToMetadata but since for non-geographical country calling codes
// (e.g. +800) we use the country calling codes instead of the region code as
// key in the map we have to make sure regionCode is not a number to prevent
// returning true for non-geographical country calling codes.
return regionCode != null &&
isNaN(regionCode) &&
regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata;
};
/**
* Helper function to check the country calling code is valid.
*
* @param {number} countryCallingCode the country calling code.
* @return {boolean} true if country calling code code is valid.
* @private
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.hasValidCountryCallingCode_ =
function(countryCallingCode) {
return countryCallingCode in
i18n.phonenumbers.metadata.countryCodeToRegionCodeMap;
};
/**
* Formats a phone number in the specified format using default rules. Note that
* this does not promise to produce a phone number that the user can dial from
* where they are - although we do format in either 'national' or
* 'international' format depending on what the client asks for, we do not
* currently support a more abbreviated format, such as for users in the same
* 'area' who could potentially dial the number without area code. Note that if
* the phone number has a country calling code of 0 or an otherwise invalid
* country calling code, we cannot work out which formatting rules to apply so
* we return the national significant number with no formatting applied.
*
* @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
* formatted.
* @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
* phone number should be formatted into.
* @return {string} the formatted phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.format =
function(number, numberFormat) {
if (number.getNationalNumber() == 0 && number.hasRawInput()) {
// Unparseable numbers that kept their raw input just use that.
// This is the only case where a number can be formatted as E164 without a
// leading '+' symbol (but the original number wasn't parseable anyway).
// TODO: Consider removing the 'if' above so that unparseable strings
// without raw input format to the empty string instead of "+00"
/** @type {string} */
var rawInput = number.getRawInputOrDefault();
if (rawInput.length > 0) {
return rawInput;
}
}
/** @type {number} */
var countryCallingCode = number.getCountryCodeOrDefault();
/** @type {string} */
var nationalSignificantNumber = this.getNationalSignificantNumber(number);
if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
// Early exit for E164 case (even if the country calling code is invalid)
// since no formatting of the national number needs to be applied.
// Extensions are not formatted.
return this.prefixNumberWithCountryCallingCode_(
countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.E164,
nationalSignificantNumber, '');
}
if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
return nationalSignificantNumber;
}
// Note getRegionCodeForCountryCode() is used because formatting information
// for regions which share a country calling code is contained by only one
// region for performance reasons. For example, for NANPA regions it will be
// contained in the metadata for US.
/** @type {string} */
var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
// Metadata cannot be null because the country calling code is valid (which
// means that the region code cannot be ZZ and must be one of our supported
// region codes).
/** @type {i18n.phonenumbers.PhoneMetadata} */
var metadata =
this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
/** @type {string} */
var formattedExtension =
this.maybeGetFormattedExtension_(number, metadata, numberFormat);
/** @type {string} */
var formattedNationalNumber =
this.formatNsn_(nationalSignificantNumber, metadata, numberFormat);
return this.prefixNumberWithCountryCallingCode_(countryCallingCode,
numberFormat,
formattedNationalNumber,
formattedExtension);
};
/**
* Formats a phone number in the specified format using client-defined
* formatting rules. Note that if the phone number has a country calling code of
* zero or an otherwise invalid country calling code, we cannot work out things
* like whether there should be a national prefix applied, or how to format
* extensions, so we return the national significant number with no formatting
* applied.
*
* @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
* formatted.
* @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
* phone number should be formatted into.
* @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
* rules specified by clients.
* @return {string} the formatted phone number.
*/
i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
function(number, numberFormat, userDefinedFormats) {
/** @type {number} */
var countryCallingCode = number.getCountryCodeOrDefault();
/** @type {string} */
var nationalSignificantNumber = this.getNationalSignificantNumber(number);
if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
return nationalSignificantNumber;
}
// Note getRegionCodeForCountryCode() is used because formatting information
// for regions which share a country calling code is contained by only one
// region for performance reasons. For example, for NANPA regions it will be
// contained in the metadata for US.
/** @typ