vue-i18n 8.3.2 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,55 @@
1
+ <a name="8.7.0"></a>
2
+ # [8.7.0](https://github.com/kazupon/vue-i18n/compare/v8.6.0...v8.7.0) (2019-01-02)
3
+
4
+
5
+ ### :zap: Improvements
6
+
7
+ * **directive:** Preserve directive content ([#495](https://github.com/kazupon/vue-i18n/issues/495)) by [@bponomarenko](https://github.com/bponomarenko) ([c29edba](https://github.com/kazupon/vue-i18n/commit/c29edba)), closes [#495](https://github.com/kazupon/vue-i18n/issues/495) [#408](https://github.com/kazupon/vue-i18n/issues/408) [#408](https://github.com/kazupon/vue-i18n/issues/408)
8
+
9
+
10
+
11
+ <a name="8.6.0"></a>
12
+ # [8.6.0](https://github.com/kazupon/vue-i18n/compare/v8.5.0...v8.6.0) (2018-12-25)
13
+
14
+
15
+ ### :bug: Bug Fixes
16
+
17
+ * **pluralization:** inherit pluralization rules ⚠ ([#493](https://github.com/kazupon/vue-i18n/issues/493)) by [@Raiondesu](https://github.com/Raiondesu) ([7a23f32](https://github.com/kazupon/vue-i18n/commit/7a23f32)), closes [#493](https://github.com/kazupon/vue-i18n/issues/493)
18
+
19
+
20
+ ### :zap: Improvements
21
+
22
+ * **format:** Add the path as argument to the custom formatter ([#489](https://github.com/kazupon/vue-i18n/issues/489)) by [@Raiondesu](https://github.com/Raiondesu) ([b9437ea](https://github.com/kazupon/vue-i18n/commit/b9437ea)), closes [#489](https://github.com/kazupon/vue-i18n/issues/489) [#484](https://github.com/kazupon/vue-i18n/issues/484) [#484](https://github.com/kazupon/vue-i18n/issues/484)
23
+
24
+
25
+
26
+ <a name="8.5.0"></a>
27
+ # [8.5.0](https://github.com/kazupon/vue-i18n/compare/v8.4.0...v8.5.0) (2018-12-17)
28
+
29
+
30
+ ### :bug: Bug Fixes
31
+
32
+ * **index:** evaluate availabilities lazily (fix [#477](https://github.com/kazupon/vue-i18n/issues/477)) ([#483](https://github.com/kazupon/vue-i18n/issues/483)) by [@gamtiq](https://github.com/gamtiq) ([b66f02e](https://github.com/kazupon/vue-i18n/commit/b66f02e)), closes [#477](https://github.com/kazupon/vue-i18n/issues/477) [#483](https://github.com/kazupon/vue-i18n/issues/483)
33
+
34
+
35
+ ### :zap: Improvements
36
+
37
+ * **index:** Allow pluralization customization via constructor options (closes [#464](https://github.com/kazupon/vue-i18n/issues/464)) ([#482](https://github.com/kazupon/vue-i18n/issues/482)) by [@Raiondesu](https://github.com/Raiondesu) ([ef4b1a6](https://github.com/kazupon/vue-i18n/commit/ef4b1a6)), closes [#464](https://github.com/kazupon/vue-i18n/issues/464) [#482](https://github.com/kazupon/vue-i18n/issues/482) [#464](https://github.com/kazupon/vue-i18n/issues/464) [#464](https://github.com/kazupon/vue-i18n/issues/464) [#464](https://github.com/kazupon/vue-i18n/issues/464) [#464](https://github.com/kazupon/vue-i18n/issues/464) [#451](https://github.com/kazupon/vue-i18n/issues/451)
38
+ * **index:** make silentTranslationWarn work for dates and numbers too ([#481](https://github.com/kazupon/vue-i18n/issues/481)) by [@Raiondesu](https://github.com/Raiondesu) ([402092b](https://github.com/kazupon/vue-i18n/commit/402092b)), closes [#481](https://github.com/kazupon/vue-i18n/issues/481)
39
+ * **types:** typed autocomplete in date and number format options ([#485](https://github.com/kazupon/vue-i18n/issues/485)) by [@Raiondesu](https://github.com/Raiondesu) ([e2e5993](https://github.com/kazupon/vue-i18n/commit/e2e5993)), closes [#485](https://github.com/kazupon/vue-i18n/issues/485)
40
+
41
+
42
+
43
+ <a name="8.4.0"></a>
44
+ # [8.4.0](https://github.com/kazupon/vue-i18n/compare/v8.3.2...v8.4.0) (2018-11-30)
45
+
46
+
47
+ ### :star: New Features
48
+
49
+ * **index:** Add linked message formatting ([#467](https://github.com/kazupon/vue-i18n/issues/467)) by [@exoego](https://github.com/exoego) ([776b81b](https://github.com/kazupon/vue-i18n/commit/776b81b)), closes [#467](https://github.com/kazupon/vue-i18n/issues/467)
50
+
51
+
52
+
1
53
  <a name="8.3.2"></a>
2
54
  ## [8.3.2](https://github.com/kazupon/vue-i18n/compare/v8.3.1...v8.3.2) (2018-11-16)
3
55
 
package/README.md CHANGED
@@ -5,18 +5,11 @@
5
5
  <a href="https://codecov.io/gh/kazupon/vue-i18n"><img src="https://codecov.io/gh/kazupon/vue-i18n/branch/dev/graph/badge.svg" alt="Coverage Status"></a>
6
6
  <a href="http://badge.fury.io/js/vue-i18n"><img src="https://badge.fury.io/js/vue-i18n.svg" alt="NPM version"></a>
7
7
  <a href="https://discord.gg/4yCnk2m"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="vue-i18n channel on Discord"></a>
8
+ <a href="https://devtoken.rocks/package/vue-i18n"><img src="https://badge.devtoken.rocks/vue-i18n" alt="vue-i18n Dev Token"></a>
8
9
  </p>
9
10
 
10
11
  <p align="center">Internationalization plugin for Vue.js</p>
11
12
 
12
- <h3 align="center">Silver Sponsors</h3>
13
-
14
- <p align="center">
15
- <a href="https://locize.com/" target="_blank">
16
- <img src="https://raw.githubusercontent.com/kazupon/vue-i18n/dev/vuepress/.vuepress/public/patrons/locize.png" width="240px">
17
- </a>
18
- </p>
19
-
20
13
  <p align="center">
21
14
  <a href="https://www.patreon.com/kazupon" target="_blank">
22
15
  <img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
package/decls/i18n.js CHANGED
@@ -61,7 +61,11 @@ declare type I18nOptions = {
61
61
  root?: I18n, // for internal
62
62
  fallbackRoot?: boolean,
63
63
  sync?: boolean,
64
- silentTranslationWarn?: boolean
64
+ silentTranslationWarn?: boolean,
65
+ pluralizationRules?: {
66
+ [lang: string]: (choice: number, choicesLength: number) => number,
67
+ },
68
+ preserveDirectiveContent?: boolean,
65
69
  };
66
70
 
67
71
  declare type IntlAvailability = {
@@ -100,9 +104,13 @@ declare interface I18n {
100
104
  getNumberFormat (locale: Locale): NumberFormat,
101
105
  setNumberFormat (locale: Locale, format: NumberFormat): void,
102
106
  mergeNumberFormat (locale: Locale, format: NumberFormat): void,
103
- n (value: number, ...args: any): NumberFormatResult
107
+ n (value: number, ...args: any): NumberFormatResult,
108
+ pluralizationRules: {
109
+ [lang: string]: (choice: number, choicesLength: number) => number
110
+ },
111
+ preserveDirectiveContent: boolean
104
112
  };
105
113
 
106
114
  declare interface Formatter {
107
- interpolate (message: string, values?: any): Array<any>
115
+ interpolate (message: string, values: any, path: string): (Array<any> | null)
108
116
  };
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v8.3.2
3
- * (c) 2018 kazuya kawaguchi
2
+ * vue-i18n v8.7.0
3
+ * (c) 2019 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  'use strict';
@@ -133,12 +133,6 @@ function looseEqual (a, b) {
133
133
  }
134
134
  }
135
135
 
136
- var canUseDateTimeFormat =
137
- typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined';
138
-
139
- var canUseNumberFormat =
140
- typeof Intl !== 'undefined' && typeof Intl.NumberFormat !== 'undefined';
141
-
142
136
  /* */
143
137
 
144
138
  function extend (Vue) {
@@ -223,6 +217,8 @@ var mixin = {
223
217
  options.i18n.formatter = this.$root.$i18n.formatter;
224
218
  options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale;
225
219
  options.i18n.silentTranslationWarn = this.$root.$i18n.silentTranslationWarn;
220
+ options.i18n.pluralizationRules = this.$root.$i18n.pluralizationRules;
221
+ options.i18n.preserveDirectiveContent = this.$root.$i18n.preserveDirectiveContent;
226
222
  }
227
223
 
228
224
  // init locale messages via custom blocks
@@ -396,7 +392,10 @@ function unbind (el, binding, vnode, oldVNode) {
396
392
  return
397
393
  }
398
394
 
399
- el.textContent = '';
395
+ var i18n = vnode.context.$i18n || {};
396
+ if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
397
+ el.textContent = '';
398
+ }
400
399
  el._vt = undefined;
401
400
  delete el['_vt'];
402
401
  el._locale = undefined;
@@ -937,8 +936,15 @@ var numberFormatKeys = [
937
936
  'localeMatcher',
938
937
  'formatMatcher'
939
938
  ];
940
- var linkKeyMatcher = /(?:@:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
939
+ var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
940
+ var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
941
941
  var bracketsMatcher = /[()]/g;
942
+ var formatters = {
943
+ 'upper': function (str) { return str.toLocaleUpperCase(); },
944
+ 'lower': function (str) { return str.toLocaleLowerCase(); }
945
+ };
946
+
947
+ var defaultFormatter = new BaseFormatter();
942
948
 
943
949
  var VueI18n = function VueI18n (options) {
944
950
  var this$1 = this;
@@ -959,7 +965,7 @@ var VueI18n = function VueI18n (options) {
959
965
  var numberFormats = options.numberFormats || {};
960
966
 
961
967
  this._vm = null;
962
- this._formatter = options.formatter || new BaseFormatter();
968
+ this._formatter = options.formatter || defaultFormatter;
963
969
  this._missing = options.missing || null;
964
970
  this._root = options.root || null;
965
971
  this._sync = options.sync === undefined ? true : !!options.sync;
@@ -974,6 +980,11 @@ var VueI18n = function VueI18n (options) {
974
980
  this._path = new I18nPath();
975
981
  this._dataListeners = [];
976
982
 
983
+ this.pluralizationRules = options.pluralizationRules || {};
984
+ this.preserveDirectiveContent = options.preserveDirectiveContent === undefined
985
+ ? false
986
+ : !!options.preserveDirectiveContent;
987
+
977
988
  this._exist = function (message, key) {
978
989
  if (!message || !key) { return false }
979
990
  return !isNull(this$1._path.getPathValue(message, key))
@@ -1119,11 +1130,11 @@ VueI18n.prototype._interpolate = function _interpolate (
1119
1130
  }
1120
1131
 
1121
1132
  // Check for the existence of links within the translated string
1122
- if (ret.indexOf('@:') >= 0) {
1133
+ if (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0) {
1123
1134
  ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack);
1124
1135
  }
1125
1136
 
1126
- return this._render(ret, interpolateMode, values)
1137
+ return this._render(ret, interpolateMode, values, key)
1127
1138
  };
1128
1139
 
1129
1140
  VueI18n.prototype._link = function _link (
@@ -1150,8 +1161,12 @@ VueI18n.prototype._link = function _link (
1150
1161
  continue
1151
1162
  }
1152
1163
  var link = matches[idx];
1153
- // Remove the leading @: and the brackets
1154
- var linkPlaceholder = link.substr(2).replace(bracketsMatcher, '');
1164
+ var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
1165
+ var linkPrefix = linkKeyPrefixMatches[0];
1166
+ var formatterName = linkKeyPrefixMatches[1];
1167
+
1168
+ // Remove the leading @:, @.case: and the brackets
1169
+ var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
1155
1170
 
1156
1171
  if (visitedLinkStack.includes(linkPlaceholder)) {
1157
1172
  if (process.env.NODE_ENV !== 'production') {
@@ -1185,6 +1200,9 @@ VueI18n.prototype._link = function _link (
1185
1200
  locale, linkPlaceholder, translated, host,
1186
1201
  Array.isArray(values) ? values : [values]
1187
1202
  );
1203
+ if (formatters.hasOwnProperty(formatterName)) {
1204
+ translated = formatters[formatterName](translated);
1205
+ }
1188
1206
 
1189
1207
  visitedLinkStack.pop();
1190
1208
 
@@ -1195,8 +1213,14 @@ VueI18n.prototype._link = function _link (
1195
1213
  return ret
1196
1214
  };
1197
1215
 
1198
- VueI18n.prototype._render = function _render (message, interpolateMode, values) {
1199
- var ret = this._formatter.interpolate(message, values);
1216
+ VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
1217
+ var ret = this._formatter.interpolate(message, values, path);
1218
+
1219
+ // If the custom formatter refuses to work - apply the default one
1220
+ if (!ret) {
1221
+ ret = defaultFormatter.interpolate(message, values, path);
1222
+ }
1223
+
1200
1224
  // if interpolateMode is **not** 'string' ('row'),
1201
1225
  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
1202
1226
  return interpolateMode === 'string' ? ret.join('') : ret
@@ -1324,17 +1348,26 @@ VueI18n.prototype.fetchChoice = function fetchChoice (message, choice) {
1324
1348
  * @returns a final choice index
1325
1349
  */
1326
1350
  VueI18n.prototype.getChoiceIndex = function getChoiceIndex (choice, choicesLength) {
1327
- choice = Math.abs(choice);
1328
-
1329
- if (choicesLength === 2) {
1330
- return choice
1331
- ? choice > 1
1332
- ? 1
1333
- : 0
1334
- : 1
1335
- }
1351
+ // Default (old) getChoiceIndex implementation - english-compatible
1352
+ var defaultImpl = function (_choice, _choicesLength) {
1353
+ _choice = Math.abs(_choice);
1354
+
1355
+ if (_choicesLength === 2) {
1356
+ return _choice
1357
+ ? _choice > 1
1358
+ ? 1
1359
+ : 0
1360
+ : 1
1361
+ }
1362
+
1363
+ return _choice ? Math.min(_choice, 2) : 0
1364
+ };
1336
1365
 
1337
- return choice ? Math.min(choice, 2) : 0
1366
+ if (this.locale in this.pluralizationRules) {
1367
+ return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
1368
+ } else {
1369
+ return defaultImpl(choice, choicesLength)
1370
+ }
1338
1371
  };
1339
1372
 
1340
1373
  VueI18n.prototype.tc = function tc (key, choice) {
@@ -1393,7 +1426,7 @@ VueI18n.prototype._localizeDateTime = function _localizeDateTime (
1393
1426
 
1394
1427
  // fallback locale
1395
1428
  if (isNull(formats) || isNull(formats[key])) {
1396
- if (process.env.NODE_ENV !== 'production') {
1429
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1397
1430
  warn(("Fall back to '" + fallback + "' datetime formats from '" + locale + " datetime formats."));
1398
1431
  }
1399
1432
  _locale = fallback;
@@ -1427,7 +1460,7 @@ VueI18n.prototype._d = function _d (value, locale, key) {
1427
1460
  var ret =
1428
1461
  this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
1429
1462
  if (this._isFallbackRoot(ret)) {
1430
- if (process.env.NODE_ENV !== 'production') {
1463
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1431
1464
  warn(("Fall back to datetime localization of root: key '" + key + "' ."));
1432
1465
  }
1433
1466
  /* istanbul ignore if */
@@ -1493,7 +1526,7 @@ VueI18n.prototype._localizeNumber = function _localizeNumber (
1493
1526
 
1494
1527
  // fallback locale
1495
1528
  if (isNull(formats) || isNull(formats[key])) {
1496
- if (process.env.NODE_ENV !== 'production') {
1529
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1497
1530
  warn(("Fall back to '" + fallback + "' number formats from '" + locale + " number formats."));
1498
1531
  }
1499
1532
  _locale = fallback;
@@ -1537,7 +1570,7 @@ VueI18n.prototype._n = function _n (value, locale, key, options) {
1537
1570
  var ret =
1538
1571
  this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
1539
1572
  if (this._isFallbackRoot(ret)) {
1540
- if (process.env.NODE_ENV !== 'production') {
1573
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1541
1574
  warn(("Fall back to number localization of root: key '" + key + "' ."));
1542
1575
  }
1543
1576
  /* istanbul ignore if */
@@ -1591,11 +1624,22 @@ VueI18n.prototype.n = function n (value) {
1591
1624
 
1592
1625
  Object.defineProperties( VueI18n.prototype, prototypeAccessors );
1593
1626
 
1594
- VueI18n.availabilities = {
1595
- dateTimeFormat: canUseDateTimeFormat,
1596
- numberFormat: canUseNumberFormat
1597
- };
1627
+ var availabilities;
1628
+ // $FlowFixMe
1629
+ Object.defineProperty(VueI18n, 'availabilities', {
1630
+ get: function get () {
1631
+ if (!availabilities) {
1632
+ var intlDefined = typeof Intl !== 'undefined';
1633
+ availabilities = {
1634
+ dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
1635
+ numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
1636
+ };
1637
+ }
1638
+
1639
+ return availabilities
1640
+ }
1641
+ });
1598
1642
  VueI18n.install = install;
1599
- VueI18n.version = '8.3.2';
1643
+ VueI18n.version = '8.7.0';
1600
1644
 
1601
1645
  module.exports = VueI18n;
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v8.3.2
3
- * (c) 2018 kazuya kawaguchi
2
+ * vue-i18n v8.7.0
3
+ * (c) 2019 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  /* */
@@ -131,12 +131,6 @@ function looseEqual (a, b) {
131
131
  }
132
132
  }
133
133
 
134
- var canUseDateTimeFormat =
135
- typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined';
136
-
137
- var canUseNumberFormat =
138
- typeof Intl !== 'undefined' && typeof Intl.NumberFormat !== 'undefined';
139
-
140
134
  /* */
141
135
 
142
136
  function extend (Vue) {
@@ -221,6 +215,8 @@ var mixin = {
221
215
  options.i18n.formatter = this.$root.$i18n.formatter;
222
216
  options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale;
223
217
  options.i18n.silentTranslationWarn = this.$root.$i18n.silentTranslationWarn;
218
+ options.i18n.pluralizationRules = this.$root.$i18n.pluralizationRules;
219
+ options.i18n.preserveDirectiveContent = this.$root.$i18n.preserveDirectiveContent;
224
220
  }
225
221
 
226
222
  // init locale messages via custom blocks
@@ -394,7 +390,10 @@ function unbind (el, binding, vnode, oldVNode) {
394
390
  return
395
391
  }
396
392
 
397
- el.textContent = '';
393
+ var i18n = vnode.context.$i18n || {};
394
+ if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
395
+ el.textContent = '';
396
+ }
398
397
  el._vt = undefined;
399
398
  delete el['_vt'];
400
399
  el._locale = undefined;
@@ -935,8 +934,15 @@ var numberFormatKeys = [
935
934
  'localeMatcher',
936
935
  'formatMatcher'
937
936
  ];
938
- var linkKeyMatcher = /(?:@:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
937
+ var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
938
+ var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
939
939
  var bracketsMatcher = /[()]/g;
940
+ var formatters = {
941
+ 'upper': function (str) { return str.toLocaleUpperCase(); },
942
+ 'lower': function (str) { return str.toLocaleLowerCase(); }
943
+ };
944
+
945
+ var defaultFormatter = new BaseFormatter();
940
946
 
941
947
  var VueI18n = function VueI18n (options) {
942
948
  var this$1 = this;
@@ -957,7 +963,7 @@ var VueI18n = function VueI18n (options) {
957
963
  var numberFormats = options.numberFormats || {};
958
964
 
959
965
  this._vm = null;
960
- this._formatter = options.formatter || new BaseFormatter();
966
+ this._formatter = options.formatter || defaultFormatter;
961
967
  this._missing = options.missing || null;
962
968
  this._root = options.root || null;
963
969
  this._sync = options.sync === undefined ? true : !!options.sync;
@@ -972,6 +978,11 @@ var VueI18n = function VueI18n (options) {
972
978
  this._path = new I18nPath();
973
979
  this._dataListeners = [];
974
980
 
981
+ this.pluralizationRules = options.pluralizationRules || {};
982
+ this.preserveDirectiveContent = options.preserveDirectiveContent === undefined
983
+ ? false
984
+ : !!options.preserveDirectiveContent;
985
+
975
986
  this._exist = function (message, key) {
976
987
  if (!message || !key) { return false }
977
988
  return !isNull(this$1._path.getPathValue(message, key))
@@ -1117,11 +1128,11 @@ VueI18n.prototype._interpolate = function _interpolate (
1117
1128
  }
1118
1129
 
1119
1130
  // Check for the existence of links within the translated string
1120
- if (ret.indexOf('@:') >= 0) {
1131
+ if (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0) {
1121
1132
  ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack);
1122
1133
  }
1123
1134
 
1124
- return this._render(ret, interpolateMode, values)
1135
+ return this._render(ret, interpolateMode, values, key)
1125
1136
  };
1126
1137
 
1127
1138
  VueI18n.prototype._link = function _link (
@@ -1148,8 +1159,12 @@ VueI18n.prototype._link = function _link (
1148
1159
  continue
1149
1160
  }
1150
1161
  var link = matches[idx];
1151
- // Remove the leading @: and the brackets
1152
- var linkPlaceholder = link.substr(2).replace(bracketsMatcher, '');
1162
+ var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
1163
+ var linkPrefix = linkKeyPrefixMatches[0];
1164
+ var formatterName = linkKeyPrefixMatches[1];
1165
+
1166
+ // Remove the leading @:, @.case: and the brackets
1167
+ var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
1153
1168
 
1154
1169
  if (visitedLinkStack.includes(linkPlaceholder)) {
1155
1170
  if (process.env.NODE_ENV !== 'production') {
@@ -1183,6 +1198,9 @@ VueI18n.prototype._link = function _link (
1183
1198
  locale, linkPlaceholder, translated, host,
1184
1199
  Array.isArray(values) ? values : [values]
1185
1200
  );
1201
+ if (formatters.hasOwnProperty(formatterName)) {
1202
+ translated = formatters[formatterName](translated);
1203
+ }
1186
1204
 
1187
1205
  visitedLinkStack.pop();
1188
1206
 
@@ -1193,8 +1211,14 @@ VueI18n.prototype._link = function _link (
1193
1211
  return ret
1194
1212
  };
1195
1213
 
1196
- VueI18n.prototype._render = function _render (message, interpolateMode, values) {
1197
- var ret = this._formatter.interpolate(message, values);
1214
+ VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
1215
+ var ret = this._formatter.interpolate(message, values, path);
1216
+
1217
+ // If the custom formatter refuses to work - apply the default one
1218
+ if (!ret) {
1219
+ ret = defaultFormatter.interpolate(message, values, path);
1220
+ }
1221
+
1198
1222
  // if interpolateMode is **not** 'string' ('row'),
1199
1223
  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
1200
1224
  return interpolateMode === 'string' ? ret.join('') : ret
@@ -1322,17 +1346,26 @@ VueI18n.prototype.fetchChoice = function fetchChoice (message, choice) {
1322
1346
  * @returns a final choice index
1323
1347
  */
1324
1348
  VueI18n.prototype.getChoiceIndex = function getChoiceIndex (choice, choicesLength) {
1325
- choice = Math.abs(choice);
1326
-
1327
- if (choicesLength === 2) {
1328
- return choice
1329
- ? choice > 1
1330
- ? 1
1331
- : 0
1332
- : 1
1333
- }
1349
+ // Default (old) getChoiceIndex implementation - english-compatible
1350
+ var defaultImpl = function (_choice, _choicesLength) {
1351
+ _choice = Math.abs(_choice);
1352
+
1353
+ if (_choicesLength === 2) {
1354
+ return _choice
1355
+ ? _choice > 1
1356
+ ? 1
1357
+ : 0
1358
+ : 1
1359
+ }
1360
+
1361
+ return _choice ? Math.min(_choice, 2) : 0
1362
+ };
1334
1363
 
1335
- return choice ? Math.min(choice, 2) : 0
1364
+ if (this.locale in this.pluralizationRules) {
1365
+ return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
1366
+ } else {
1367
+ return defaultImpl(choice, choicesLength)
1368
+ }
1336
1369
  };
1337
1370
 
1338
1371
  VueI18n.prototype.tc = function tc (key, choice) {
@@ -1391,7 +1424,7 @@ VueI18n.prototype._localizeDateTime = function _localizeDateTime (
1391
1424
 
1392
1425
  // fallback locale
1393
1426
  if (isNull(formats) || isNull(formats[key])) {
1394
- if (process.env.NODE_ENV !== 'production') {
1427
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1395
1428
  warn(("Fall back to '" + fallback + "' datetime formats from '" + locale + " datetime formats."));
1396
1429
  }
1397
1430
  _locale = fallback;
@@ -1425,7 +1458,7 @@ VueI18n.prototype._d = function _d (value, locale, key) {
1425
1458
  var ret =
1426
1459
  this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
1427
1460
  if (this._isFallbackRoot(ret)) {
1428
- if (process.env.NODE_ENV !== 'production') {
1461
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1429
1462
  warn(("Fall back to datetime localization of root: key '" + key + "' ."));
1430
1463
  }
1431
1464
  /* istanbul ignore if */
@@ -1491,7 +1524,7 @@ VueI18n.prototype._localizeNumber = function _localizeNumber (
1491
1524
 
1492
1525
  // fallback locale
1493
1526
  if (isNull(formats) || isNull(formats[key])) {
1494
- if (process.env.NODE_ENV !== 'production') {
1527
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1495
1528
  warn(("Fall back to '" + fallback + "' number formats from '" + locale + " number formats."));
1496
1529
  }
1497
1530
  _locale = fallback;
@@ -1535,7 +1568,7 @@ VueI18n.prototype._n = function _n (value, locale, key, options) {
1535
1568
  var ret =
1536
1569
  this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
1537
1570
  if (this._isFallbackRoot(ret)) {
1538
- if (process.env.NODE_ENV !== 'production') {
1571
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
1539
1572
  warn(("Fall back to number localization of root: key '" + key + "' ."));
1540
1573
  }
1541
1574
  /* istanbul ignore if */
@@ -1589,11 +1622,22 @@ VueI18n.prototype.n = function n (value) {
1589
1622
 
1590
1623
  Object.defineProperties( VueI18n.prototype, prototypeAccessors );
1591
1624
 
1592
- VueI18n.availabilities = {
1593
- dateTimeFormat: canUseDateTimeFormat,
1594
- numberFormat: canUseNumberFormat
1595
- };
1625
+ var availabilities;
1626
+ // $FlowFixMe
1627
+ Object.defineProperty(VueI18n, 'availabilities', {
1628
+ get: function get () {
1629
+ if (!availabilities) {
1630
+ var intlDefined = typeof Intl !== 'undefined';
1631
+ availabilities = {
1632
+ dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
1633
+ numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
1634
+ };
1635
+ }
1636
+
1637
+ return availabilities
1638
+ }
1639
+ });
1596
1640
  VueI18n.install = install;
1597
- VueI18n.version = '8.3.2';
1641
+ VueI18n.version = '8.7.0';
1598
1642
 
1599
1643
  export default VueI18n;
package/dist/vue-i18n.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v8.3.2
3
- * (c) 2018 kazuya kawaguchi
2
+ * vue-i18n v8.7.0
3
+ * (c) 2019 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  (function (global, factory) {
@@ -137,12 +137,6 @@
137
137
  }
138
138
  }
139
139
 
140
- var canUseDateTimeFormat =
141
- typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined';
142
-
143
- var canUseNumberFormat =
144
- typeof Intl !== 'undefined' && typeof Intl.NumberFormat !== 'undefined';
145
-
146
140
  /* */
147
141
 
148
142
  function extend (Vue) {
@@ -227,6 +221,8 @@
227
221
  options.i18n.formatter = this.$root.$i18n.formatter;
228
222
  options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale;
229
223
  options.i18n.silentTranslationWarn = this.$root.$i18n.silentTranslationWarn;
224
+ options.i18n.pluralizationRules = this.$root.$i18n.pluralizationRules;
225
+ options.i18n.preserveDirectiveContent = this.$root.$i18n.preserveDirectiveContent;
230
226
  }
231
227
 
232
228
  // init locale messages via custom blocks
@@ -400,7 +396,10 @@
400
396
  return
401
397
  }
402
398
 
403
- el.textContent = '';
399
+ var i18n = vnode.context.$i18n || {};
400
+ if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
401
+ el.textContent = '';
402
+ }
404
403
  el._vt = undefined;
405
404
  delete el['_vt'];
406
405
  el._locale = undefined;
@@ -941,8 +940,15 @@
941
940
  'localeMatcher',
942
941
  'formatMatcher'
943
942
  ];
944
- var linkKeyMatcher = /(?:@:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
943
+ var linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g;
944
+ var linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/;
945
945
  var bracketsMatcher = /[()]/g;
946
+ var formatters = {
947
+ 'upper': function (str) { return str.toLocaleUpperCase(); },
948
+ 'lower': function (str) { return str.toLocaleLowerCase(); }
949
+ };
950
+
951
+ var defaultFormatter = new BaseFormatter();
946
952
 
947
953
  var VueI18n = function VueI18n (options) {
948
954
  var this$1 = this;
@@ -963,7 +969,7 @@
963
969
  var numberFormats = options.numberFormats || {};
964
970
 
965
971
  this._vm = null;
966
- this._formatter = options.formatter || new BaseFormatter();
972
+ this._formatter = options.formatter || defaultFormatter;
967
973
  this._missing = options.missing || null;
968
974
  this._root = options.root || null;
969
975
  this._sync = options.sync === undefined ? true : !!options.sync;
@@ -978,6 +984,11 @@
978
984
  this._path = new I18nPath();
979
985
  this._dataListeners = [];
980
986
 
987
+ this.pluralizationRules = options.pluralizationRules || {};
988
+ this.preserveDirectiveContent = options.preserveDirectiveContent === undefined
989
+ ? false
990
+ : !!options.preserveDirectiveContent;
991
+
981
992
  this._exist = function (message, key) {
982
993
  if (!message || !key) { return false }
983
994
  return !isNull(this$1._path.getPathValue(message, key))
@@ -1123,11 +1134,11 @@
1123
1134
  }
1124
1135
 
1125
1136
  // Check for the existence of links within the translated string
1126
- if (ret.indexOf('@:') >= 0) {
1137
+ if (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0) {
1127
1138
  ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack);
1128
1139
  }
1129
1140
 
1130
- return this._render(ret, interpolateMode, values)
1141
+ return this._render(ret, interpolateMode, values, key)
1131
1142
  };
1132
1143
 
1133
1144
  VueI18n.prototype._link = function _link (
@@ -1154,8 +1165,12 @@
1154
1165
  continue
1155
1166
  }
1156
1167
  var link = matches[idx];
1157
- // Remove the leading @: and the brackets
1158
- var linkPlaceholder = link.substr(2).replace(bracketsMatcher, '');
1168
+ var linkKeyPrefixMatches = link.match(linkKeyPrefixMatcher);
1169
+ var linkPrefix = linkKeyPrefixMatches[0];
1170
+ var formatterName = linkKeyPrefixMatches[1];
1171
+
1172
+ // Remove the leading @:, @.case: and the brackets
1173
+ var linkPlaceholder = link.replace(linkPrefix, '').replace(bracketsMatcher, '');
1159
1174
 
1160
1175
  if (visitedLinkStack.includes(linkPlaceholder)) {
1161
1176
  {
@@ -1189,6 +1204,9 @@
1189
1204
  locale, linkPlaceholder, translated, host,
1190
1205
  Array.isArray(values) ? values : [values]
1191
1206
  );
1207
+ if (formatters.hasOwnProperty(formatterName)) {
1208
+ translated = formatters[formatterName](translated);
1209
+ }
1192
1210
 
1193
1211
  visitedLinkStack.pop();
1194
1212
 
@@ -1199,8 +1217,14 @@
1199
1217
  return ret
1200
1218
  };
1201
1219
 
1202
- VueI18n.prototype._render = function _render (message, interpolateMode, values) {
1203
- var ret = this._formatter.interpolate(message, values);
1220
+ VueI18n.prototype._render = function _render (message, interpolateMode, values, path) {
1221
+ var ret = this._formatter.interpolate(message, values, path);
1222
+
1223
+ // If the custom formatter refuses to work - apply the default one
1224
+ if (!ret) {
1225
+ ret = defaultFormatter.interpolate(message, values, path);
1226
+ }
1227
+
1204
1228
  // if interpolateMode is **not** 'string' ('row'),
1205
1229
  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
1206
1230
  return interpolateMode === 'string' ? ret.join('') : ret
@@ -1328,17 +1352,26 @@
1328
1352
  * @returns a final choice index
1329
1353
  */
1330
1354
  VueI18n.prototype.getChoiceIndex = function getChoiceIndex (choice, choicesLength) {
1331
- choice = Math.abs(choice);
1332
-
1333
- if (choicesLength === 2) {
1334
- return choice
1335
- ? choice > 1
1336
- ? 1
1337
- : 0
1338
- : 1
1339
- }
1355
+ // Default (old) getChoiceIndex implementation - english-compatible
1356
+ var defaultImpl = function (_choice, _choicesLength) {
1357
+ _choice = Math.abs(_choice);
1358
+
1359
+ if (_choicesLength === 2) {
1360
+ return _choice
1361
+ ? _choice > 1
1362
+ ? 1
1363
+ : 0
1364
+ : 1
1365
+ }
1366
+
1367
+ return _choice ? Math.min(_choice, 2) : 0
1368
+ };
1340
1369
 
1341
- return choice ? Math.min(choice, 2) : 0
1370
+ if (this.locale in this.pluralizationRules) {
1371
+ return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
1372
+ } else {
1373
+ return defaultImpl(choice, choicesLength)
1374
+ }
1342
1375
  };
1343
1376
 
1344
1377
  VueI18n.prototype.tc = function tc (key, choice) {
@@ -1397,7 +1430,7 @@
1397
1430
 
1398
1431
  // fallback locale
1399
1432
  if (isNull(formats) || isNull(formats[key])) {
1400
- {
1433
+ if (!this._silentTranslationWarn) {
1401
1434
  warn(("Fall back to '" + fallback + "' datetime formats from '" + locale + " datetime formats."));
1402
1435
  }
1403
1436
  _locale = fallback;
@@ -1431,7 +1464,7 @@
1431
1464
  var ret =
1432
1465
  this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key);
1433
1466
  if (this._isFallbackRoot(ret)) {
1434
- {
1467
+ if (!this._silentTranslationWarn) {
1435
1468
  warn(("Fall back to datetime localization of root: key '" + key + "' ."));
1436
1469
  }
1437
1470
  /* istanbul ignore if */
@@ -1497,7 +1530,7 @@
1497
1530
 
1498
1531
  // fallback locale
1499
1532
  if (isNull(formats) || isNull(formats[key])) {
1500
- {
1533
+ if (!this._silentTranslationWarn) {
1501
1534
  warn(("Fall back to '" + fallback + "' number formats from '" + locale + " number formats."));
1502
1535
  }
1503
1536
  _locale = fallback;
@@ -1541,7 +1574,7 @@
1541
1574
  var ret =
1542
1575
  this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options);
1543
1576
  if (this._isFallbackRoot(ret)) {
1544
- {
1577
+ if (!this._silentTranslationWarn) {
1545
1578
  warn(("Fall back to number localization of root: key '" + key + "' ."));
1546
1579
  }
1547
1580
  /* istanbul ignore if */
@@ -1595,12 +1628,23 @@
1595
1628
 
1596
1629
  Object.defineProperties( VueI18n.prototype, prototypeAccessors );
1597
1630
 
1598
- VueI18n.availabilities = {
1599
- dateTimeFormat: canUseDateTimeFormat,
1600
- numberFormat: canUseNumberFormat
1601
- };
1631
+ var availabilities;
1632
+ // $FlowFixMe
1633
+ Object.defineProperty(VueI18n, 'availabilities', {
1634
+ get: function get () {
1635
+ if (!availabilities) {
1636
+ var intlDefined = typeof Intl !== 'undefined';
1637
+ availabilities = {
1638
+ dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
1639
+ numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
1640
+ };
1641
+ }
1642
+
1643
+ return availabilities
1644
+ }
1645
+ });
1602
1646
  VueI18n.install = install;
1603
- VueI18n.version = '8.3.2';
1647
+ VueI18n.version = '8.7.0';
1604
1648
 
1605
1649
  return VueI18n;
1606
1650
 
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v8.3.2
3
- * (c) 2018 kazuya kawaguchi
2
+ * vue-i18n v8.7.0
3
+ * (c) 2019 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueI18n=e()}(this,function(){"use strict";function t(t,e){"undefined"!=typeof console&&(console.warn("[vue-i18n] "+t),e&&console.warn(e.stack))}function e(t){return null!==t&&"object"==typeof t}function n(t){return L.call(t)===O}function r(t){return null===t||void 0===t}function i(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var r=null,i=null;return 1===t.length?e(t[0])||Array.isArray(t[0])?i=t[0]:"string"==typeof t[0]&&(r=t[0]):2===t.length&&("string"==typeof t[0]&&(r=t[0]),(e(t[1])||Array.isArray(t[1]))&&(i=t[1])),{locale:r,params:i}}function a(t){return JSON.parse(JSON.stringify(t))}function o(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}function s(t,e){return M.call(t,e)}function c(t){for(var n=arguments,r=Object(t),i=1;i<arguments.length;i++){var a=n[i];if(void 0!==a&&null!==a){var o=void 0;for(o in a)s(a,o)&&(e(a[o])?r[o]=c(r[o],a[o]):r[o]=a[o])}}return r}function l(t,n){if(t===n)return!0;var r=e(t),i=e(n);if(!r||!i)return!r&&!i&&String(t)===String(n);try{var a=Array.isArray(t),o=Array.isArray(n);if(a&&o)return t.length===n.length&&t.every(function(t,e){return l(t,n[e])});if(a||o)return!1;var s=Object.keys(t),c=Object.keys(n);return s.length===c.length&&s.every(function(e){return l(t[e],n[e])})}catch(t){return!1}}function u(t){t.prototype.hasOwnProperty("$i18n")||Object.defineProperty(t.prototype,"$i18n",{get:function(){return this._i18n}}),t.prototype.$t=function(t){for(var e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];var r=this.$i18n;return r._t.apply(r,[t,r.locale,r._getMessages(),this].concat(e))},t.prototype.$tc=function(t,e){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];var i=this.$i18n;return i._tc.apply(i,[t,i.locale,i._getMessages(),this,e].concat(n))},t.prototype.$te=function(t,e){var n=this.$i18n;return n._te(t,n.locale,n._getMessages(),e)},t.prototype.$d=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).d.apply(e,[t].concat(n))},t.prototype.$n=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).n.apply(e,[t].concat(n))}}function f(t,e,n){m(t,n)&&g(t,e,n)}function h(t,e,n,r){if(m(t,n)){var i=n.context.$i18n;_(t,n)&&l(e.value,e.oldValue)&&l(t._localeMessage,i.getLocaleMessage(i.locale))||g(t,e,n)}}function p(e,n,r,i){if(!r.context)return void t("Vue instance does not exists in VNode context");e.textContent="",e._vt=void 0,delete e._vt,e._locale=void 0,delete e._locale,e._localeMessage=void 0,delete e._localeMessage}function m(e,n){var r=n.context;return r?!!r.$i18n||(t("VueI18n instance does not exists in Vue instance"),!1):(t("Vue instance doest not exists in VNode context"),!1)}function _(t,e){var n=e.context;return t._locale===n.$i18n.locale}function g(e,n,r){var i,a,o=n.value,s=v(o),c=s.path,l=s.locale,u=s.args,f=s.choice;if(!c&&!l&&!u)return void t("value type not supported");if(!c)return void t("`path` is required in v-t directive");var h=r.context;e._vt=e.textContent=f?(i=h.$i18n).tc.apply(i,[c,f].concat(y(l,u))):(a=h.$i18n).t.apply(a,[c].concat(y(l,u))),e._locale=h.$i18n.locale,e._localeMessage=h.$i18n.getLocaleMessage(h.$i18n.locale)}function v(t){var e,r,i,a;return"string"==typeof t?e=t:n(t)&&(e=t.path,r=t.locale,i=t.args,a=t.choice),{path:e,locale:r,args:i,choice:a}}function y(t,e){var r=[];return t&&r.push(t),e&&(Array.isArray(e)||n(e))&&r.push(e),r}function d(t){d.installed=!0,D=t;D.version&&Number(D.version.split(".")[0]);u(D),D.mixin(N),D.directive("t",{bind:f,update:h,unbind:p}),D.component(I.name,I),D.config.optionMergeStrategies.i18n=function(t,e){return void 0===e?t:e}}function b(t){for(var e=[],n=0,r="";n<t.length;){var i=t[n++];if("{"===i){r&&e.push({type:"text",value:r}),r="";var a="";for(i=t[n++];void 0!==i&&"}"!==i;)a+=i,i=t[n++];var o="}"===i,s=C.test(a)?"list":o&&S.test(a)?"named":"unknown";e.push({value:a,type:s})}else"%"===i?"{"!==t[n]&&(r+=i):r+=i}return r&&e.push({type:"text",value:r}),e}function $(t,n){var r=[],i=0,a=Array.isArray(n)?"list":e(n)?"named":"unknown";if("unknown"===a)return r;for(;i<t.length;){var o=t[i];switch(o.type){case"text":r.push(o.value);break;case"list":r.push(n[parseInt(o.value,10)]);break;case"named":"named"===a&&r.push(n[o.value])}i++}return r}function F(t){return K.test(t)}function w(t){var e=t.charCodeAt(0);return e!==t.charCodeAt(t.length-1)||34!==e&&39!==e?t:t.slice(1,-1)}function k(t){if(void 0===t||null===t)return"eof";switch(t.charCodeAt(0)){case 91:case 93:case 46:case 34:case 39:return t;case 95:case 36:case 45:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return"ident"}function T(t){var e=t.trim();return("0"!==t.charAt(0)||!isNaN(t))&&(F(e)?w(e):"*"+e)}function x(t){var e,n,r,i,a,o,s,c=[],l=-1,u=z,f=0,h=[];for(h[E]=function(){void 0!==n&&(c.push(n),n=void 0)},h[V]=function(){void 0===n?n=r:n+=r},h[P]=function(){h[V](),f++},h[R]=function(){if(f>0)f--,u=J,h[V]();else{if(f=0,!1===(n=T(n)))return!1;h[E]()}};null!==u;)if(l++,"\\"!==(e=t[l])||!function(){var e=t[l+1];if(u===U&&"'"===e||u===q&&'"'===e)return l++,r="\\"+e,h[V](),!0}()){if(i=k(e),s=H[u],(a=s[i]||s.else||B)===B)return;if(u=a[0],(o=h[a[1]])&&(r=a[2],r=void 0===r?e:r,!1===o()))return;if(u===G)return c}}var D,L=Object.prototype.toString,O="[object Object]",M=Object.prototype.hasOwnProperty,A="undefined"!=typeof Intl&&void 0!==Intl.DateTimeFormat,j="undefined"!=typeof Intl&&void 0!==Intl.NumberFormat,N={beforeCreate:function(){var t=this.$options;if(t.i18n=t.i18n||(t.__i18n?{}:null),t.i18n){if(t.i18n instanceof tt){if(t.__i18n)try{var e={};t.__i18n.forEach(function(t){e=c(e,JSON.parse(t))}),Object.keys(e).forEach(function(n){t.i18n.mergeLocaleMessage(n,e[n])})}catch(t){}this._i18n=t.i18n,this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0}else if(n(t.i18n)){if(this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof tt&&(t.i18n.root=this.$root,t.i18n.formatter=this.$root.$i18n.formatter,t.i18n.fallbackLocale=this.$root.$i18n.fallbackLocale,t.i18n.silentTranslationWarn=this.$root.$i18n.silentTranslationWarn),t.__i18n)try{var r={};t.__i18n.forEach(function(t){r=c(r,JSON.parse(t))}),t.i18n.messages=r}catch(t){}this._i18n=new tt(t.i18n),this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0,(void 0===t.i18n.sync||t.i18n.sync)&&(this._localeWatcher=this.$i18n.watchLocale())}}else this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof tt?(this._i18n=this.$root.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0):t.parent&&t.parent.$i18n&&t.parent.$i18n instanceof tt&&(this._i18n=t.parent.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0)},beforeDestroy:function(){this._i18n&&(this._subscribing&&(this._i18n.unsubscribeDataChanging(this),delete this._subscribing),this._i18nWatcher&&(this._i18nWatcher(),delete this._i18nWatcher),this._localeWatcher&&(this._localeWatcher(),delete this._localeWatcher),this._i18n=null)}},I={name:"i18n",functional:!0,props:{tag:{type:String,default:"span"},path:{type:String,required:!0},locale:{type:String},places:{type:[Array,Object]}},render:function(t,e){var n=e.props,r=e.data,i=e.children,a=e.parent,o=a.$i18n;if(i=(i||[]).filter(function(t){return t.tag||(t.text=t.text.trim())}),!o)return i;var s=n.path,c=n.locale,l={},u=n.places||{},f=(Array.isArray(u)?u.length:Object.keys(u).length,i.every(function(t){if(t.data&&t.data.attrs){var e=t.data.attrs.place;return void 0!==e&&""!==e}}));return Array.isArray(u)?u.forEach(function(t,e){l[e]=t}):Object.keys(u).forEach(function(t){l[t]=u[t]}),i.forEach(function(t,e){var n=f?""+t.data.attrs.place:""+e;l[n]=t}),t(n.tag,r,o.i(s,c,l))}},W=function(){this._caches=Object.create(null)};W.prototype.interpolate=function(t,e){if(!e)return[t];var n=this._caches[t];return n||(n=b(t),this._caches[t]=n),$(n,e)};var C=/^(?:\d)+/,S=/^(?:\w)+/,V=0,E=1,P=2,R=3,z=0,J=4,U=5,q=6,G=7,B=8,H=[];H[z]={ws:[z],ident:[3,V],"[":[J],eof:[G]},H[1]={ws:[1],".":[2],"[":[J],eof:[G]},H[2]={ws:[2],ident:[3,V],0:[3,V],number:[3,V]},H[3]={ident:[3,V],0:[3,V],number:[3,V],ws:[1,E],".":[2,E],"[":[J,E],eof:[G,E]},H[J]={"'":[U,V],'"':[q,V],"[":[J,P],"]":[1,R],eof:B,else:[J,V]},H[U]={"'":[J,V],eof:B,else:[U,V]},H[q]={'"':[J,V],eof:B,else:[q,V]};var K=/^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/,Q=function(){this._cache=Object.create(null)};Q.prototype.parsePath=function(t){var e=this._cache[t];return e||(e=x(t))&&(this._cache[t]=e),e||[]},Q.prototype.getPathValue=function(t,n){if(!e(t))return null;var r=this.parsePath(n);if(0===r.length)return null;for(var i=r.length,a=t,o=0;o<i;){var s=a[r[o]];if(void 0===s)return null;a=s,o++}return a};var X=["style","currency","currencyDisplay","useGrouping","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits","localeMatcher","formatMatcher"],Y=/(?:@:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g,Z=/[()]/g,tt=function(t){var e=this;void 0===t&&(t={}),!D&&"undefined"!=typeof window&&window.Vue&&d(window.Vue);var n=t.locale||"en-US",i=t.fallbackLocale||"en-US",a=t.messages||{},o=t.dateTimeFormats||{},s=t.numberFormats||{};this._vm=null,this._formatter=t.formatter||new W,this._missing=t.missing||null,this._root=t.root||null,this._sync=void 0===t.sync||!!t.sync,this._fallbackRoot=void 0===t.fallbackRoot||!!t.fallbackRoot,this._silentTranslationWarn=void 0!==t.silentTranslationWarn&&!!t.silentTranslationWarn,this._dateTimeFormatters={},this._numberFormatters={},this._path=new Q,this._dataListeners=[],this._exist=function(t,n){return!(!t||!n)&&!r(e._path.getPathValue(t,n))},this._initVM({locale:n,fallbackLocale:i,messages:a,dateTimeFormats:o,numberFormats:s})},et={vm:{configurable:!0},messages:{configurable:!0},dateTimeFormats:{configurable:!0},numberFormats:{configurable:!0},locale:{configurable:!0},fallbackLocale:{configurable:!0},missing:{configurable:!0},formatter:{configurable:!0},silentTranslationWarn:{configurable:!0}};return tt.prototype._initVM=function(t){var e=D.config.silent;D.config.silent=!0,this._vm=new D({data:t}),D.config.silent=e},tt.prototype.subscribeDataChanging=function(t){this._dataListeners.push(t)},tt.prototype.unsubscribeDataChanging=function(t){o(this._dataListeners,t)},tt.prototype.watchI18nData=function(){var t=this;return this._vm.$watch("$data",function(){for(var e=t._dataListeners.length;e--;)D.nextTick(function(){t._dataListeners[e]&&t._dataListeners[e].$forceUpdate()})},{deep:!0})},tt.prototype.watchLocale=function(){if(!this._sync||!this._root)return null;var t=this._vm;return this._root.$i18n.vm.$watch("locale",function(e){t.$set(t,"locale",e),t.$forceUpdate()},{immediate:!0})},et.vm.get=function(){return this._vm},et.messages.get=function(){return a(this._getMessages())},et.dateTimeFormats.get=function(){return a(this._getDateTimeFormats())},et.numberFormats.get=function(){return a(this._getNumberFormats())},et.locale.get=function(){return this._vm.locale},et.locale.set=function(t){this._vm.$set(this._vm,"locale",t)},et.fallbackLocale.get=function(){return this._vm.fallbackLocale},et.fallbackLocale.set=function(t){this._vm.$set(this._vm,"fallbackLocale",t)},et.missing.get=function(){return this._missing},et.missing.set=function(t){this._missing=t},et.formatter.get=function(){return this._formatter},et.formatter.set=function(t){this._formatter=t},et.silentTranslationWarn.get=function(){return this._silentTranslationWarn},et.silentTranslationWarn.set=function(t){this._silentTranslationWarn=t},tt.prototype._getMessages=function(){return this._vm.messages},tt.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats},tt.prototype._getNumberFormats=function(){return this._vm.numberFormats},tt.prototype._warnDefault=function(t,e,n,i,a){if(!r(n))return n;if(this._missing){var o=this._missing.apply(null,[t,e,i,a]);if("string"==typeof o)return o}return e},tt.prototype._isFallbackRoot=function(t){return!t&&!r(this._root)&&this._fallbackRoot},tt.prototype._interpolate=function(t,e,i,a,o,s,c){if(!e)return null;var l=this._path.getPathValue(e,i);if(Array.isArray(l)||n(l))return l;var u;if(r(l)){if(!n(e))return null;if("string"!=typeof(u=e[i]))return null}else{if("string"!=typeof l)return null;u=l}return u.indexOf("@:")>=0&&(u=this._link(t,e,u,a,o,s,c)),this._render(u,o,s)},tt.prototype._link=function(t,e,n,r,i,a,o){var s=this,c=n,l=c.match(Y);for(var u in l)if(l.hasOwnProperty(u)){var f=l[u],h=f.substr(2).replace(Z,"");if(o.includes(h))return c;o.push(h);var p=s._interpolate(t,e,h,r,"raw"===i?"string":i,"raw"===i?void 0:a,o);if(s._isFallbackRoot(p)){if(!s._root)throw Error("unexpected error");var m=s._root.$i18n;p=m._translate(m._getMessages(),m.locale,m.fallbackLocale,h,r,i,a)}p=s._warnDefault(t,h,p,r,Array.isArray(a)?a:[a]),o.pop(),c=p?c.replace(f,p):c}return c},tt.prototype._render=function(t,e,n){var r=this._formatter.interpolate(t,n);return"string"===e?r.join(""):r},tt.prototype._translate=function(t,e,n,i,a,o,s){var c=this._interpolate(e,t[e],i,a,o,s,[i]);return r(c)?(c=this._interpolate(n,t[n],i,a,o,s,[i]),r(c)?null:c):c},tt.prototype._t=function(t,e,n,r){for(var a,o=[],s=arguments.length-4;s-- >0;)o[s]=arguments[s+4];if(!t)return"";var c=i.apply(void 0,o),l=c.locale||e,u=this._translate(n,l,this.fallbackLocale,t,r,"string",c.params);if(this._isFallbackRoot(u)){if(!this._root)throw Error("unexpected error");return(a=this._root).$t.apply(a,[t].concat(o))}return this._warnDefault(l,t,u,r,o)},tt.prototype.t=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this)._t.apply(e,[t,this.locale,this._getMessages(),null].concat(n))},tt.prototype._i=function(t,e,n,r,i){var a=this._translate(n,e,this.fallbackLocale,t,r,"raw",i);if(this._isFallbackRoot(a)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.i(t,e,i)}return this._warnDefault(e,t,a,r,[i])},tt.prototype.i=function(t,e,n){return t?("string"!=typeof e&&(e=this.locale),this._i(t,e,this._getMessages(),null,n)):""},tt.prototype._tc=function(t,e,n,r,a){for(var o,s=[],c=arguments.length-5;c-- >0;)s[c]=arguments[c+5];if(!t)return"";void 0===a&&(a=1);var l={count:a,n:a},u=i.apply(void 0,s);return u.params=Object.assign(l,u.params),s=null===u.locale?[u.params]:[u.locale,u.params],this.fetchChoice((o=this)._t.apply(o,[t,e,n,r].concat(s)),a)},tt.prototype.fetchChoice=function(t,e){if(!t&&"string"!=typeof t)return null;var n=t.split("|");return e=this.getChoiceIndex(e,n.length),n[e]?n[e].trim():t},tt.prototype.getChoiceIndex=function(t,e){return t=Math.abs(t),2===e?t?t>1?1:0:1:t?Math.min(t,2):0},tt.prototype.tc=function(t,e){for(var n,r=[],i=arguments.length-2;i-- >0;)r[i]=arguments[i+2];return(n=this)._tc.apply(n,[t,this.locale,this._getMessages(),null,e].concat(r))},tt.prototype._te=function(t,e,n){for(var r=[],a=arguments.length-3;a-- >0;)r[a]=arguments[a+3];var o=i.apply(void 0,r).locale||e;return this._exist(n[o],t)},tt.prototype.te=function(t,e){return this._te(t,this.locale,this._getMessages(),e)},tt.prototype.getLocaleMessage=function(t){return a(this._vm.messages[t]||{})},tt.prototype.setLocaleMessage=function(t,e){this._vm.$set(this._vm.messages,t,e)},tt.prototype.mergeLocaleMessage=function(t,e){this._vm.$set(this._vm.messages,t,c(this._vm.messages[t]||{},e))},tt.prototype.getDateTimeFormat=function(t){return a(this._vm.dateTimeFormats[t]||{})},tt.prototype.setDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,e)},tt.prototype.mergeDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,c(this._vm.dateTimeFormats[t]||{},e))},tt.prototype._localizeDateTime=function(t,e,n,i,a){var o=e,s=i[o];if((r(s)||r(s[a]))&&(o=n,s=i[o]),r(s)||r(s[a]))return null;var c=s[a],l=o+"__"+a,u=this._dateTimeFormatters[l];return u||(u=this._dateTimeFormatters[l]=new Intl.DateTimeFormat(o,c)),u.format(t)},tt.prototype._d=function(t,e,n){if(!n)return new Intl.DateTimeFormat(e).format(t);var r=this._localizeDateTime(t,e,this.fallbackLocale,this._getDateTimeFormats(),n);if(this._isFallbackRoot(r)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.d(t,n,e)}return r||""},tt.prototype.d=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,a=null;return 1===n.length?"string"==typeof n[0]?a=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(a=n[0].key)):2===n.length&&("string"==typeof n[0]&&(a=n[0]),"string"==typeof n[1]&&(i=n[1])),this._d(t,i,a)},tt.prototype.getNumberFormat=function(t){return a(this._vm.numberFormats[t]||{})},tt.prototype.setNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,e)},tt.prototype.mergeNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,c(this._vm.numberFormats[t]||{},e))},tt.prototype._localizeNumber=function(t,e,n,i,a,o){var s=e,c=i[s];if((r(c)||r(c[a]))&&(s=n,c=i[s]),r(c)||r(c[a]))return null;var l,u=c[a];if(o)l=new Intl.NumberFormat(s,Object.assign({},u,o));else{var f=s+"__"+a;l=this._numberFormatters[f],l||(l=this._numberFormatters[f]=new Intl.NumberFormat(s,u))}return l.format(t)},tt.prototype._n=function(t,e,n,r){if(!tt.availabilities.numberFormat)return"";if(!n){return(r?new Intl.NumberFormat(e,r):new Intl.NumberFormat(e)).format(t)}var i=this._localizeNumber(t,e,this.fallbackLocale,this._getNumberFormats(),n,r);if(this._isFallbackRoot(i)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.n(t,Object.assign({},{key:n,locale:e},r))}return i||""},tt.prototype.n=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,a=null,o=null;return 1===n.length?"string"==typeof n[0]?a=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(a=n[0].key),o=Object.keys(n[0]).reduce(function(t,e){var r;return X.includes(e)?Object.assign({},t,(r={},r[e]=n[0][e],r)):t},null)):2===n.length&&("string"==typeof n[0]&&(a=n[0]),"string"==typeof n[1]&&(i=n[1])),this._n(t,i,a,o)},Object.defineProperties(tt.prototype,et),tt.availabilities={dateTimeFormat:A,numberFormat:j},tt.install=d,tt.version="8.3.2",tt});
6
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueI18n=e()}(this,function(){"use strict";function t(t,e){"undefined"!=typeof console&&(console.warn("[vue-i18n] "+t),e&&console.warn(e.stack))}function e(t){return null!==t&&"object"==typeof t}function n(t){return L.call(t)===O}function r(t){return null===t||void 0===t}function i(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var r=null,i=null;return 1===t.length?e(t[0])||Array.isArray(t[0])?i=t[0]:"string"==typeof t[0]&&(r=t[0]):2===t.length&&("string"==typeof t[0]&&(r=t[0]),(e(t[1])||Array.isArray(t[1]))&&(i=t[1])),{locale:r,params:i}}function a(t){return JSON.parse(JSON.stringify(t))}function o(t,e){if(t.length){var n=t.indexOf(e);if(n>-1)return t.splice(n,1)}}function s(t,e){return M.call(t,e)}function c(t){for(var n=arguments,r=Object(t),i=1;i<arguments.length;i++){var a=n[i];if(void 0!==a&&null!==a){var o=void 0;for(o in a)s(a,o)&&(e(a[o])?r[o]=c(r[o],a[o]):r[o]=a[o])}}return r}function l(t,n){if(t===n)return!0;var r=e(t),i=e(n);if(!r||!i)return!r&&!i&&String(t)===String(n);try{var a=Array.isArray(t),o=Array.isArray(n);if(a&&o)return t.length===n.length&&t.every(function(t,e){return l(t,n[e])});if(a||o)return!1;var s=Object.keys(t),c=Object.keys(n);return s.length===c.length&&s.every(function(e){return l(t[e],n[e])})}catch(t){return!1}}function u(t){t.prototype.hasOwnProperty("$i18n")||Object.defineProperty(t.prototype,"$i18n",{get:function(){return this._i18n}}),t.prototype.$t=function(t){for(var e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];var r=this.$i18n;return r._t.apply(r,[t,r.locale,r._getMessages(),this].concat(e))},t.prototype.$tc=function(t,e){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];var i=this.$i18n;return i._tc.apply(i,[t,i.locale,i._getMessages(),this,e].concat(n))},t.prototype.$te=function(t,e){var n=this.$i18n;return n._te(t,n.locale,n._getMessages(),e)},t.prototype.$d=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).d.apply(e,[t].concat(n))},t.prototype.$n=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this.$i18n).n.apply(e,[t].concat(n))}}function f(t,e,n){m(t,n)&&g(t,e,n)}function h(t,e,n,r){if(m(t,n)){var i=n.context.$i18n;_(t,n)&&l(e.value,e.oldValue)&&l(t._localeMessage,i.getLocaleMessage(i.locale))||g(t,e,n)}}function p(e,n,r,i){if(!r.context)return void t("Vue instance does not exists in VNode context");var a=r.context.$i18n||{};n.modifiers.preserve||a.preserveDirectiveContent||(e.textContent=""),e._vt=void 0,delete e._vt,e._locale=void 0,delete e._locale,e._localeMessage=void 0,delete e._localeMessage}function m(e,n){var r=n.context;return r?!!r.$i18n||(t("VueI18n instance does not exists in Vue instance"),!1):(t("Vue instance doest not exists in VNode context"),!1)}function _(t,e){var n=e.context;return t._locale===n.$i18n.locale}function g(e,n,r){var i,a,o=n.value,s=v(o),c=s.path,l=s.locale,u=s.args,f=s.choice;if(!c&&!l&&!u)return void t("value type not supported");if(!c)return void t("`path` is required in v-t directive");var h=r.context;e._vt=e.textContent=f?(i=h.$i18n).tc.apply(i,[c,f].concat(y(l,u))):(a=h.$i18n).t.apply(a,[c].concat(y(l,u))),e._locale=h.$i18n.locale,e._localeMessage=h.$i18n.getLocaleMessage(h.$i18n.locale)}function v(t){var e,r,i,a;return"string"==typeof t?e=t:n(t)&&(e=t.path,r=t.locale,i=t.args,a=t.choice),{path:e,locale:r,args:i,choice:a}}function y(t,e){var r=[];return t&&r.push(t),e&&(Array.isArray(e)||n(e))&&r.push(e),r}function d(t){d.installed=!0,T=t;T.version&&Number(T.version.split(".")[0]);u(T),T.mixin(A),T.directive("t",{bind:f,update:h,unbind:p}),T.component(C.name,C),T.config.optionMergeStrategies.i18n=function(t,e){return void 0===e?t:e}}function b(t){for(var e=[],n=0,r="";n<t.length;){var i=t[n++];if("{"===i){r&&e.push({type:"text",value:r}),r="";var a="";for(i=t[n++];void 0!==i&&"}"!==i;)a+=i,i=t[n++];var o="}"===i,s=N.test(a)?"list":o&&W.test(a)?"named":"unknown";e.push({value:a,type:s})}else"%"===i?"{"!==t[n]&&(r+=i):r+=i}return r&&e.push({type:"text",value:r}),e}function $(t,n){var r=[],i=0,a=Array.isArray(n)?"list":e(n)?"named":"unknown";if("unknown"===a)return r;for(;i<t.length;){var o=t[i];switch(o.type){case"text":r.push(o.value);break;case"list":r.push(n[parseInt(o.value,10)]);break;case"named":"named"===a&&r.push(n[o.value])}i++}return r}function w(t){return B.test(t)}function F(t){var e=t.charCodeAt(0);return e!==t.charCodeAt(t.length-1)||34!==e&&39!==e?t:t.slice(1,-1)}function k(t){if(void 0===t||null===t)return"eof";switch(t.charCodeAt(0)){case 91:case 93:case 46:case 34:case 39:return t;case 95:case 36:case 45:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return"ident"}function D(t){var e=t.trim();return("0"!==t.charAt(0)||!isNaN(t))&&(w(e)?F(e):"*"+e)}function x(t){var e,n,r,i,a,o,s,c=[],l=-1,u=z,f=0,h=[];for(h[R]=function(){void 0!==n&&(c.push(n),n=void 0)},h[I]=function(){void 0===n?n=r:n+=r},h[S]=function(){h[I](),f++},h[V]=function(){if(f>0)f--,u=P,h[I]();else{if(f=0,!1===(n=D(n)))return!1;h[R]()}};null!==u;)if(l++,"\\"!==(e=t[l])||!function(){var e=t[l+1];if(u===E&&"'"===e||u===U&&'"'===e)return l++,r="\\"+e,h[I](),!0}()){if(i=k(e),s=G[u],(a=s[i]||s.else||q)===q)return;if(u=a[0],(o=h[a[1]])&&(r=a[2],r=void 0===r?e:r,!1===o()))return;if(u===J)return c}}var T,L=Object.prototype.toString,O="[object Object]",M=Object.prototype.hasOwnProperty,A={beforeCreate:function(){var t=this.$options;if(t.i18n=t.i18n||(t.__i18n?{}:null),t.i18n){if(t.i18n instanceof et){if(t.__i18n)try{var e={};t.__i18n.forEach(function(t){e=c(e,JSON.parse(t))}),Object.keys(e).forEach(function(n){t.i18n.mergeLocaleMessage(n,e[n])})}catch(t){}this._i18n=t.i18n,this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0}else if(n(t.i18n)){if(this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof et&&(t.i18n.root=this.$root,t.i18n.formatter=this.$root.$i18n.formatter,t.i18n.fallbackLocale=this.$root.$i18n.fallbackLocale,t.i18n.silentTranslationWarn=this.$root.$i18n.silentTranslationWarn,t.i18n.pluralizationRules=this.$root.$i18n.pluralizationRules,t.i18n.preserveDirectiveContent=this.$root.$i18n.preserveDirectiveContent),t.__i18n)try{var r={};t.__i18n.forEach(function(t){r=c(r,JSON.parse(t))}),t.i18n.messages=r}catch(t){}this._i18n=new et(t.i18n),this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0,(void 0===t.i18n.sync||t.i18n.sync)&&(this._localeWatcher=this.$i18n.watchLocale())}}else this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof et?(this._i18n=this.$root.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0):t.parent&&t.parent.$i18n&&t.parent.$i18n instanceof et&&(this._i18n=t.parent.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0)},beforeDestroy:function(){this._i18n&&(this._subscribing&&(this._i18n.unsubscribeDataChanging(this),delete this._subscribing),this._i18nWatcher&&(this._i18nWatcher(),delete this._i18nWatcher),this._localeWatcher&&(this._localeWatcher(),delete this._localeWatcher),this._i18n=null)}},C={name:"i18n",functional:!0,props:{tag:{type:String,default:"span"},path:{type:String,required:!0},locale:{type:String},places:{type:[Array,Object]}},render:function(t,e){var n=e.props,r=e.data,i=e.children,a=e.parent,o=a.$i18n;if(i=(i||[]).filter(function(t){return t.tag||(t.text=t.text.trim())}),!o)return i;var s=n.path,c=n.locale,l={},u=n.places||{},f=(Array.isArray(u)?u.length:Object.keys(u).length,i.every(function(t){if(t.data&&t.data.attrs){var e=t.data.attrs.place;return void 0!==e&&""!==e}}));return Array.isArray(u)?u.forEach(function(t,e){l[e]=t}):Object.keys(u).forEach(function(t){l[t]=u[t]}),i.forEach(function(t,e){var n=f?""+t.data.attrs.place:""+e;l[n]=t}),t(n.tag,r,o.i(s,c,l))}},j=function(){this._caches=Object.create(null)};j.prototype.interpolate=function(t,e){if(!e)return[t];var n=this._caches[t];return n||(n=b(t),this._caches[t]=n),$(n,e)};var N=/^(?:\d)+/,W=/^(?:\w)+/,I=0,R=1,S=2,V=3,z=0,P=4,E=5,U=6,J=7,q=8,G=[];G[z]={ws:[z],ident:[3,I],"[":[P],eof:[J]},G[1]={ws:[1],".":[2],"[":[P],eof:[J]},G[2]={ws:[2],ident:[3,I],0:[3,I],number:[3,I]},G[3]={ident:[3,I],0:[3,I],number:[3,I],ws:[1,R],".":[2,R],"[":[P,R],eof:[J,R]},G[P]={"'":[E,I],'"':[U,I],"[":[P,S],"]":[1,V],eof:q,else:[P,I]},G[E]={"'":[P,I],eof:q,else:[E,I]},G[U]={'"':[P,I],eof:q,else:[U,I]};var B=/^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/,H=function(){this._cache=Object.create(null)};H.prototype.parsePath=function(t){var e=this._cache[t];return e||(e=x(t))&&(this._cache[t]=e),e||[]},H.prototype.getPathValue=function(t,n){if(!e(t))return null;var r=this.parsePath(n);if(0===r.length)return null;for(var i=r.length,a=t,o=0;o<i;){var s=a[r[o]];if(void 0===s)return null;a=s,o++}return a};var K=["style","currency","currencyDisplay","useGrouping","minimumIntegerDigits","minimumFractionDigits","maximumFractionDigits","minimumSignificantDigits","maximumSignificantDigits","localeMatcher","formatMatcher"],Q=/(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g,X=/^@(?:\.([a-z]+))?:/,Y=/[()]/g,Z={upper:function(t){return t.toLocaleUpperCase()},lower:function(t){return t.toLocaleLowerCase()}},tt=new j,et=function(t){var e=this;void 0===t&&(t={}),!T&&"undefined"!=typeof window&&window.Vue&&d(window.Vue);var n=t.locale||"en-US",i=t.fallbackLocale||"en-US",a=t.messages||{},o=t.dateTimeFormats||{},s=t.numberFormats||{};this._vm=null,this._formatter=t.formatter||tt,this._missing=t.missing||null,this._root=t.root||null,this._sync=void 0===t.sync||!!t.sync,this._fallbackRoot=void 0===t.fallbackRoot||!!t.fallbackRoot,this._silentTranslationWarn=void 0!==t.silentTranslationWarn&&!!t.silentTranslationWarn,this._dateTimeFormatters={},this._numberFormatters={},this._path=new H,this._dataListeners=[],this.pluralizationRules=t.pluralizationRules||{},this.preserveDirectiveContent=void 0!==t.preserveDirectiveContent&&!!t.preserveDirectiveContent,this._exist=function(t,n){return!(!t||!n)&&!r(e._path.getPathValue(t,n))},this._initVM({locale:n,fallbackLocale:i,messages:a,dateTimeFormats:o,numberFormats:s})},nt={vm:{configurable:!0},messages:{configurable:!0},dateTimeFormats:{configurable:!0},numberFormats:{configurable:!0},locale:{configurable:!0},fallbackLocale:{configurable:!0},missing:{configurable:!0},formatter:{configurable:!0},silentTranslationWarn:{configurable:!0}};et.prototype._initVM=function(t){var e=T.config.silent;T.config.silent=!0,this._vm=new T({data:t}),T.config.silent=e},et.prototype.subscribeDataChanging=function(t){this._dataListeners.push(t)},et.prototype.unsubscribeDataChanging=function(t){o(this._dataListeners,t)},et.prototype.watchI18nData=function(){var t=this;return this._vm.$watch("$data",function(){for(var e=t._dataListeners.length;e--;)T.nextTick(function(){t._dataListeners[e]&&t._dataListeners[e].$forceUpdate()})},{deep:!0})},et.prototype.watchLocale=function(){if(!this._sync||!this._root)return null;var t=this._vm;return this._root.$i18n.vm.$watch("locale",function(e){t.$set(t,"locale",e),t.$forceUpdate()},{immediate:!0})},nt.vm.get=function(){return this._vm},nt.messages.get=function(){return a(this._getMessages())},nt.dateTimeFormats.get=function(){return a(this._getDateTimeFormats())},nt.numberFormats.get=function(){return a(this._getNumberFormats())},nt.locale.get=function(){return this._vm.locale},nt.locale.set=function(t){this._vm.$set(this._vm,"locale",t)},nt.fallbackLocale.get=function(){return this._vm.fallbackLocale},nt.fallbackLocale.set=function(t){this._vm.$set(this._vm,"fallbackLocale",t)},nt.missing.get=function(){return this._missing},nt.missing.set=function(t){this._missing=t},nt.formatter.get=function(){return this._formatter},nt.formatter.set=function(t){this._formatter=t},nt.silentTranslationWarn.get=function(){return this._silentTranslationWarn},nt.silentTranslationWarn.set=function(t){this._silentTranslationWarn=t},et.prototype._getMessages=function(){return this._vm.messages},et.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats},et.prototype._getNumberFormats=function(){return this._vm.numberFormats},et.prototype._warnDefault=function(t,e,n,i,a){if(!r(n))return n;if(this._missing){var o=this._missing.apply(null,[t,e,i,a]);if("string"==typeof o)return o}return e},et.prototype._isFallbackRoot=function(t){return!t&&!r(this._root)&&this._fallbackRoot},et.prototype._interpolate=function(t,e,i,a,o,s,c){if(!e)return null;var l=this._path.getPathValue(e,i);if(Array.isArray(l)||n(l))return l;var u;if(r(l)){if(!n(e))return null;if("string"!=typeof(u=e[i]))return null}else{if("string"!=typeof l)return null;u=l}return(u.indexOf("@:")>=0||u.indexOf("@.")>=0)&&(u=this._link(t,e,u,a,o,s,c)),this._render(u,o,s,i)},et.prototype._link=function(t,e,n,r,i,a,o){var s=this,c=n,l=c.match(Q);for(var u in l)if(l.hasOwnProperty(u)){var f=l[u],h=f.match(X),p=h[0],m=h[1],_=f.replace(p,"").replace(Y,"");if(o.includes(_))return c;o.push(_);var g=s._interpolate(t,e,_,r,"raw"===i?"string":i,"raw"===i?void 0:a,o);if(s._isFallbackRoot(g)){if(!s._root)throw Error("unexpected error");var v=s._root.$i18n;g=v._translate(v._getMessages(),v.locale,v.fallbackLocale,_,r,i,a)}g=s._warnDefault(t,_,g,r,Array.isArray(a)?a:[a]),Z.hasOwnProperty(m)&&(g=Z[m](g)),o.pop(),c=g?c.replace(f,g):c}return c},et.prototype._render=function(t,e,n,r){var i=this._formatter.interpolate(t,n,r);return i||(i=tt.interpolate(t,n,r)),"string"===e?i.join(""):i},et.prototype._translate=function(t,e,n,i,a,o,s){var c=this._interpolate(e,t[e],i,a,o,s,[i]);return r(c)?(c=this._interpolate(n,t[n],i,a,o,s,[i]),r(c)?null:c):c},et.prototype._t=function(t,e,n,r){for(var a,o=[],s=arguments.length-4;s-- >0;)o[s]=arguments[s+4];if(!t)return"";var c=i.apply(void 0,o),l=c.locale||e,u=this._translate(n,l,this.fallbackLocale,t,r,"string",c.params);if(this._isFallbackRoot(u)){if(!this._root)throw Error("unexpected error");return(a=this._root).$t.apply(a,[t].concat(o))}return this._warnDefault(l,t,u,r,o)},et.prototype.t=function(t){for(var e,n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(e=this)._t.apply(e,[t,this.locale,this._getMessages(),null].concat(n))},et.prototype._i=function(t,e,n,r,i){var a=this._translate(n,e,this.fallbackLocale,t,r,"raw",i);if(this._isFallbackRoot(a)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.i(t,e,i)}return this._warnDefault(e,t,a,r,[i])},et.prototype.i=function(t,e,n){return t?("string"!=typeof e&&(e=this.locale),this._i(t,e,this._getMessages(),null,n)):""},et.prototype._tc=function(t,e,n,r,a){for(var o,s=[],c=arguments.length-5;c-- >0;)s[c]=arguments[c+5];if(!t)return"";void 0===a&&(a=1);var l={count:a,n:a},u=i.apply(void 0,s);return u.params=Object.assign(l,u.params),s=null===u.locale?[u.params]:[u.locale,u.params],this.fetchChoice((o=this)._t.apply(o,[t,e,n,r].concat(s)),a)},et.prototype.fetchChoice=function(t,e){if(!t&&"string"!=typeof t)return null;var n=t.split("|");return e=this.getChoiceIndex(e,n.length),n[e]?n[e].trim():t},et.prototype.getChoiceIndex=function(t,e){return this.locale in this.pluralizationRules?this.pluralizationRules[this.locale].apply(this,[t,e]):function(t,e){return t=Math.abs(t),2===e?t?t>1?1:0:1:t?Math.min(t,2):0}(t,e)},et.prototype.tc=function(t,e){for(var n,r=[],i=arguments.length-2;i-- >0;)r[i]=arguments[i+2];return(n=this)._tc.apply(n,[t,this.locale,this._getMessages(),null,e].concat(r))},et.prototype._te=function(t,e,n){for(var r=[],a=arguments.length-3;a-- >0;)r[a]=arguments[a+3];var o=i.apply(void 0,r).locale||e;return this._exist(n[o],t)},et.prototype.te=function(t,e){return this._te(t,this.locale,this._getMessages(),e)},et.prototype.getLocaleMessage=function(t){return a(this._vm.messages[t]||{})},et.prototype.setLocaleMessage=function(t,e){this._vm.$set(this._vm.messages,t,e)},et.prototype.mergeLocaleMessage=function(t,e){this._vm.$set(this._vm.messages,t,c(this._vm.messages[t]||{},e))},et.prototype.getDateTimeFormat=function(t){return a(this._vm.dateTimeFormats[t]||{})},et.prototype.setDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,e)},et.prototype.mergeDateTimeFormat=function(t,e){this._vm.$set(this._vm.dateTimeFormats,t,c(this._vm.dateTimeFormats[t]||{},e))},et.prototype._localizeDateTime=function(t,e,n,i,a){var o=e,s=i[o];if((r(s)||r(s[a]))&&(o=n,s=i[o]),r(s)||r(s[a]))return null;var c=s[a],l=o+"__"+a,u=this._dateTimeFormatters[l];return u||(u=this._dateTimeFormatters[l]=new Intl.DateTimeFormat(o,c)),u.format(t)},et.prototype._d=function(t,e,n){if(!n)return new Intl.DateTimeFormat(e).format(t);var r=this._localizeDateTime(t,e,this.fallbackLocale,this._getDateTimeFormats(),n);if(this._isFallbackRoot(r)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.d(t,n,e)}return r||""},et.prototype.d=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,a=null;return 1===n.length?"string"==typeof n[0]?a=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(a=n[0].key)):2===n.length&&("string"==typeof n[0]&&(a=n[0]),"string"==typeof n[1]&&(i=n[1])),this._d(t,i,a)},et.prototype.getNumberFormat=function(t){return a(this._vm.numberFormats[t]||{})},et.prototype.setNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,e)},et.prototype.mergeNumberFormat=function(t,e){this._vm.$set(this._vm.numberFormats,t,c(this._vm.numberFormats[t]||{},e))},et.prototype._localizeNumber=function(t,e,n,i,a,o){var s=e,c=i[s];if((r(c)||r(c[a]))&&(s=n,c=i[s]),r(c)||r(c[a]))return null;var l,u=c[a];if(o)l=new Intl.NumberFormat(s,Object.assign({},u,o));else{var f=s+"__"+a;l=this._numberFormatters[f],l||(l=this._numberFormatters[f]=new Intl.NumberFormat(s,u))}return l.format(t)},et.prototype._n=function(t,e,n,r){if(!et.availabilities.numberFormat)return"";if(!n){return(r?new Intl.NumberFormat(e,r):new Intl.NumberFormat(e)).format(t)}var i=this._localizeNumber(t,e,this.fallbackLocale,this._getNumberFormats(),n,r);if(this._isFallbackRoot(i)){if(!this._root)throw Error("unexpected error");return this._root.$i18n.n(t,Object.assign({},{key:n,locale:e},r))}return i||""},et.prototype.n=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,a=null,o=null;return 1===n.length?"string"==typeof n[0]?a=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(a=n[0].key),o=Object.keys(n[0]).reduce(function(t,e){var r;return K.includes(e)?Object.assign({},t,(r={},r[e]=n[0][e],r)):t},null)):2===n.length&&("string"==typeof n[0]&&(a=n[0]),"string"==typeof n[1]&&(i=n[1])),this._n(t,i,a,o)},Object.defineProperties(et.prototype,nt);var rt;return Object.defineProperty(et,"availabilities",{get:function(){if(!rt){var t="undefined"!=typeof Intl;rt={dateTimeFormat:t&&void 0!==Intl.DateTimeFormat,numberFormat:t&&void 0!==Intl.NumberFormat}}return rt}}),et.install=d,et.version="8.7.0",et});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vue-i18n",
3
3
  "description": "Internationalization plugin for Vue.js",
4
- "version": "8.3.2",
4
+ "version": "8.7.0",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
package/src/directive.js CHANGED
@@ -26,7 +26,10 @@ export function unbind (el: any, binding: Object, vnode: any, oldVNode: any): vo
26
26
  return
27
27
  }
28
28
 
29
- el.textContent = ''
29
+ const i18n: any = vnode.context.$i18n || {}
30
+ if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
31
+ el.textContent = ''
32
+ }
30
33
  el._vt = undefined
31
34
  delete el['_vt']
32
35
  el._locale = undefined
package/src/index.js CHANGED
@@ -9,9 +9,7 @@ import {
9
9
  isObject,
10
10
  looseClone,
11
11
  remove,
12
- merge,
13
- canUseDateTimeFormat,
14
- canUseNumberFormat
12
+ merge
15
13
  } from './util'
16
14
  import BaseFormatter from './format'
17
15
  import I18nPath from './path'
@@ -31,8 +29,15 @@ const numberFormatKeys = [
31
29
  'localeMatcher',
32
30
  'formatMatcher'
33
31
  ]
34
- const linkKeyMatcher = /(?:@:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g
32
+ const linkKeyMatcher = /(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))/g
33
+ const linkKeyPrefixMatcher = /^@(?:\.([a-z]+))?:/
35
34
  const bracketsMatcher = /[()]/g
35
+ const formatters = {
36
+ 'upper': (str) => str.toLocaleUpperCase(),
37
+ 'lower': (str) => str.toLocaleLowerCase()
38
+ }
39
+
40
+ const defaultFormatter = new BaseFormatter()
36
41
 
37
42
  export default class VueI18n {
38
43
  static install: () => void
@@ -53,6 +58,10 @@ export default class VueI18n {
53
58
  _numberFormatters: Object
54
59
  _path: I18nPath
55
60
  _dataListeners: Array<any>
61
+ pluralizationRules: {
62
+ [lang: string]: (choice: number, choicesLength: number) => number
63
+ }
64
+ preserveDirectiveContent: boolean
56
65
 
57
66
  constructor (options: I18nOptions = {}) {
58
67
  // Auto install if it is not done yet and `window` has `Vue`.
@@ -70,7 +79,7 @@ export default class VueI18n {
70
79
  const numberFormats = options.numberFormats || {}
71
80
 
72
81
  this._vm = null
73
- this._formatter = options.formatter || new BaseFormatter()
82
+ this._formatter = options.formatter || defaultFormatter
74
83
  this._missing = options.missing || null
75
84
  this._root = options.root || null
76
85
  this._sync = options.sync === undefined ? true : !!options.sync
@@ -85,6 +94,11 @@ export default class VueI18n {
85
94
  this._path = new I18nPath()
86
95
  this._dataListeners = []
87
96
 
97
+ this.pluralizationRules = options.pluralizationRules || {}
98
+ this.preserveDirectiveContent = options.preserveDirectiveContent === undefined
99
+ ? false
100
+ : !!options.preserveDirectiveContent
101
+
88
102
  this._exist = (message: Object, key: Path): boolean => {
89
103
  if (!message || !key) { return false }
90
104
  return !isNull(this._path.getPathValue(message, key))
@@ -234,11 +248,11 @@ export default class VueI18n {
234
248
  }
235
249
 
236
250
  // Check for the existence of links within the translated string
237
- if (ret.indexOf('@:') >= 0) {
251
+ if (ret.indexOf('@:') >= 0 || ret.indexOf('@.') >= 0) {
238
252
  ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack)
239
253
  }
240
254
 
241
- return this._render(ret, interpolateMode, values)
255
+ return this._render(ret, interpolateMode, values, key)
242
256
  }
243
257
 
244
258
  _link (
@@ -263,8 +277,11 @@ export default class VueI18n {
263
277
  continue
264
278
  }
265
279
  const link: string = matches[idx]
266
- // Remove the leading @: and the brackets
267
- const linkPlaceholder: string = link.substr(2).replace(bracketsMatcher, '')
280
+ const linkKeyPrefixMatches: any = link.match(linkKeyPrefixMatcher)
281
+ const [linkPrefix, formatterName] = linkKeyPrefixMatches
282
+
283
+ // Remove the leading @:, @.case: and the brackets
284
+ const linkPlaceholder: string = link.replace(linkPrefix, '').replace(bracketsMatcher, '')
268
285
 
269
286
  if (visitedLinkStack.includes(linkPlaceholder)) {
270
287
  if (process.env.NODE_ENV !== 'production') {
@@ -298,6 +315,9 @@ export default class VueI18n {
298
315
  locale, linkPlaceholder, translated, host,
299
316
  Array.isArray(values) ? values : [values]
300
317
  )
318
+ if (formatters.hasOwnProperty(formatterName)) {
319
+ translated = formatters[formatterName](translated)
320
+ }
301
321
 
302
322
  visitedLinkStack.pop()
303
323
 
@@ -308,8 +328,14 @@ export default class VueI18n {
308
328
  return ret
309
329
  }
310
330
 
311
- _render (message: string, interpolateMode: string, values: any): any {
312
- const ret = this._formatter.interpolate(message, values)
331
+ _render (message: string, interpolateMode: string, values: any, path: string): any {
332
+ let ret = this._formatter.interpolate(message, values, path)
333
+
334
+ // If the custom formatter refuses to work - apply the default one
335
+ if (!ret) {
336
+ ret = defaultFormatter.interpolate(message, values, path)
337
+ }
338
+
313
339
  // if interpolateMode is **not** 'string' ('row'),
314
340
  // return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
315
341
  return interpolateMode === 'string' ? ret.join('') : ret
@@ -426,17 +452,26 @@ export default class VueI18n {
426
452
  * @returns a final choice index
427
453
  */
428
454
  getChoiceIndex (choice: number, choicesLength: number): number {
429
- choice = Math.abs(choice)
430
-
431
- if (choicesLength === 2) {
432
- return choice
433
- ? choice > 1
434
- ? 1
435
- : 0
436
- : 1
455
+ // Default (old) getChoiceIndex implementation - english-compatible
456
+ const defaultImpl = (_choice: number, _choicesLength: number) => {
457
+ _choice = Math.abs(_choice)
458
+
459
+ if (_choicesLength === 2) {
460
+ return _choice
461
+ ? _choice > 1
462
+ ? 1
463
+ : 0
464
+ : 1
465
+ }
466
+
467
+ return _choice ? Math.min(_choice, 2) : 0
437
468
  }
438
469
 
439
- return choice ? Math.min(choice, 2) : 0
470
+ if (this.locale in this.pluralizationRules) {
471
+ return this.pluralizationRules[this.locale].apply(this, [choice, choicesLength])
472
+ } else {
473
+ return defaultImpl(choice, choicesLength)
474
+ }
440
475
  }
441
476
 
442
477
  tc (key: Path, choice?: number, ...values: any): TranslateResult {
@@ -488,7 +523,7 @@ export default class VueI18n {
488
523
 
489
524
  // fallback locale
490
525
  if (isNull(formats) || isNull(formats[key])) {
491
- if (process.env.NODE_ENV !== 'production') {
526
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
492
527
  warn(`Fall back to '${fallback}' datetime formats from '${locale} datetime formats.`)
493
528
  }
494
529
  _locale = fallback
@@ -522,7 +557,7 @@ export default class VueI18n {
522
557
  const ret: ?DateTimeFormatResult =
523
558
  this._localizeDateTime(value, locale, this.fallbackLocale, this._getDateTimeFormats(), key)
524
559
  if (this._isFallbackRoot(ret)) {
525
- if (process.env.NODE_ENV !== 'production') {
560
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
526
561
  warn(`Fall back to datetime localization of root: key '${key}' .`)
527
562
  }
528
563
  /* istanbul ignore if */
@@ -585,7 +620,7 @@ export default class VueI18n {
585
620
 
586
621
  // fallback locale
587
622
  if (isNull(formats) || isNull(formats[key])) {
588
- if (process.env.NODE_ENV !== 'production') {
623
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
589
624
  warn(`Fall back to '${fallback}' number formats from '${locale} number formats.`)
590
625
  }
591
626
  _locale = fallback
@@ -629,7 +664,7 @@ export default class VueI18n {
629
664
  const ret: ?NumberFormatResult =
630
665
  this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options)
631
666
  if (this._isFallbackRoot(ret)) {
632
- if (process.env.NODE_ENV !== 'production') {
667
+ if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
633
668
  warn(`Fall back to number localization of root: key '${key}' .`)
634
669
  }
635
670
  /* istanbul ignore if */
@@ -677,9 +712,20 @@ export default class VueI18n {
677
712
  }
678
713
  }
679
714
 
680
- VueI18n.availabilities = {
681
- dateTimeFormat: canUseDateTimeFormat,
682
- numberFormat: canUseNumberFormat
683
- }
715
+ let availabilities: IntlAvailability
716
+ // $FlowFixMe
717
+ Object.defineProperty(VueI18n, 'availabilities', {
718
+ get () {
719
+ if (!availabilities) {
720
+ const intlDefined = typeof Intl !== 'undefined'
721
+ availabilities = {
722
+ dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
723
+ numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
724
+ }
725
+ }
726
+
727
+ return availabilities
728
+ }
729
+ })
684
730
  VueI18n.install = install
685
731
  VueI18n.version = '__VERSION__'
package/src/mixin.js CHANGED
@@ -37,6 +37,8 @@ export default {
37
37
  options.i18n.formatter = this.$root.$i18n.formatter
38
38
  options.i18n.fallbackLocale = this.$root.$i18n.fallbackLocale
39
39
  options.i18n.silentTranslationWarn = this.$root.$i18n.silentTranslationWarn
40
+ options.i18n.pluralizationRules = this.$root.$i18n.pluralizationRules
41
+ options.i18n.preserveDirectiveContent = this.$root.$i18n.preserveDirectiveContent
40
42
  }
41
43
 
42
44
  // init locale messages via custom blocks
package/src/util.js CHANGED
@@ -120,9 +120,3 @@ export function looseEqual (a: any, b: any): boolean {
120
120
  return false
121
121
  }
122
122
  }
123
-
124
- export const canUseDateTimeFormat: boolean =
125
- typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined'
126
-
127
- export const canUseNumberFormat: boolean =
128
- typeof Intl !== 'undefined' && typeof Intl.NumberFormat !== 'undefined'
package/types/index.d.ts CHANGED
@@ -10,43 +10,67 @@ declare namespace VueI18n {
10
10
  interface LocaleMessageArray { [index: number]: LocaleMessage; }
11
11
  interface LocaleMessages { [key: string]: LocaleMessageObject; }
12
12
  type TranslateResult = string | LocaleMessages;
13
- interface DateTimeFormatOptions {
14
- year?: string;
15
- month?: string;
16
- day?: string;
17
- hour?: string;
18
- minute?: string;
19
- second?: string;
20
- weekday?: string;
21
- hour12?: boolean;
22
- era?: string;
23
- timeZone?: string;
24
- timeZoneName?: string;
25
- localeMatcher?: string;
26
- formatMatcher?: string;
13
+
14
+ type LocaleMatcher = 'lookup' | 'best-fit';
15
+ type FormatMatcher = 'basic' | 'best-fit';
16
+
17
+ type DateTimeHumanReadable = 'long' | 'short' | 'narrow';
18
+ type DateTimeDigital = 'numeric' | '2-digit';
19
+
20
+ interface SpecificDateTimeFormatOptions extends Intl.DateTimeFormatOptions {
21
+ year?: DateTimeDigital;
22
+ month?: DateTimeDigital | DateTimeHumanReadable;
23
+ day?: DateTimeDigital;
24
+ hour?: DateTimeDigital;
25
+ minute?: DateTimeDigital;
26
+ second?: DateTimeDigital;
27
+ weekday?: DateTimeHumanReadable;
28
+ era?: DateTimeHumanReadable;
29
+ timeZoneName?: 'long' | 'short';
30
+ localeMatcher?: LocaleMatcher;
31
+ formatMatcher?: FormatMatcher;
27
32
  }
33
+
34
+ type DateTimeFormatOptions = Intl.DateTimeFormatOptions | SpecificDateTimeFormatOptions;
35
+
28
36
  interface DateTimeFormat { [key: string]: DateTimeFormatOptions; }
29
- interface DateTimeFormats { [key: string]: DateTimeFormat; }
37
+ interface DateTimeFormats { [locale: string]: DateTimeFormat; }
30
38
  type DateTimeFormatResult = string;
31
- interface NumberFormatOptions {
32
- style?: string;
39
+
40
+ type CurrencyDisplay = 'symbol' | 'code' | 'name';
41
+
42
+ interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions {
43
+ style?: 'decimal' | 'percent';
33
44
  currency?: string;
34
- currencyDisplay?: string;
35
- useGrouping?: boolean;
36
- minimumIntegerDigits?: number;
37
- minimumFractionDigits?: number;
38
- maximumFractionDigits?: number;
39
- minimumSignificantDigits?: number;
40
- maximumSignificantDigits?: number;
41
- localeMatcher?: string;
42
- formatMatcher?: string;
45
+ currencyDisplay?: CurrencyDisplay;
46
+ localeMatcher?: LocaleMatcher;
47
+ formatMatcher?: FormatMatcher;
43
48
  }
49
+
50
+ interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions {
51
+ style: 'currency';
52
+ currency: string; // Obligatory if style is 'currency'
53
+ currencyDisplay?: CurrencyDisplay;
54
+ localeMatcher?: LocaleMatcher;
55
+ formatMatcher?: FormatMatcher;
56
+ }
57
+
58
+ type NumberFormatOptions = Intl.NumberFormatOptions | SpecificNumberFormatOptions | CurrencyNumberFormatOptions;
59
+
44
60
  interface NumberFormat { [key: string]: NumberFormatOptions; }
45
- interface NumberFormats { [key: string]: NumberFormat; }
61
+ interface NumberFormats { [locale: string]: NumberFormat; }
46
62
  type NumberFormatResult = string;
63
+ type PluralizationRulesMap = {
64
+ /**
65
+ * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
66
+ * @param choicesLength {number} an overall amount of available choices
67
+ * @returns a final choice index
68
+ */
69
+ [lang: string]: (choice: number, choicesLength: number) => number;
70
+ };
47
71
 
48
72
  interface Formatter {
49
- interpolate(message: string, values?: Values): any[];
73
+ interpolate(message: string, values: Values | undefined, path: string): (any[] | null);
50
74
  }
51
75
 
52
76
  type MissingHandler = (locale: Locale, key: Path, vm?: Vue) => string | void;
@@ -68,6 +92,8 @@ declare namespace VueI18n {
68
92
  fallbackRoot?: boolean;
69
93
  sync?: boolean;
70
94
  silentTranslationWarn?: boolean;
95
+ pluralizationRules?: PluralizationRulesMap;
96
+ preserveDirectiveContent?: boolean;
71
97
  }
72
98
  }
73
99
 
@@ -103,6 +129,8 @@ export declare interface IVueI18n {
103
129
  missing: VueI18n.MissingHandler;
104
130
  formatter: VueI18n.Formatter;
105
131
  silentTranslationWarn: boolean;
132
+ pluralizationRules: VueI18n.PluralizationRulesMap;
133
+ preserveDirectiveContent: boolean;
106
134
  }
107
135
 
108
136
  declare class VueI18n {