Added compiled JavaScript to repository for GitHub pages

This feels like a mistake...
This commit is contained in:
Simon Brooke 2020-10-20 14:44:11 +01:00
parent 3d5a2fb322
commit dc226b1f25
468 changed files with 212152 additions and 2 deletions

View file

@ -0,0 +1,876 @@
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// 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 functions for supporting Bidi issues.
*/
/**
* Namespace for bidi supporting functions.
*/
goog.provide('goog.i18n.bidi');
goog.provide('goog.i18n.bidi.Dir');
goog.provide('goog.i18n.bidi.DirectionalString');
goog.provide('goog.i18n.bidi.Format');
/**
* @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant
* to say that the current locale is a RTL locale. This should only be used
* if you want to override the default behavior for deciding whether the
* current locale is RTL or not.
*
* {@see goog.i18n.bidi.IS_RTL}
*/
goog.define('goog.i18n.bidi.FORCE_RTL', false);
/**
* Constant that defines whether or not the current locale is a RTL locale.
* If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default
* to check that {@link goog.LOCALE} is one of a few major RTL locales.
*
* <p>This is designed to be a maximally efficient compile-time constant. For
* example, for the default goog.LOCALE, compiling
* "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It
* is this design consideration that limits the implementation to only
* supporting a few major RTL locales, as opposed to the broader repertoire of
* something like goog.i18n.bidi.isRtlLanguage.
*
* <p>Since this constant refers to the directionality of the locale, it is up
* to the caller to determine if this constant should also be used for the
* direction of the UI.
*
* {@see goog.LOCALE}
*
* @type {boolean}
*
* TODO(user): write a test that checks that this is a compile-time constant.
*/
goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL ||
((goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'he' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' ||
goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') &&
(goog.LOCALE.length == 2 || goog.LOCALE.substring(2, 3) == '-' ||
goog.LOCALE.substring(2, 3) == '_')) ||
(goog.LOCALE.length >= 3 &&
goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' &&
(goog.LOCALE.length == 3 || goog.LOCALE.substring(3, 4) == '-' ||
goog.LOCALE.substring(3, 4) == '_'));
/**
* Unicode formatting characters and directionality string constants.
* @enum {string}
*/
goog.i18n.bidi.Format = {
/** Unicode "Left-To-Right Embedding" (LRE) character. */
LRE: '\u202A',
/** Unicode "Right-To-Left Embedding" (RLE) character. */
RLE: '\u202B',
/** Unicode "Pop Directional Formatting" (PDF) character. */
PDF: '\u202C',
/** Unicode "Left-To-Right Mark" (LRM) character. */
LRM: '\u200E',
/** Unicode "Right-To-Left Mark" (RLM) character. */
RLM: '\u200F'
};
/**
* Directionality enum.
* @enum {number}
*/
goog.i18n.bidi.Dir = {
/**
* Left-to-right.
*/
LTR: 1,
/**
* Right-to-left.
*/
RTL: -1,
/**
* Neither left-to-right nor right-to-left.
*/
NEUTRAL: 0
};
/**
* 'right' string constant.
* @type {string}
*/
goog.i18n.bidi.RIGHT = 'right';
/**
* 'left' string constant.
* @type {string}
*/
goog.i18n.bidi.LEFT = 'left';
/**
* 'left' if locale is RTL, 'right' if not.
* @type {string}
*/
goog.i18n.bidi.I18N_RIGHT =
goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT : goog.i18n.bidi.RIGHT;
/**
* 'right' if locale is RTL, 'left' if not.
* @type {string}
*/
goog.i18n.bidi.I18N_LEFT =
goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT;
/**
* Convert a directionality given in various formats to a goog.i18n.bidi.Dir
* constant. Useful for interaction with different standards of directionality
* representation.
*
* @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given
* in one of the following formats:
* 1. A goog.i18n.bidi.Dir constant.
* 2. A number (positive = LTR, negative = RTL, 0 = neutral).
* 3. A boolean (true = RTL, false = LTR).
* 4. A null for unknown directionality.
* @param {boolean=} opt_noNeutral Whether a givenDir of zero or
* goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in
* order to preserve legacy behavior.
* @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the
* given directionality. If given null, returns null (i.e. unknown).
*/
goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) {
if (typeof givenDir == 'number') {
// This includes the non-null goog.i18n.bidi.Dir case.
return givenDir > 0 ? goog.i18n.bidi.Dir.LTR : givenDir < 0 ?
goog.i18n.bidi.Dir.RTL :
opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL;
} else if (givenDir == null) {
return null;
} else {
// Must be typeof givenDir == 'boolean'.
return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR;
}
};
/**
* A practical pattern to identify strong LTR characters. This pattern is not
* theoretically correct according to the Unicode standard. It is simplified for
* performance and small code size.
* @type {string}
* @private
*/
goog.i18n.bidi.ltrChars_ =
'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
'\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF';
/**
* A practical pattern to identify strong RTL character. This pattern is not
* theoretically correct according to the Unicode standard. It is simplified
* for performance and small code size.
* @type {string}
* @private
*/
goog.i18n.bidi.rtlChars_ =
'\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC';
/**
* Simplified regular expression for an HTML tag (opening or closing) or an HTML
* escape. We might want to skip over such expressions when estimating the text
* directionality.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g;
/**
* Returns the input text with spaces instead of HTML tags or HTML escapes, if
* opt_isStripNeeded is true. Else returns the input as is.
* Useful for text directionality estimation.
* Note: the function should not be used in other contexts; it is not 100%
* correct, but rather a good-enough implementation for directionality
* estimation purposes.
* @param {string} str The given string.
* @param {boolean=} opt_isStripNeeded Whether to perform the stripping.
* Default: false (to retain consistency with calling functions).
* @return {string} The given string cleaned of HTML tags / escapes.
* @private
*/
goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) {
return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') : str;
};
/**
* Regular expression to check for RTL characters.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']');
/**
* Regular expression to check for LTR characters.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']');
/**
* Test whether the given string has any RTL characters in it.
* @param {string} str The given string that need to be tested.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether the string contains RTL characters.
*/
goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) {
return goog.i18n.bidi.rtlCharReg_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Test whether the given string has any RTL characters in it.
* @param {string} str The given string that need to be tested.
* @return {boolean} Whether the string contains RTL characters.
* @deprecated Use hasAnyRtl.
*/
goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl;
/**
* Test whether the given string has any LTR characters in it.
* @param {string} str The given string that need to be tested.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether the string contains LTR characters.
*/
goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) {
return goog.i18n.bidi.ltrCharReg_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Regular expression pattern to check if the first character in the string
* is LTR.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']');
/**
* Regular expression pattern to check if the first character in the string
* is RTL.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']');
/**
* Check if the first character in the string is RTL or not.
* @param {string} str The given string that need to be tested.
* @return {boolean} Whether the first character in str is an RTL char.
*/
goog.i18n.bidi.isRtlChar = function(str) {
return goog.i18n.bidi.rtlRe_.test(str);
};
/**
* Check if the first character in the string is LTR or not.
* @param {string} str The given string that need to be tested.
* @return {boolean} Whether the first character in str is an LTR char.
*/
goog.i18n.bidi.isLtrChar = function(str) {
return goog.i18n.bidi.ltrRe_.test(str);
};
/**
* Check if the first character in the string is neutral or not.
* @param {string} str The given string that need to be tested.
* @return {boolean} Whether the first character in str is a neutral char.
*/
goog.i18n.bidi.isNeutralChar = function(str) {
return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str);
};
/**
* Regular expressions to check if a piece of text is of LTR directionality
* on first character with strong directionality.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.ltrDirCheckRe_ = new RegExp(
'^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']');
/**
* Regular expressions to check if a piece of text is of RTL directionality
* on first character with strong directionality.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rtlDirCheckRe_ = new RegExp(
'^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']');
/**
* Check whether the first strongly directional character (if any) is RTL.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether RTL directionality is detected using the first
* strongly-directional character method.
*/
goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) {
return goog.i18n.bidi.rtlDirCheckRe_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Check whether the first strongly directional character (if any) is RTL.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether RTL directionality is detected using the first
* strongly-directional character method.
* @deprecated Use startsWithRtl.
*/
goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl;
/**
* Check whether the first strongly directional character (if any) is LTR.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether LTR directionality is detected using the first
* strongly-directional character method.
*/
goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) {
return goog.i18n.bidi.ltrDirCheckRe_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Check whether the first strongly directional character (if any) is LTR.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether LTR directionality is detected using the first
* strongly-directional character method.
* @deprecated Use startsWithLtr.
*/
goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr;
/**
* Regular expression to check if a string looks like something that must
* always be LTR even in RTL text, e.g. a URL. When estimating the
* directionality of text containing these, we treat these as weakly LTR,
* like numbers.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/;
/**
* Check whether the input string either contains no strongly directional
* characters or looks like a url.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether neutral directionality is detected.
*/
goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) {
str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml);
return goog.i18n.bidi.isRequiredLtrRe_.test(str) ||
!goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str);
};
/**
* Regular expressions to check if the last strongly-directional character in a
* piece of text is LTR.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp(
'[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$');
/**
* Regular expressions to check if the last strongly-directional character in a
* piece of text is RTL.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp(
'[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$');
/**
* Check if the exit directionality a piece of text is LTR, i.e. if the last
* strongly-directional character in the string is LTR.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether LTR exit directionality was detected.
*/
goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) {
return goog.i18n.bidi.ltrExitDirCheckRe_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Check if the exit directionality a piece of text is LTR, i.e. if the last
* strongly-directional character in the string is LTR.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether LTR exit directionality was detected.
* @deprecated Use endsWithLtr.
*/
goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr;
/**
* Check if the exit directionality a piece of text is RTL, i.e. if the last
* strongly-directional character in the string is RTL.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether RTL exit directionality was detected.
*/
goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) {
return goog.i18n.bidi.rtlExitDirCheckRe_.test(
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
};
/**
* Check if the exit directionality a piece of text is RTL, i.e. if the last
* strongly-directional character in the string is RTL.
* @param {string} str String being checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether RTL exit directionality was detected.
* @deprecated Use endsWithRtl.
*/
goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl;
/**
* A regular expression for matching right-to-left language codes.
* See {@link #isRtlLanguage} for the design.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rtlLocalesRe_ = new RegExp(
'^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' +
'.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' +
'(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)',
'i');
/**
* Check if a BCP 47 / III language code indicates an RTL language, i.e. either:
* - a language code explicitly specifying one of the right-to-left scripts,
* e.g. "az-Arab", or<p>
* - a language code specifying one of the languages normally written in a
* right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying
* Latin or Cyrillic script (which are the usual LTR alternatives).<p>
* The list of right-to-left scripts appears in the 100-199 range in
* http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
* Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
* Tifinagh, which also have significant modern usage. The rest (Syriac,
* Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
* and are not recognized to save on code size.
* The languages usually written in a right-to-left script are taken as those
* with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in
* http://www.iana.org/assignments/language-subtag-registry,
* as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug).
* Other subtags of the language code, e.g. regions like EG (Egypt), are
* ignored.
* @param {string} lang BCP 47 (a.k.a III) language code.
* @return {boolean} Whether the language code is an RTL language.
*/
goog.i18n.bidi.isRtlLanguage = function(lang) {
return goog.i18n.bidi.rtlLocalesRe_.test(lang);
};
/**
* Regular expression for bracket guard replacement in text.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.bracketGuardTextRe_ =
/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g;
/**
* Apply bracket guard using LRM and RLM. This is to address the problem of
* messy bracket display frequently happens in RTL layout.
* This function works for plain text, not for HTML. In HTML, the opening
* bracket might be in a different context than the closing bracket (such as
* an attribute value).
* @param {string} s The string that need to be processed.
* @param {boolean=} opt_isRtlContext specifies default direction (usually
* direction of the UI).
* @return {string} The processed string, with all bracket guarded.
*/
goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) {
var useRtl = opt_isRtlContext === undefined ? goog.i18n.bidi.hasAnyRtl(s) :
opt_isRtlContext;
var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM;
return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark);
};
/**
* Enforce the html snippet in RTL directionality regardless overall context.
* If the html piece was enclosed by tag, dir will be applied to existing
* tag, otherwise a span tag will be added as wrapper. For this reason, if
* html snippet start with with tag, this tag must enclose the whole piece. If
* the tag already has a dir specified, this new one will override existing
* one in behavior (tested on FF and IE).
* @param {string} html The string that need to be processed.
* @return {string} The processed string, with directionality enforced to RTL.
*/
goog.i18n.bidi.enforceRtlInHtml = function(html) {
if (html.charAt(0) == '<') {
return html.replace(/<\w+/, '$& dir=rtl');
}
// '\n' is important for FF so that it won't incorrectly merge span groups
return '\n<span dir=rtl>' + html + '</span>';
};
/**
* Enforce RTL on both end of the given text piece using unicode BiDi formatting
* characters RLE and PDF.
* @param {string} text The piece of text that need to be wrapped.
* @return {string} The wrapped string after process.
*/
goog.i18n.bidi.enforceRtlInText = function(text) {
return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF;
};
/**
* Enforce the html snippet in RTL directionality regardless overall context.
* If the html piece was enclosed by tag, dir will be applied to existing
* tag, otherwise a span tag will be added as wrapper. For this reason, if
* html snippet start with with tag, this tag must enclose the whole piece. If
* the tag already has a dir specified, this new one will override existing
* one in behavior (tested on FF and IE).
* @param {string} html The string that need to be processed.
* @return {string} The processed string, with directionality enforced to RTL.
*/
goog.i18n.bidi.enforceLtrInHtml = function(html) {
if (html.charAt(0) == '<') {
return html.replace(/<\w+/, '$& dir=ltr');
}
// '\n' is important for FF so that it won't incorrectly merge span groups
return '\n<span dir=ltr>' + html + '</span>';
};
/**
* Enforce LTR on both end of the given text piece using unicode BiDi formatting
* characters LRE and PDF.
* @param {string} text The piece of text that need to be wrapped.
* @return {string} The wrapped string after process.
*/
goog.i18n.bidi.enforceLtrInText = function(text) {
return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF;
};
/**
* Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;"
* @type {RegExp}
* @private
*/
goog.i18n.bidi.dimensionsRe_ =
/:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g;
/**
* Regular expression for left.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.leftRe_ = /left/gi;
/**
* Regular expression for right.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.rightRe_ = /right/gi;
/**
* Placeholder regular expression for swapping.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.tempRe_ = /%%%%/g;
/**
* Swap location parameters and 'left'/'right' in CSS specification. The
* processed string will be suited for RTL layout. Though this function can
* cover most cases, there are always exceptions. It is suggested to put
* those exceptions in separate group of CSS string.
* @param {string} cssStr CSS spefication string.
* @return {string} Processed CSS specification string.
*/
goog.i18n.bidi.mirrorCSS = function(cssStr) {
return cssStr
.
// reverse dimensions
replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2')
.replace(goog.i18n.bidi.leftRe_, '%%%%')
. // swap left and right
replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT)
.replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT);
};
/**
* Regular expression for hebrew double quote substitution, finding quote
* directly after hebrew characters.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g;
/**
* Regular expression for hebrew single quote substitution, finding quote
* directly after hebrew characters.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g;
/**
* Replace the double and single quote directly after a Hebrew character with
* GERESH and GERSHAYIM. In such case, most likely that's user intention.
* @param {string} str String that need to be processed.
* @return {string} Processed string with double/single quote replaced.
*/
goog.i18n.bidi.normalizeHebrewQuote = function(str) {
return str.replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4')
.replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3');
};
/**
* Regular expression to split a string into "words" for directionality
* estimation based on relative word counts.
* @type {RegExp}
* @private
*/
goog.i18n.bidi.wordSeparatorRe_ = /\s+/;
/**
* Regular expression to check if a string contains any numerals. Used to
* differentiate between completely neutral strings and those containing
* numbers, which are weakly LTR.
*
* Native Arabic digits (\u0660 - \u0669) are not included because although they
* do flow left-to-right inside a number, this is the case even if the overall
* directionality is RTL, and a mathematical expression using these digits is
* supposed to flow right-to-left overall, including unary plus and minus
* appearing to the right of a number, and this does depend on the overall
* directionality being RTL. The digits used in Farsi (\u06F0 - \u06F9), on the
* other hand, are included, since Farsi math (including unary plus and minus)
* does flow left-to-right.
*
* @type {RegExp}
* @private
*/
goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/;
/**
* This constant controls threshold of RTL directionality.
* @type {number}
* @private
*/
goog.i18n.bidi.rtlDetectionThreshold_ = 0.40;
/**
* Estimates the directionality of a string based on relative word counts.
* If the number of RTL words is above a certain percentage of the total number
* of strongly directional words, returns RTL.
* Otherwise, if any words are strongly or weakly LTR, returns LTR.
* Otherwise, returns UNKNOWN, which is used to mean "neutral".
* Numbers are counted as weakly LTR.
* @param {string} str The string to be checked.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}.
*/
goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) {
var rtlCount = 0;
var totalCount = 0;
var hasWeaklyLtr = false;
var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)
.split(goog.i18n.bidi.wordSeparatorRe_);
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (goog.i18n.bidi.startsWithRtl(token)) {
rtlCount++;
totalCount++;
} else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) {
hasWeaklyLtr = true;
} else if (goog.i18n.bidi.hasAnyLtr(token)) {
totalCount++;
} else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) {
hasWeaklyLtr = true;
}
}
return totalCount == 0 ?
(hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) :
(rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ?
goog.i18n.bidi.Dir.RTL :
goog.i18n.bidi.Dir.LTR);
};
/**
* Check the directionality of a piece of text, return true if the piece of
* text should be laid out in RTL direction.
* @param {string} str The piece of text that need to be detected.
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
* Default: false.
* @return {boolean} Whether this piece of text should be laid out in RTL.
*/
goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) {
return goog.i18n.bidi.estimateDirection(str, opt_isHtml) ==
goog.i18n.bidi.Dir.RTL;
};
/**
* Sets text input element's directionality and text alignment based on a
* given directionality. Does nothing if the given directionality is unknown or
* neutral.
* @param {Element} element Input field element to set directionality to.
* @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality,
* given in one of the following formats:
* 1. A goog.i18n.bidi.Dir constant.
* 2. A number (positive = LRT, negative = RTL, 0 = neutral).
* 3. A boolean (true = RTL, false = LTR).
* 4. A null for unknown directionality.
*/
goog.i18n.bidi.setElementDirAndAlign = function(element, dir) {
if (element) {
dir = goog.i18n.bidi.toDir(dir);
if (dir) {
element.style.textAlign = dir == goog.i18n.bidi.Dir.RTL ?
goog.i18n.bidi.RIGHT :
goog.i18n.bidi.LEFT;
element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
}
}
};
/**
* Sets element dir based on estimated directionality of the given text.
* @param {!Element} element
* @param {string} text
*/
goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) {
switch (goog.i18n.bidi.estimateDirection(text)) {
case (goog.i18n.bidi.Dir.LTR):
element.dir = 'ltr';
break;
case (goog.i18n.bidi.Dir.RTL):
element.dir = 'rtl';
break;
default:
// Default for no direction, inherit from document.
element.removeAttribute('dir');
}
};
/**
* Strings that have an (optional) known direction.
*
* Implementations of this interface are string-like objects that carry an
* attached direction, if known.
* @interface
*/
goog.i18n.bidi.DirectionalString = function() {};
/**
* Interface marker of the DirectionalString interface.
*
* This property can be used to determine at runtime whether or not an object
* implements this interface. All implementations of this interface set this
* property to {@code true}.
* @type {boolean}
*/
goog.i18n.bidi.DirectionalString.prototype
.implementsGoogI18nBidiDirectionalString;
/**
* Retrieves this object's known direction (if any).
* @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown.
*/
goog.i18n.bidi.DirectionalString.prototype.getDirection;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,437 @@
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// 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 A utility to get better currency format pattern.
*
* This module implements a new currency format representation model. It
* provides 3 currency representation forms: global, portable and local. Local
* format is the most popular format people use to represent currency in its
* circulating country without worrying about how it should be distinguished
* from other currencies. Global format is a formal representation in context
* of multiple currencies in same page, it is ISO 4217 currency code. Portable
* format is a compromise between global and local. It looks similar to how
* people would like to see how their currency is being represented in other
* media. While at the same time, it should be distinguishable to world's
* popular currencies (like USD, EUR) and currencies somewhat relevant in the
* area (like CNY in HK, though native currency is HKD). There is no guarantee
* of uniqueness.
*
*/
goog.provide('goog.i18n.currency');
goog.provide('goog.i18n.currency.CurrencyInfo');
goog.provide('goog.i18n.currency.CurrencyInfoTier2');
/**
* The mask of precision field.
* @private
*/
goog.i18n.currency.PRECISION_MASK_ = 0x07;
/**
* Whether the currency sign should be positioned after the number.
* @private
*/
goog.i18n.currency.POSITION_FLAG_ = 0x10;
/**
* Whether a space should be inserted between the number and currency sign.
* @private
*/
goog.i18n.currency.SPACE_FLAG_ = 0x20;
/**
* Whether tier2 was enabled already by calling addTier2Support().
* @private
*/
goog.i18n.currency.tier2Enabled_ = false;
/**
* This function will add tier2 currency support. Be default, only tier1
* (most popular currencies) are supported. If an application really needs
* to support some of the rarely used currencies, it should call this function
* before any other functions in this namespace.
*/
goog.i18n.currency.addTier2Support = function() {
// Protection from executing this these again and again.
if (!goog.i18n.currency.tier2Enabled_) {
for (var key in goog.i18n.currency.CurrencyInfoTier2) {
goog.i18n.currency.CurrencyInfo[key] =
goog.i18n.currency.CurrencyInfoTier2[key];
}
goog.i18n.currency.tier2Enabled_ = true;
}
};
/**
* Global currency pattern always uses ISO-4217 currency code as prefix. Local
* currency sign is added if it is different from currency code. Each currency
* is unique in this form. The negative side is that ISO code looks weird in
* some countries as people normally do not use it. Local currency sign
* alleviates the problem, but also makes it a little verbose.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Global currency pattern string for given currency.
*/
goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
var patternNum = info[0];
if (currencyCode == info[1]) {
return goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
}
return currencyCode + ' ' +
goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
};
/**
* Return global currency sign string for those applications
* that want to handle currency sign themselves.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Global currency sign for given currency.
*/
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
return (currencyCode == info[1]) ? currencyCode :
currencyCode + ' ' + info[1];
};
/**
* Local currency pattern is the most frequently used pattern in currency's
* native region. It does not care about how it is distinguished from other
* currencies.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Local currency pattern string for given currency.
*/
goog.i18n.currency.getLocalCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
return goog.i18n.currency.getCurrencyPattern_(info[0], info[1]);
};
/**
* Returns local currency sign string for those applications that need to
* handle currency sign separately.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Local currency sign for given currency.
*/
goog.i18n.currency.getLocalCurrencySign = function(currencyCode) {
return goog.i18n.currency.CurrencyInfo[currencyCode][1];
};
/**
* Portable currency pattern is a compromise between local and global. It is
* not a mere blend or mid-way between the two. Currency sign is chosen so that
* it looks familiar to native users. It also has enough information to
* distinguish itself from other popular currencies in its native region.
* In this pattern, currency sign symbols that has availability problem in
* popular fonts are also avoided.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Portable currency pattern string for given currency.
*/
goog.i18n.currency.getPortableCurrencyPattern = function(currencyCode) {
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
return goog.i18n.currency.getCurrencyPattern_(info[0], info[2]);
};
/**
* Return portable currency sign string for those applications that need to
* handle currency sign themselves.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {string} Portable currency sign for given currency.
*/
goog.i18n.currency.getPortableCurrencySign = function(currencyCode) {
return goog.i18n.currency.CurrencyInfo[currencyCode][2];
};
/**
* This function returns the default currency sign position. Some applications
* may want to handle currency sign and currency amount separately. This
* function can be used in such situations to correctly position the currency
* sign relative to the amount.
*
* To match the behavior of ICU, position is not determined by display locale.
*
* @param {string} currencyCode ISO-4217 3-letter currency code.
* @return {boolean} true if currency should be positioned before amount field.
*/
goog.i18n.currency.isPrefixSignPosition = function(currencyCode) {
return (goog.i18n.currency.CurrencyInfo[currencyCode][0] &
goog.i18n.currency.POSITION_FLAG_) == 0;
};
/**
* This function constructs the currency pattern. Currency sign is provided. The
* pattern information is encoded in patternNum.
*
* @param {number} patternNum Encoded pattern number that has
* currency pattern information.
* @param {string} sign The currency sign that will be used in pattern.
* @return {string} currency pattern string.
* @private
*/
goog.i18n.currency.getCurrencyPattern_ = function(patternNum, sign) {
var strParts = ['#,##0'];
var precision = patternNum & goog.i18n.currency.PRECISION_MASK_;
if (precision > 0) {
strParts.push('.');
for (var i = 0; i < precision; i++) {
strParts.push('0');
}
}
if ((patternNum & goog.i18n.currency.POSITION_FLAG_) == 0) {
strParts.unshift(
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? "' " : "'");
strParts.unshift(sign);
strParts.unshift("'");
} else {
strParts.push(
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'", sign, "'");
}
return strParts.join('');
};
/**
* Modify currency pattern string by adjusting precision for given currency.
* Standard currency pattern will have 2 digit after decimal point.
* Examples:
* $#,##0.00 -> $#,##0 (precision == 0)
* $#,##0.00 -> $#,##0.0 (precision == 1)
* $#,##0.00 -> $#,##0.000 (precision == 3)
*
* @param {string} pattern currency pattern string.
* @param {string} currencyCode 3-letter currency code.
* @return {string} modified currency pattern string.
*/
goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
var strParts = ['0'];
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
var precision = info[0] & goog.i18n.currency.PRECISION_MASK_;
if (precision > 0) {
strParts.push('.');
for (var i = 0; i < precision; i++) {
strParts.push('0');
}
}
return pattern.replace(/0.00/g, strParts.join(''));
};
/**
* Tier 1 currency information.
*
* The first number in the array is a combination of the precision mask and
* other flags. The precision mask indicates how many decimal places to show for
* the currency. Valid values are [0..7]. The position flag indicates whether
* the currency sign should be positioned after the number. Valid values are 0
* (before the number) or 16 (after the number). The space flag indicates
* whether a space should be inserted between the currency sign and number.
* Valid values are 0 (no space) and 32 (space).
*
* The number in the array is calculated by adding together the mask and flag
* values. For example:
*
* 0: no precision (0), currency sign first (0), no space (0)
* 2: two decimals precision (2), currency sign first (0), no space (0)
* 18: two decimals precision (2), currency sign last (16), no space (0)
* 50: two decimals precision (2), currency sign last (16), space (32)
*
* @const {!Object<!Array<?>>}
*/
goog.i18n.currency.CurrencyInfo = {
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
'ALL': [0, 'Lek', 'Lek'],
'AUD': [2, '$', 'AU$'],
'BDT': [2, '\u09F3', 'Tk'],
'BGN': [2, 'lev', 'lev'],
'BRL': [2, 'R$', 'R$'],
'CAD': [2, '$', 'C$'],
'CDF': [2, 'FrCD', 'CDF'],
'CHF': [2, 'CHF', 'CHF'],
'CLP': [0, '$', 'CL$'],
'CNY': [2, '¥', 'RMB¥'],
'COP': [32, '$', 'COL$'],
'CRC': [0, '\u20a1', 'CR\u20a1'],
'CZK': [50, 'K\u010d', 'K\u010d'],
'DKK': [50, 'kr.', 'kr.'],
'DOP': [2, 'RD$', 'RD$'],
'EGP': [2, '£', 'LE'],
'ETB': [2, 'Birr', 'Birr'],
'EUR': [2, '€', '€'],
'GBP': [2, '£', 'GB£'],
'HKD': [2, '$', 'HK$'],
'HRK': [2, 'kn', 'kn'],
'HUF': [34, 'Ft', 'Ft'],
'IDR': [0, 'Rp', 'Rp'],
'ILS': [34, '\u20AA', 'IL\u20AA'],
'INR': [2, '\u20B9', 'Rs'],
'IRR': [0, 'Rial', 'IRR'],
'ISK': [0, 'kr', 'kr'],
'JMD': [2, '$', 'JA$'],
'JPY': [0, '¥', 'JP¥'],
'KRW': [0, '\u20A9', 'KR₩'],
'LKR': [2, 'Rs', 'SLRs'],
'LTL': [2, 'Lt', 'Lt'],
'MNT': [0, '\u20AE', 'MN₮'],
'MVR': [2, 'Rf', 'MVR'],
'MXN': [2, '$', 'Mex$'],
'MYR': [2, 'RM', 'RM'],
'NOK': [50, 'kr', 'NOkr'],
'PAB': [2, 'B/.', 'B/.'],
'PEN': [2, 'S/.', 'S/.'],
'PHP': [2, '\u20B1', 'Php'],
'PKR': [0, 'Rs', 'PKRs.'],
'PLN': [50, 'z\u0142', 'z\u0142'],
'RON': [2, 'RON', 'RON'],
'RSD': [0, 'din', 'RSD'],
'RUB': [50, '\u20bd', 'RUB'],
'SAR': [2, 'Rial', 'Rial'],
'SEK': [50, 'kr', 'kr'],
'SGD': [2, '$', 'S$'],
'THB': [2, '\u0e3f', 'THB'],
'TRY': [2, 'TL', 'YTL'],
'TWD': [2, 'NT$', 'NT$'],
'TZS': [0, 'TSh', 'TSh'],
'UAH': [2, 'грн.', 'UAH'],
'USD': [2, '$', 'US$'],
'UYU': [2, '$', '$U'],
'VND': [48, '\u20AB', 'VN\u20AB'],
'YER': [0, 'Rial', 'Rial'],
'ZAR': [2, 'R', 'ZAR']
};
/**
* Tier 2 currency information.
* @const {!Object<!Array<?>>}
*/
goog.i18n.currency.CurrencyInfoTier2 = {
'AFN': [48, 'Af.', 'AFN'],
'AMD': [32, 'Dram', 'dram'],
'ANG': [2, 'NAf.', 'ANG'],
'AOA': [2, 'Kz', 'Kz'],
'ARS': [34, '$', 'AR$'],
'AWG': [2, 'Afl.', 'Afl.'],
'AZN': [34, '\u20bc', 'AZN'],
'BAM': [2, 'KM', 'KM'],
'BBD': [2, '$', 'Bds$'],
'BHD': [3, 'din', 'din'],
'BIF': [0, 'FBu', 'FBu'],
'BMD': [2, '$', 'BD$'],
'BND': [2, '$', 'B$'],
'BOB': [2, 'Bs', 'Bs'],
'BSD': [2, '$', 'BS$'],
'BTN': [2, 'Nu.', 'Nu.'],
'BWP': [2, 'P', 'pula'],
'BYR': [48, 'p.', 'BYR'],
'BZD': [2, '$', 'BZ$'],
'CUC': [1, '$', 'CUC$'],
'CUP': [2, '$', 'CU$'],
'CVE': [2, 'CVE', 'Esc'],
'DJF': [0, 'Fdj', 'Fdj'],
'DZD': [2, 'din', 'din'],
'ERN': [2, 'Nfk', 'Nfk'],
'FJD': [2, '$', 'FJ$'],
'FKP': [2, '£', 'FK£'],
'GEL': [2, 'GEL', 'GEL'],
'GHS': [2, 'GHS', 'GHS'],
'GIP': [2, '£', 'GI£'],
'GMD': [2, 'GMD', 'GMD'],
'GNF': [0, 'FG', 'FG'],
'GTQ': [2, 'Q', 'GTQ'],
'GYD': [0, '$', 'GY$'],
'HNL': [2, 'L', 'HNL'],
'HTG': [2, 'HTG', 'HTG'],
'IQD': [0, 'din', 'IQD'],
'JOD': [3, 'din', 'JOD'],
'KES': [2, 'Ksh', 'Ksh'],
'KGS': [2, 'KGS', 'KGS'],
'KHR': [2, 'Riel', 'KHR'],
'KMF': [0, 'CF', 'KMF'],
'KPW': [0, '\u20A9KP', 'KPW'],
'KWD': [3, 'din', 'KWD'],
'KYD': [2, '$', 'KY$'],
'KZT': [2, '\u20B8', 'KZT'],
'LAK': [0, '\u20AD', '\u20AD'],
'LBP': [0, 'L£', 'LBP'],
'LRD': [2, '$', 'L$'],
'LSL': [2, 'LSL', 'LSL'],
'LYD': [3, 'din', 'LD'],
'MAD': [2, 'dh', 'MAD'],
'MDL': [2, 'MDL', 'MDL'],
'MGA': [0, 'Ar', 'MGA'],
'MKD': [2, 'din', 'MKD'],
'MMK': [0, 'K', 'MMK'],
'MOP': [2, 'MOP', 'MOP$'],
'MRO': [0, 'MRO', 'MRO'],
'MUR': [0, 'MURs', 'MURs'],
'MWK': [2, 'MWK', 'MWK'],
'MZN': [2, 'MTn', 'MTn'],
'NAD': [2, '$', 'N$'],
'NGN': [2, '\u20A6', 'NG\u20A6'],
'NIO': [2, 'C$', 'C$'],
'NPR': [2, 'Rs', 'NPRs'],
'NZD': [2, '$', 'NZ$'],
'OMR': [3, 'Rial', 'OMR'],
'PGK': [2, 'PGK', 'PGK'],
'PYG': [16, 'Gs.', 'PYG'],
'QAR': [2, 'Rial', 'QR'],
'RWF': [0, 'RF', 'RF'],
'SBD': [2, '$', 'SI$'],
'SCR': [2, 'SCR', 'SCR'],
'SDG': [2, 'SDG', 'SDG'],
'SHP': [2, '£', 'SH£'],
'SLL': [0, 'SLL', 'SLL'],
'SOS': [0, 'SOS', 'SOS'],
'SRD': [2, '$', 'SR$'],
'SSP': [2, '£', 'SSP'],
'STD': [0, 'Db', 'Db'],
'SYP': [0, '£', 'SY£'],
'SZL': [2, 'SZL', 'SZL'],
'TJS': [2, 'Som', 'TJS'],
'TND': [3, 'din', 'DT'],
'TOP': [2, 'T$', 'T$'],
'TTD': [2, '$', 'TT$'],
'UGX': [0, 'UGX', 'UGX'],
'UZS': [0, 'so\u02bcm', 'UZS'],
'VEF': [2, 'Bs', 'Bs'],
'VUV': [0, 'VUV', 'VUV'],
'WST': [2, 'WST', 'WST'],
'XAF': [0, 'FCFA', 'FCFA'],
'XCD': [2, '$', 'EC$'],
'XOF': [0, 'CFA', 'CFA'],
'XPF': [0, 'FCFP', 'FCFP'],
'ZMW': [0, 'ZMW', 'ZMW'],
'ZWD': [0, '$', 'Z$']
};

View file

@ -0,0 +1,882 @@
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// 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 Functions for dealing with date/time formatting.
*/
/**
* Namespace for i18n date/time formatting functions
*/
goog.provide('goog.i18n.DateTimeFormat');
goog.provide('goog.i18n.DateTimeFormat.Format');
goog.require('goog.asserts');
goog.require('goog.date');
goog.require('goog.i18n.DateTimeSymbols');
goog.require('goog.i18n.TimeZone');
goog.require('goog.string');
/**
* Datetime formatting functions following the pattern specification as defined
* in JDK, ICU and CLDR, with minor modification for typical usage in JS.
* Pattern specification:
* {@link http://userguide.icu-project.org/formatparse/datetime}
* <pre>
* Symbol Meaning Presentation Example
* ------ ------- ------------ -------
* G# era designator (Text) AD
* y# year (Number) 1996
* Y* year (week of year) (Number) 1997
* u* extended year (Number) 4601
* Q# quarter (Text) Q3 & 3rd quarter
* M month in year (Text & Number) July & 07
* L month in year (standalone) (Text & Number) July & 07
* d day in month (Number) 10
* h hour in am/pm (1~12) (Number) 12
* H hour in day (0~23) (Number) 0
* m minute in hour (Number) 30
* s second in minute (Number) 55
* S fractional second (Number) 978
* E# day of week (Text) Tue & Tuesday
* e* day of week (local 1~7) (Number) 2
* c# day of week (standalone) (Text & Number) 2 & Tues & Tuesday & T
* D* day in year (Number) 189
* F* day of week in month (Number) 2 (2nd Wed in July)
* w week in year (Number) 27
* W* week in month (Number) 2
* a am/pm marker (Text) PM
* k hour in day (1~24) (Number) 24
* K hour in am/pm (0~11) (Number) 0
* z time zone (Text) Pacific Standard Time
* Z# time zone (RFC 822) (Number) -0800
* v# time zone (generic) (Text) America/Los_Angeles
* V# time zone (Text) Los Angeles Time
* g* Julian day (Number) 2451334
* A* milliseconds in day (Number) 69540000
* ' escape for text (Delimiter) 'Date='
* '' single quote (Literal) 'o''clock'
*
* Item marked with '*' are not supported yet.
* Item marked with '#' works different than java
*
* The count of pattern letters determine the format.
* (Text): 4 or more, use full form, <4, use short or abbreviated form if it
* exists. (e.g., "EEEE" produces "Monday", "EEE" produces "Mon")
*
* (Number): the minimum number of digits. Shorter numbers are zero-padded to
* this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled
* specially; that is, if the count of 'y' is 2, the Year will be truncated to
* 2 digits. (e.g., if "yyyy" produces "1997", "yy" produces "97".) Unlike other
* fields, fractional seconds are padded on the right with zero.
*
* :(Text & Number) 3 or over, use text, otherwise use number. (e.g., "M"
* produces "1", "MM" produces "01", "MMM" produces "Jan", and "MMMM" produces
* "January".)
*
* Any characters in the pattern that are not in the ranges of ['a'..'z'] and
* ['A'..'Z'] will be treated as quoted text. For instance, characters like ':',
* '.', ' ', '#' and '@' will appear in the resulting time text even they are
* not embraced within single quotes.
* </pre>
*/
/**
* Construct a DateTimeFormat object based on current locale.
* @constructor
* @param {string|number} pattern pattern specification or pattern type.
* @param {!Object=} opt_dateTimeSymbols Optional symbols to use for this
* instance rather than the global symbols.
* @final
*/
goog.i18n.DateTimeFormat = function(pattern, opt_dateTimeSymbols) {
goog.asserts.assert(goog.isDef(pattern), 'Pattern must be defined');
goog.asserts.assert(
goog.isDef(opt_dateTimeSymbols) || goog.isDef(goog.i18n.DateTimeSymbols),
'goog.i18n.DateTimeSymbols or explicit symbols must be defined');
this.patternParts_ = [];
/**
* Data structure that with all the locale info needed for date formatting.
* (day/month names, most common patterns, rules for week-end, etc.)
* @private {!goog.i18n.DateTimeSymbolsType}
*/
this.dateTimeSymbols_ = /** @type {!goog.i18n.DateTimeSymbolsType} */ (
opt_dateTimeSymbols || goog.i18n.DateTimeSymbols);
if (typeof pattern == 'number') {
this.applyStandardPattern_(pattern);
} else {
this.applyPattern_(pattern);
}
};
/**
* Enum to identify predefined Date/Time format pattern.
* @enum {number}
*/
goog.i18n.DateTimeFormat.Format = {
FULL_DATE: 0,
LONG_DATE: 1,
MEDIUM_DATE: 2,
SHORT_DATE: 3,
FULL_TIME: 4,
LONG_TIME: 5,
MEDIUM_TIME: 6,
SHORT_TIME: 7,
FULL_DATETIME: 8,
LONG_DATETIME: 9,
MEDIUM_DATETIME: 10,
SHORT_DATETIME: 11
};
/**
* regular expression pattern for parsing pattern string
* @type {Array<RegExp>}
* @private
*/
goog.i18n.DateTimeFormat.TOKENS_ = [
// quote string
/^\'(?:[^\']|\'\')*\'/,
// pattern chars
/^(?:G+|y+|M+|k+|S+|E+|a+|h+|K+|H+|c+|L+|Q+|d+|m+|s+|v+|V+|w+|z+|Z+)/,
// and all the other chars
/^[^\'GyMkSEahKHcLQdmsvVwzZ]+/ // and all the other chars
];
/**
* These are token types, corresponding to above token definitions.
* @enum {number}
* @private
*/
goog.i18n.DateTimeFormat.PartTypes_ = {
QUOTED_STRING: 0,
FIELD: 1,
LITERAL: 2
};
/**
* @param {!goog.date.DateLike} date
* @return {number}
* @private
*/
goog.i18n.DateTimeFormat.getHours_ = function(date) {
return date.getHours ? date.getHours() : 0;
};
/**
* Apply specified pattern to this formatter object.
* @param {string} pattern String specifying how the date should be formatted.
* @private
*/
goog.i18n.DateTimeFormat.prototype.applyPattern_ = function(pattern) {
if (goog.i18n.DateTimeFormat.removeRlmInPatterns_) {
// Remove RLM unicode control character from pattern.
pattern = pattern.replace(/\u200f/g, '');
}
// lex the pattern, once for all uses
while (pattern) {
for (var i = 0; i < goog.i18n.DateTimeFormat.TOKENS_.length; ++i) {
var m = pattern.match(goog.i18n.DateTimeFormat.TOKENS_[i]);
if (m) {
var part = m[0];
pattern = pattern.substring(part.length);
if (i == goog.i18n.DateTimeFormat.PartTypes_.QUOTED_STRING) {
if (part == "''") {
part = "'"; // '' -> '
} else {
part = part.substring(1, part.length - 1); // strip quotes
part = part.replace(/\'\'/, "'");
}
}
this.patternParts_.push({text: part, type: i});
break;
}
}
}
};
/**
* Format the given date object according to preset pattern and current locale.
* @param {goog.date.DateLike} date The Date object that is being formatted.
* @param {goog.i18n.TimeZone=} opt_timeZone optional, if specified, time
* related fields will be formatted based on its setting. When this field
* is not specified, "undefined" will be pass around and those function
* that really need time zone service will create a default one.
* @return {string} Formatted string for the given date.
* Throws an error if the date is null or if one tries to format a date-only
* object (for instance goog.date.Date) using a pattern with time fields.
*/
goog.i18n.DateTimeFormat.prototype.format = function(date, opt_timeZone) {
if (!date) throw Error('The date to format must be non-null.');
// We don't want to write code to calculate each date field because we
// want to maximize performance and minimize code size.
// JavaScript only provide API to render local time.
// Suppose target date is: 16:00 GMT-0400
// OS local time is: 12:00 GMT-0800
// We want to create a Local Date Object : 16:00 GMT-0800, and fix the
// time zone display ourselves.
// Thing get a little bit tricky when daylight time transition happens. For
// example, suppose OS timeZone is America/Los_Angeles, it is impossible to
// represent "2006/4/2 02:30" even for those timeZone that has no transition
// at this time. Because 2:00 to 3:00 on that day does not exist in
// America/Los_Angeles time zone. To avoid calculating date field through
// our own code, we uses 3 Date object instead, one for "Year, month, day",
// one for time within that day, and one for timeZone object since it need
// the real time to figure out actual time zone offset.
var diff = opt_timeZone ?
(date.getTimezoneOffset() - opt_timeZone.getOffset(date)) * 60000 :
0;
var dateForDate = diff ? new Date(date.getTime() + diff) : date;
var dateForTime = dateForDate;
// When the time manipulation applied above spans the DST on/off hour, this
// could alter the time incorrectly by adding or subtracting an additional
// hour.
// We can mitigate this by:
// - Adding the difference in timezone offset to the date. This ensures that
// the dateForDate is still within the right day if the extra DST hour
// affected the date.
// - Move the time one day forward if we applied a timezone offset backwards,
// or vice versa. This trick ensures that the time is in the same offset
// as the original date, so we remove the additional hour added or
// subtracted by the DST switch.
if (opt_timeZone &&
dateForDate.getTimezoneOffset() != date.getTimezoneOffset()) {
var dstDiff =
(dateForDate.getTimezoneOffset() - date.getTimezoneOffset()) * 60000;
dateForDate = new Date(dateForDate.getTime() + dstDiff);
diff += diff > 0 ? -goog.date.MS_PER_DAY : goog.date.MS_PER_DAY;
dateForTime = new Date(date.getTime() + diff);
}
var out = [];
for (var i = 0; i < this.patternParts_.length; ++i) {
var text = this.patternParts_[i].text;
if (goog.i18n.DateTimeFormat.PartTypes_.FIELD ==
this.patternParts_[i].type) {
out.push(
this.formatField_(
text, date, dateForDate, dateForTime, opt_timeZone));
} else {
out.push(text);
}
}
return out.join('');
};
/**
* Apply a predefined pattern as identified by formatType, which is stored in
* locale specific repository.
* @param {number} formatType A number that identified the predefined pattern.
* @private
*/
goog.i18n.DateTimeFormat.prototype.applyStandardPattern_ = function(
formatType) {
var pattern;
if (formatType < 4) {
pattern = this.dateTimeSymbols_.DATEFORMATS[formatType];
} else if (formatType < 8) {
pattern = this.dateTimeSymbols_.TIMEFORMATS[formatType - 4];
} else if (formatType < 12) {
pattern = this.dateTimeSymbols_.DATETIMEFORMATS[formatType - 8];
pattern = pattern.replace(
'{1}', this.dateTimeSymbols_.DATEFORMATS[formatType - 8]);
pattern = pattern.replace(
'{0}', this.dateTimeSymbols_.TIMEFORMATS[formatType - 8]);
} else {
this.applyStandardPattern_(goog.i18n.DateTimeFormat.Format.MEDIUM_DATETIME);
return;
}
this.applyPattern_(pattern);
};
/**
* Localizes a string potentially containing numbers, replacing ASCII digits
* with native digits if specified so by the locale. Leaves other characters.
* @param {string} input the string to be localized, using ASCII digits.
* @return {string} localized string, potentially using native digits.
* @private
*/
goog.i18n.DateTimeFormat.prototype.localizeNumbers_ = function(input) {
return goog.i18n.DateTimeFormat.localizeNumbers(input, this.dateTimeSymbols_);
};
/**
* If the usage of Ascii digits should be enforced regardless of locale.
* @type {boolean}
* @private
*/
goog.i18n.DateTimeFormat.enforceAsciiDigits_ = false;
/**
* If RLM unicode characters should be removed from date/time patterns (useful
* when enforcing ASCII digits for Arabic). See {@code #setEnforceAsciiDigits}.
* @type {boolean}
* @private
*/
goog.i18n.DateTimeFormat.removeRlmInPatterns_ = false;
/**
* Sets if the usage of Ascii digits in formatting should be enforced in
* formatted date/time even for locales where native digits are indicated.
* Also sets whether to remove RLM unicode control characters when using
* standard enumerated patterns (they exist e.g. in standard d/M/y for Arabic).
* Production code should call this once before any {@code DateTimeFormat}
* object is instantiated.
* Caveats:
* * Enforcing ASCII digits affects all future formatting by new or existing
* {@code DateTimeFormat} objects.
* * Removal of RLM characters only applies to {@code DateTimeFormat} objects
* instantiated after this call.
* @param {boolean} enforceAsciiDigits Whether Ascii digits should be enforced.
*/
goog.i18n.DateTimeFormat.setEnforceAsciiDigits = function(enforceAsciiDigits) {
goog.i18n.DateTimeFormat.enforceAsciiDigits_ = enforceAsciiDigits;
// Also setting removal of RLM chracters when forcing ASCII digits since it's
// the right thing to do for Arabic standard patterns. One could add an
// optional argument here or to the {@code DateTimeFormat} constructor to
// enable an alternative behavior.
goog.i18n.DateTimeFormat.removeRlmInPatterns_ = enforceAsciiDigits;
};
/**
* @return {boolean} Whether enforcing ASCII digits for all locales. See
* {@code #setEnforceAsciiDigits} for more details.
*/
goog.i18n.DateTimeFormat.isEnforceAsciiDigits = function() {
return goog.i18n.DateTimeFormat.enforceAsciiDigits_;
};
/**
* Localizes a string potentially containing numbers, replacing ASCII digits
* with native digits if specified so by the locale. Leaves other characters.
* @param {number|string} input the string to be localized, using ASCII digits.
* @param {!Object=} opt_dateTimeSymbols Optional symbols to use rather than
* the global symbols.
* @return {string} localized string, potentially using native digits.
*/
goog.i18n.DateTimeFormat.localizeNumbers = function(
input, opt_dateTimeSymbols) {
input = String(input);
var dateTimeSymbols = opt_dateTimeSymbols || goog.i18n.DateTimeSymbols;
if (dateTimeSymbols.ZERODIGIT === undefined ||
goog.i18n.DateTimeFormat.enforceAsciiDigits_) {
return input;
}
var parts = [];
for (var i = 0; i < input.length; i++) {
var c = input.charCodeAt(i);
parts.push(
(0x30 <= c && c <= 0x39) ? // '0' <= c <= '9'
String.fromCharCode(dateTimeSymbols.ZERODIGIT + c - 0x30) :
input.charAt(i));
}
return parts.join('');
};
/**
* Formats Era field according to pattern specified.
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatEra_ = function(count, date) {
var value = date.getFullYear() > 0 ? 1 : 0;
return count >= 4 ? this.dateTimeSymbols_.ERANAMES[value] :
this.dateTimeSymbols_.ERAS[value];
};
/**
* Formats Year field according to pattern specified
* Javascript Date object seems incapable handling 1BC and
* year before. It can show you year 0 which does not exists.
* following we just keep consistent with javascript's
* toString method. But keep in mind those things should be
* unsupported.
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatYear_ = function(count, date) {
var value = date.getFullYear();
if (value < 0) {
value = -value;
}
if (count == 2) {
// See comment about special casing 'yy' at the start of the file, this
// matches ICU and CLDR behaviour. See also:
// http://icu-project.org/apiref/icu4j/com/ibm/icu/text/SimpleDateFormat.html
// http://www.unicode.org/reports/tr35/tr35-dates.html
value = value % 100;
}
return this.localizeNumbers_(goog.string.padNumber(value, count));
};
/**
* Formats Month field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatMonth_ = function(count, date) {
var value = date.getMonth();
switch (count) {
case 5:
return this.dateTimeSymbols_.NARROWMONTHS[value];
case 4:
return this.dateTimeSymbols_.MONTHS[value];
case 3:
return this.dateTimeSymbols_.SHORTMONTHS[value];
default:
return this.localizeNumbers_(goog.string.padNumber(value + 1, count));
}
};
/**
* Validates is the goog.date.DateLike object to format has a time.
* DateLike means Date|goog.date.Date, and goog.date.DateTime inherits
* from goog.date.Date. But goog.date.Date does not have time related
* members (getHours, getMinutes, getSeconds).
* Formatting can be done, if there are no time placeholders in the pattern.
*
* @param {!goog.date.DateLike} date the object to validate.
* @private
*/
goog.i18n.DateTimeFormat.validateDateHasTime_ = function(date) {
if (date.getHours && date.getSeconds && date.getMinutes) return;
// if (date instanceof Date || date instanceof goog.date.DateTime)
throw Error(
'The date to format has no time (probably a goog.date.Date). ' +
'Use Date or goog.date.DateTime, or use a pattern without time fields.');
};
/**
* Formats (1..24) Hours field according to pattern specified
*
* @param {number} count Number of time pattern char repeats. This controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.format24Hours_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
var hours = goog.i18n.DateTimeFormat.getHours_(date) || 24;
return this.localizeNumbers_(goog.string.padNumber(hours, count));
};
/**
* Formats Fractional seconds field according to pattern
* specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
*
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatFractionalSeconds_ = function(
count, date) {
// Fractional seconds left-justify, append 0 for precision beyond 3
var value = date.getTime() % 1000 / 1000;
return this.localizeNumbers_(
value.toFixed(Math.min(3, count)).substr(2) +
(count > 3 ? goog.string.padNumber(0, count - 3) : ''));
};
/**
* Formats Day of week field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatDayOfWeek_ = function(count, date) {
var value = date.getDay();
return count >= 4 ? this.dateTimeSymbols_.WEEKDAYS[value] :
this.dateTimeSymbols_.SHORTWEEKDAYS[value];
};
/**
* Formats Am/Pm field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatAmPm_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
var hours = goog.i18n.DateTimeFormat.getHours_(date);
return this.dateTimeSymbols_.AMPMS[hours >= 12 && hours < 24 ? 1 : 0];
};
/**
* Formats (1..12) Hours field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.format1To12Hours_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
var hours = goog.i18n.DateTimeFormat.getHours_(date) % 12 || 12;
return this.localizeNumbers_(goog.string.padNumber(hours, count));
};
/**
* Formats (0..11) Hours field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.format0To11Hours_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
var hours = goog.i18n.DateTimeFormat.getHours_(date) % 12;
return this.localizeNumbers_(goog.string.padNumber(hours, count));
};
/**
* Formats (0..23) Hours field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.format0To23Hours_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
var hours = goog.i18n.DateTimeFormat.getHours_(date);
return this.localizeNumbers_(goog.string.padNumber(hours, count));
};
/**
* Formats Standalone weekday field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatStandaloneDay_ = function(
count, date) {
var value = date.getDay();
switch (count) {
case 5:
return this.dateTimeSymbols_.STANDALONENARROWWEEKDAYS[value];
case 4:
return this.dateTimeSymbols_.STANDALONEWEEKDAYS[value];
case 3:
return this.dateTimeSymbols_.STANDALONESHORTWEEKDAYS[value];
default:
return this.localizeNumbers_(goog.string.padNumber(value, 1));
}
};
/**
* Formats Standalone Month field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatStandaloneMonth_ = function(
count, date) {
var value = date.getMonth();
switch (count) {
case 5:
return this.dateTimeSymbols_.STANDALONENARROWMONTHS[value];
case 4:
return this.dateTimeSymbols_.STANDALONEMONTHS[value];
case 3:
return this.dateTimeSymbols_.STANDALONESHORTMONTHS[value];
default:
return this.localizeNumbers_(goog.string.padNumber(value + 1, count));
}
};
/**
* Formats Quarter field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatQuarter_ = function(count, date) {
var value = Math.floor(date.getMonth() / 3);
return count < 4 ? this.dateTimeSymbols_.SHORTQUARTERS[value] :
this.dateTimeSymbols_.QUARTERS[value];
};
/**
* Formats Date field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatDate_ = function(count, date) {
return this.localizeNumbers_(goog.string.padNumber(date.getDate(), count));
};
/**
* Formats Minutes field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatMinutes_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
return this.localizeNumbers_(
goog.string.padNumber(
/** @type {!goog.date.DateTime} */ (date).getMinutes(), count));
};
/**
* Formats Seconds field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatSeconds_ = function(count, date) {
goog.i18n.DateTimeFormat.validateDateHasTime_(date);
return this.localizeNumbers_(
goog.string.padNumber(
/** @type {!goog.date.DateTime} */ (date).getSeconds(), count));
};
/**
* Formats the week of year field according to pattern specified
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatWeekOfYear_ = function(count, date) {
var weekNum = goog.date.getWeekNumber(
date.getFullYear(), date.getMonth(), date.getDate(),
this.dateTimeSymbols_.FIRSTWEEKCUTOFFDAY,
this.dateTimeSymbols_.FIRSTDAYOFWEEK);
return this.localizeNumbers_(goog.string.padNumber(weekNum, count));
};
/**
* Formats TimeZone field following RFC
*
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date It holds the date object to be formatted.
* @param {goog.i18n.TimeZone=} opt_timeZone This holds current time zone info.
* @return {string} Formatted string that represent this field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatTimeZoneRFC_ = function(
count, date, opt_timeZone) {
opt_timeZone = opt_timeZone ||
goog.i18n.TimeZone.createTimeZone(date.getTimezoneOffset());
// RFC 822 formats should be kept in ASCII, but localized GMT formats may need
// to use native digits.
return count < 4 ? opt_timeZone.getRFCTimeZoneString(date) :
this.localizeNumbers_(opt_timeZone.getGMTString(date));
};
/**
* Generate GMT timeZone string for given date
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date Whose value being evaluated.
* @param {goog.i18n.TimeZone=} opt_timeZone This holds current time zone info.
* @return {string} GMT timeZone string.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatTimeZone_ = function(
count, date, opt_timeZone) {
opt_timeZone = opt_timeZone ||
goog.i18n.TimeZone.createTimeZone(date.getTimezoneOffset());
return count < 4 ? opt_timeZone.getShortName(date) :
opt_timeZone.getLongName(date);
};
/**
* Generate GMT timeZone string for given date
* @param {!goog.date.DateLike} date Whose value being evaluated.
* @param {goog.i18n.TimeZone=} opt_timeZone This holds current time zone info.
* @return {string} GMT timeZone string.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatTimeZoneId_ = function(
date, opt_timeZone) {
opt_timeZone = opt_timeZone ||
goog.i18n.TimeZone.createTimeZone(date.getTimezoneOffset());
return opt_timeZone.getTimeZoneId();
};
/**
* Generate localized, location dependent time zone id
* @param {number} count Number of time pattern char repeats, it controls
* how a field should be formatted.
* @param {!goog.date.DateLike} date Whose value being evaluated.
* @param {goog.i18n.TimeZone=} opt_timeZone This holds current time zone info.
* @return {string} GMT timeZone string.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatTimeZoneLocationId_ = function(
count, date, opt_timeZone) {
opt_timeZone = opt_timeZone ||
goog.i18n.TimeZone.createTimeZone(date.getTimezoneOffset());
return count <= 2 ? opt_timeZone.getTimeZoneId() :
opt_timeZone.getGenericLocation(date);
};
/**
* Formatting one date field.
* @param {string} patternStr The pattern string for the field being formatted.
* @param {!goog.date.DateLike} date represents the real date to be formatted.
* @param {!goog.date.DateLike} dateForDate used to resolve date fields
* for formatting.
* @param {!goog.date.DateLike} dateForTime used to resolve time fields
* for formatting.
* @param {goog.i18n.TimeZone=} opt_timeZone This holds current time zone info.
* @return {string} string representation for the given field.
* @private
*/
goog.i18n.DateTimeFormat.prototype.formatField_ = function(
patternStr, date, dateForDate, dateForTime, opt_timeZone) {
var count = patternStr.length;
switch (patternStr.charAt(0)) {
case 'G':
return this.formatEra_(count, dateForDate);
case 'y':
return this.formatYear_(count, dateForDate);
case 'M':
return this.formatMonth_(count, dateForDate);
case 'k':
return this.format24Hours_(count, dateForTime);
case 'S':
return this.formatFractionalSeconds_(count, dateForTime);
case 'E':
return this.formatDayOfWeek_(count, dateForDate);
case 'a':
return this.formatAmPm_(count, dateForTime);
case 'h':
return this.format1To12Hours_(count, dateForTime);
case 'K':
return this.format0To11Hours_(count, dateForTime);
case 'H':
return this.format0To23Hours_(count, dateForTime);
case 'c':
return this.formatStandaloneDay_(count, dateForDate);
case 'L':
return this.formatStandaloneMonth_(count, dateForDate);
case 'Q':
return this.formatQuarter_(count, dateForDate);
case 'd':
return this.formatDate_(count, dateForDate);
case 'm':
return this.formatMinutes_(count, dateForTime);
case 's':
return this.formatSeconds_(count, dateForTime);
case 'v':
return this.formatTimeZoneId_(date, opt_timeZone);
case 'V':
return this.formatTimeZoneLocationId_(count, date, opt_timeZone);
case 'w':
return this.formatWeekOfYear_(count, dateForTime);
case 'z':
return this.formatTimeZone_(count, date, opt_timeZone);
case 'Z':
return this.formatTimeZoneRFC_(count, date, opt_timeZone);
default:
return '';
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,780 @@
// Copyright 2010 The Closure Library Authors. All Rights Reserved
//
// 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 Message/plural format library with locale support.
*
* Message format grammar:
*
* messageFormatPattern := string ( "{" messageFormatElement "}" string )*
* messageFormatElement := argumentIndex [ "," elementFormat ]
* elementFormat := "plural" "," pluralStyle
* | "selectordinal" "," ordinalStyle
* | "select" "," selectStyle
* pluralStyle := pluralFormatPattern
* ordinalStyle := selectFormatPattern
* selectStyle := selectFormatPattern
* pluralFormatPattern := [ "offset" ":" offsetIndex ] pluralForms*
* selectFormatPattern := pluralForms*
* pluralForms := stringKey "{" ( "{" messageFormatElement "}"|string )* "}"
*
* This is a subset of the ICU MessageFormatSyntax:
* http://userguide.icu-project.org/formatparse/messages
* See also http://go/plurals and http://go/ordinals for internal details.
*
*
* Message example:
*
* I see {NUM_PEOPLE, plural, offset:1
* =0 {no one at all}
* =1 {{WHO}}
* one {{WHO} and one other person}
* other {{WHO} and # other people}}
* in {PLACE}.
*
* Calling format({'NUM_PEOPLE': 2, 'WHO': 'Mark', 'PLACE': 'Athens'}) would
* produce "I see Mark and one other person in Athens." as output.
*
* OR:
*
* {NUM_FLOOR, selectordinal,
* one {Take the elevator to the #st floor.}
* two {Take the elevator to the #nd floor.}
* few {Take the elevator to the #rd floor.}
* other {Take the elevator to the #th floor.}}
*
* Calling format({'NUM_FLOOR': 22}) would produce
* "Take the elevator to the 22nd floor".
*
* See messageformat_test.html for more examples.
*/
goog.provide('goog.i18n.MessageFormat');
goog.require('goog.asserts');
goog.require('goog.i18n.NumberFormat');
goog.require('goog.i18n.ordinalRules');
goog.require('goog.i18n.pluralRules');
/**
* Constructor of MessageFormat.
* @param {string} pattern The pattern we parse and apply positional parameters
* to.
* @constructor
* @final
*/
goog.i18n.MessageFormat = function(pattern) {
/**
* All encountered literals during parse stage. Indices tell us the order of
* replacement.
* @type {!Array<string>}
* @private
*/
this.literals_ = [];
/**
* Input pattern gets parsed into objects for faster formatting.
* @type {!Array<!Object>}
* @private
*/
this.parsedPattern_ = [];
/**
* Locale aware number formatter.
* @type {goog.i18n.NumberFormat}
* @private
*/
this.numberFormatter_ =
new goog.i18n.NumberFormat(goog.i18n.NumberFormat.Format.DECIMAL);
this.parsePattern_(pattern);
};
/**
* Literal strings, including '', are replaced with \uFDDF_x_ for
* parsing purposes, and recovered during format phase.
* \uFDDF is a Unicode nonprinting character, not expected to be found in the
* typical message.
* @type {string}
* @private
*/
goog.i18n.MessageFormat.LITERAL_PLACEHOLDER_ = '\uFDDF_';
/**
* Marks a string and block during parsing.
* @enum {number}
* @private
*/
goog.i18n.MessageFormat.Element_ = {
STRING: 0,
BLOCK: 1
};
/**
* Block type.
* @enum {number}
* @private
*/
goog.i18n.MessageFormat.BlockType_ = {
PLURAL: 0,
ORDINAL: 1,
SELECT: 2,
SIMPLE: 3,
STRING: 4,
UNKNOWN: 5
};
/**
* Mandatory option in both select and plural form.
* @type {string}
* @private
*/
goog.i18n.MessageFormat.OTHER_ = 'other';
/**
* Regular expression for looking for string literals.
* @type {RegExp}
* @private
*/
goog.i18n.MessageFormat.REGEX_LITERAL_ = new RegExp("'([{}#].*?)'", 'g');
/**
* Regular expression for looking for '' in the message.
* @type {RegExp}
* @private
*/
goog.i18n.MessageFormat.REGEX_DOUBLE_APOSTROPHE_ = new RegExp("''", 'g');
/** @typedef {{ type: goog.i18n.MessageFormat.Element_, value: ? }} */
goog.i18n.MessageFormat.TypeVal_;
/**
* Formats a message, treating '#' with special meaning representing
* the number (plural_variable - offset).
* @param {!Object} namedParameters Parameters that either
* influence the formatting or are used as actual data.
* I.e. in call to fmt.format({'NUM_PEOPLE': 5, 'NAME': 'Angela'}),
* object {'NUM_PEOPLE': 5, 'NAME': 'Angela'} holds positional parameters.
* 1st parameter could mean 5 people, which could influence plural format,
* and 2nd parameter is just a data to be printed out in proper position.
* @return {string} Formatted message.
*/
goog.i18n.MessageFormat.prototype.format = function(namedParameters) {
return this.format_(namedParameters, false);
};
/**
* Formats a message, treating '#' as literary character.
* @param {!Object} namedParameters Parameters that either
* influence the formatting or are used as actual data.
* I.e. in call to fmt.format({'NUM_PEOPLE': 5, 'NAME': 'Angela'}),
* object {'NUM_PEOPLE': 5, 'NAME': 'Angela'} holds positional parameters.
* 1st parameter could mean 5 people, which could influence plural format,
* and 2nd parameter is just a data to be printed out in proper position.
* @return {string} Formatted message.
*/
goog.i18n.MessageFormat.prototype.formatIgnoringPound = function(
namedParameters) {
return this.format_(namedParameters, true);
};
/**
* Formats a message.
* @param {!Object} namedParameters Parameters that either
* influence the formatting or are used as actual data.
* I.e. in call to fmt.format({'NUM_PEOPLE': 5, 'NAME': 'Angela'}),
* object {'NUM_PEOPLE': 5, 'NAME': 'Angela'} holds positional parameters.
* 1st parameter could mean 5 people, which could influence plural format,
* and 2nd parameter is just a data to be printed out in proper position.
* @param {boolean} ignorePound If true, treat '#' in plural messages as a
* literary character, else treat it as an ICU syntax character, resolving
* to the number (plural_variable - offset).
* @return {string} Formatted message.
* @private
*/
goog.i18n.MessageFormat.prototype.format_ = function(
namedParameters, ignorePound) {
if (this.parsedPattern_.length == 0) {
return '';
}
var result = [];
this.formatBlock_(this.parsedPattern_, namedParameters, ignorePound, result);
var message = result.join('');
if (!ignorePound) {
goog.asserts.assert(message.search('#') == -1, 'Not all # were replaced.');
}
while (this.literals_.length > 0) {
message = message.replace(
this.buildPlaceholder_(this.literals_), this.literals_.pop());
}
return message;
};
/**
* Parses generic block and returns a formatted string.
* @param {!Array<!goog.i18n.MessageFormat.TypeVal_>} parsedPattern
* Holds parsed tree.
* @param {!Object} namedParameters Parameters that either influence
* the formatting or are used as actual data.
* @param {boolean} ignorePound If true, treat '#' in plural messages as a
* literary character, else treat it as an ICU syntax character, resolving
* to the number (plural_variable - offset).
* @param {!Array<!string>} result Each formatting stage appends its product
* to the result.
* @private
*/
goog.i18n.MessageFormat.prototype.formatBlock_ = function(
parsedPattern, namedParameters, ignorePound, result) {
for (var i = 0; i < parsedPattern.length; i++) {
switch (parsedPattern[i].type) {
case goog.i18n.MessageFormat.BlockType_.STRING:
result.push(parsedPattern[i].value);
break;
case goog.i18n.MessageFormat.BlockType_.SIMPLE:
var pattern = parsedPattern[i].value;
this.formatSimplePlaceholder_(pattern, namedParameters, result);
break;
case goog.i18n.MessageFormat.BlockType_.SELECT:
var pattern = parsedPattern[i].value;
this.formatSelectBlock_(pattern, namedParameters, ignorePound, result);
break;
case goog.i18n.MessageFormat.BlockType_.PLURAL:
var pattern = parsedPattern[i].value;
this.formatPluralOrdinalBlock_(
pattern, namedParameters, goog.i18n.pluralRules.select, ignorePound,
result);
break;
case goog.i18n.MessageFormat.BlockType_.ORDINAL:
var pattern = parsedPattern[i].value;
this.formatPluralOrdinalBlock_(
pattern, namedParameters, goog.i18n.ordinalRules.select,
ignorePound, result);
break;
default:
goog.asserts.fail('Unrecognized block type: ' + parsedPattern[i].type);
}
}
};
/**
* Formats simple placeholder.
* @param {!Object} parsedPattern JSON object containing placeholder info.
* @param {!Object} namedParameters Parameters that are used as actual data.
* @param {!Array<!string>} result Each formatting stage appends its product
* to the result.
* @private
*/
goog.i18n.MessageFormat.prototype.formatSimplePlaceholder_ = function(
parsedPattern, namedParameters, result) {
var value = namedParameters[parsedPattern];
if (!goog.isDef(value)) {
result.push('Undefined parameter - ' + parsedPattern);
return;
}
// Don't push the value yet, it may contain any of # { } in it which
// will break formatter. Insert a placeholder and replace at the end.
this.literals_.push(value);
result.push(this.buildPlaceholder_(this.literals_));
};
/**
* Formats select block. Only one option is selected.
* @param {!{argumentIndex:?}} parsedPattern JSON object containing select
* block info.
* @param {!Object} namedParameters Parameters that either influence
* the formatting or are used as actual data.
* @param {boolean} ignorePound If true, treat '#' in plural messages as a
* literary character, else treat it as an ICU syntax character, resolving
* to the number (plural_variable - offset).
* @param {!Array<!string>} result Each formatting stage appends its product
* to the result.
* @private
*/
goog.i18n.MessageFormat.prototype.formatSelectBlock_ = function(
parsedPattern, namedParameters, ignorePound, result) {
var argumentIndex = parsedPattern.argumentIndex;
if (!goog.isDef(namedParameters[argumentIndex])) {
result.push('Undefined parameter - ' + argumentIndex);
return;
}
var option = parsedPattern[namedParameters[argumentIndex]];
if (!goog.isDef(option)) {
option = parsedPattern[goog.i18n.MessageFormat.OTHER_];
goog.asserts.assertArray(
option, 'Invalid option or missing other option for select block.');
}
this.formatBlock_(option, namedParameters, ignorePound, result);
};
/**
* Formats plural or selectordinal block. Only one option is selected and all #
* are replaced.
* @param {!{argumentIndex, argumentOffset}} parsedPattern JSON object
* containing plural block info.
* @param {!Object} namedParameters Parameters that either influence
* the formatting or are used as actual data.
* @param {!function(number, number=):string} pluralSelector A select function
* from goog.i18n.pluralRules or goog.i18n.ordinalRules which determines
* which plural/ordinal form to use based on the input number's cardinality.
* @param {boolean} ignorePound If true, treat '#' in plural messages as a
* literary character, else treat it as an ICU syntax character, resolving
* to the number (plural_variable - offset).
* @param {!Array<!string>} result Each formatting stage appends its product
* to the result.
* @private
*/
goog.i18n.MessageFormat.prototype.formatPluralOrdinalBlock_ = function(
parsedPattern, namedParameters, pluralSelector, ignorePound, result) {
var argumentIndex = parsedPattern.argumentIndex;
var argumentOffset = parsedPattern.argumentOffset;
var pluralValue = +namedParameters[argumentIndex];
if (isNaN(pluralValue)) {
// TODO(user): Distinguish between undefined and invalid parameters.
result.push('Undefined or invalid parameter - ' + argumentIndex);
return;
}
var diff = pluralValue - argumentOffset;
// Check if there is an exact match.
var option = parsedPattern[namedParameters[argumentIndex]];
if (!goog.isDef(option)) {
goog.asserts.assert(diff >= 0, 'Argument index smaller than offset.');
var item;
if (this.numberFormatter_.getMinimumFractionDigits) { // number formatter?
// If we know the number of fractional digits we can make better decisions
// We can decide (for instance) between "1 dollar" and "1.00 dollars".
item = pluralSelector(
diff, this.numberFormatter_.getMinimumFractionDigits());
} else {
item = pluralSelector(diff);
}
goog.asserts.assertString(item, 'Invalid plural key.');
option = parsedPattern[item];
// If option is not provided fall back to "other".
if (!goog.isDef(option)) {
option = parsedPattern[goog.i18n.MessageFormat.OTHER_];
}
goog.asserts.assertArray(
option, 'Invalid option or missing other option for plural block.');
}
var pluralResult = [];
this.formatBlock_(option, namedParameters, ignorePound, pluralResult);
var plural = pluralResult.join('');
goog.asserts.assertString(plural, 'Empty block in plural.');
if (ignorePound) {
result.push(plural);
} else {
var localeAwareDiff = this.numberFormatter_.format(diff);
result.push(plural.replace(/#/g, localeAwareDiff));
}
};
/**
* Parses input pattern into an array, for faster reformatting with
* different input parameters.
* Parsing is locale independent.
* @param {string} pattern MessageFormat pattern to parse.
* @private
*/
goog.i18n.MessageFormat.prototype.parsePattern_ = function(pattern) {
if (pattern) {
pattern = this.insertPlaceholders_(pattern);
this.parsedPattern_ = this.parseBlock_(pattern);
}
};
/**
* Replaces string literals with literal placeholders.
* Literals are string of the form '}...', '{...' and '#...' where ... is
* set of characters not containing '
* Builds a dictionary so we can recover literals during format phase.
* @param {string} pattern Pattern to clean up.
* @return {string} Pattern with literals replaced with placeholders.
* @private
*/
goog.i18n.MessageFormat.prototype.insertPlaceholders_ = function(pattern) {
var literals = this.literals_;
var buildPlaceholder = goog.bind(this.buildPlaceholder_, this);
// First replace '' with single quote placeholder since they can be found
// inside other literals.
pattern = pattern.replace(
goog.i18n.MessageFormat.REGEX_DOUBLE_APOSTROPHE_, function() {
literals.push("'");
return buildPlaceholder(literals);
});
pattern = pattern.replace(
goog.i18n.MessageFormat.REGEX_LITERAL_, function(match, text) {
literals.push(text);
return buildPlaceholder(literals);
});
return pattern;
};
/**
* Breaks pattern into strings and top level {...} blocks.
* @param {string} pattern (sub)Pattern to be broken.
* @return {!Array<goog.i18n.MessageFormat.TypeVal_>}
* @private
*/
goog.i18n.MessageFormat.prototype.extractParts_ = function(pattern) {
var prevPos = 0;
var inBlock = false;
var braceStack = [];
var results = [];
var braces = /[{}]/g;
braces.lastIndex = 0; // lastIndex doesn't get set to 0 so we have to.
var match;
while (match = braces.exec(pattern)) {
var pos = match.index;
if (match[0] == '}') {
var brace = braceStack.pop();
goog.asserts.assert(
goog.isDef(brace) && brace == '{', 'No matching { for }.');
if (braceStack.length == 0) {
// End of the block.
var part = {};
part.type = goog.i18n.MessageFormat.Element_.BLOCK;
part.value = pattern.substring(prevPos, pos);
results.push(part);
prevPos = pos + 1;
inBlock = false;
}
} else {
if (braceStack.length == 0) {
inBlock = true;
var substring = pattern.substring(prevPos, pos);
if (substring != '') {
results.push({
type: goog.i18n.MessageFormat.Element_.STRING,
value: substring
});
}
prevPos = pos + 1;
}
braceStack.push('{');
}
}
// Take care of the final string, and check if the braceStack is empty.
goog.asserts.assert(
braceStack.length == 0, 'There are mismatched { or } in the pattern.');
var substring = pattern.substring(prevPos);
if (substring != '') {
results.push(
{type: goog.i18n.MessageFormat.Element_.STRING, value: substring});
}
return results;
};
/**
* A regular expression to parse the plural block, extracting the argument
* index and offset (if any).
* @type {RegExp}
* @private
*/
goog.i18n.MessageFormat.PLURAL_BLOCK_RE_ =
/^\s*(\w+)\s*,\s*plural\s*,(?:\s*offset:(\d+))?/;
/**
* A regular expression to parse the ordinal block, extracting the argument
* index.
* @type {RegExp}
* @private
*/
goog.i18n.MessageFormat.ORDINAL_BLOCK_RE_ = /^\s*(\w+)\s*,\s*selectordinal\s*,/;
/**
* A regular expression to parse the select block, extracting the argument
* index.
* @type {RegExp}
* @private
*/
goog.i18n.MessageFormat.SELECT_BLOCK_RE_ = /^\s*(\w+)\s*,\s*select\s*,/;
/**
* Detects which type of a block is the pattern.
* @param {string} pattern Content of the block.
* @return {goog.i18n.MessageFormat.BlockType_} One of the block types.
* @private
*/
goog.i18n.MessageFormat.prototype.parseBlockType_ = function(pattern) {
if (goog.i18n.MessageFormat.PLURAL_BLOCK_RE_.test(pattern)) {
return goog.i18n.MessageFormat.BlockType_.PLURAL;
}
if (goog.i18n.MessageFormat.ORDINAL_BLOCK_RE_.test(pattern)) {
return goog.i18n.MessageFormat.BlockType_.ORDINAL;
}
if (goog.i18n.MessageFormat.SELECT_BLOCK_RE_.test(pattern)) {
return goog.i18n.MessageFormat.BlockType_.SELECT;
}
if (/^\s*\w+\s*/.test(pattern)) {
return goog.i18n.MessageFormat.BlockType_.SIMPLE;
}
return goog.i18n.MessageFormat.BlockType_.UNKNOWN;
};
/**
* Parses generic block.
* @param {string} pattern Content of the block to parse.
* @return {!Array<!Object>} Subblocks marked as strings, select...
* @private
*/
goog.i18n.MessageFormat.prototype.parseBlock_ = function(pattern) {
var result = [];
var parts = this.extractParts_(pattern);
for (var i = 0; i < parts.length; i++) {
var block = {};
if (goog.i18n.MessageFormat.Element_.STRING == parts[i].type) {
block.type = goog.i18n.MessageFormat.BlockType_.STRING;
block.value = parts[i].value;
} else if (goog.i18n.MessageFormat.Element_.BLOCK == parts[i].type) {
var blockType = this.parseBlockType_(parts[i].value);
switch (blockType) {
case goog.i18n.MessageFormat.BlockType_.SELECT:
block.type = goog.i18n.MessageFormat.BlockType_.SELECT;
block.value = this.parseSelectBlock_(parts[i].value);
break;
case goog.i18n.MessageFormat.BlockType_.PLURAL:
block.type = goog.i18n.MessageFormat.BlockType_.PLURAL;
block.value = this.parsePluralBlock_(parts[i].value);
break;
case goog.i18n.MessageFormat.BlockType_.ORDINAL:
block.type = goog.i18n.MessageFormat.BlockType_.ORDINAL;
block.value = this.parseOrdinalBlock_(parts[i].value);
break;
case goog.i18n.MessageFormat.BlockType_.SIMPLE:
block.type = goog.i18n.MessageFormat.BlockType_.SIMPLE;
block.value = parts[i].value;
break;
default:
goog.asserts.fail(
'Unknown block type for pattern: ' + parts[i].value);
}
} else {
goog.asserts.fail('Unknown part of the pattern.');
}
result.push(block);
}
return result;
};
/**
* Parses a select type of a block and produces JSON object for it.
* @param {string} pattern Subpattern that needs to be parsed as select pattern.
* @return {!Object} Object with select block info.
* @private
*/
goog.i18n.MessageFormat.prototype.parseSelectBlock_ = function(pattern) {
var argumentIndex = '';
var replaceRegex = goog.i18n.MessageFormat.SELECT_BLOCK_RE_;
pattern = pattern.replace(replaceRegex, function(string, name) {
argumentIndex = name;
return '';
});
var result = {};
result.argumentIndex = argumentIndex;
var parts = this.extractParts_(pattern);
// Looking for (key block)+ sequence. One of the keys has to be "other".
var pos = 0;
while (pos < parts.length) {
var key = parts[pos].value;
goog.asserts.assertString(key, 'Missing select key element.');
pos++;
goog.asserts.assert(
pos < parts.length, 'Missing or invalid select value element.');
if (goog.i18n.MessageFormat.Element_.BLOCK == parts[pos].type) {
var value = this.parseBlock_(parts[pos].value);
} else {
goog.asserts.fail('Expected block type.');
}
result[key.replace(/\s/g, '')] = value;
pos++;
}
goog.asserts.assertArray(
result[goog.i18n.MessageFormat.OTHER_],
'Missing other key in select statement.');
return result;
};
/**
* Parses a plural type of a block and produces JSON object for it.
* @param {string} pattern Subpattern that needs to be parsed as plural pattern.
* @return {!Object} Object with select block info.
* @private
*/
goog.i18n.MessageFormat.prototype.parsePluralBlock_ = function(pattern) {
var argumentIndex = '';
var argumentOffset = 0;
var replaceRegex = goog.i18n.MessageFormat.PLURAL_BLOCK_RE_;
pattern = pattern.replace(replaceRegex, function(string, name, offset) {
argumentIndex = name;
if (offset) {
argumentOffset = parseInt(offset, 10);
}
return '';
});
var result = {};
result.argumentIndex = argumentIndex;
result.argumentOffset = argumentOffset;
var parts = this.extractParts_(pattern);
// Looking for (key block)+ sequence.
var pos = 0;
while (pos < parts.length) {
var key = parts[pos].value;
goog.asserts.assertString(key, 'Missing plural key element.');
pos++;
goog.asserts.assert(
pos < parts.length, 'Missing or invalid plural value element.');
if (goog.i18n.MessageFormat.Element_.BLOCK == parts[pos].type) {
var value = this.parseBlock_(parts[pos].value);
} else {
goog.asserts.fail('Expected block type.');
}
result[key.replace(/\s*(?:=)?(\w+)\s*/, '$1')] = value;
pos++;
}
goog.asserts.assertArray(
result[goog.i18n.MessageFormat.OTHER_],
'Missing other key in plural statement.');
return result;
};
/**
* Parses an ordinal type of a block and produces JSON object for it.
* For example the input string:
* '{FOO, selectordinal, one {Message A}other {Message B}}'
* Should result in the output object:
* {
* argumentIndex: 'FOO',
* argumentOffest: 0,
* one: [ { type: 4, value: 'Message A' } ],
* other: [ { type: 4, value: 'Message B' } ]
* }
* @param {string} pattern Subpattern that needs to be parsed as plural pattern.
* @return {!Object} Object with select block info.
* @private
*/
goog.i18n.MessageFormat.prototype.parseOrdinalBlock_ = function(pattern) {
var argumentIndex = '';
var replaceRegex = goog.i18n.MessageFormat.ORDINAL_BLOCK_RE_;
pattern = pattern.replace(replaceRegex, function(string, name) {
argumentIndex = name;
return '';
});
var result = {};
result.argumentIndex = argumentIndex;
result.argumentOffset = 0;
var parts = this.extractParts_(pattern);
// Looking for (key block)+ sequence.
var pos = 0;
while (pos < parts.length) {
var key = parts[pos].value;
goog.asserts.assertString(key, 'Missing ordinal key element.');
pos++;
goog.asserts.assert(
pos < parts.length, 'Missing or invalid ordinal value element.');
if (goog.i18n.MessageFormat.Element_.BLOCK == parts[pos].type) {
var value = this.parseBlock_(parts[pos].value);
} else {
goog.asserts.fail('Expected block type.');
}
result[key.replace(/\s*(?:=)?(\w+)\s*/, '$1')] = value;
pos++;
}
goog.asserts.assertArray(
result[goog.i18n.MessageFormat.OTHER_],
'Missing other key in selectordinal statement.');
return result;
};
/**
* Builds a placeholder from the last index of the array.
* @param {!Array<string>} literals All literals encountered during parse.
* @return {string} \uFDDF_ + last index + _.
* @private
*/
goog.i18n.MessageFormat.prototype.buildPlaceholder_ = function(literals) {
goog.asserts.assert(literals.length > 0, 'Literal array is empty.');
var index = (literals.length - 1).toString(10);
return goog.i18n.MessageFormat.LITERAL_PLACEHOLDER_ + index + '_';
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,783 @@
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
//
// 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 Ordinal rules.
*
* This file is autogenerated by script:
* http://go/generate_pluralrules.py
* File generated from CLDR ver. 29
*
* Before check in, this file could have been manually edited. This is to
* incorporate changes before we could fix CLDR. All manual modification must be
* documented in this section, and should be removed after those changes land to
* CLDR.
*/
// clang-format off
goog.provide('goog.i18n.ordinalRules');
/**
* Ordinal pattern keyword
* @enum {string}
*/
goog.i18n.ordinalRules.Keyword = {
ZERO: 'zero',
ONE: 'one',
TWO: 'two',
FEW: 'few',
MANY: 'many',
OTHER: 'other'
};
/**
* Default Ordinal select rule.
* @param {number} n The count of items.
* @param {number=} opt_precision optional, precision.
* @return {goog.i18n.ordinalRules.Keyword} Default value.
* @private
*/
goog.i18n.ordinalRules.defaultSelect_ = function(n, opt_precision) {
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Returns the fractional part of a number (3.1416 => 1416)
* @param {number} n The count of items.
* @return {number} The fractional part.
* @private
*/
goog.i18n.ordinalRules.decimals_ = function(n) {
var str = n + '';
var result = str.indexOf('.');
return (result == -1) ? 0 : str.length - result - 1;
};
/**
* Calculates v and f as per CLDR plural rules.
* The short names for parameters / return match the CLDR syntax and UTS #35
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
* @param {number} n The count of items.
* @param {number=} opt_precision optional, precision.
* @return {!{v:number, f:number}} The v and f.
* @private
*/
goog.i18n.ordinalRules.get_vf_ = function(n, opt_precision) {
var DEFAULT_DIGITS = 3;
if (undefined === opt_precision) {
var v = Math.min(goog.i18n.ordinalRules.decimals_(n), DEFAULT_DIGITS);
} else {
var v = opt_precision;
}
var base = Math.pow(10, v);
var f = ((n * base) | 0) % base;
return {v: v, f: f};
};
/**
* Calculates w and t as per CLDR plural rules.
* The short names for parameters / return match the CLDR syntax and UTS #35
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
* @param {number} v Calculated previously.
* @param {number} f Calculated previously.
* @return {!{w:number, t:number}} The w and t.
* @private
*/
goog.i18n.ordinalRules.get_wt_ = function(v, f) {
if (f === 0) {
return {w: 0, t: 0};
}
while ((f % 10) === 0) {
f /= 10;
v--;
}
return {w: v, t: f};
};
/**
* Ordinal select rules for cy locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.cySelect_ = function(n, opt_precision) {
if (n == 0 || n == 7 || n == 8 || n == 9) {
return goog.i18n.ordinalRules.Keyword.ZERO;
}
if (n == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n == 2) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n == 3 || n == 4) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
if (n == 5 || n == 6) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for en locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.enSelect_ = function(n, opt_precision) {
if (n % 10 == 1 && n % 100 != 11) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n % 10 == 2 && n % 100 != 12) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n % 10 == 3 && n % 100 != 13) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for uk locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.ukSelect_ = function(n, opt_precision) {
if (n % 10 == 3 && n % 100 != 13) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for it locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.itSelect_ = function(n, opt_precision) {
if (n == 11 || n == 8 || n == 80 || n == 800) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for ne locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.neSelect_ = function(n, opt_precision) {
if (n >= 1 && n <= 4) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for be locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.beSelect_ = function(n, opt_precision) {
if ((n % 10 == 2 || n % 10 == 3) && n % 100 != 12 && n % 100 != 13) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for az locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.azSelect_ = function(n, opt_precision) {
var i = n | 0;
if ((i % 10 == 1 || i % 10 == 2 || i % 10 == 5 || i % 10 == 7 || i % 10 == 8) || (i % 100 == 20 || i % 100 == 50 || i % 100 == 70 || i % 100 == 80)) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if ((i % 10 == 3 || i % 10 == 4) || (i % 1000 == 100 || i % 1000 == 200 || i % 1000 == 300 || i % 1000 == 400 || i % 1000 == 500 || i % 1000 == 600 || i % 1000 == 700 || i % 1000 == 800 || i % 1000 == 900)) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
if (i == 0 || i % 10 == 6 || (i % 100 == 40 || i % 100 == 60 || i % 100 == 90)) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for ka locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.kaSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (i == 0 || (i % 100 >= 2 && i % 100 <= 20 || i % 100 == 40 || i % 100 == 60 || i % 100 == 80)) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for mr locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.mrSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n == 2 || n == 3) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n == 4) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for sv locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.svSelect_ = function(n, opt_precision) {
if ((n % 10 == 1 || n % 10 == 2) && n % 100 != 11 && n % 100 != 12) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for kk locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.kkSelect_ = function(n, opt_precision) {
if (n % 10 == 6 || n % 10 == 9 || n % 10 == 0 && n != 0) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for mk locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.mkSelect_ = function(n, opt_precision) {
var i = n | 0;
if (i % 10 == 1 && i % 100 != 11) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (i % 10 == 2 && i % 100 != 12) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if ((i % 10 == 7 || i % 10 == 8) && i % 100 != 17 && i % 100 != 18) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for hu locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.huSelect_ = function(n, opt_precision) {
if (n == 1 || n == 5) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for fr locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.frSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for sq locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.sqSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n % 10 == 4 && n % 100 != 14) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for ca locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.caSelect_ = function(n, opt_precision) {
if (n == 1 || n == 3) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n == 2) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n == 4) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for gu locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.guSelect_ = function(n, opt_precision) {
if (n == 1) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n == 2 || n == 3) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n == 4) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
if (n == 6) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Ordinal select rules for as locale
*
* @param {number} n The count of items.
* @param {number=} opt_precision Precision for number formatting, if not default.
* @return {goog.i18n.ordinalRules.Keyword} Locale-specific ordinal value.
* @private
*/
goog.i18n.ordinalRules.asSelect_ = function(n, opt_precision) {
if (n == 1 || n == 5 || n == 7 || n == 8 || n == 9 || n == 10) {
return goog.i18n.ordinalRules.Keyword.ONE;
}
if (n == 2 || n == 3) {
return goog.i18n.ordinalRules.Keyword.TWO;
}
if (n == 4) {
return goog.i18n.ordinalRules.Keyword.FEW;
}
if (n == 6) {
return goog.i18n.ordinalRules.Keyword.MANY;
}
return goog.i18n.ordinalRules.Keyword.OTHER;
};
/**
* Selected Ordinal rules by locale.
*/
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
if (goog.LOCALE == 'af') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'am') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ar') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'az') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.azSelect_;
}
if (goog.LOCALE == 'be') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.beSelect_;
}
if (goog.LOCALE == 'bg') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'bn') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.asSelect_;
}
if (goog.LOCALE == 'br') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'bs') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ca') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.caSelect_;
}
if (goog.LOCALE == 'chr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'cs') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'cy') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.cySelect_;
}
if (goog.LOCALE == 'da') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'de') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'de_AT' || goog.LOCALE == 'de-AT') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'de_CH' || goog.LOCALE == 'de-CH') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'el') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'en') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_AU' || goog.LOCALE == 'en-AU') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_CA' || goog.LOCALE == 'en-CA') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_GB' || goog.LOCALE == 'en-GB') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_IE' || goog.LOCALE == 'en-IE') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_IN' || goog.LOCALE == 'en-IN') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_SG' || goog.LOCALE == 'en-SG') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_US' || goog.LOCALE == 'en-US') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'en_ZA' || goog.LOCALE == 'en-ZA') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.enSelect_;
}
if (goog.LOCALE == 'es') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'es_419' || goog.LOCALE == 'es-419') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'es_ES' || goog.LOCALE == 'es-ES') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'es_MX' || goog.LOCALE == 'es-MX') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'es_US' || goog.LOCALE == 'es-US') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'et') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'eu') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'fa') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'fi') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'fil') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'fr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'fr_CA' || goog.LOCALE == 'fr-CA') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'ga') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'gl') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'gsw') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'gu') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.guSelect_;
}
if (goog.LOCALE == 'haw') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'he') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'hi') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.guSelect_;
}
if (goog.LOCALE == 'hr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'hu') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.huSelect_;
}
if (goog.LOCALE == 'hy') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'id') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'in') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'is') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'it') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.itSelect_;
}
if (goog.LOCALE == 'iw') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ja') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ka') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.kaSelect_;
}
if (goog.LOCALE == 'kk') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.kkSelect_;
}
if (goog.LOCALE == 'km') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'kn') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ko') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ky') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ln') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'lo') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'lt') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'lv') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'mk') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.mkSelect_;
}
if (goog.LOCALE == 'ml') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'mn') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'mo') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'mr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.mrSelect_;
}
if (goog.LOCALE == 'ms') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'mt') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'my') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'nb') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ne') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.neSelect_;
}
if (goog.LOCALE == 'nl') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'no') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'no_NO' || goog.LOCALE == 'no-NO') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'or') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'pa') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'pl') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'pt') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'pt_BR' || goog.LOCALE == 'pt-BR') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'pt_PT' || goog.LOCALE == 'pt-PT') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ro') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'ru') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sh') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'si') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sk') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sl') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sq') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.sqSelect_;
}
if (goog.LOCALE == 'sr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sr_Latn' || goog.LOCALE == 'sr-Latn') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'sv') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.svSelect_;
}
if (goog.LOCALE == 'sw') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'ta') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'te') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'th') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'tl') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'tr') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'uk') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.ukSelect_;
}
if (goog.LOCALE == 'ur') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'uz') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'vi') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.frSelect_;
}
if (goog.LOCALE == 'zh') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'zh_CN' || goog.LOCALE == 'zh-CN') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'zh_HK' || goog.LOCALE == 'zh-HK') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'zh_TW' || goog.LOCALE == 'zh-TW') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}
if (goog.LOCALE == 'zu') {
goog.i18n.ordinalRules.select = goog.i18n.ordinalRules.defaultSelect_;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,422 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// 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 Functions to provide timezone information for use with
* date/time format.
*/
goog.provide('goog.i18n.TimeZone');
goog.require('goog.array');
/** @suppress {extraRequire} goog.date.DateLike represents a Date or a
* goog.Date object. It is a parameter in the following methods:
* - getDaylightAdjustment
* - getGMTString
* - getLongName
* - getOffset
* - getRFCTimeZoneString
* - getShortName
* - isDaylightTime
* - getLongNameGMT
* - getGenericLocation
* Lint warns that this require is unnecessary but the closure compiler needs
* it in order to accept a Date or a goog.Date object as a goog.date.DateLike
* parameter in any of these methods. */
goog.require('goog.date.DateLike');
goog.require('goog.object');
goog.require('goog.string');
/**
* TimeZone class implemented a time zone resolution and name information
* source for client applications. The time zone object is initiated from
* a time zone information object. Application can initiate a time zone
* statically, or it may choose to initiate from a data obtained from server.
* Each time zone information array is small, but the whole set of data
* is too much for client application to download. If end user is allowed to
* change time zone setting, dynamic retrieval should be the method to use.
* In case only time zone offset is known, there is a decent fallback
* that only use the time zone offset to create a TimeZone object.
* A whole set of time zone information array was available under
* http://go/js_locale_data. It is generated based on CLDR/ICU and
* Olson time zone data base, and will be updated timely.
*
* @constructor
* @final
*/
goog.i18n.TimeZone = function() {
/**
* The standard time zone id.
* @type {string}
* @private
*/
this.timeZoneId_;
/**
* The standard, non-daylight time zone offset, in minutes WEST of UTC.
* @type {number}
* @private
*/
this.standardOffset_;
/**
* An array of strings that can have 2 or 4 elements. The first two elements
* are the long and short names for standard time in this time zone, and the
* last two elements (if present) are the long and short names for daylight
* time in this time zone.
* @type {Array<string>}
* @private
*/
this.tzNames_;
/**
* An object of 2 to 4 elements. The STD_* are always available, while the
* DST_* are only available when daylight saving time is available for this
* time zone.
* <ul>
* <li>STD_LONG_NAME_GMT: long GMT name for standard time</li>
* <li>STD_GENERIC_LOCATION: generic location for standard time</li>
* <li>DST_LONG_NAME_GMT: long GMT for daylight saving time</li>
* <li>DST_GENERIC_LOCATION: generic location for daylight saving time</li>
* </ul>
* @type { { STD_LONG_NAME_GMT:string, STD_GENERIC_LOCATION:string } |
* { STD_LONG_NAME_GMT:string, STD_GENERIC_LOCATION:string,
* DST_LONG_NAME_GMT:string, DST_GENERIC_LOCATION:string }
* }
* @private
*/
this.tzNamesExt_;
/**
* This array specifies the Daylight Saving Time transitions for this time
* zone. This is a flat array of numbers which are interpreted in pairs:
* [time1, adjustment1, time2, adjustment2, ...] where each time is a DST
* transition point given as a number of hours since 00:00 UTC, January 1,
* 1970, and each adjustment is the adjustment to apply for times after the
* DST transition, given as minutes EAST of UTC.
* @type {Array<number>}
* @private
*/
this.transitions_;
};
/**
* The number of milliseconds in an hour.
* @type {number}
* @private
*/
goog.i18n.TimeZone.MILLISECONDS_PER_HOUR_ = 3600 * 1000;
/**
* Indices into the array of time zone names.
* @enum {number}
*/
goog.i18n.TimeZone.NameType = {
STD_SHORT_NAME: 0,
STD_LONG_NAME: 1,
DLT_SHORT_NAME: 2,
DLT_LONG_NAME: 3
};
/**
* This factory method creates a time zone instance. It takes either an object
* containing complete time zone information, or a single number representing a
* constant time zone offset. If the latter form is used, DST functionality is
* not available.
*
* @param {number|Object} timeZoneData If this parameter is a number, it should
* indicate minutes WEST of UTC to be used as a constant time zone offset.
* Otherwise, it should be an object with these four fields:
* <ul>
* <li>id: A string ID for the time zone.
* <li>std_offset: The standard time zone offset in minutes EAST of UTC.
* <li>names: An array of four names (standard short name, standard long
* name, daylight short name, daylight long, name)
* <li>names_ext: A hash of four fields (standard long name gmt, daylight
* long name gmt, standard generic location, daylight generic
* location)
* <li>transitions: An array of numbers which are interpreted in pairs:
* [time1, adjustment1, time2, adjustment2, ...] where each time is
* a DST transition point given as a number of hours since 00:00 UTC,
* January 1, 1970, and each adjustment is the adjustment to apply
* for times after the DST transition, given as minutes EAST of UTC.
* </ul>
* @return {!goog.i18n.TimeZone} A goog.i18n.TimeZone object for the given
* time zone data.
*/
goog.i18n.TimeZone.createTimeZone = function(timeZoneData) {
if (typeof timeZoneData == 'number') {
return goog.i18n.TimeZone.createSimpleTimeZone_(timeZoneData);
}
var tz = new goog.i18n.TimeZone();
tz.timeZoneId_ = timeZoneData['id'];
tz.standardOffset_ = -timeZoneData['std_offset'];
tz.tzNames_ = timeZoneData['names'];
tz.tzNamesExt_ = timeZoneData['names_ext'];
tz.transitions_ = timeZoneData['transitions'];
return tz;
};
/**
* This factory method creates a time zone object with a constant offset.
* @param {number} timeZoneOffsetInMinutes Offset in minutes WEST of UTC.
* @return {!goog.i18n.TimeZone} A time zone object with the given constant
* offset. Note that the time zone ID of this object will use the POSIX
* convention, which has a reversed sign ("Etc/GMT+8" means UTC-8 or PST).
* @private
*/
goog.i18n.TimeZone.createSimpleTimeZone_ = function(timeZoneOffsetInMinutes) {
var tz = new goog.i18n.TimeZone();
tz.standardOffset_ = timeZoneOffsetInMinutes;
tz.timeZoneId_ =
goog.i18n.TimeZone.composePosixTimeZoneID_(timeZoneOffsetInMinutes);
var str = goog.i18n.TimeZone.composeUTCString_(timeZoneOffsetInMinutes);
var strGMT = goog.i18n.TimeZone.composeGMTString_(timeZoneOffsetInMinutes);
tz.tzNames_ = [str, str];
tz.tzNamesExt_ = {STD_LONG_NAME_GMT: strGMT, STD_GENERIC_LOCATION: strGMT};
tz.transitions_ = [];
return tz;
};
/**
* Generate a GMT-relative string for a constant time zone offset.
* @param {number} offset The time zone offset in minutes WEST of UTC.
* @return {string} The GMT string for this offset, which will indicate
* hours EAST of UTC.
* @private
*/
goog.i18n.TimeZone.composeGMTString_ = function(offset) {
var parts = ['GMT'];
parts.push(offset <= 0 ? '+' : '-');
offset = Math.abs(offset);
parts.push(
goog.string.padNumber(Math.floor(offset / 60) % 100, 2), ':',
goog.string.padNumber(offset % 60, 2));
return parts.join('');
};
/**
* Generate a POSIX time zone ID for a constant time zone offset.
* @param {number} offset The time zone offset in minutes WEST of UTC.
* @return {string} The POSIX time zone ID for this offset, which will indicate
* hours WEST of UTC.
* @private
*/
goog.i18n.TimeZone.composePosixTimeZoneID_ = function(offset) {
if (offset == 0) {
return 'Etc/GMT';
}
var parts = ['Etc/GMT', offset < 0 ? '-' : '+'];
offset = Math.abs(offset);
parts.push(Math.floor(offset / 60) % 100);
offset = offset % 60;
if (offset != 0) {
parts.push(':', goog.string.padNumber(offset, 2));
}
return parts.join('');
};
/**
* Generate a UTC-relative string for a constant time zone offset.
* @param {number} offset The time zone offset in minutes WEST of UTC.
* @return {string} The UTC string for this offset, which will indicate
* hours EAST of UTC.
* @private
*/
goog.i18n.TimeZone.composeUTCString_ = function(offset) {
if (offset == 0) {
return 'UTC';
}
var parts = ['UTC', offset < 0 ? '+' : '-'];
offset = Math.abs(offset);
parts.push(Math.floor(offset / 60) % 100);
offset = offset % 60;
if (offset != 0) {
parts.push(':', offset);
}
return parts.join('');
};
/**
* Convert the contents of time zone object to a timeZoneData object, suitable
* for passing to goog.i18n.TimeZone.createTimeZone.
* @return {!Object} A timeZoneData object (see the documentation for
* goog.i18n.TimeZone.createTimeZone).
*/
goog.i18n.TimeZone.prototype.getTimeZoneData = function() {
return {
'id': this.timeZoneId_,
'std_offset': -this.standardOffset_, // note createTimeZone flips the sign
'names': goog.array.clone(this.tzNames_), // avoid aliasing the array
'names_ext': goog.object.clone(this.tzNamesExt_), // avoid aliasing
'transitions': goog.array.clone(this.transitions_) // avoid aliasing
};
};
/**
* Return the DST adjustment to the time zone offset for a given time.
* While Daylight Saving Time is in effect, this number is positive.
* Otherwise, it is zero.
* @param {goog.date.DateLike} date The time to check.
* @return {number} The DST adjustment in minutes EAST of UTC.
*/
goog.i18n.TimeZone.prototype.getDaylightAdjustment = function(date) {
var timeInMs = Date.UTC(
date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes());
var timeInHours = timeInMs / goog.i18n.TimeZone.MILLISECONDS_PER_HOUR_;
var index = 0;
while (index < this.transitions_.length &&
timeInHours >= this.transitions_[index]) {
index += 2;
}
return (index == 0) ? 0 : this.transitions_[index - 1];
};
/**
* Return the GMT representation of this time zone object.
* @param {goog.date.DateLike} date The date for which time to retrieve
* GMT string.
* @return {string} GMT representation string.
*/
goog.i18n.TimeZone.prototype.getGMTString = function(date) {
return goog.i18n.TimeZone.composeGMTString_(this.getOffset(date));
};
/**
* Get the long time zone name for a given date/time.
* @param {goog.date.DateLike} date The time for which to retrieve
* the long time zone name.
* @return {string} The long time zone name.
*/
goog.i18n.TimeZone.prototype.getLongName = function(date) {
return this.tzNames_[this.isDaylightTime(date) ?
goog.i18n.TimeZone.NameType.DLT_LONG_NAME :
goog.i18n.TimeZone.NameType.STD_LONG_NAME];
};
/**
* Get the time zone offset in minutes WEST of UTC for a given date/time.
* @param {goog.date.DateLike} date The time for which to retrieve
* the time zone offset.
* @return {number} The time zone offset in minutes WEST of UTC.
*/
goog.i18n.TimeZone.prototype.getOffset = function(date) {
return this.standardOffset_ - this.getDaylightAdjustment(date);
};
/**
* Get the RFC representation of the time zone for a given date/time.
* @param {goog.date.DateLike} date The time for which to retrieve the
* RFC time zone string.
* @return {string} The RFC time zone string.
*/
goog.i18n.TimeZone.prototype.getRFCTimeZoneString = function(date) {
var offset = -this.getOffset(date);
var parts = [offset < 0 ? '-' : '+'];
offset = Math.abs(offset);
parts.push(
goog.string.padNumber(Math.floor(offset / 60) % 100, 2),
goog.string.padNumber(offset % 60, 2));
return parts.join('');
};
/**
* Get the short time zone name for given date/time.
* @param {goog.date.DateLike} date The time for which to retrieve
* the short time zone name.
* @return {string} The short time zone name.
*/
goog.i18n.TimeZone.prototype.getShortName = function(date) {
return this.tzNames_[this.isDaylightTime(date) ?
goog.i18n.TimeZone.NameType.DLT_SHORT_NAME :
goog.i18n.TimeZone.NameType.STD_SHORT_NAME];
};
/**
* Return the time zone ID for this time zone.
* @return {string} The time zone ID.
*/
goog.i18n.TimeZone.prototype.getTimeZoneId = function() {
return this.timeZoneId_;
};
/**
* Check if Daylight Saving Time is in effect at a given time in this time zone.
* @param {goog.date.DateLike} date The time to check.
* @return {boolean} True if Daylight Saving Time is in effect.
*/
goog.i18n.TimeZone.prototype.isDaylightTime = function(date) {
return this.getDaylightAdjustment(date) > 0;
};
/**
* Get the long GMT time zone name for a given date/time.
* @param {!goog.date.DateLike} date The time for which to retrieve
* the long GMT time zone name.
* @return {string} The long GMT time zone name.
*/
goog.i18n.TimeZone.prototype.getLongNameGMT = function(date) {
if (this.isDaylightTime(date)) {
return (goog.isDef(this.tzNamesExt_.DST_LONG_NAME_GMT)) ?
this.tzNamesExt_.DST_LONG_NAME_GMT :
this.tzNamesExt_['DST_LONG_NAME_GMT'];
} else {
return (goog.isDef(this.tzNamesExt_.STD_LONG_NAME_GMT)) ?
this.tzNamesExt_.STD_LONG_NAME_GMT :
this.tzNamesExt_['STD_LONG_NAME_GMT'];
}
};
/**
* Get the generic location time zone name for a given date/time.
* @param {!goog.date.DateLike} date The time for which to retrieve
* the generic location time zone name.
* @return {string} The generic location time zone name.
*/
goog.i18n.TimeZone.prototype.getGenericLocation = function(date) {
if (this.isDaylightTime(date)) {
return (goog.isDef(this.tzNamesExt_.DST_GENERIC_LOCATION)) ?
this.tzNamesExt_.DST_GENERIC_LOCATION :
this.tzNamesExt_['DST_GENERIC_LOCATION'];
} else {
return (goog.isDef(this.tzNamesExt_.STD_GENERIC_LOCATION)) ?
this.tzNamesExt_.STD_GENERIC_LOCATION :
this.tzNamesExt_['STD_GENERIC_LOCATION'];
}
};